diff --git a/GENERATING_MODELS.md b/GENERATING_MODELS.md index b97e7f2fe..73bc17b74 100644 --- a/GENERATING_MODELS.md +++ b/GENERATING_MODELS.md @@ -4,11 +4,11 @@ We use custom mustache templates to generate the open api client for the API spe **Step 1**: Generate the the client for a Schema using open api Docker image or cli. Provide the following parameters -- `-i` path to open api spec yaml -- `-t` path to custom templates in `./templates/go` -- `-g` generator type `go` -- `-p packageName= ` -- `-o` output path `./src/` +- `-i` path to open api spec yaml +- `-t` path to custom templates in `./templates/go` +- `-g` generator type `go` +- `-p packageName= ` +- `-o` output path `./src/` ``` docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate \ @@ -32,16 +32,15 @@ openapi-generator-cli generate \ **Step 2**: Delete the following files/folders from `./src/`. If the foldername is not in lowercase, rename it -- `configuration.go` -- `client.go` -- `utils.go` -- `response.go` -- `travis.yml` -- `git_push.sh` -- `go.mod` -- `go.sum` -- `docs` - +- `configuration.go` +- `client.go` +- `utils.go` +- `response.go` +- `travis.yml` +- `git_push.sh` +- `go.mod` +- `go.sum` +- `docs` **Step 3**: Remove the HTTP method(Post, Get, Put, Patch) suffix on API endpoint methods (Regex to find them `([A-Z][a-zA-Z0-9]*)Post\(request`) @@ -79,6 +78,8 @@ func NewClient(cfg *common.Config) *APIClient { **Step 5**: Run `make run` or `go run main.go` and Fix any issues found -**Step 6**: Add tests for the new APIs created under `./src/` +**Step 6**: Change any model fields that have `anyof` or `oneof` fields to `interface{}` (if we have typed structs) or `map[string]interface{}` (if its a key value pair). If `interface{}` is used then make sure to add a custom `UnmarshalJSON` method on the structs with test cases. See `src/checkout/model_payment_response.go` for example + +**Step 7**: Add tests for the new APIs created under `./src/` -**Step 7**: Run `make test` or `go test ./...` and Fix any issues found +**Step 8**: Run `make test` or `go test ./...` and Fix any issues found diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md new file mode 100644 index 000000000..90968f326 --- /dev/null +++ b/RELEASE_PROCESS.md @@ -0,0 +1,17 @@ +## Steps for Release of this library + +Release is done on GitHub on the `master` branch all development is done on the `develop` branch only + +**Step 1**: Update the exact library version to be released in `LibVersion` constant on `src/common/configuration.go` + +**Step 2**: If a open-api spec update was done, make sure the to follow [GENERATING_MODELS.md](/GENERATING_MODELS.md) and make sure appropriate versions and URLS are updated on `src/adyen/api.go` + +**Step 3**: Run `make build` to ensure there are no build errors + +**Step 4**: For patch and minor version releases go to step 6, For major version releases go to step 5 + +**Step 5**: Find and replace `github.com/adyen/adyen-go-api-library/v` with `github.com/adyen/adyen-go-api-library/v` through out the project including test files and readme. For example `github.com/adyen/adyen-go-api-library/v5` will become `github.com/adyen/adyen-go-api-library/v6` + +**Step 6**: create a PR form `develop` to `master` and wait for all tests to pass and for approvals + +**Step 7**: once ready merge the PR to master and create a GitHub release with changelog and a new tag corresponding to the version diff --git a/src/adyen/api.go b/src/adyen/api.go index 633538d6b..e32974a22 100644 --- a/src/adyen/api.go +++ b/src/adyen/api.go @@ -26,27 +26,31 @@ import ( // Constants used for the client API const ( - EndpointTest = "https://pal-test.adyen.com" - EndpointLive = "https://pal-live.adyen.com" - EndpointLiveSuffix = "-pal-live.adyenpayments.com" - MarketpayEndpointTest = "https://cal-test.adyen.com/cal/services" - MarketpayEndpointLive = "https://cal-live.adyen.com/cal/services" + EndpointTest = "https://pal-test.adyen.com" + EndpointLive = "https://pal-live.adyen.com" + EndpointLiveSuffix = "-pal-live.adyenpayments.com" + MarketpayEndpointTest = "https://cal-test.adyen.com/cal/services" + MarketpayEndpointLive = "https://cal-live.adyen.com/cal/services" + CheckoutEndpointTest = "https://checkout-test.adyen.com/checkout" + CheckoutEndpointLiveSuffix = "-checkout-live.adyenpayments.com/checkout" + BinLookupPalSuffix = "/pal/servlet/BinLookup/" + TerminalAPIEndpointTest = "https://terminal-api-test.adyen.com" + TerminalAPIEndpointLive = "https://terminal-api-live.adyen.com" + DisputesEndpointTest = "https://ca-test.adyen.com/ca/services/DisputeService" + DisputesEndpointLive = "https://ca-live.adyen.com/ca/services/DisputeService" +) + +// also update LibVersion in src/common/configuration.go when a version is updated and a major lib version is released +const ( MarketpayAccountAPIVersion = "v6" MarketpayFundAPIVersion = "v6" MarketpayNotificationAPIVersion = "v6" MarketpayHopAPIVersion = "v6" PaymentAPIVersion = "v64" RecurringAPIVersion = "v49" - CheckoutEndpointTest = "https://checkout-test.adyen.com/checkout" - CheckoutEndpointLiveSuffix = "-checkout-live.adyenpayments.com/checkout" CheckoutAPIVersion = "v67" - BinLookupPalSuffix = "/pal/servlet/BinLookup/" BinLookupAPIVersion = "v50" - TerminalAPIEndpointTest = "https://terminal-api-test.adyen.com" - TerminalAPIEndpointLive = "https://terminal-api-live.adyen.com" EndpointProtocol = "https://" - DisputesEndpointTest = "https://ca-test.adyen.com/ca/services/DisputeService" - DisputesEndpointLive = "https://ca-live.adyen.com/ca/services/DisputeService" DisputesAPIVersion = "v30" ) diff --git a/src/checkout/model_checkout_balance_check_response.go b/src/checkout/model_checkout_balance_check_response.go index dae2393e0..d72154128 100644 --- a/src/checkout/model_checkout_balance_check_response.go +++ b/src/checkout/model_checkout_balance_check_response.go @@ -9,17 +9,20 @@ */ package checkout + +import "github.com/adyen/adyen-go-api-library/v5/src/common" + // CheckoutBalanceCheckResponse struct for CheckoutBalanceCheckResponse type CheckoutBalanceCheckResponse struct { // This field contains additional data, which may be required to return in a particular payment response. To choose data fields to be returned, go to **Customer Area** > **Account** > **API URLs** > **Additional data settings**. AdditionalData map[string]string `json:"additionalData,omitempty"` - Balance Amount `json:"balance"` - FraudResult *FraudResult `json:"fraudResult,omitempty"` + Balance Amount `json:"balance"` + FraudResult *FraudResult `json:"fraudResult,omitempty"` // Adyen's 16-character string reference associated with the transaction/request. This value is globally unique; quote it when communicating with us about this request. > `pspReference` is returned only for non-redirect payment methods. PspReference string `json:"pspReference,omitempty"` // If the payment's authorisation is refused or an error occurs during authorisation, this field holds Adyen's mapped reason for the refusal or a description of the error. When a transaction fails, the authorisation response includes `resultCode` and `refusalReason` values. For more information, see [Refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). RefusalReason string `json:"refusalReason,omitempty"` // The result of the payment. For more information, see [Result codes](https://docs.adyen.com/online-payments/payment-result-codes). Possible values: * **AuthenticationFinished** – The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2 authentication-only transactions. * **AuthenticationNotRequired** – The transaction does not require 3D Secure authentication. Returned for [standalone authentication-only integrations](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only). * **Authorised** – The payment was successfully authorised. This state serves as an indicator to proceed with the delivery of goods and services. This is a final state. * **Cancelled** – Indicates the payment has been cancelled (either by the shopper or the merchant) before processing was completed. This is a final state. * **ChallengeShopper** – The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Error** – There was an error when the payment was being processed. The reason is given in the `refusalReason` field. This is a final state. * **IdentifyShopper** – The issuer requires the shopper's device fingerprint before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Pending** – Indicates that it is not possible to obtain the final status of the payment. This can happen if the systems providing final status information for the payment are unavailable, or if the shopper needs to take further action to complete the payment. * **PresentToShopper** – Indicates that the response contains additional information that you need to present to a shopper, so that they can use it to complete a payment. * **Received** – Indicates the payment has successfully been received by Adyen, and will be processed. This is the initial state for all payments. * **RedirectShopper** – Indicates the shopper should be redirected to an external web page or app to complete the authorisation. * **Refused** – Indicates the payment was refused. The reason is given in the `refusalReason` field. This is a final state. - ResultCode string `json:"resultCode,omitempty"` - TransactionLimit *Amount `json:"transactionLimit,omitempty"` + ResultCode *common.ResultCode `json:"resultCode,omitempty"` + TransactionLimit *Amount `json:"transactionLimit,omitempty"` } diff --git a/src/checkout/model_checkout_create_order_response.go b/src/checkout/model_checkout_create_order_response.go index 11d8e086d..961bef616 100644 --- a/src/checkout/model_checkout_create_order_response.go +++ b/src/checkout/model_checkout_create_order_response.go @@ -9,20 +9,23 @@ */ package checkout + +import "github.com/adyen/adyen-go-api-library/v5/src/common" + // CheckoutCreateOrderResponse struct for CheckoutCreateOrderResponse type CheckoutCreateOrderResponse struct { // This field contains additional data, which may be required to return in a particular payment response. To choose data fields to be returned, go to **Customer Area** > **Account** > **API URLs** > **Additional data settings**. AdditionalData map[string]string `json:"additionalData,omitempty"` // The date that the order will expire. - ExpiresAt string `json:"expiresAt"` + ExpiresAt string `json:"expiresAt"` FraudResult *FraudResult `json:"fraudResult,omitempty"` // The encrypted data that will be used by merchant for adding payments to the order. OrderData string `json:"orderData"` // Adyen's 16-character string reference associated with the transaction/request. This value is globally unique; quote it when communicating with us about this request. > `pspReference` is returned only for non-redirect payment methods. PspReference string `json:"pspReference,omitempty"` // If the payment's authorisation is refused or an error occurs during authorisation, this field holds Adyen's mapped reason for the refusal or a description of the error. When a transaction fails, the authorisation response includes `resultCode` and `refusalReason` values. For more information, see [Refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). - RefusalReason string `json:"refusalReason,omitempty"` + RefusalReason string `json:"refusalReason,omitempty"` RemainingAmount Amount `json:"remainingAmount"` // The result of the payment. For more information, see [Result codes](https://docs.adyen.com/online-payments/payment-result-codes). Possible values: * **AuthenticationFinished** – The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2 authentication-only transactions. * **AuthenticationNotRequired** – The transaction does not require 3D Secure authentication. Returned for [standalone authentication-only integrations](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only). * **Authorised** – The payment was successfully authorised. This state serves as an indicator to proceed with the delivery of goods and services. This is a final state. * **Cancelled** – Indicates the payment has been cancelled (either by the shopper or the merchant) before processing was completed. This is a final state. * **ChallengeShopper** – The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Error** – There was an error when the payment was being processed. The reason is given in the `refusalReason` field. This is a final state. * **IdentifyShopper** – The issuer requires the shopper's device fingerprint before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Pending** – Indicates that it is not possible to obtain the final status of the payment. This can happen if the systems providing final status information for the payment are unavailable, or if the shopper needs to take further action to complete the payment. * **PresentToShopper** – Indicates that the response contains additional information that you need to present to a shopper, so that they can use it to complete a payment. * **Received** – Indicates the payment has successfully been received by Adyen, and will be processed. This is the initial state for all payments. * **RedirectShopper** – Indicates the shopper should be redirected to an external web page or app to complete the authorisation. * **Refused** – Indicates the payment was refused. The reason is given in the `refusalReason` field. This is a final state. - ResultCode string `json:"resultCode,omitempty"` + ResultCode *common.ResultCode `json:"resultCode,omitempty"` } diff --git a/src/checkout/model_payment_details_response.go b/src/checkout/model_payment_details_response.go index 34a982e79..96f5c4703 100644 --- a/src/checkout/model_payment_details_response.go +++ b/src/checkout/model_payment_details_response.go @@ -9,17 +9,20 @@ */ package checkout + +import "github.com/adyen/adyen-go-api-library/v5/src/common" + // PaymentDetailsResponse struct for PaymentDetailsResponse type PaymentDetailsResponse struct { // This field contains additional data, which may be required to return in a particular payment response. To choose data fields to be returned, go to **Customer Area** > **Account** > **API URLs** > **Additional data settings**. AdditionalData map[string]string `json:"additionalData,omitempty"` - Amount *Amount `json:"amount,omitempty"` + Amount *Amount `json:"amount,omitempty"` // Donation Token containing payment details for Adyen Giving. - DonationToken string `json:"donationToken,omitempty"` - FraudResult *FraudResult `json:"fraudResult,omitempty"` + DonationToken string `json:"donationToken,omitempty"` + FraudResult *FraudResult `json:"fraudResult,omitempty"` // The reference to uniquely identify a payment. This reference is used in all communication with you about the payment status. We recommend using a unique value per payment; however, it is not a requirement. If you need to provide multiple references for a transaction, separate them with hyphens (\"-\"). Maximum length: 80 characters. - MerchantReference string `json:"merchantReference,omitempty"` - Order *CheckoutOrderResponse `json:"order,omitempty"` + MerchantReference string `json:"merchantReference,omitempty"` + Order *CheckoutOrderResponse `json:"order,omitempty"` // Adyen's 16-character string reference associated with the transaction/request. This value is globally unique; quote it when communicating with us about this request. > `pspReference` is returned only for non-redirect payment methods. PspReference string `json:"pspReference,omitempty"` // If the payment's authorisation is refused or an error occurs during authorisation, this field holds Adyen's mapped reason for the refusal or a description of the error. When a transaction fails, the authorisation response includes `resultCode` and `refusalReason` values. For more information, see [Refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). @@ -27,6 +30,7 @@ type PaymentDetailsResponse struct { // Code that specifies the refusal reason. For more information, see [Authorisation refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). RefusalReasonCode string `json:"refusalReasonCode,omitempty"` // The result of the payment. For more information, see [Result codes](https://docs.adyen.com/online-payments/payment-result-codes). Possible values: * **AuthenticationFinished** – The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2 authentication-only transactions. * **AuthenticationNotRequired** – The transaction does not require 3D Secure authentication. Returned for [standalone authentication-only integrations](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only). * **Authorised** – The payment was successfully authorised. This state serves as an indicator to proceed with the delivery of goods and services. This is a final state. * **Cancelled** – Indicates the payment has been cancelled (either by the shopper or the merchant) before processing was completed. This is a final state. * **ChallengeShopper** – The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Error** – There was an error when the payment was being processed. The reason is given in the `refusalReason` field. This is a final state. * **IdentifyShopper** – The issuer requires the shopper's device fingerprint before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Pending** – Indicates that it is not possible to obtain the final status of the payment. This can happen if the systems providing final status information for the payment are unavailable, or if the shopper needs to take further action to complete the payment. * **PresentToShopper** – Indicates that the response contains additional information that you need to present to a shopper, so that they can use it to complete a payment. * **Received** – Indicates the payment has successfully been received by Adyen, and will be processed. This is the initial state for all payments. * **RedirectShopper** – Indicates the shopper should be redirected to an external web page or app to complete the authorisation. * **Refused** – Indicates the payment was refused. The reason is given in the `refusalReason` field. This is a final state. - ResultCode string `json:"resultCode,omitempty"` + ResultCode *common.ResultCode `json:"resultCode,omitempty"` + ThreeDS2Result *ThreeDS2Result `json:"threeDS2Result,omitempty"` } diff --git a/src/checkout/model_payment_request.go b/src/checkout/model_payment_request.go index 8d0eaa3ae..c9f171112 100644 --- a/src/checkout/model_payment_request.go +++ b/src/checkout/model_payment_request.go @@ -11,6 +11,7 @@ package checkout import ( + "encoding/json" "time" ) @@ -116,3 +117,507 @@ type PaymentRequest struct { // Set to true if the payment should be routed to a trusted MID. TrustedShopper bool `json:"trustedShopper,omitempty"` } + +// UnmarshalJSON unmarshals a quoted json string to PaymentRequest struct +func (req *PaymentRequest) UnmarshalJSON(b []byte) error { + + type PaymentRequestAlias PaymentRequest + + temp := &struct { + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + if err := json.Unmarshal(b, &temp); err != nil { + return err + } + if temp.PaymentMethod != nil { + + pmtype := temp.PaymentMethod.(map[string]interface{})["type"].(string) + + switch pmtype { + case "scheme": + intermediate := &struct { + PaymentMethod *CardDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + case "ach": + intermediate := &struct { + PaymentMethod *AchDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "amazonpay": + intermediate := &struct { + PaymentMethod *AmazonPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "androidpay": + intermediate := &struct { + PaymentMethod *AndroidPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "applepay": + intermediate := &struct { + PaymentMethod *ApplePayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "directdebit_GB": + intermediate := &struct { + PaymentMethod *BacsDirectDebitDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "billdesk_online": + intermediate := &struct { + PaymentMethod *BillDeskOnlineDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "billdesk_wallet": + intermediate := &struct { + PaymentMethod *BillDeskWalletDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "blik": + intermediate := &struct { + PaymentMethod *BlikDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "cellulant": + intermediate := &struct { + PaymentMethod *CellulantDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "doku_mandiri_va": + case "doku_cimb_va": + case "doku_danamon_va": + case "doku_bni_va": + case "doku_permata_lite_atm": + case "doku_permata_atm": + case "doku_bri_va": + case "doku_bca_va": + case "doku_alfamart": + case "doku_indomaret": + case "doku_sinarmas_va": + intermediate := &struct { + PaymentMethod *DokuDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "dotpay": + intermediate := &struct { + PaymentMethod *DotpayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "dragonpay_ebanking": + case "dragonpay_otc_banking": + case "dragonpay_otc_non_banking": + case "dragonpay_otc_philippines": + intermediate := &struct { + PaymentMethod *DragonpayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "econtext_seveneleven": + case "econtext_stores": + intermediate := &struct { + PaymentMethod *EcontextVoucherDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "entercash": + intermediate := &struct { + PaymentMethod *EntercashDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "giropay": + intermediate := &struct { + PaymentMethod *GiropayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "paywithgoogle": + intermediate := &struct { + PaymentMethod *GooglePayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "ideal": + intermediate := &struct { + PaymentMethod *IdealDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "klarna": + case "klarnapayments": + case "klarnapayments_account": + case "klarnapayments_b2b": + case "klarna_paynow": + case "klarna_account": + case "klarna_b2b": + intermediate := &struct { + PaymentMethod *KlarnaDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "lianlianpay_ebanking_enterprise": + case "lianlianpay_ebanking_credit": + case "lianlianpay_ebanking_debit": + intermediate := &struct { + PaymentMethod *LianLianPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "masterpass": + intermediate := &struct { + PaymentMethod *MasterpassDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "mbway": + intermediate := &struct { + PaymentMethod *MbwayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "molpay_ebanking_fpx_MY": + case "molpay_ebanking_TH": + case "molpay_ebanking_VN": + case "molpay_ebanking_MY": + case "molpay_ebanking_direct_MY": + case "molpay_fpx": + intermediate := &struct { + PaymentMethod *MolPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "mobilepay": + intermediate := &struct { + PaymentMethod *MobilePayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "paypal": + intermediate := &struct { + PaymentMethod *PayPalDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "payu_IN_upi": + intermediate := &struct { + PaymentMethod *PayUUpiDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "qiwiwallet": + intermediate := &struct { + PaymentMethod *QiwiWalletDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "samsungpay": + intermediate := &struct { + PaymentMethod *SamsungPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "sepadirectdebit": + intermediate := &struct { + PaymentMethod *SepaDirectDebitDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "upi": + intermediate := &struct { + PaymentMethod *UpiDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "vipps": + intermediate := &struct { + PaymentMethod *VippsDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "visacheckout": + intermediate := &struct { + PaymentMethod *VisaCheckoutDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "wechatpay": + intermediate := &struct { + PaymentMethod *WeChatPayDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + case "wechatpayMiniProgram": + intermediate := &struct { + PaymentMethod *WeChatPayMiniProgramDetails `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + + default: + intermediate := &struct { + PaymentMethod map[string]interface{} `json:"paymentMethod"` + *PaymentRequestAlias + }{ + PaymentRequestAlias: (*PaymentRequestAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.PaymentMethod = intermediate.PaymentMethod + } + } + + return nil +} diff --git a/src/checkout/model_payment_request_payment_method_one_of.go b/src/checkout/model_payment_request_payment_method_one_of.go deleted file mode 100644 index d63b7d7ae..000000000 --- a/src/checkout/model_payment_request_payment_method_one_of.go +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Adyen Checkout API - * - * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/checkout). ## Authentication Each request to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/user-management/how-to-get-the-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v65/payments ``` - * - * API version: 65 - * Contact: support@adyen.com - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package checkout - -// PaymentRequestPaymentMethodOneOf struct for PaymentRequestPaymentMethodOneOf -type PaymentRequestPaymentMethodOneOf struct { - PaymentRequestPaymentMethodOneOfInterface interface { } -} diff --git a/src/checkout/model_payment_response.go b/src/checkout/model_payment_response.go index 6449fc847..8544962af 100644 --- a/src/checkout/model_payment_response.go +++ b/src/checkout/model_payment_response.go @@ -10,12 +10,16 @@ package checkout -import "github.com/adyen/adyen-go-api-library/v5/src/common" +import ( + "encoding/json" + + "github.com/adyen/adyen-go-api-library/v5/src/common" +) // PaymentResponse struct for PaymentResponse type PaymentResponse struct { // Action to be taken for completing the payment. - Action *interface{} `json:"action,omitempty"` + Action interface{} `json:"action,omitempty"` // This field contains additional data, which may be required to return in a particular payment response. To choose data fields to be returned, go to **Customer Area** > **Account** > **API URLs** > **Additional data settings**. AdditionalData map[string]string `json:"additionalData,omitempty"` Amount *Amount `json:"amount,omitempty"` @@ -32,6 +36,164 @@ type PaymentResponse struct { // Code that specifies the refusal reason. For more information, see [Authorisation refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). RefusalReasonCode string `json:"refusalReasonCode,omitempty"` // The result of the payment. For more information, see [Result codes](https://docs.adyen.com/online-payments/payment-result-codes). Possible values: * **AuthenticationFinished** – The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2 authentication-only transactions. * **AuthenticationNotRequired** – The transaction does not require 3D Secure authentication. Returned for [standalone authentication-only integrations](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only). * **Authorised** – The payment was successfully authorised. This state serves as an indicator to proceed with the delivery of goods and services. This is a final state. * **Cancelled** – Indicates the payment has been cancelled (either by the shopper or the merchant) before processing was completed. This is a final state. * **ChallengeShopper** – The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Error** – There was an error when the payment was being processed. The reason is given in the `refusalReason` field. This is a final state. * **IdentifyShopper** – The issuer requires the shopper's device fingerprint before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Pending** – Indicates that it is not possible to obtain the final status of the payment. This can happen if the systems providing final status information for the payment are unavailable, or if the shopper needs to take further action to complete the payment. * **PresentToShopper** – Indicates that the response contains additional information that you need to present to a shopper, so that they can use it to complete a payment. * **Received** – Indicates the payment has successfully been received by Adyen, and will be processed. This is the initial state for all payments. * **RedirectShopper** – Indicates the shopper should be redirected to an external web page or app to complete the authorisation. * **Refused** – Indicates the payment was refused. The reason is given in the `refusalReason` field. This is a final state. - ResultCode common.ResultCode `json:"resultCode,omitempty"` - ThreeDS2Result *ThreeDS2Result `json:"threeDS2Result,omitempty"` + ResultCode *common.ResultCode `json:"resultCode,omitempty"` + ThreeDS2Result *ThreeDS2Result `json:"threeDS2Result,omitempty"` +} + +// UnmarshalJSON unmarshals a quoted json string to PaymentResponse struct +func (req *PaymentResponse) UnmarshalJSON(b []byte) error { + + type PaymentResponseAlias PaymentResponse + + temp := &struct { + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + if err := json.Unmarshal(b, &temp); err != nil { + return err + } + if temp.Action != nil { + + actiontype := temp.Action.(map[string]interface{})["type"].(string) + + switch actiontype { + case "donation": + intermediate := &struct { + Action *CheckoutDonationAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "qrCode": + intermediate := &struct { + Action *CheckoutQrCodeAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "redirect": + intermediate := &struct { + Action *CheckoutRedirectAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "sdk": + intermediate := &struct { + Action *CheckoutSDKAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "threeDS2Challenge": + intermediate := &struct { + Action *CheckoutThreeDS2ChallengeAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "threeDS2Fingerprint": + intermediate := &struct { + Action *CheckoutThreeDS2FingerPrintAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "threeDS2Action": + case "threeDS2": + intermediate := &struct { + Action *CheckoutThreeDS2Action `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "await": + intermediate := &struct { + Action *CheckoutAwaitAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "voucher": + intermediate := &struct { + Action *CheckoutVoucherAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + case "oneTimePasscode": + intermediate := &struct { + Action *CheckoutOneTimePasscodeAction `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + + default: + intermediate := &struct { + Action map[string]interface{} `json:"action"` + *PaymentResponseAlias + }{ + PaymentResponseAlias: (*PaymentResponseAlias)(req), + } + + if err := json.Unmarshal(b, &intermediate); err != nil { + return err + } + req.Action = intermediate.Action + } + } + + return nil } diff --git a/src/checkout/model_payment_response_action_one_of.go b/src/checkout/model_payment_response_action_one_of.go deleted file mode 100644 index e50c5dedb..000000000 --- a/src/checkout/model_payment_response_action_one_of.go +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Adyen Checkout API - * - * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/checkout). ## Authentication Each request to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/user-management/how-to-get-the-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v65/payments ``` - * - * API version: 65 - * Contact: support@adyen.com - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package checkout - -// PaymentResponseActionOneOf struct for PaymentResponseActionOneOf -type PaymentResponseActionOneOf struct { - PaymentResponseActionOneOfInterface interface { } -} diff --git a/src/checkout/model_payment_verification_response.go b/src/checkout/model_payment_verification_response.go index 79abce957..64a8e302c 100644 --- a/src/checkout/model_payment_verification_response.go +++ b/src/checkout/model_payment_verification_response.go @@ -10,6 +10,8 @@ package checkout +import "github.com/adyen/adyen-go-api-library/v5/src/common" + // PaymentVerificationResponse struct for PaymentVerificationResponse type PaymentVerificationResponse struct { // This field contains additional data, which may be required to return in a particular payment response. To choose data fields to be returned, go to **Customer Area** > **Account** > **API URLs** > **Additional data settings**. @@ -27,8 +29,8 @@ type PaymentVerificationResponse struct { // Code that specifies the refusal reason. For more information, see [Authorisation refusal reasons](https://docs.adyen.com/development-resources/refusal-reasons). RefusalReasonCode string `json:"refusalReasonCode,omitempty"` // The result of the payment. For more information, see [Result codes](https://docs.adyen.com/online-payments/payment-result-codes). Possible values: * **AuthenticationFinished** – The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2 authentication-only transactions. * **AuthenticationNotRequired** – The transaction does not require 3D Secure authentication. Returned for [standalone authentication-only integrations](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only). * **Authorised** – The payment was successfully authorised. This state serves as an indicator to proceed with the delivery of goods and services. This is a final state. * **Cancelled** – Indicates the payment has been cancelled (either by the shopper or the merchant) before processing was completed. This is a final state. * **ChallengeShopper** – The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Error** – There was an error when the payment was being processed. The reason is given in the `refusalReason` field. This is a final state. * **IdentifyShopper** – The issuer requires the shopper's device fingerprint before the payment can be authenticated. Returned for 3D Secure 2 transactions. * **Pending** – Indicates that it is not possible to obtain the final status of the payment. This can happen if the systems providing final status information for the payment are unavailable, or if the shopper needs to take further action to complete the payment. * **PresentToShopper** – Indicates that the response contains additional information that you need to present to a shopper, so that they can use it to complete a payment. * **Received** – Indicates the payment has successfully been received by Adyen, and will be processed. This is the initial state for all payments. * **RedirectShopper** – Indicates the shopper should be redirected to an external web page or app to complete the authorisation. * **Refused** – Indicates the payment was refused. The reason is given in the `refusalReason` field. This is a final state. - ResultCode string `json:"resultCode,omitempty"` - ServiceError *ServiceError `json:"serviceError,omitempty"` + ResultCode *common.ResultCode `json:"resultCode,omitempty"` + ServiceError *ServiceError `json:"serviceError,omitempty"` // The shopperLocale value provided in the payment request. ShopperLocale string `json:"shopperLocale"` } diff --git a/src/common/configuration.go b/src/common/configuration.go index e19c69887..4f4e04368 100644 --- a/src/common/configuration.go +++ b/src/common/configuration.go @@ -61,7 +61,7 @@ const ( const ( LibName = "adyen-go-api-library" - LibVersion = "4.0.0" + LibVersion = "5.0.1" ) // Config stores the configuration of the API client diff --git a/src/common/result_code.go b/src/common/result_code.go index 221af7e6a..264ab6902 100644 --- a/src/common/result_code.go +++ b/src/common/result_code.go @@ -28,6 +28,7 @@ const ( Received RedirectShopper Refused + Success ) // ResultCodeValues should be in same order as the const defined above @@ -44,6 +45,7 @@ var ResultCodeValues = [...]string{ "Received", "RedirectShopper", "Refused", + "Success", } func (s ResultCode) String() string { diff --git a/src/platformsnotificationconfiguration/api_default.go b/src/platformsnotificationconfiguration/api_default.go index 421831746..776c9b75e 100644 --- a/src/platformsnotificationconfiguration/api_default.go +++ b/src/platformsnotificationconfiguration/api_default.go @@ -66,7 +66,7 @@ This endpoint is used to retrieve the details of the configurations of all of th * @param ctxs ..._context.Context - optional, for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return GetNotificationConfigurationListResponse */ -func (a PlatformsNotificationConfiguration) GetNotificationConfigurationList(req *interface{}, ctxs ..._context.Context) (GetNotificationConfigurationListResponse, *_nethttp.Response, error) { +func (a PlatformsNotificationConfiguration) GetNotificationConfigurationList(req interface{}, ctxs ..._context.Context) (GetNotificationConfigurationListResponse, *_nethttp.Response, error) { res := &GetNotificationConfigurationListResponse{} httpRes, err := a.Client.MakeHTTPPostRequest(req, res, a.BasePath()+"/getNotificationConfigurationList", ctxs...) return *res, httpRes, err diff --git a/tests/checkout_test.go b/tests/checkout_test.go index dc04ce9cb..5851768b5 100644 --- a/tests/checkout_test.go +++ b/tests/checkout_test.go @@ -72,7 +72,7 @@ func Test_Checkout(t *testing.T) { }) require.NotNil(t, err) - assert.Equal(t, true, strings.Contains(err.Error(), "Reference Missing")) + assert.Contains(t, err.Error(), "'reference' is not provided") require.NotNil(t, httpRes) require.NotNil(t, res) }) @@ -146,7 +146,7 @@ func Test_Checkout(t *testing.T) { }) require.NotNil(t, err) - assert.Equal(t, true, strings.Contains(err.Error(), "paymentMethod object has not been provided")) + assert.Contains(t, err.Error(), "'paymentMethod' is not provided") require.NotNil(t, httpRes) assert.Equal(t, 422, httpRes.StatusCode) require.NotNil(t, res) @@ -162,9 +162,9 @@ func Test_Checkout(t *testing.T) { MerchantAccount: MerchantAccount, Channel: "Web", ReturnUrl: "http://localhost:3000/redirect", - PaymentMethod: map[string]interface{}{ - "type": "ideal", - "issuer": "1121", + PaymentMethod: checkout.IdealDetails{ + Type: "ideal", + Issuer: "1121", }, } @@ -176,15 +176,14 @@ func Test_Checkout(t *testing.T) { require.NotNil(t, httpRes) assert.Equal(t, 200, httpRes.StatusCode) require.NotNil(t, res) - assert.Equal(t, common.RedirectShopper, res.ResultCode) + assert.Equal(t, common.RedirectShopper, *res.ResultCode) require.NotNil(t, res.Action) // Make sure the actions is there - action := *res.Action - redirectAction := action.(map[string]interface{}) + redirectAction := res.Action.(*checkout.CheckoutRedirectAction) require.NotNil(t, redirectAction) - require.NotNil(t, redirectAction["url"]) - require.Equal(t, "GET", redirectAction["method"]) + require.NotNil(t, redirectAction.Url) + require.Equal(t, "GET", redirectAction.Method) // check if req has ApplicationInfo added to it require.NotNil(t, req.ApplicationInfo) @@ -264,7 +263,7 @@ func Test_Checkout(t *testing.T) { require.NotNil(t, httpRes) assert.Equal(t, 200, httpRes.StatusCode) require.NotNil(t, res) - assert.Equal(t, common.RedirectShopper, res.ResultCode) + assert.Equal(t, common.RedirectShopper, *res.ResultCode) require.NotNil(t, res.Action) // check if req has ApplicationInfo added to it @@ -288,10 +287,11 @@ func Test_Checkout(t *testing.T) { }) require.NotNil(t, err) - assert.Equal(t, true, strings.Contains(err.Error(), "Invalid paymentData (validation: 14_003)")) + assert.Contains(t, err.Error(), "'paymentData' is not valid") require.NotNil(t, httpRes) assert.Equal(t, 422, httpRes.StatusCode) require.NotNil(t, res) + require.Nil(t, res.ResultCode) }) }) @@ -310,7 +310,7 @@ func Test_Checkout(t *testing.T) { }) require.NotNil(t, err) - assert.Equal(t, true, strings.Contains(err.Error(), "Token is missing")) + assert.Contains(t, err.Error(), "'token' is not provided.") require.NotNil(t, httpRes) assert.Equal(t, 422, httpRes.StatusCode) require.NotNil(t, res) diff --git a/tests/model_payment_request_test.go b/tests/model_payment_request_test.go new file mode 100644 index 000000000..b9b37fa48 --- /dev/null +++ b/tests/model_payment_request_test.go @@ -0,0 +1,148 @@ +/* + * Adyen Checkout API + * + * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/online-payments). ## Authentication Each request to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/development-resources/api-credentials#generate-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v67/payments ``` + * + * API version: 67 + * Contact: developer-experience@adyen.com + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package tests + +import ( + "encoding/json" + "testing" + + "github.com/adyen/adyen-go-api-library/v5/src/checkout" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPaymentRequest_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + req checkout.PaymentRequest + json string + wantErr bool + wantFn func(pm checkout.PaymentRequest, t *testing.T) + }{ + { + "unmarshalls an empty payment request correctly", + checkout.PaymentRequest{}, + "{}", + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.Nil(t, got.PaymentMethod) + }, + }, + { + "unmarshalls a payment request without payment method correctly", + checkout.PaymentRequest{}, + `{ + "riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4w"}, + "browserInfo":{"acceptHeader":"*/*","colorDepth":24,"language":"en-US","javaEnabled":false,"screenHeight":1080,"screenWidth":1920,"userAgent":"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0","timeZoneOffset":-60} + }`, + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.Nil(t, got.PaymentMethod) + require.NotNil(t, got.RiskData) + require.NotNil(t, got.BrowserInfo) + }, + }, + { + "unmarshalls a payment request with ideal correctly", + checkout.PaymentRequest{}, + `{ + "riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4"}, + "paymentMethod":{"type":"ideal","issuer":"1121"} + }`, + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.PaymentMethod) + require.NotNil(t, got.RiskData) + assert.Equal(t, "ideal", got.PaymentMethod.(*checkout.IdealDetails).Type) + assert.Equal(t, "1121", got.PaymentMethod.(*checkout.IdealDetails).Issuer) + }, + }, + { + "unmarshalls a payment request with scheme correctly", + checkout.PaymentRequest{}, + `{ + "riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4w"}, + "paymentMethod":{"type":"scheme","holderName":"d","encryptedCardNumber":"adyenjs_0_1_25$J8/5xp5l6DjYVPokO6FwAQj","encryptedExpiryMonth":"adyenjs_0_1_25$bLCWe/ZHR37Okz0d28bzrDBYXw","encryptedExpiryYear":"adyenjs_0_1_25$nqasksbOSfn0grzrmna2vpWkQMhOHT6Cd","encryptedSecurityCode":"adyenjs_0_1_25$TbomjrfaGwHFfxpPuf","brand":"amex"}, + "browserInfo":{"acceptHeader":"*/*","colorDepth":24,"language":"en-US","javaEnabled":false,"screenHeight":1080,"screenWidth":1920,"userAgent":"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0","timeZoneOffset":-60} + }`, + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.PaymentMethod) + require.NotNil(t, got.RiskData) + require.NotNil(t, got.BrowserInfo) + assert.Equal(t, "scheme", got.PaymentMethod.(*checkout.CardDetails).Type) + assert.Equal(t, "adyenjs_0_1_25$J8/5xp5l6DjYVPokO6FwAQj", got.PaymentMethod.(*checkout.CardDetails).EncryptedCardNumber) + + jsonString, err := json.Marshal(got) + assert.Nil(t, err) + assert.Equal(t, `{"amount":{"currency":"","value":0},"browserInfo":{"acceptHeader":"*/*","colorDepth":24,"javaEnabled":false,"language":"en-US","screenHeight":1080,"screenWidth":1920,"timeZoneOffset":-60,"userAgent":"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0"},"merchantAccount":"","paymentMethod":{"encryptedCardNumber":"adyenjs_0_1_25$J8/5xp5l6DjYVPokO6FwAQj","encryptedExpiryMonth":"adyenjs_0_1_25$bLCWe/ZHR37Okz0d28bzrDBYXw","encryptedExpiryYear":"adyenjs_0_1_25$nqasksbOSfn0grzrmna2vpWkQMhOHT6Cd","encryptedSecurityCode":"adyenjs_0_1_25$TbomjrfaGwHFfxpPuf","holderName":"d","type":"scheme"},"reference":"","returnUrl":"","riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4w"}}`, string(jsonString)) + }, + }, + { + "unmarshalls a payment request with ach correctly", + checkout.PaymentRequest{}, + `{ + "riskData":{"clientData":"eyJ2ZX"}, + "paymentMethod":{"type":"ach","encryptedBankAccountNumber":"adyenjs_0_1_25","encryptedBankLocationId":"adyenjs_0_1_25","ownerName":"test"}, + "billingAddress":{"street":"test","houseNumberOrName":"2","postalCode":"123456","city":"porto rico","stateOrProvince":"N/A","country":"PR"} + }`, + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.PaymentMethod) + require.NotNil(t, got.RiskData) + require.NotNil(t, got.BillingAddress) + assert.Equal(t, "test", got.BillingAddress.Street) + assert.Equal(t, "ach", got.PaymentMethod.(*checkout.AchDetails).Type) + assert.Equal(t, "adyenjs_0_1_25", got.PaymentMethod.(*checkout.AchDetails).EncryptedBankAccountNumber) + }, + }, + { + "unmarshalls a payment request with a payment type not defined with concrete struct correctly", + checkout.PaymentRequest{}, + `{ + "riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4w"}, + "paymentMethod":{"type":"mypay","holderName":"d","number":"1234", "brand":"amex"}, + "browserInfo":{"acceptHeader":"*/*","colorDepth":24,"language":"en-US","javaEnabled":false,"screenHeight":1080,"screenWidth":1920,"userAgent":"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0","timeZoneOffset":-60} + }`, + false, + func(got checkout.PaymentRequest, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.PaymentMethod) + require.NotNil(t, got.RiskData) + require.NotNil(t, got.BrowserInfo) + assert.Equal(t, "mypay", got.PaymentMethod.(map[string]interface{})["type"].(string)) + assert.Equal(t, "1234", got.PaymentMethod.(map[string]interface{})["number"]) + assert.Equal(t, "amex", got.PaymentMethod.(map[string]interface{})["brand"]) + + jsonString, err := json.Marshal(got) + assert.Nil(t, err) + assert.Equal(t, `{"amount":{"currency":"","value":0},"browserInfo":{"acceptHeader":"*/*","colorDepth":24,"javaEnabled":false,"language":"en-US","screenHeight":1080,"screenWidth":1920,"timeZoneOffset":-60,"userAgent":"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0"},"merchantAccount":"","paymentMethod":{"brand":"amex","holderName":"d","number":"1234","type":"mypay"},"reference":"","returnUrl":"","riskData":{"clientData":"eyJ2ZXJzaW9uIjoiMS4w"}}`, string(jsonString)) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pm := checkout.PaymentRequest{} + err := json.Unmarshal([]byte(tt.json), &pm) + if (err != nil) != tt.wantErr { + t.Errorf("PaymentRequest.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + require.Nil(t, err) + tt.wantFn(pm, t) + }) + } +} diff --git a/tests/model_payment_response_test.go b/tests/model_payment_response_test.go new file mode 100644 index 000000000..d8e889bb4 --- /dev/null +++ b/tests/model_payment_response_test.go @@ -0,0 +1,142 @@ +/* + * Adyen Checkout API + * + * Adyen Checkout API provides a simple and flexible way to initiate and authorise online payments. You can use the same integration for payments made with cards (including 3D Secure), mobile wallets, and local payment methods (for example, iDEAL and Sofort). This API reference provides information on available endpoints and how to interact with them. To learn more about the API, visit [Checkout documentation](https://docs.adyen.com/online-payments). ## Authentication Each response to the Checkout API must be signed with an API key. For this, obtain an API Key from your Customer Area, as described in [How to get the API key](https://docs.adyen.com/development-resources/api-credentials#generate-api-key). Then set this key to the `X-API-Key` header value, for example: ``` curl -H \"Content-Type: application/json\" \\ -H \"X-API-Key: Your_Checkout_API_key\" \\ ... ``` Note that when going live, you need to generate a new API Key to access the [live endpoints](https://docs.adyen.com/development-resources/live-endpoints). ## Versioning Checkout API supports versioning of its endpoints through a version suffix in the endpoint URL. This suffix has the following format: \"vXX\", where XX is the version number. For example: ``` https://checkout-test.adyen.com/v67/payments ``` + * + * API version: 67 + * Contact: developer-experience@adyen.com + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package tests + +import ( + "encoding/json" + "testing" + + "github.com/adyen/adyen-go-api-library/v5/src/checkout" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPaymentResponse_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + req checkout.PaymentResponse + json string + wantErr bool + wantFn func(pm checkout.PaymentResponse, t *testing.T) + }{ + { + "unmarshalls an empty payment response correctly", + checkout.PaymentResponse{}, + "{}", + false, + func(got checkout.PaymentResponse, t *testing.T) { + require.NotNil(t, got) + require.Nil(t, got.Action) + }, + }, + { + "unmarshalls a payment response without an action correctly", + checkout.PaymentResponse{}, + `{ + "resultCode":"Error", + "PspReference":"12345" + }`, + false, + func(got checkout.PaymentResponse, t *testing.T) { + require.NotNil(t, got) + require.Nil(t, got.Action) + assert.Equal(t, "Error", got.ResultCode.String()) + assert.Equal(t, "12345", got.PspReference) + }, + }, + { + "unmarshalls a payment response with redirect action correctly", + checkout.PaymentResponse{}, + `{ + "action":{ + "method":"GET", + "paymentMethodType":"ideal", + "type":"redirect", + "url":"https://checkoutshopper-test.adyen.com/checkoutshopper/checkoutPaymentRedirect?redirectData=X6XtfGC3..." + }, + "resultCode":"RedirectShopper" + }`, + false, + func(got checkout.PaymentResponse, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.Action) + require.NotNil(t, got.ResultCode) + assert.Equal(t, "redirect", got.Action.(*checkout.CheckoutRedirectAction).Type) + assert.Equal(t, "ideal", got.Action.(*checkout.CheckoutRedirectAction).PaymentMethodType) + assert.Equal(t, "https://checkoutshopper-test.adyen.com/checkoutshopper/checkoutPaymentRedirect?redirectData=X6XtfGC3...", got.Action.(*checkout.CheckoutRedirectAction).Url) + }, + }, + { + "unmarshalls a payment response with 3ds2 action correctly", + checkout.PaymentResponse{}, + `{ + "resultCode": "IdentifyShopper", + "action": { + "paymentData": "Ab02b4c0!BQABAgCCFm6bRbO...", + "paymentMethodType": "scheme", + "authorisationToken": "BQABAQCOY3Jh1O4zAJC7AEESc...", + "subtype": "fingerprint", + "token": "eyJ0aHJlZURTTWVzc2FnZVZ...", + "type": "threeDS2" + } + }`, + false, + func(got checkout.PaymentResponse, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.Action) + require.NotNil(t, got.ResultCode) + assert.Equal(t, "threeDS2", got.Action.(*checkout.CheckoutThreeDS2Action).Type) + assert.Equal(t, "fingerprint", got.Action.(*checkout.CheckoutThreeDS2Action).Subtype) + assert.Equal(t, "eyJ0aHJlZURTTWVzc2FnZVZ...", got.Action.(*checkout.CheckoutThreeDS2Action).Token) + + jsonString, err := json.Marshal(got) + assert.Nil(t, err) + assert.Equal(t, `{"action":{"authorisationToken":"BQABAQCOY3Jh1O4zAJC7AEESc...","paymentData":"Ab02b4c0!BQABAgCCFm6bRbO...","paymentMethodType":"scheme","subtype":"fingerprint","token":"eyJ0aHJlZURTTWVzc2FnZVZ...","type":"threeDS2"},"resultCode":"IdentifyShopper"}`, string(jsonString)) + }, + }, + { + "unmarshalls a payment response with an action type not defined with concrete struct correctly", + checkout.PaymentResponse{}, + `{ + "resultCode": "IdentifyShopper", + "action": { + "paymentMethodType": "scheme", + "token": "eyJ0aHJlZURTTWVzc2FnZVZ...", + "type": "unknown" + } + }`, + false, + func(got checkout.PaymentResponse, t *testing.T) { + require.NotNil(t, got) + require.NotNil(t, got.Action) + require.NotNil(t, got.ResultCode) + assert.Equal(t, "unknown", got.Action.(map[string]interface{})["type"].(string)) + assert.Equal(t, "scheme", got.Action.(map[string]interface{})["paymentMethodType"]) + + jsonString, err := json.Marshal(got) + assert.Nil(t, err) + assert.Equal(t, `{"action":{"paymentMethodType":"scheme","token":"eyJ0aHJlZURTTWVzc2FnZVZ...","type":"unknown"},"resultCode":"IdentifyShopper"}`, string(jsonString)) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pm := checkout.PaymentResponse{} + err := json.Unmarshal([]byte(tt.json), &pm) + if (err != nil) != tt.wantErr { + t.Errorf("PaymentResponse.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + require.Nil(t, err) + tt.wantFn(pm, t) + }) + } +}