diff --git a/merchant/base.go b/merchant/base.go new file mode 100644 index 0000000..2d6ba8f --- /dev/null +++ b/merchant/base.go @@ -0,0 +1,81 @@ +package merchant + +import ( + "strings" +) + +// BaseRequest is base struct for api request +type BaseRequest struct { + Method string `url:"METHOD"` + Action string `url:"PAYMENTREQUEST_0_PAYMENTACTION,omitempty"` +} + +// BaseResponse is base struct for api response +type BaseResponse struct { + Timestamp string `url:"TIMESTAMP"` + ACK string `url:"ACK"` + Version string `url:"VERSION"` + Build string `url:"BUILD"` + CorrelationID string `url:"CORRELATIONID"` + + // error0 + ErrorCode string `url:"L_ERRORCODE0"` + ShortMessage string `url:"L_SHORTMESSAGE0"` + LongMessage string `url:"L_LONGMESSAGE0"` + SeverityCode string `url:"L_SEVERITYCODE0"` + + // error1 + ErrorCode1 string `url:"L_ERRORCODE1"` + ShortMessage1 string `url:"L_SHORTMESSAGE1"` + LongMessage1 string `url:"L_LONGMESSAGE1"` + SeverityCode1 string `url:"L_SEVERITYCODE1"` +} + +func (r BaseResponse) baseError() []string { + var errs []string + if r.ShortMessage != "" { + errs = append(errs, r.ShortMessage+" "+r.LongMessage) + } + if r.ShortMessage1 != "" { + errs = append(errs, r.ShortMessage1+" "+r.LongMessage1) + } + return errs +} + +// Error returns error message +func (r BaseResponse) Error() string { + return parseErrors(r.baseError()) +} + +// Errors returns error messages +func (r BaseResponse) Errors(s []string) string { + errs := r.baseError() + errs = append(errs, s...) + return parseErrors(errs) +} + +func parseErrors(errs []string) string { + return strings.Join(errs, ",") +} + +// MerchantResponse is interface of response from each API +type MerchantResponse interface { + IsSuccess() bool + IsRequestSuccess() bool + IsOperationSuccess() bool + Error() string +} + +// ShippingResponse is for shipping information +type ShippingResponse struct { + ShipToName string `url:"SHIPTONAME"` + ShipToStreet string `url:"SHIPTOSTREET"` + ShipToCity string `url:"SHIPTOCITY"` + ShipToState string `url:"SHIPTOSTATE"` + ShipToZip string `url:"SHIPTOZIP"` + ShipToCountryCode string `url:"SHIPTOCOUNTRYCODE"` + ShipToCountry string `url:"SHIPTOCOUNTRY"` + ShipToCountryName string `url:"SHIPTOCOUNTRYNAME"` + ShipAddressOwner string `url:"SHIPADDRESSOWNER"` + ShipAddressStatus string `url:"SHIPADDRESSSTATUS"` +} diff --git a/merchant/client.go b/merchant/client.go index 84b1425..d92f08d 100644 --- a/merchant/client.go +++ b/merchant/client.go @@ -1,8 +1,6 @@ package merchant import ( - "strings" - "github.com/evalphobia/go-paypal-classic/config" "github.com/evalphobia/go-paypal-classic/request" ) @@ -21,10 +19,11 @@ const ( itemCategoryDigital = "Digital" billingTypeRecurring = "RecurringPayments" - ackSuccess = "Success" - ackFailure = "Failure" - statusActive = "Active" - profileActive = "ActiveProfile" + ackSuccess = "Success" + ackFailure = "Failure" + statusActive = "Active" + profileActive = "ActiveProfile" + paymentStatusComleted = "Completed" ) // Merchant is base struct for PayPal Classic API @@ -65,62 +64,3 @@ func (m Merchant) redirectBase() string { } return redirectSandbox } - -// BaseRequest is base struct for api request -type BaseRequest struct { - Method string `url:"METHOD"` - Action string `url:"PAYMENTREQUEST_0_PAYMENTACTION,omitempty"` -} - -type BaseResponse struct { - Timestamp string `url:"TIMESTAMP"` - ACK string `url:"ACK"` - Version string `url:"VERSION"` - Build string `url:"BUILD"` - CorrelationID string `url:"CORRELATIONID"` - - // error0 - ErrorCode string `url:"L_ERRORCODE0"` - ShortMessage string `url:"L_SHORTMESSAGE0"` - LongMessage string `url:"L_LONGMESSAGE0"` - SeverityCode string `url:"L_SEVERITYCODE0"` - - // error1 - ErrorCode1 string `url:"L_ERRORCODE1"` - ShortMessage1 string `url:"L_SHORTMESSAGE1"` - LongMessage1 string `url:"L_LONGMESSAGE1"` - SeverityCode1 string `url:"L_SEVERITYCODE1"` -} - -func (r BaseResponse) baseError() []string { - var errs []string - if r.ShortMessage != "" { - errs = append(errs, r.ShortMessage+" "+r.LongMessage) - } - if r.ShortMessage1 != "" { - errs = append(errs, r.ShortMessage1+" "+r.LongMessage1) - } - return errs -} - -func (r BaseResponse) Error() string { - return parseErrors(r.baseError()) -} - -func (r BaseResponse) Errors(s []string) string { - errs := r.baseError() - errs = append(errs, s...) - return parseErrors(errs) -} - -func parseErrors(errs []string) string { - return strings.Join(errs, ",") -} - -// MerchantResponse is interface of response from each API -type MerchantResponse interface { - IsSuccess() bool - IsRequestSuccess() bool - IsOperationSuccess() bool - Error() string -} diff --git a/merchant/get_recurring_payments_profile_detail.go b/merchant/get_recurring_payments_profile_detail.go index 7af4263..39b1a83 100644 --- a/merchant/get_recurring_payments_profile_detail.go +++ b/merchant/get_recurring_payments_profile_detail.go @@ -64,17 +64,10 @@ type GetRecurringPaymentsProfileDetailsResponse struct { RegularShippingAmount string `url:"REGULARSHIPPINGAMT"` RegularTaxAmount string `url:"REGULARTAXAMT"` - ShipToStreet string `url:"SHIPTOSTREET"` - ShipToCity string `url:"SHIPTOCITY"` - ShipToState string `url:"SHIPTOSTATE"` - ShipToZip string `url:"SHIPTOZIP"` - ShipToCountryCode string `url:"SHIPTOCOUNTRYCODE"` - ShipToCountry string `url:"SHIPTOCOUNTRY"` - ShipToCountryName string `url:"SHIPTOCOUNTRYNAME"` - ShipAddressOwner string `url:"SHIPADDRESSOWNER"` - ShipAddressStatus string `url:"SHIPADDRESSSTATUS"` + ShippingResponse `url:",squash"` } +// IsActive checks the recurring payment is still active func (r *GetRecurringPaymentsProfileDetailsResponse) IsActive() bool { return r.Status == statusActive } diff --git a/merchant/get_transaction_details.go b/merchant/get_transaction_details.go new file mode 100644 index 0000000..f2ec9e6 --- /dev/null +++ b/merchant/get_transaction_details.go @@ -0,0 +1,86 @@ +package merchant + +// GetTransactionDetails is struct for GetTransactionDetails API +// see: https://developer.paypal.com/docs/classic/api/merchant/GetTransactionDetails_API_Operation_NVP/ +type GetTransactionDetails struct { + Merchant `url:",squash"` + BaseRequest `url:",squash"` + + TransactionID string `url:"TRANSACTIONID"` +} + +// SetMerchant sets Merchant +func (svc *GetTransactionDetails) SetMerchant(m Merchant) { + svc.Merchant = m +} + +// Do executes GetTransactionDetails operation +func (svc *GetTransactionDetails) Do(m Merchant) (*GetTransactionDetailsResponse, error) { + const method = "GetTransactionDetails" + svc.BaseRequest.Method = method + + result := &GetTransactionDetailsResponse{} + err := m.call(svc, result) + return result, err +} + +// GetTransactionDetailsResponse is struct for response of GetTransactionDetails API +type GetTransactionDetailsResponse struct { + BaseResponse `url:",squash"` + + // success + TransactionID string `url:"TRANSACTIONID"` + TransactionType string `url:"TRANSACTIONTYPE"` + PaymentType string `url:"PAYMENTTYPE"` + Subject string `url:"SUBJECT"` + + CurrencyCode string `url:"CURRENCYCODE"` + Amount string `url:"AMT"` + ShippingAmount string `url:"SHIPPINGAMT"` + TaxAmount string `url:"TAXAMT"` + FeeAmount string `url:"FEEAMT"` + OrderTime string `url:"ORDERTIME"` + + PaymentStatus string `url:"PAYMENTSTATUS"` + PendingReason string `url:"PENDINGREASON"` + ReasonCode string `url:"REASONCODE"` + ProtectionEligibility string `url:"PROTECTIONELIGIBILITY"` + ProtectionEligibilityType string `url:"PROTECTIONELIGIBILITYTYPE"` + + PayerID string `url:"PAYERID"` + PayerStatus string `url:"PAYERSTATUS"` + FirstName string `url:"FIRSTNAME"` + LastName string `url:"LASTNAME"` + Emain string `url:"EMAIL"` + ReceiverID string `url:"RECEIVERID"` + ReceiverEmail string `url:"RECEIVEREMAIL"` + CountryCode string `url:"COUNTRYCODE"` + AddressOwner string `url:"ADDRESSOWNER"` + AddressStatus string `url:"ADDRESSSTATUS"` + + SalesTax string `url:"SALESTAX"` + ShipAmount string `url:"SHIPAMOUNT"` + ShipHandleAmount string `url:"SHIPHANDLEAMOUNT"` + + ShippingResponse `url:",squash"` +} + +// IsSuccess checks the request is success or not +func (r *GetTransactionDetailsResponse) IsSuccess() bool { + return r.IsRequestSuccess() && r.IsOperationSuccess() +} + +// IsRequestSuccess checks the request is success or not +func (r *GetTransactionDetailsResponse) IsRequestSuccess() bool { + return r.ACK == ackSuccess +} + +// IsOperationSuccess checks the request is success or not +func (r *GetTransactionDetailsResponse) IsOperationSuccess() bool { + return r.PaymentStatus == paymentStatusComleted +} + +// Error returns error text +func (r *GetTransactionDetailsResponse) Error() string { + return r.BaseResponse.Error() +} diff --git a/merchant/get_transaction_details_test.go b/merchant/get_transaction_details_test.go new file mode 100644 index 0000000..e9ecda3 --- /dev/null +++ b/merchant/get_transaction_details_test.go @@ -0,0 +1,25 @@ +package merchant + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetTransactionDetails(t *testing.T) { + assert := assert.New(t) + + m := NewDefault() + // error + svc := &GetTransactionDetails{ + TransactionID: "XXXXXXXXXXXXX", + } + v, err := svc.Do(m) + + assert.Nil(err) + assert.Equal("Failure", v.ACK) + assert.Equal("124", v.Version) + assert.Equal("000000", v.Build) + assert.Equal("10004", v.ErrorCode) + +} diff --git a/merchant/manage_recurring_payments_profile_status.go b/merchant/manage_recurring_payments_profile_status.go index 6cc0e77..16e8a4d 100644 --- a/merchant/manage_recurring_payments_profile_status.go +++ b/merchant/manage_recurring_payments_profile_status.go @@ -23,7 +23,7 @@ func (svc *ManageRecurringPaymentsProfileStatus) SetAsCancel(desc string) *Manag return svc } -// SetAsSuspend sets action as `Suspend` +// SetAsSuspend sets action as `Suspend` func (svc *ManageRecurringPaymentsProfileStatus) SetAsSuspend(desc string) *ManageRecurringPaymentsProfileStatus { svc.Action = "Suspend" svc.Note = desc