From 72c24d8e4db3d472b3af9d0c1219c330b272d2fb Mon Sep 17 00:00:00 2001 From: Alessio Zampatti Date: Mon, 26 Nov 2018 10:18:11 +0100 Subject: [PATCH 01/29] PW-781: Code optimizations (#53) * PW-781: Code optimizations: raise an exception if response contains errorCode, removed redundant status_code 422, always return an error_code along with a message in AdyenExceptions closes #47, closes #48, closes #49 * pycodestyle fix * pycodestyle fix --- Adyen/client.py | 60 ++++++++++++++++++++++++------------ Adyen/exceptions.py | 8 ++--- test/ModificationTest.py | 14 ++++----- test/RecurringTest.py | 11 ++++--- test/ThirdPartyPayoutTest.py | 24 ++++----------- 5 files changed, 62 insertions(+), 55 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 6b563e79..e9e928a0 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -26,7 +26,7 @@ class AdyenResult(object): status_code (int, optional): Default 200. HTTP response code, ie 200, 404, 500, etc. psp (str, optional): Psp reference returned by Adyen for a payment. - raw_request (str, optionl): Raw request placed to Adyen. + raw_request (str, optional): Raw request placed to Adyen. raw_response (str, optional): Raw response returned by Adyen. """ @@ -401,7 +401,20 @@ def _handle_response(self, url, raw_response, raw_request, try: if response['errorCode']: - return raw_response + raise AdyenAPICommunicationError( + "Unexpected error while communicating with Adyen." + " Received the response data:'{}', HTTP Code:'{}'. " + "Please reach out to support@adyen.com if the " + "problem persists with the psp:{}" + .format(raw_response, status_code, + headers.get('pspReference')), + status_code=status_code, + raw_request=raw_request, + raw_response=raw_response, + url=url, + psp=headers.get('pspReference'), + headers=headers, + error_code=response['errorCode']) except KeyError: erstr = 'KeyError: errorCode' raise AdyenAPICommunicationError(erstr) @@ -454,7 +467,9 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, erstr = "Received a 404 for url:'{}'. Please ensure that" \ " the custom merchant specific url is correct" \ .format(url) - raise AdyenAPICommunicationError(erstr) + raise AdyenAPICommunicationError(erstr, + error_code=response_obj.get( + "errorCode")) else: erstr = "Unexpected error while communicating with Adyen." \ " Please reach out to support@adyen.com" \ @@ -464,8 +479,10 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, raw_response=raw_response, url=url, psp=psp_ref, - headers=headers) - elif status_code in [400, 422]: + headers=headers, + error_code=response_obj.get( + "errorCode")) + elif status_code == 400: erstr = "Received validation error with errorCode: %s," \ " message: %s, HTTP Code: %s. Please verify" \ " the values provided. Please reach out" \ @@ -474,13 +491,16 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, response_obj["errorCode"], response_obj["message"], status_code, psp_ref) - raise AdyenAPIValidationError(erstr) + raise AdyenAPIValidationError(erstr, error_code=response_obj.get( + "errorCode")) elif status_code == 401: erstr = "Unable to authenticate with Adyen's Servers." \ " Please verify the credentials set with the Adyen base" \ " class. Please reach out to your Adyen Admin" \ " if the problem persists" - raise AdyenAPIAuthenticationError(erstr) + raise AdyenAPIAuthenticationError(erstr, + error_code=response_obj.get( + "errorCode")) elif status_code == 403: if response_obj.get("message") == "Invalid Merchant Account": @@ -490,7 +510,9 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, "Reach out to support@adyen.com" " if the issue persists") \ % raw_request['merchantAccount'] - raise AdyenAPIInvalidPermission(erstr) + raise AdyenAPIInvalidPermission(erstr, + error_code=response_obj.get( + "errorCode")) erstr = "Unable to perform the requested action. message: %s." \ " If you think your webservice user: %s might not have" \ @@ -498,18 +520,15 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, " Please reach out to support@adyen.com, providing" \ " the PSP reference: %s" % ( response_obj["message"], self.username, psp_ref) - - raise AdyenAPIInvalidPermission(erstr, self.username, psp_ref, - raw_request=raw_request, - raw_response=raw_response, url=url, - psp=psp_ref, headers=headers) + raise AdyenAPIInvalidPermission(erstr, error_code=response_obj.get( + "errorCode")) elif status_code == 422: if response_obj.get("message") == "Invalid amount specified": raise AdyenAPIInvalidAmount( "Invalid amount specified" "Amount may be improperly formatted, too small or too big." - "If the issue persists, contact support@adyen.com" - ) + "If the issue persists, contact support@adyen.com", + error_code=response_obj.get("errorCode")) elif status_code == 500: if response_obj.get("errorType") == "validation": @@ -519,14 +538,17 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, erstr = "Received validation error with errorCode: %s," \ " message: %s, HTTP Code: %s. Please verify" \ " the values provided." % err_args - raise AdyenAPIValidationError(erstr) + raise AdyenAPIValidationError(erstr, + error_code=response_obj.get( + "errorCode")) if response_obj.get("message") == "Failed to serialize node " \ "Failed to parse [123.34]" \ " as a Long": raise AdyenAPIInvalidFormat( - "The paymount amount must be set in cents," - " and can not contain commas or points." + "The payment amount must be set in cents," + " and can not contain commas or points.", + error_code=response_obj.get("errorCode") ) else: raise AdyenAPICommunicationError( @@ -539,7 +561,7 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, raw_response=raw_response, url=url, psp=psp_ref, - headers=headers) + headers=headers, error_code=response_obj.get("errorCode")) def _error_from_hpp(self, html): # Must be updated when Adyen response is changed: diff --git a/Adyen/exceptions.py b/Adyen/exceptions.py index 1b99efe7..aa8caa57 100644 --- a/Adyen/exceptions.py +++ b/Adyen/exceptions.py @@ -9,7 +9,8 @@ def __init__(self, url="", psp="", headers="", - status_code=""): + status_code="", + error_code=""): self.message = message self.raw_request = raw_request self.raw_response = raw_response @@ -17,6 +18,7 @@ def __init__(self, self.psp = psp self.headers = headers self.status_code = status_code + self.error_code = error_code def __str__(self): return repr("{}:{}".format(self.__class__.__name__, self.message)) @@ -42,13 +44,9 @@ class AdyenInvalidRequestError(AdyenError): class AdyenAPIResponseError(AdyenError): def __init__(self, message, - result="", - error_code="", *args, **kwargs): super(AdyenAPIResponseError, self).__init__(message, *args, **kwargs) - self.error_code = error_code - self.result = result class AdyenAPIAuthenticationError(AdyenAPIResponseError): diff --git a/test/ModificationTest.py b/test/ModificationTest.py index 6b56a88f..77eb0c33 100644 --- a/test/ModificationTest.py +++ b/test/ModificationTest.py @@ -36,14 +36,12 @@ def test_capture_error_167(self): 'test/mocks/' 'capture-error-167' '.json') - self.assertRaisesRegexp(Adyen.AdyenAPIValidationError, - "Received validation error with errorCode:" - " 167, message: Original pspReference required" - " for this operation, HTTP Code: 422." + - " Please verify the values provided. Please " - "reach out to support@adyen.com if the problem" - " persists, providing the PSP reference.*", - self.ady.payment.capture, request) + self.assertRaisesRegexp( + Adyen.AdyenAPICommunicationError, + "Unexpected error", + self.ady.payment.capture, + request + ) def test_cancel_or_refund_received(self): request = {} diff --git a/test/RecurringTest.py b/test/RecurringTest.py index 4bb1072e..7cdfbd44 100644 --- a/test/RecurringTest.py +++ b/test/RecurringTest.py @@ -60,11 +60,12 @@ def test_disable_803(self): 'recurring/' 'disable-error-803' '.json') - self.assertRaisesRegexp(Adyen.AdyenAPIValidationError, - "Received validation error with errorCode: " - "803, message: PaymentDetail not found, " - "HTTP Code: 422.*", - self.ady.recurring.disable, request) + self.assertRaisesRegexp( + Adyen.AdyenAPICommunicationError, + "Unexpected error", + self.ady.recurring.disable, + request + ) TestRecurring.client.http_force = "requests" diff --git a/test/ThirdPartyPayoutTest.py b/test/ThirdPartyPayoutTest.py index 0d63acbf..517d48a0 100644 --- a/test/ThirdPartyPayoutTest.py +++ b/test/ThirdPartyPayoutTest.py @@ -132,12 +132,8 @@ def test_submit_invalid_recurring_reference(self): resp = 'test/mocks/payout/submit-invalid-reference.json' self.ady.client = self.test.create_client_from_file(422, request, resp) self.assertRaisesRegexp( - Adyen.AdyenAPIValidationError, - "Received validation error with errorCode: 800," - " message: Contract not found, HTTP Code: 422." - " Please verify the values provided." - " Please reach out to support@adyen.com" - " if the problem persists, providing the PSP reference.*", + Adyen.AdyenAPICommunicationError, + "Unexpected error", self.ady.payout.submit, request ) @@ -183,12 +179,8 @@ def test_store_detail_and_submit_missing_payment(self): resp = 'test/mocks/payout/storeDetailAndSubmit-missing-payment.json' self.ady.client = self.test.create_client_from_file(422, request, resp) self.assertRaisesRegexp( - Adyen.AdyenAPIValidationError, - "Received validation error with errorCode: 000," - " message: Please supply paymentDetails, HTTP Code: 422." - " Please verify the values provided." - " Please reach out to support@adyen.com" - " if the problem persists, providing the PSP reference:.*", + Adyen.AdyenAPICommunicationError, + "Unexpected error", self.ady.payout.store_detail_and_submit, request ) @@ -215,12 +207,8 @@ def test_store_detail_and_submit_invalid_iban(self): resp = 'test/mocks/payout/storeDetailAndSubmit-invalid-iban.json' self.ady.client = self.test.create_client_from_file(422, request, resp) self.assertRaisesRegexp( - Adyen.AdyenAPIValidationError, - "Received validation error with errorCode: 161," - " message: Invalid iban, HTTP Code: 422." - " Please verify the values provided." - " Please reach out to support@adyen.com" - " if the problem persists, providing the PSP reference:.*", + Adyen.AdyenAPICommunicationError, + "Unexpected error", self.ady.payout.store_detail_and_submit, request ) From 26cccd9858f1975cc1ecfbb44d3816054ea500cb Mon Sep 17 00:00:00 2001 From: alexandros Date: Thu, 3 Jan 2019 16:59:11 +0100 Subject: [PATCH 02/29] Add payment methods with mock test --- Adyen/__init__.py | 6 +- Adyen/client.py | 88 +- Adyen/services.py | 45 +- Adyen/settings.py | 2 + Adyen/validation.py | 2 + test/CheckoutTest.py | 27 + .../paymentmethods-error-forbidden-403.json | 6 + .../checkout/paymentmethods-success.json | 985 ++++++++++++++++++ .../payments-error-invalid-data-422.json | 6 + test/mocks/checkout/payments-success.json | 97 ++ ...aymentsdetails-error-invalid-data-422.json | 6 + .../checkout/paymentsdetails-sucess.json | 8 + ...paymentsession-error-invalid-data-422.json | 6 + .../mocks/checkout/paymentsession-sucess.json | 3 + ...result-error-invalid-data-payload-422.json | 6 + .../mocks/checkout/paymentsresult-sucess.json | 4 + .../checkoututility/originkeys-success.json | 7 + 17 files changed, 1295 insertions(+), 9 deletions(-) create mode 100644 test/CheckoutTest.py create mode 100644 test/mocks/checkout/paymentmethods-error-forbidden-403.json create mode 100644 test/mocks/checkout/paymentmethods-success.json create mode 100644 test/mocks/checkout/payments-error-invalid-data-422.json create mode 100644 test/mocks/checkout/payments-success.json create mode 100644 test/mocks/checkout/paymentsdetails-error-invalid-data-422.json create mode 100644 test/mocks/checkout/paymentsdetails-sucess.json create mode 100644 test/mocks/checkout/paymentsession-error-invalid-data-422.json create mode 100644 test/mocks/checkout/paymentsession-sucess.json create mode 100644 test/mocks/checkout/paymentsresult-error-invalid-data-payload-422.json create mode 100644 test/mocks/checkout/paymentsresult-sucess.json create mode 100644 test/mocks/checkoututility/originkeys-success.json diff --git a/Adyen/__init__.py b/Adyen/__init__.py index a4afcd2d..c1b08313 100644 --- a/Adyen/__init__.py +++ b/Adyen/__init__.py @@ -18,7 +18,8 @@ AdyenRecurring, AdyenPayment, AdyenThirdPartyPayout, - AdyenHPP) + AdyenHPP, + AdyenCheckoutApi) from .httpclient import HTTPClient @@ -30,6 +31,8 @@ def __init__(self, **kwargs): self.payout = AdyenThirdPartyPayout(client=self.client) self.hpp = AdyenHPP(client=self.client) self.recurring = AdyenRecurring(client=self.client) + self.checkout = AdyenCheckoutApi(client=self.client) + _base_adyen_obj = Adyen() @@ -37,3 +40,4 @@ def __init__(self, **kwargs): hpp = _base_adyen_obj.hpp payment = _base_adyen_obj.payment payout = _base_adyen_obj.payout +checkout = _base_adyen_obj.checkout diff --git a/Adyen/client.py b/Adyen/client.py index e9e928a0..5224f4da 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -66,7 +66,7 @@ class AdyenClient(object): hmac (str, optional): Hmac key that is used for signature calculation. """ - def __init__(self, username=None, password=None, + def __init__(self, username=None, password=None, xapikey=None, review_payout_username=None, review_payout_password=None, store_payout_username=None, store_payout_password=None, platform="test", merchant_account=None, @@ -75,6 +75,7 @@ def __init__(self, username=None, password=None, http_force=None): self.username = username self.password = password + self.xapikey = xapikey self.review_payout_username = review_payout_username self.review_payout_password = review_payout_password self.store_payout_username = store_payout_username @@ -121,6 +122,20 @@ def _determine_hpp_url(self, platform, action): result = '/'.join([base_uri, service]) return result + def _determine_checkout_url(self, platform, service, action): + """This returns the Adyen API endpoint based on the provided platform, + service and action. + + Args: + platform (str): Adyen platform, ie 'live' or 'test'. + service (str): API service to place request through. + action (str): the API action to perform. + """ + base_uri = settings.BASE_CHECKOUT_URL.format(platform) + api_version = settings.CHECKOUT_API_VERSION + + return '/'.join([base_uri, api_version, action]) + def _review_payout_username(self, **kwargs): if 'username' in kwargs: return kwargs['username'] @@ -331,6 +346,73 @@ class instance. status_code, headers, message) return adyen_result + def call_checkout_api(self, request_data, service, action, **kwargs): + """This will call the checkout adyen api. xapi key merchant_account, + and platform are pulled from root module level and or self object. + AdyenResult will be returned on 200 response. Otherwise, an exception + is raised. + + Args: + request_data (dict): The dictionary of the request to place. This + should be in the structure of the Adyen API. + https://docs.adyen.com/developers/checkout/api-integration + service (str): This is the API service to be called. + action (str): The specific action of the API service to be called + """ + if not self.http_init: + self.http_client = HTTPClient(self.app_name, + self.USER_AGENT_SUFFIX, + self.LIB_VERSION, + self.http_force) + self.http_init = True + + # xapi at self object has highest priority. fallback to root module + # and ensure that it is set. + if self.xapikey: + xapikey = self.xapikey + elif 'xapikey' in kwargs: + xapikey = kwargs.pop("xapikey") + + if not xapikey: + errorstring = """Please set your webservice xapikey. + You can do this by running 'Adyen.xapikey = 'Your xapikey'""" + raise AdyenInvalidRequestError(errorstring) + + # platform at self object has highest priority. fallback to root module + # and ensure that it is set to either 'live' or 'test'. + if self.platform: + platform = self.platform + elif 'platform' in kwargs: + platform = kwargs.pop('platform') + + if not isinstance(platform, str): + errorstring = "'platform' value must be type of string" + raise TypeError(errorstring) + elif platform.lower() not in ['live', 'test']: + errorstring = "'platform' must be the value of 'live' or 'test'" + raise ValueError(errorstring) + + message = request_data + + if not message.get('merchantAccount'): + message['merchantAccount'] = self.merchant_account + + # Adyen requires this header to be set and uses the combination of + # merchant account and merchant reference to determine uniqueness. + headers = {} + + url = self._determine_checkout_url(platform, service, action) + + raw_response, raw_request, status_code, headers = \ + self.http_client.request(url, json=message, xapikey=xapikey , headers=headers, + **kwargs) + + # Creates AdyenResponse if request was successful, raises error if not. + adyen_result = self._handle_response(url, raw_response, raw_request, + status_code, headers, message) + + return adyen_result + def hpp_payment(self, request_data, action, hmac_key="", **kwargs): if not self.http_init: @@ -406,8 +488,8 @@ def _handle_response(self, url, raw_response, raw_request, " Received the response data:'{}', HTTP Code:'{}'. " "Please reach out to support@adyen.com if the " "problem persists with the psp:{}" - .format(raw_response, status_code, - headers.get('pspReference')), + .format(raw_response, status_code, + headers.get('pspReference')), status_code=status_code, raw_request=raw_request, raw_response=raw_response, diff --git a/Adyen/services.py b/Adyen/services.py index ac8e79c3..2e9d2007 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -117,7 +117,7 @@ def hpp_payment(self, request="", skip_details=None, **kwargs): if all(k in request for k in ("shopperEmail", "shopperReference", "recurringContract")): recc = request['recurringContract'] - if recc != 'ONECLICK' and recc != 'RECURRING'\ + if recc != 'ONECLICK' and recc != 'RECURRING' \ and recc != 'ONECLICK,RECURRING': raise ValueError( "HPP: recurringContract must be on of the following" @@ -190,8 +190,8 @@ def capture(self, request="", **kwargs): action = "capture" if validation.check_in(request, action): - if request['modificationAmount']["value"] == "" or\ - request['modificationAmount']['value'] == "0": + if request['modificationAmount']["value"] == "" or \ + request['modificationAmount']['value'] == "0": raise ValueError( "Set the 'modificationAmount' to the original transaction" " amount, or less for a partial capture. " @@ -210,8 +210,8 @@ def refund(self, request="", **kwargs): action = "refund" if validation.check_in(request, action): - if request['modificationAmount']['value'] == "" or\ - request['modificationAmount']['value'] == "0": + if request['modificationAmount']['value'] == "" or \ + request['modificationAmount']['value'] == "0": raise ValueError( "To refund this payment, provide the original value. " "Set the value to less than the original amount, " @@ -279,3 +279,38 @@ def store_detail_and_submit(self, request=None, **kwargs): return self.client.call_api( request, self.service, action, **kwargs ) + + +class AdyenCheckoutApi(AdyenServiceBase): + """This represents the Adyen Checkout API . + + API calls currently implemented: + paymentMethods + payments + payments/details + originKeys + Please refer to the checkout documentation for specifics around the API. + https://docs.adyen.com/developers/checkout + + The AdyenPayment class, is accessible as adyen.payment.method(args) + + Args: + client (AdyenAPIClient, optional): An API client for the service to + use. If not provided, a new API client will be created. + """ + + def __init__(self, client=""): + super(AdyenCheckoutApi, self).__init__(client=client) + self.service = "Checkout" + + def payment_methods(self, request="", **kwargs): + action = "paymentMethods" + if validation.check_in(request, action): + if 'merchantAccount' in request: + if request['merchantAccount'] == '': + raise ValueError( + 'merchantAccount must contain the merchant account' + ' when retrieving payment methods.') + + return self.client.call_checkout_api(request, self.service, + action, **kwargs) diff --git a/Adyen/settings.py b/Adyen/settings.py index 2364ed4b..28c8e1d4 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -2,5 +2,7 @@ BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" +BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com/" +CHECKOUT_API_VERSION = "v40" API_VERSION = "v30" API_RECURRING_VERSION = "v25" diff --git a/Adyen/validation.py b/Adyen/validation.py index 58e8c768..dd84d0db 100644 --- a/Adyen/validation.py +++ b/Adyen/validation.py @@ -17,6 +17,8 @@ actions['refund'] = ["modificationAmount", "originalReference"] actions['cancelOrRefund'] = ["originalReference"] +actions['paymentMethods'] = ["merchantAccount"] + payout_required_fields = { 'confirmThirdParty': ( 'merchantAccount', diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py new file mode 100644 index 00000000..9aed4c7d --- /dev/null +++ b/test/CheckoutTest.py @@ -0,0 +1,27 @@ +import Adyen +import unittest +from BaseTest import BaseTest +import pprint + + +class TestCheckout(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.xapikey = "YourXapikey" + client.platform = "test" + client.app_name = "appname" + + def test_payment_methods_success_mocked(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + + self.ady.client = self.test.create_client_from_file(200, request, + 'test/mocks/checkout/' + 'paymentmethods-success' + '.json') + result = self.ady.checkout.payment_methods(request) + self.assertEqual("AliPay", result.message['paymentMethods'][0]['name']) + self.assertEqual("Credit Card", result.message['paymentMethods'][2]['name']) + self.assertEqual("Credit Card via AsiaPay", result.message['paymentMethods'][3]['name']) diff --git a/test/mocks/checkout/paymentmethods-error-forbidden-403.json b/test/mocks/checkout/paymentmethods-error-forbidden-403.json new file mode 100644 index 00000000..28afc988 --- /dev/null +++ b/test/mocks/checkout/paymentmethods-error-forbidden-403.json @@ -0,0 +1,6 @@ +{ + "status": 403, + "errorCode": "901", + "message": "Invalid Merchant Account", + "errorType": "security" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentmethods-success.json b/test/mocks/checkout/paymentmethods-success.json new file mode 100644 index 00000000..d79ce47b --- /dev/null +++ b/test/mocks/checkout/paymentmethods-success.json @@ -0,0 +1,985 @@ +{ + "paymentMethods": [ + { + "name": "AliPay", + "type": "alipay" + }, + { + "name": "AliPay", + "type": "alipay_wap" + }, + { + "details": [ + { + "key": "additionalData.card.encrypted.json", + "type": "cardToken" + } + ], + "name": "Credit Card", + "type": "scheme" + }, + { + "name": "Credit Card via AsiaPay", + "type": "asiapay" + }, + { + "name": "BancNet", + "type": "bancnet" + }, + { + "name": "Bank Transfer (BE)", + "type": "bankTransfer_BE" + }, + { + "name": "Bank Transfer (DE)", + "type": "bankTransfer_DE" + }, + { + "name": "Bank Transfer (DK)", + "type": "bankTransfer_DK" + }, + { + "name": "Bank Transfer (GB)", + "type": "bankTransfer_GB" + }, + { + "name": "SEPA Bank Transfer", + "type": "bankTransfer_IBAN" + }, + { + "name": "Bank Transfer (NL)", + "type": "bankTransfer_NL" + }, + { + "name": "Bank Transfer (NO)", + "type": "bankTransfer_NO" + }, + { + "name": "Bank Transfer (PL)", + "type": "bankTransfer_PL" + }, + { + "name": "Bank Transfer (SE)", + "type": "bankTransfer_SE" + }, + { + "name": "Russian Bank Transfer", + "type": "bank_ru" + }, + { + "details": [ + { + "key": "additionalData.card.encrypted.json", + "type": "cardToken" + } + ], + "name": "Bancontact card", + "type": "bcmc" + }, + { + "name": "Boleto Bancario via HSBC", + "type": "boletobancario_hsbc" + }, + { + "name": "Boleto Bancario via Itau", + "type": "boletobancario_itau" + }, + { + "name": "Boleto Bancario via Santander", + "type": "boletobancario_santander" + }, + { + "name": "c_cash", + "type": "c_cash" + }, + { + "name": "CashU", + "type": "cashu" + }, + { + "name": "Paiement en 3 fois par Cartes Bancaires", + "type": "cofinoga_3xcb" + }, + { + "name": "DineroMail", + "type": "dineromail" + }, + { + "name": "Online bank transfer.", + "type": "directEbanking" + }, + { + "name": "Direct Debit Brazil - Banco do Brazil", + "type": "directdebit_BR_bancodobrasil" + }, + { + "name": "Direct Debit Brazil - Bradesco", + "type": "directdebit_BR_bradesco" + }, + { + "name": "Direct Debit Brazil - Caixa Economica Federal", + "type": "directdebit_BR_caixa" + }, + { + "name": "Direct Debit Brazil - HSBC", + "type": "directdebit_BR_hsbc" + }, + { + "name": "Direct Debit Brazil - Itau", + "type": "directdebit_BR_itau" + }, + { + "name": "Direct Debit Brazil - Santander", + "type": "directdebit_BR_santander" + }, + { + "name": "Eenmalige machtiging", + "type": "directdebit_NL" + }, + { + "details": [ + { + "items": [ + { + "id": "11", + "name": "Bank transfer / postal" + }, + { + "id": "74", + "name": "Banki Spółdzielcze" + }, + { + "id": "73", + "name": "BLIK" + }, + { + "id": "32", + "name": "BNP Paribas" + }, + { + "id": "16", + "name": "Credit Agricole" + }, + { + "id": "83", + "name": "EnveloBank" + }, + { + "id": "55", + "name": "erata - dotpay installment" + }, + { + "id": "93", + "name": "eSKOK" + }, + { + "id": "56", + "name": "eurobank płatności online" + }, + { + "id": "76", + "name": "Getin Bank PBL" + }, + { + "id": "81", + "name": "Idea Cloud" + }, + { + "id": "7", + "name": "ING Corporate customers" + }, + { + "id": "35", + "name": "Kantor Polski" + }, + { + "id": "44", + "name": "Millennium - Płatności Internetowe" + }, + { + "id": "10", + "name": "Millennium Corporate customers" + }, + { + "id": "68", + "name": "mRaty" + }, + { + "id": "1", + "name": "mTransfer" + }, + { + "id": "80", + "name": "Noble Pay" + }, + { + "id": "50", + "name": "Pay Way Toyota Bank" + }, + { + "id": "45", + "name": "Pay with Alior Bank" + }, + { + "id": "65", + "name": "Paylink Idea Bank" + }, + { + "id": "36", + "name": "Pekao24Przelew" + }, + { + "id": "70", + "name": "Pocztowy24" + }, + { + "id": "6", + "name": "Przelew24" + }, + { + "id": "46", + "name": "Płacę z Citi Handlowy" + }, + { + "id": "38", + "name": "Płacę z ING" + }, + { + "id": "2", + "name": "Płacę z Inteligo" + }, + { + "id": "4", + "name": "Płacę z iPKO" + }, + { + "id": "72", + "name": "Płacę z Orange" + }, + { + "id": "66", + "name": "Płacę z PBS" + }, + { + "id": "75", + "name": "Płacę z Plus Bank" + }, + { + "id": "51", + "name": "Płać z BOŚ" + }, + { + "id": "48", + "name": "R-Przelew" + }, + { + "id": "88", + "name": "Raiffeisen" + }, + { + "id": "52", + "name": "SkyCash" + }, + { + "id": "58", + "name": "Szybkie Platnosci Internetowe z Deutsche Bank PBC" + }, + { + "id": "60", + "name": "T-Mobile usługi bankowe" + }, + { + "id": "21", + "name": "VIA - Moje Rachunki" + }, + { + "id": "84", + "name": "Volkswagen Bank direct" + }, + { + "id": "31", + "name": "Zaplac w Zabce i we Freshmarket" + }, + { + "id": "24", + "name": "mPay" + } + ], + "key": "issuer", + "type": "select" + } + ], + "name": "Local Polish Payment Methods", + "type": "dotpay" + }, + { + "name": "Finnish E-Banking", + "type": "ebanking_FI" + }, + { + "name": "Lastschrift (ELV)", + "type": "elv" + }, + { + "details": [ + { + "items": [ + { + "id": "550", + "name": "?eská spo?itelna" + }, + { + "id": "231", + "name": "POP Pankki" + }, + { + "id": "551", + "name": "Kb" + }, + { + "id": "232", + "name": "Aktia" + }, + { + "id": "552", + "name": "Raiffeisen" + }, + { + "id": "750", + "name": "Swedbank" + }, + { + "id": "211", + "name": "Nordea" + }, + { + "id": "233", + "name": "Säästöpankki" + }, + { + "id": "553", + "name": "Csob" + }, + { + "id": "751", + "name": "SEB" + }, + { + "id": "234", + "name": "S-Pankki" + }, + { + "id": "554", + "name": "Moneta" + }, + { + "id": "752", + "name": "Nordea" + }, + { + "id": "235", + "name": "OmaSP" + }, + { + "id": "213", + "name": "Op-Pohjola" + }, + { + "id": "555", + "name": "UniCredit" + }, + { + "id": "753", + "name": "LHV" + }, + { + "id": "556", + "name": "Fio" + }, + { + "id": "557", + "name": "mBank" + }, + { + "id": "216", + "name": "Handelsbanken" + }, + { + "id": "260", + "name": "Länsförsäkringar" + }, + { + "id": "240", + "name": "BankDeposit" + }, + { + "id": "265", + "name": "Sparbanken" + }, + { + "id": "640", + "name": "BankDeposit" + }, + { + "id": "200", + "name": "Ålandsbanken" + }, + { + "id": "720", + "name": "Swedbank" + }, + { + "id": "940", + "name": "Swedbank" + }, + { + "id": "204", + "name": "Danske Bank" + }, + { + "id": "721", + "name": "SEB" + }, + { + "id": "941", + "name": "SEB" + }, + { + "id": "722", + "name": "DNB" + }, + { + "id": "942", + "name": "Citadele" + }, + { + "id": "205", + "name": "Handelsbanken" + }, + { + "id": "723", + "name": "Šiaulių Bankas" + }, + { + "id": "943", + "name": "DNB" + }, + { + "id": "206", + "name": "Nordea" + }, + { + "id": "724", + "name": "Nordea" + }, + { + "id": "207", + "name": "SEB" + }, + { + "id": "208", + "name": "Skandiabanken" + }, + { + "id": "209", + "name": "Swedbank" + } + ], + "key": "issuer", + "type": "select" + } + ], + "name": "Bank Payment", + "type": "entercash" + }, + { + "name": "Nationale Entertainment Card", + "type": "entertainmentcard" + }, + { + "name": "Gall & Gall", + "type": "gallgall" + }, + { + "name": "Generic GiftCard", + "type": "genericgiftcard" + }, + { + "details": [ + { + "key": "bic", + "type": "text" + } + ], + "name": "GiroPay", + "type": "giropay" + }, + { + "name": "Globe GCash", + "type": "globegcash" + }, + { + "name": "Hunkemoller Lingerie Card", + "type": "hmlingerie" + }, + { + "details": [ + { + "items": [ + { + "id": "1121", + "name": "Test Issuer" + }, + { + "id": "1154", + "name": "Test Issuer 5" + }, + { + "id": "1153", + "name": "Test Issuer 4" + }, + { + "id": "1152", + "name": "Test Issuer 3" + }, + { + "id": "1151", + "name": "Test Issuer 2" + }, + { + "id": "1162", + "name": "Test Issuer Cancelled" + }, + { + "id": "1161", + "name": "Test Issuer Pending" + }, + { + "id": "1160", + "name": "Test Issuer Refused" + }, + { + "id": "1159", + "name": "Test Issuer 10" + }, + { + "id": "1158", + "name": "Test Issuer 9" + }, + { + "id": "1157", + "name": "Test Issuer 8" + }, + { + "id": "1156", + "name": "Test Issuer 7" + }, + { + "id": "1155", + "name": "Test Issuer 6" + } + ], + "key": "idealIssuer", + "type": "select" + } + ], + "name": "iDEAL", + "type": "ideal" + }, + { + "name": "Phone Payment", + "type": "ivr" + }, + { + "name": "Landline phone", + "type": "ivrLandline" + }, + { + "name": "Mobile phone", + "type": "ivrMobile" + }, + { + "details": [ + { + "details": [ + { + "key": "firstName", + "type": "text" + }, + { + "key": "infix", + "optional": "true", + "type": "text" + }, + { + "key": "lastName", + "type": "text" + }, + { + "items": [ + { + "id": "M", + "name": "MALE" + }, + { + "id": "F", + "name": "FEMALE" + } + ], + "key": "gender", + "type": "radio" + }, + { + "key": "dateOfBirth", + "type": "date" + }, + { + "key": "telephoneNumber", + "type": "tel" + }, + { + "key": "socialSecurityNumber", + "optional": "true", + "type": "text" + }, + { + "key": "shopperEmail", + "type": "emailAddress" + } + ], + "key": "personalDetails", + "type": "fieldSet" + }, + { + "details": [ + { + "key": "street", + "type": "text" + }, + { + "key": "houseNumberOrName", + "type": "text" + }, + { + "key": "city", + "type": "text" + }, + { + "key": "postalCode", + "type": "text" + }, + { + "key": "stateOrProvince", + "optional": "true", + "type": "text" + }, + { + "items": [ + { + "id": "SE", + "name": "SWEDEN" + }, + { + "id": "NO", + "name": "NORWAY" + }, + { + "id": "FI", + "name": "FINLAND" + }, + { + "id": "DK", + "name": "DENMARK" + }, + { + "id": "AT", + "name": "AUSTRIA" + }, + { + "id": "DE", + "name": "GERMANY" + }, + { + "id": "NL", + "name": "NETHERLANDS" + } + ], + "key": "country", + "type": "select" + } + ], + "key": "billingAddress", + "type": "address" + }, + { + "key": "separateDeliveryAddress", + "optional": "true", + "type": "boolean", + "value": "false" + }, + { + "details": [ + { + "key": "street", + "type": "text" + }, + { + "key": "houseNumberOrName", + "type": "text" + }, + { + "key": "city", + "type": "text" + }, + { + "key": "postalCode", + "type": "text" + }, + { + "key": "stateOrProvince", + "optional": "true", + "type": "text" + }, + { + "items": [ + { + "id": "SE", + "name": "SWEDEN" + }, + { + "id": "NO", + "name": "NORWAY" + }, + { + "id": "FI", + "name": "FINLAND" + }, + { + "id": "DK", + "name": "DENMARK" + }, + { + "id": "AT", + "name": "AUSTRIA" + }, + { + "id": "DE", + "name": "GERMANY" + }, + { + "id": "NL", + "name": "NETHERLANDS" + } + ], + "key": "country", + "type": "select" + } + ], + "key": "deliveryAddress", + "optional": "true", + "type": "address" + } + ], + "name": "Pay later with Klarna.", + "type": "klarna" + }, + { + "name": "Multibanco", + "type": "multibanco" + }, + { + "name": "Russian Online Payments", + "type": "online_RU" + }, + { + "name": "Invoice", + "type": "openinvoice" + }, + { + "name": "PayPal", + "type": "paypal" + }, + { + "name": "Paysafecard", + "type": "paysafecard" + }, + { + "name": "POLi", + "type": "poli" + }, + { + "details": [ + { + "items": [ + { + "id": "+7", + "name": "RU" + }, + { + "id": "+9955", + "name": "GE" + }, + { + "id": "+507", + "name": "PA" + }, + { + "id": "+44", + "name": "GB" + }, + { + "id": "+992", + "name": "TJ" + }, + { + "id": "+370", + "name": "LT" + }, + { + "id": "+972", + "name": "IL" + }, + { + "id": "+996", + "name": "KG" + }, + { + "id": "+380", + "name": "UA" + }, + { + "id": "+84", + "name": "VN" + }, + { + "id": "+90", + "name": "TR" + }, + { + "id": "+994", + "name": "AZ" + }, + { + "id": "+374", + "name": "AM" + }, + { + "id": "+371", + "name": "LV" + }, + { + "id": "+91", + "name": "IN" + }, + { + "id": "+66", + "name": "TH" + }, + { + "id": "+373", + "name": "MD" + }, + { + "id": "+1", + "name": "US" + }, + { + "id": "+81", + "name": "JP" + }, + { + "id": "+998", + "name": "UZ" + }, + { + "id": "+77", + "name": "KZ" + }, + { + "id": "+375", + "name": "BY" + }, + { + "id": "+372", + "name": "EE" + }, + { + "id": "+40", + "name": "RO" + }, + { + "id": "+82", + "name": "KR" + } + ], + "key": "qiwiwallet.telephoneNumberPrefix", + "type": "select" + }, + { + "key": "qiwiwallet.telephoneNumber", + "type": "text" + } + ], + "name": "Qiwi Wallet", + "type": "qiwiwallet" + }, + { + "name": "RatePay Invoice", + "type": "ratepay" + }, + { + "name": "SafetyPay", + "type": "safetypay" + }, + { + "details": [ + { + "key": "sepa.ownerName", + "type": "text" + }, + { + "key": "sepa.ibanNumber", + "type": "text" + } + ], + "name": "SEPA Direct Debit", + "type": "sepadirectdebit" + }, + { + "name": "Premium SMS", + "type": "sms" + }, + { + "name": "TenPay", + "type": "tenpay" + }, + { + "name": "Russian Cash Terminal Payments", + "type": "terminal_RU" + }, + { + "name": "Trustly Direct bank e-Payments", + "type": "trustly" + }, + { + "name": "Online Banking by Trustpay", + "type": "trustpay" + }, + { + "name": "UnionPay", + "type": "unionpay" + }, + { + "name": "Russian Wallet Payments", + "type": "wallet_RU" + }, + { + "name": "Webshop Giftcard", + "type": "webshopgiftcard" + }, + { + "name": "Your Gift", + "type": "yourgift" + } + ] +} \ No newline at end of file diff --git a/test/mocks/checkout/payments-error-invalid-data-422.json b/test/mocks/checkout/payments-error-invalid-data-422.json new file mode 100644 index 00000000..540ea247 --- /dev/null +++ b/test/mocks/checkout/payments-error-invalid-data-422.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "130", + "message": "Reference Missing", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/checkout/payments-success.json b/test/mocks/checkout/payments-success.json new file mode 100644 index 00000000..c4ed10fb --- /dev/null +++ b/test/mocks/checkout/payments-success.json @@ -0,0 +1,97 @@ +{ + "additionalData": { + "expiryDate": "8/2018", + "fraudResultType": "GREEN", + "cardBin": "411111", + "cardSummary": "1111", + "fraudManualReview": "false", + "aliasType": "Default", + "alias": "H167852639363479", + "cardPaymentMethod": "visa", + "cardIssuingCountry": "NL" + }, + "fraudResult": { + "accountScore": 0, + "results": [ + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 2, + "name": "CardChunkUsage" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 3, + "name": "PaymentDetailUsage" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 4, + "name": "HolderNameUsage" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 1, + "name": "PaymentDetailRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 13, + "name": "IssuerRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 15, + "name": "IssuingCountryReferral" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 27, + "name": "PmOwnerRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 82, + "name": "CustomFieldCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 25, + "name": "CVCAuthResultCheck" + } + } + ] + }, + "pspReference": "8535296650153317", + "resultCode": "Authorised" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsdetails-error-invalid-data-422.json b/test/mocks/checkout/paymentsdetails-error-invalid-data-422.json new file mode 100644 index 00000000..ce814f1e --- /dev/null +++ b/test/mocks/checkout/paymentsdetails-error-invalid-data-422.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "101", + "message": "Invalid card number", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsdetails-sucess.json b/test/mocks/checkout/paymentsdetails-sucess.json new file mode 100644 index 00000000..50d14663 --- /dev/null +++ b/test/mocks/checkout/paymentsdetails-sucess.json @@ -0,0 +1,8 @@ +{ + "pspReference":"8515232733321252", + "resultCode":"Authorised", + "additionalData":{ + "liabilityShift":"true", + "refusalReasonRaw":"AUTHORISED" + } +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsession-error-invalid-data-422.json b/test/mocks/checkout/paymentsession-error-invalid-data-422.json new file mode 100644 index 00000000..8e7c76da --- /dev/null +++ b/test/mocks/checkout/paymentsession-error-invalid-data-422.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "14_012", + "message": "The provided SDK token could not be parsed.", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsession-sucess.json b/test/mocks/checkout/paymentsession-sucess.json new file mode 100644 index 00000000..42446ad4 --- /dev/null +++ b/test/mocks/checkout/paymentsession-sucess.json @@ -0,0 +1,3 @@ +{ + "paymentSession": "eyJjaGVja291dHNob3BwZXJCYXNlVXJsIjoiaHR0cHM6XC9cL2NoZWNrb3V0c2asdHBlci10ZXN0LmFkeWVuLmNvbVwvY2hlY2tvdXRzaG9wcGVyXC8iLCJkaXNhYmxlUmVjdXJyaW5nRGV0YWlsVXJsIjoiaHR0cHM6XC9cL2NoZWNrb3V0c2hvcHBlci10ZXN0LmFkeWVuLmNvbVwvY2hlY2tvdXRzaG9wcGVyXC9zZXJ2aWNlc1wvUGF5bWVudEluaXRpYXRpb25cL3YxXC9kaXNhYmxlUmVjdXJyaW5nRGV0YWlsIiwiZ2VuZXJhdGlvbnRpbWUiOiIyMDE4LTA2LTIyVDE0OjMxOjI1WiIsImluaXRpYXRpb25VcmwiOiJodHRwczpcL1wvY2hlY2tvdXRzaG9wcGVyLXRlc3QuYWR5ZW4uY29tXC9jaGVja291dHNob3BwZXJcL3NlcnZpY2VzXC9QYXltZW50SW5pdGlhdGlvblwvdjFcL2luaXRpYXRlIiwib3JpZ2luIjoiIiwicGF5bWVudCI6eyJhbW91bnQiOnsiY3VycmVuY3kiOiJFVVIiLCJ2YWx1ZSI6MTAwMH0sImNvdW50cnlDb2RlIjoiTkwiLCJyZWZlcmVuY2UiOiJZb3VyIG9yZGVyIG51bWJlciIsInJldHVyblVybCI6Imh0dHBzOlwvXC95b3VyLWNvbXBhbnkuY29tXC8iLCJzZXNzaW9uVmFsaWRpdHkiOiIyMDE4LTA2LTIyVDE1OjMxOjI1WiJ9LCJwYXltZW50RGF0YSI6IkFiMDJiNGMwIUJRQUJBZ0FJemlidUZ2Z3hsMGVTOTFQZWtjbDB3VHJhRG1xTU1BWFdZUGdxOXI1NXJjKzJ5N2l5bWV2ZWswR0VWdU9sZDhPSkwyeTBzWnl3UVlYWFhHUDkwa0pZU21SVzIzS1dHYXp3VEhyMDV0cGpGMGZOMHJrZ2lPNTFBdkxrVnhQSWI4RE1iQUtmeVlyRVErdjlpZWIyUjI0emdiTXhYWGJJMWtjZGJWeEdKbENMRWVaXC9kNDUzclVGZ0NnRktWczNXUk1JRHVTTlBoQ1hCclwvMlhqMXJ4dDRFTkFFZEN3czVwb1VnTEdWdnBQK0RSSU9FNlU1bHB1djVJV1k0N256azBIeHdGdWZnNVZmUWhWOGZHd2RCQzZrdW4wTWI2dlZcL1JqWDc5Tm9FVHBKcUlXcDNseEFpQW5HZjl5Mlp0Q3UzNEROUlNOZUR4eUQ1UFFhaTlwWHRNTFo2YnBlMkZEMG1BRkpHNXAyUk9kNUc2RkM0UXRDMzA3YTRcL2d3ZVh5TklpeFN2MHBXdVZzV2RsUzlUM1RDN2dXZEZVSEVLb1ozU041MzZqeVdTZGRMTVNoMlRJZWwxN25ISnZsMnBxTmltQTlBRWpmUG05NG53U0M1SGJkd1NuSDlpQmdmY3NqaSsxVXYrVmlzVnVHbUk5V2lDYjRIR2pPZlFoQUxXbmxWZWZXVlhPWGs0NmkwOExRemZPN1krUXNRMjVRNmVkdEduM1ZCeHlUdDEwajlWMTZnMlwvaTl1Y3pcL2owZ0piODRoUGw3NFZ3bTlWYTNPZEl2bk1MdjdXNE14bG9MWlhcL2paakF3NGZ5V0ZtNHhQclp5ZUpWK2ZLbkV4UHdsY2FzbjVLQkp4SHpcLzJXNk9MOWQ1cE02T003WnprOE9RNVIwOWhcL1pKOHNSMTBGT29kOU1nQkJTNW1YeUMrWXU2Q1JSaGR6N2I4ZlRBRXA3SW10bGVTSTZJa0ZHTUVGQlFURXdNME5CTlRNM1JVRkZSRGczUXpJMFJFUTFNemt3T1VJNE1FRTNPRUU1TWpORk16Z3lNMFEyT0VSQlEwTTVORUk1UmtZNE16QTFSRU1pZlFkd01idGdFczlUZGRXeU96NGQrdlYyQVQxVUEwV3h3XC9NR05Pa0owdWxoaGhPYXVCQVpLK0RIdU5xXC9vQnQzRVQ0S3N2MDd2VnZRWFBZNkc2MzQ4Q2pzWWYyQURHQjV3NzlpeDc3ZERtZzZhWGRhSG95T3RxdHdDcyt2VUUxbXJhVytFOVhpZlh6Qm1UK2Roc2t4WlQ0NHllTzh1VGpjMTRKQnNpVWpmXC9ESEl5YUtzOHV3UFk2UnNxK3JUNjFtR3BseTBMQ25VNWlObjNDM2lPMHRcL3Y1WDY3eGRqWXhnYW5QcHEzTFVpZ29FNDZaOUpNdnp4NEFIdTZJNWJaUDJ6S3UwQzNWcXMyWjUwSENpQjh2MlhKY3dlY0lOcWFUWEZaQmwyclhNRmdBbDlDSjY2dkMwRnJJSWp1d3B4M1ZGelQxTHJmc3psOWdkYUY1aUp4VDlRemgraGNqNk9KaEhmcTNnQ0RGUFZsUnZIWkRcL1VHa3ltUmlvTGNPeDFBVEw3azhRclwvREpZQ3NjY3g5aXlEcnhhQ2hPa1FrV054VjZqcjBYSHRnaHdGSE5GeTFJc3kyeWxPcFJYMUVyY2Y0XC92bHJVU0N3WHQ2R0Z0dHhmR0xHbExlN0dBKzVaU3R3UGR4aGxUb2haeTdwMWg2a0U5ZnJxbU1tZk1YV2N1Rkt4NnZMWjVtMEtsbzZydllROWZ1Q0pUYkdKMDRENkI2RnR5WXYrOHlEWTJaeVBvRzhjbHJJZ3Z6dEtLaVlibG10RnRHakd3OVNaWkVxXC80ODBDOEZOdlVuZmtnXC9IT2FScnlKaXhvSjFicFBEK1YwRVlrYTVIbjBnWlwvRXVQTDFcL1B5eUp5Q0d5SVh2SlBFMHhZUWdDWllqcDJiNUhGZjZpMDdtUDFNdHNkYVBZd280VkQwRUNrckpDeE5DcnBIVmJqMWt3dmtcL0JxNE5QRXlFVFd2N25FamswUG1WalFySHpxZ2lpb2RIM1YrYXZodGxpSjcwNUx1RWFIdmNRTHU1aE5OSlVVRFNlTnMwR2hldVkxcGRuK3l6R1Y5ZG1OaklMSFI0N1B3UlQzRlwvMUJMNGU4elZLdFFOSWpYVnN1ZHd2UHN2RUNzamhmTGpaOEhmY3JGM1JTTW9pNnR0UlwvNkJlTVlSb1BHTlZ5bG9ybnBSQ3lqTXVsZmJlSzkzNWdaOVwvWkd6alFtZzRTRzlTWkUxSGdpaGhldFZ4bnh1YmRmMjhEcUxVNHBTZ2ZHWlFuMk83ZnYwNCt6RjQ0eHQ2VnJ6NFwvNHNzbTdaZUpKYW5HQStSVlFUZTlNTVNEYXU5Z1YyXC93Y0N4bGN6YmdkaUllYWQzb3RVK296V1FpS2VoODY2RVBrWjUxQmJraHRMNUxlT1lUYjAwYU5GRGk2QnVWZ2s2SG5sTnpJcDZIRDFcLytSaXVvc3llYTNmcVg0b1hwYVR0RE5WMEF1TlVLVnFvZUJkaktoTVVpb005UTVqbW94Q2hpcStWRndGbUlNUGFLMWpSRkpxTzRIUElsYWYwXC9MWk5cL3hzQU96WHQrVW5BQTFFZzZUU2FLYWN5amwxUXFmT21CNFV6TFwvcmx2WXRqRW5IdlwvdzZ4eUROMnp1IiwicGF5bWVudE1ldGhvZHMiOlt7ImNvbmZpZ3VyYXRpb24iOnsiY2FuSWdub3JlQ29va2llcyI6InRydWUifSwiZGV0YWlscyI6W3siaXRlbXMiOlt7ImlkIjoiMTEyMSIsIm5hbWUiOiJUZXN0IElzc3VlciJ9LHsiaWQiOiIxMTU0IiwibmFtZSI6IlRlc3QgSXNzdWVyIDUifSx7ImlkIjoiMTE1MyIsIm5hbWUiOiJUZXN0IElzc3VlciA0In0seyJpZCI6IjExNTIiLCJuYW1lIjoiVGVzdCBJc3N1ZXIgMyJ9LHsiaWQiOiIxMTUxIiwibmFtZSI6IlRlc3QgSXNzdWVyIDIifSx7ImlkIjoiMTE2MiIsIm5hbWUiOiJUZXN0IElzc3VlciBDYW5jZWxsZWQifSx7ImlkIjoiMTE2MSIsIm5hbWUiOiJUZXN0IElzc3VlciBQZW5kaW5nIn0seyJpZCI6IjExNjAiLCJuYW1lIjoiVGVzdCBJc3N1ZXIgUmVmdXNlZCJ9LHsiaWQiOiIxMTU5IiwibmFtZSI6IlRlc3QgSXNzdWVyIDEwIn0seyJpZCI6IjExNTgiLCJuYW1lIjoiVGVzdCBJc3N1ZXIgOSJ9LHsiaWQiOiIxMTU3IiwibmFtZSI6IlRlc3QgSXNzdWVyIDgifSx7ImlkIjoiMTE1NiIsIm5hbWUiOiJUZXN0IElzc3VlciA3In0seyJpZCI6IjExNTUiLCJuYW1lIjoiVGVzdCBJc3N1ZXIgNiJ9XSwia2V5IjoiaWRlYWxJc3N1ZXIiLCJ0eXBlIjoic2VsZWN0In1dLCJuYW1lIjoiaURFQUwiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBXbGtaV0ZzIiwidHlwZSI6ImlkZWFsIn0seyJkZXRhaWxzIjpbeyJrZXkiOiJlbmNyeXB0ZWRDYXJkTnVtYmVyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkU2VjdXJpdHlDb2RlIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5TW9udGgiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRFeHBpcnlZZWFyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiaG9sZGVyTmFtZSIsIm9wdGlvbmFsIjoidHJ1ZSIsInR5cGUiOiJ0ZXh0In1dLCJncm91cCI6eyJuYW1lIjoiQ3JlZGl0IENhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYTmphR1Z0WlE9PSIsInR5cGUiOiJjYXJkIn0sIm5hbWUiOiJNYXN0ZXJDYXJkIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQVzFqIiwidHlwZSI6Im1jIn0seyJuYW1lIjoiUGF5UGFsIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQWEJoZVhCaGJBPT0iLCJ0eXBlIjoicGF5cGFsIn0seyJkZXRhaWxzIjpbeyJrZXkiOiJlbmNyeXB0ZWRDYXJkTnVtYmVyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkU2VjdXJpdHlDb2RlIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5TW9udGgiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRFeHBpcnlZZWFyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiaG9sZGVyTmFtZSIsIm9wdGlvbmFsIjoidHJ1ZSIsInR5cGUiOiJ0ZXh0In1dLCJncm91cCI6eyJuYW1lIjoiQ3JlZGl0IENhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYTmphR1Z0WlE9PSIsInR5cGUiOiJjYXJkIn0sIm5hbWUiOiJWSVNBIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQWFpwYzJFPSIsInR5cGUiOiJ2aXNhIn0seyJkZXRhaWxzIjpbeyJrZXkiOiJlbmNyeXB0ZWRDYXJkTnVtYmVyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkU2VjdXJpdHlDb2RlIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5TW9udGgiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRFeHBpcnlZZWFyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiaG9sZGVyTmFtZSIsIm9wdGlvbmFsIjoidHJ1ZSIsInR5cGUiOiJ0ZXh0In1dLCJncm91cCI6eyJuYW1lIjoiQ3JlZGl0IENhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYTmphR1Z0WlE9PSIsInR5cGUiOiJjYXJkIn0sIm5hbWUiOiJBbWVyaWNhbiBFeHByZXNzIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQV0Z0WlhnPSIsInR5cGUiOiJhbWV4In0seyJuYW1lIjoiU0VQQSBEaXJlY3QgRGViaXQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYTmxjR0ZrYVhKbFkzUmtaV0pwZEE9PSIsInR5cGUiOiJzZXBhZGlyZWN0ZGViaXQifSx7Im5hbWUiOiJQYXlzYWZlY2FyZCIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFhCaGVYTmhabVZqWVhKayIsInR5cGUiOiJwYXlzYWZlY2FyZCJ9LHsibmFtZSI6IkJhbmsgVHJhbnNmZXIgKE5MKSIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdKaGJtdFVjbUZ1YzJabGNsOU9UQT09IiwidHlwZSI6ImJhbmtUcmFuc2Zlcl9OTCJ9LHsiZGV0YWlscyI6W3sia2V5IjoiZW5jcnlwdGVkQ2FyZE51bWJlciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZFNlY3VyaXR5Q29kZSIsIm9wdGlvbmFsIjoidHJ1ZSIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZEV4cGlyeU1vbnRoIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5WWVhciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImhvbGRlck5hbWUiLCJvcHRpb25hbCI6InRydWUiLCJ0eXBlIjoidGV4dCJ9XSwiZ3JvdXAiOnsibmFtZSI6IkNyZWRpdCBDYXJkIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQWE5qYUdWdFpRPT0iLCJ0eXBlIjoiY2FyZCJ9LCJuYW1lIjoiTWFlc3RybyIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFcxaFpYTjBjbTg9IiwidHlwZSI6Im1hZXN0cm8ifSx7Im5hbWUiOiJIdW5rZW1vbGxlciBMaW5nZXJpZSBDYXJkIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQV2h0YkdsdVoyVnlhV1U9IiwidHlwZSI6ImhtbGluZ2VyaWUifSx7Im5hbWUiOiJFZW5tYWxpZ2UgbWFjaHRpZ2luZyIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdScGNtVmpkR1JsWW1sMFgwNU0iLCJ0eXBlIjoiZGlyZWN0ZGViaXRfTkwifSx7Im5hbWUiOiJTRVBBIEJhbmsgVHJhbnNmZXIiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBXSmhibXRVY21GdWMyWmxjbDlKUWtGTyIsInR5cGUiOiJiYW5rVHJhbnNmZXJfSUJBTiJ9LHsibmFtZSI6ImNfY2FzaCIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdOZlkyRnphQT09IiwidHlwZSI6ImNfY2FzaCJ9LHsiZGV0YWlscyI6W3sia2V5IjoiZW5jcnlwdGVkQ2FyZE51bWJlciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZFNlY3VyaXR5Q29kZSIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZEV4cGlyeU1vbnRoIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5WWVhciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImhvbGRlck5hbWUiLCJvcHRpb25hbCI6InRydWUiLCJ0eXBlIjoidGV4dCJ9XSwiZ3JvdXAiOnsibmFtZSI6IkNyZWRpdCBDYXJkIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQWE5qYUdWdFpRPT0iLCJ0eXBlIjoiY2FyZCJ9LCJuYW1lIjoiRXhwcmVzc1BheSIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdOMWNBPT0iLCJ0eXBlIjoiY3VwIn0seyJkZXRhaWxzIjpbeyJrZXkiOiJlbmNyeXB0ZWRDYXJkTnVtYmVyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkU2VjdXJpdHlDb2RlIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5TW9udGgiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRFeHBpcnlZZWFyIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiaG9sZGVyTmFtZSIsIm9wdGlvbmFsIjoidHJ1ZSIsInR5cGUiOiJ0ZXh0In1dLCJncm91cCI6eyJuYW1lIjoiQ3JlZGl0IENhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYTmphR1Z0WlE9PSIsInR5cGUiOiJjYXJkIn0sIm5hbWUiOiJEaW5lcnMgQ2x1YiIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdScGJtVnljdz09IiwidHlwZSI6ImRpbmVycyJ9LHsiZGV0YWlscyI6W3sia2V5IjoiZW5jcnlwdGVkQ2FyZE51bWJlciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZFNlY3VyaXR5Q29kZSIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZEV4cGlyeU1vbnRoIiwidHlwZSI6ImNhcmRUb2tlbiJ9LHsia2V5IjoiZW5jcnlwdGVkRXhwaXJ5WWVhciIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImhvbGRlck5hbWUiLCJvcHRpb25hbCI6InRydWUiLCJ0eXBlIjoidGV4dCJ9XSwiZ3JvdXAiOnsibmFtZSI6IkNyZWRpdCBDYXJkIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQWE5qYUdWdFpRPT0iLCJ0eXBlIjoiY2FyZCJ9LCJuYW1lIjoiRGlzY292ZXIiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBXUnBjMk52ZG1WeSIsInR5cGUiOiJkaXNjb3ZlciJ9LHsibmFtZSI6Ik5hdGlvbmFsZSBFbnRlcnRhaW5tZW50IENhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBXVnVkR1Z5ZEdGcGJtMWxiblJqWVhKayIsInR5cGUiOiJlbnRlcnRhaW5tZW50Y2FyZCJ9LHsibmFtZSI6IkdhbGwgJiBHYWxsIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQV2RoYkd4bllXeHMiLCJ0eXBlIjoiZ2FsbGdhbGwifSx7Im5hbWUiOiJQaG9uZSBQYXltZW50IiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQV2wyY2c9PSIsInR5cGUiOiJpdnIifSx7Im5hbWUiOiJMYW5kbGluZSBwaG9uZSIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdsMmNreGhibVJzYVc1bCIsInR5cGUiOiJpdnJMYW5kbGluZSJ9LHsibmFtZSI6Ik1vYmlsZSBwaG9uZSIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdsMmNrMXZZbWxzWlE9PSIsInR5cGUiOiJpdnJNb2JpbGUifSx7ImRldGFpbHMiOlt7ImtleSI6ImVuY3J5cHRlZENhcmROdW1iZXIiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRTZWN1cml0eUNvZGUiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJlbmNyeXB0ZWRFeHBpcnlNb250aCIsInR5cGUiOiJjYXJkVG9rZW4ifSx7ImtleSI6ImVuY3J5cHRlZEV4cGlyeVllYXIiLCJ0eXBlIjoiY2FyZFRva2VuIn0seyJrZXkiOiJob2xkZXJOYW1lIiwib3B0aW9uYWwiOiJ0cnVlIiwidHlwZSI6InRleHQifV0sImdyb3VwIjp7Im5hbWUiOiJDcmVkaXQgQ2FyZCIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFhOamFHVnRaUT09IiwidHlwZSI6ImNhcmQifSwibmFtZSI6IkpDQiIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFdwallnPT0iLCJ0eXBlIjoiamNiIn0seyJuYW1lIjoiTW9uZXlib29rZXJzIiwicGF5bWVudE1ldGhvZERhdGEiOiJDZjYyZjFlMyFZbkpoYm1SRGIyUmxQVzF2Ym1WNVltOXZhMlZ5Y3c9PSIsInR5cGUiOiJtb25leWJvb2tlcnMifSx7Im5hbWUiOiJPbmViaXAiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBXOXVaV0pwY0E9PSIsInR5cGUiOiJvbmViaXAifSx7Im5hbWUiOiJQcmVtaXVtIFNNUyIsInBheW1lbnRNZXRob2REYXRhIjoiQ2Y2MmYxZTMhWW5KaGJtUkRiMlJsUFhOdGN3PT0iLCJ0eXBlIjoic21zIn0seyJuYW1lIjoiVW5pb25QYXkiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYVnVhVzl1Y0dGNSIsInR5cGUiOiJ1bmlvbnBheSJ9LHsibmFtZSI6IldlYnNob3AgR2lmdGNhcmQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYZGxZbk5vYjNCbmFXWjBZMkZ5WkE9PSIsInR5cGUiOiJ3ZWJzaG9wZ2lmdGNhcmQifSx7Im5hbWUiOiJZb3VyIEdpZnQiLCJwYXltZW50TWV0aG9kRGF0YSI6IkNmNjJmMWUzIVluSmhibVJEYjJSbFBYbHZkWEpuYVdaMCIsInR5cGUiOiJ5b3VyZ2lmdCJ9XSwicHVibGljS2V5IjoiMTAwMDF8QkNBREY4MjU3RTE4QTFBODlBQ0M0MTQ5RDBGQzMyNEU5ODMxNUMyNDA1RDc1NUU1MDRENjY0QjJDMUM3MUE2MzhCOUQxMkZEMjkwRTEyQTA0QkIxRTZCMkRBM0YzN0M1NTJEMDExQ0ZCQUJCQ0M4NDgwNkFCQjc4RUQxNjU3OERFRDk2NDQ4Q0I4QjU0MTM5RkQ3QzcyRjkwQzA4NkMzNkFFNzdFNjlFOTE3MUEzQTBENTIwRDAyMTM2MzcyNjNFMEM1REY5NjREQUQ4RDc5N0VCMURENkU1NEFENjY5RDYwQUFDMjU1NUUwQzhCRTIyNzNGODk4NDQ3M0U3NkVFNzM4N0ZFQzBFNzFCODM2ODQ0Qjg0MDZBQzkwNTk0OUZCODhGQzY4RThGMDE4NjYzMkYxRURCNEM5QjVCODg4RUY1QzU3RERFMTEzN0JCRjM2RjY1NEU0N0U1NzFGQkM4ODgyOENCRTk0MzhENzQyRjNDMDkyQUQ1RkYzRTYyQUNBRDI1MjQ2RUE0M0QyMkNGQzhBRTE0NDE5NzY3ODY3RDJDNjBEQ0JBNkFDOTIwMDhEMEQ4ODM0QkVBMTExN0FFMzQ3RjMxMkQ2QzAxQzU3Q0I0MkFERDNENEQ2MkUzNzI3QTNDRThBQTFGMDlCRjZCNzk2QTBBMzc0MUJDNDgxMTEifQ==" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsresult-error-invalid-data-payload-422.json b/test/mocks/checkout/paymentsresult-error-invalid-data-payload-422.json new file mode 100644 index 00000000..aec41bc0 --- /dev/null +++ b/test/mocks/checkout/paymentsresult-error-invalid-data-payload-422.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "14_018", + "message": "Invalid payload provided", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsresult-sucess.json b/test/mocks/checkout/paymentsresult-sucess.json new file mode 100644 index 00000000..9ee3775c --- /dev/null +++ b/test/mocks/checkout/paymentsresult-sucess.json @@ -0,0 +1,4 @@ +{ + "pspReference": "8535253563623704", + "resultCode": "Authorised" +} \ No newline at end of file diff --git a/test/mocks/checkoututility/originkeys-success.json b/test/mocks/checkoututility/originkeys-success.json new file mode 100644 index 00000000..12908762 --- /dev/null +++ b/test/mocks/checkoututility/originkeys-success.json @@ -0,0 +1,7 @@ +{ + "originKeys": { + "https://www.your-domain1.com": "pub.v2.7814286629520534.aHR0cHM6Ly93d3cueW91ci1kb21haW4xLmNvbQ.UEwIBmW9-c_uXo5wSEr2w8Hz8hVIpujXPHjpcEse3xI", + "https://www.your-domain3.com": "pub.v2.7814286629520534.aHR0cHM6Ly93d3cueW91ci1kb21haW4zLmNvbQ.fUvflu-YIdZSsLEH8Qqmr7ksE4ag_NYiiMXK0s6aq_4", + "https://www.your-domain2.com": "pub.v2.7814286629520534.aHR0cHM6Ly93d3cueW91ci1kb21haW4yLmNvbQ.EP6eXBJKk0t7-QIUl6e_b1qMuMHGepxG_SlUqxAYrfY" + } +} \ No newline at end of file From e6986a7035d5a7afa1fd6d2b0218921d682861ec Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 10:15:55 +0100 Subject: [PATCH 03/29] Format lines --- Adyen/__init__.py | 1 - Adyen/client.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Adyen/__init__.py b/Adyen/__init__.py index c1b08313..03a00f75 100644 --- a/Adyen/__init__.py +++ b/Adyen/__init__.py @@ -34,7 +34,6 @@ def __init__(self, **kwargs): self.checkout = AdyenCheckoutApi(client=self.client) - _base_adyen_obj = Adyen() recurring = _base_adyen_obj.recurring hpp = _base_adyen_obj.hpp diff --git a/Adyen/client.py b/Adyen/client.py index 5224f4da..2cd5e445 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -404,7 +404,7 @@ def call_checkout_api(self, request_data, service, action, **kwargs): url = self._determine_checkout_url(platform, service, action) raw_response, raw_request, status_code, headers = \ - self.http_client.request(url, json=message, xapikey=xapikey , headers=headers, + self.http_client.request(url, json=message, xapikey=xapikey, headers=headers, **kwargs) # Creates AdyenResponse if request was successful, raises error if not. From 40b60b0077a58ab4ed6648929a570594de2bd10a Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 10:27:55 +0100 Subject: [PATCH 04/29] Format lines for client --- Adyen/client.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 2cd5e445..2b99bf4f 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -404,7 +404,8 @@ def call_checkout_api(self, request_data, service, action, **kwargs): url = self._determine_checkout_url(platform, service, action) raw_response, raw_request, status_code, headers = \ - self.http_client.request(url, json=message, xapikey=xapikey, headers=headers, + self.http_client.request(url, json=message, + xapikey=xapikey, headers=headers, **kwargs) # Creates AdyenResponse if request was successful, raises error if not. @@ -487,9 +488,9 @@ def _handle_response(self, url, raw_response, raw_request, "Unexpected error while communicating with Adyen." " Received the response data:'{}', HTTP Code:'{}'. " "Please reach out to support@adyen.com if the " - "problem persists with the psp:{}" - .format(raw_response, status_code, - headers.get('pspReference')), + "problem persists with the psp:{}".format(raw_response, + status_code, + headers.get('pspReference')), status_code=status_code, raw_request=raw_request, raw_response=raw_response, From 2e834fb8c2c57d1b457c66d86a95a8d0b20493e1 Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 10:48:52 +0100 Subject: [PATCH 05/29] Format lines for client long lines --- Adyen/client.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 2b99bf4f..f0c4639f 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -488,9 +488,10 @@ def _handle_response(self, url, raw_response, raw_request, "Unexpected error while communicating with Adyen." " Received the response data:'{}', HTTP Code:'{}'. " "Please reach out to support@adyen.com if the " - "problem persists with the psp:{}".format(raw_response, - status_code, - headers.get('pspReference')), + "problem persists with the psp:{}".format( + raw_response, + status_code, + headers.get('pspReference')), status_code=status_code, raw_request=raw_request, raw_response=raw_response, From 25ca3f26dcb90aece4c46512d6497154cdd54560 Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 10:58:33 +0100 Subject: [PATCH 06/29] Format lines for checkout --- test/CheckoutTest.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 9aed4c7d..0128b99f 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -14,13 +14,10 @@ class TestCheckout(unittest.TestCase): client.app_name = "appname" def test_payment_methods_success_mocked(self): - request = {} - request['merchantAccount'] = "YourMerchantAccount" - + request = {'merchantAccount': "YourMerchantAccount"} + file = "test/mocks/checkout/paymentmethods-success.json" self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/checkout/' - 'paymentmethods-success' - '.json') + file) result = self.ady.checkout.payment_methods(request) self.assertEqual("AliPay", result.message['paymentMethods'][0]['name']) self.assertEqual("Credit Card", result.message['paymentMethods'][2]['name']) From bee694552c8c6ad239db4c0c46af47cc24b4fe8b Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 11:02:23 +0100 Subject: [PATCH 07/29] Format lines for checkout again --- test/CheckoutTest.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 0128b99f..ecfa8535 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -19,6 +19,9 @@ def test_payment_methods_success_mocked(self): self.ady.client = self.test.create_client_from_file(200, request, file) result = self.ady.checkout.payment_methods(request) - self.assertEqual("AliPay", result.message['paymentMethods'][0]['name']) - self.assertEqual("Credit Card", result.message['paymentMethods'][2]['name']) - self.assertEqual("Credit Card via AsiaPay", result.message['paymentMethods'][3]['name']) + self.assertEqual("AliPay", + result.message['paymentMethods'][0]['name']) + self.assertEqual("Credit Card", + result.message['paymentMethods'][2]['name']) + self.assertEqual("Credit Card via AsiaPay", + result.message['paymentMethods'][3]['name']) From 1b50cadfc98a73d8c234321cf1061f84c2362b95 Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 14:59:22 +0100 Subject: [PATCH 08/29] Add all checkout components --- Adyen/client.py | 4 + Adyen/services.py | 30 +++++++ Adyen/validation.py | 9 ++ test/CheckoutTest.py | 82 ++++++++++++++++++- test/CheckoutUtilityTest.py | 47 +++++++++++ .../checkout/paymentsdetails-success.json | 8 ++ .../checkout/paymentsdetails-sucess.json | 8 -- ...ucess.json => paymentsession-success.json} | 0 ...ucess.json => paymentsresult-success.json} | 0 9 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 test/CheckoutUtilityTest.py create mode 100644 test/mocks/checkout/paymentsdetails-success.json delete mode 100644 test/mocks/checkout/paymentsdetails-sucess.json rename test/mocks/checkout/{paymentsession-sucess.json => paymentsession-success.json} (100%) rename test/mocks/checkout/{paymentsresult-sucess.json => paymentsresult-success.json} (100%) diff --git a/Adyen/client.py b/Adyen/client.py index f0c4639f..dae03791 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -131,6 +131,10 @@ def _determine_checkout_url(self, platform, service, action): service (str): API service to place request through. action (str): the API action to perform. """ + if action == "paymentDetails": + action = "payment/details" + if action == "paymentResult": + action = "payment/result" base_uri = settings.BASE_CHECKOUT_URL.format(platform) api_version = settings.CHECKOUT_API_VERSION diff --git a/Adyen/services.py b/Adyen/services.py index 2e9d2007..52e88126 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -314,3 +314,33 @@ def payment_methods(self, request="", **kwargs): return self.client.call_checkout_api(request, self.service, action, **kwargs) + + def payments(self, request="", **kwargs): + action = "payments" + if validation.check_in(request, action): + return self.client.call_checkout_api(request, self.service, + action, **kwargs) + + def payments_details(self, request="", **kwargs): + action = "paymentsDetails" + if validation.check_in(request, action): + return self.client.call_checkout_api(request, self.service, + action, **kwargs) + + def payment_session(self, request="", **kwargs): + action = "paymentsSession" + if validation.check_in(request, action): + return self.client.call_checkout_api(request, self.service, + action, **kwargs) + + def payment_result(self, request="", **kwargs): + action = "paymentResult" + if validation.check_in(request, action): + return self.client.call_checkout_api(request, self.service, action, + **kwargs) + + def origin_key(self, request="", **kwargs): + action = "originKeys" + if validation.check_in(request, action): + return self.client.call_checkout_api(request, self.service, + action, **kwargs) diff --git a/Adyen/validation.py b/Adyen/validation.py index dd84d0db..e9e796cd 100644 --- a/Adyen/validation.py +++ b/Adyen/validation.py @@ -18,6 +18,15 @@ actions['cancelOrRefund'] = ["originalReference"] actions['paymentMethods'] = ["merchantAccount"] +actions['payments'] = ["amount", "reference", "paymentMethod", + "merchantAccount", "returnUrl"] +actions['paymentsDetails'] = ["paymentData", "details"] +actions['paymentsSession'] = ["amount", "reference", "shopperReference", + "channel", "token", "returnUrl", "countryCode", + "shopperLocale", "sessionValidity", + "merchantAccount"] +actions['paymentResult'] = ["payload"] +actions['originKeys'] = ["originDomains"] payout_required_fields = { 'confirmThirdParty': ( diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index ecfa8535..af35b39f 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -15,13 +15,87 @@ class TestCheckout(unittest.TestCase): def test_payment_methods_success_mocked(self): request = {'merchantAccount': "YourMerchantAccount"} - file = "test/mocks/checkout/paymentmethods-success.json" self.ady.client = self.test.create_client_from_file(200, request, - file) + "test/mocks/" + "checkout/" + "paymentmethods" + "-success.json") result = self.ady.checkout.payment_methods(request) - self.assertEqual("AliPay", - result.message['paymentMethods'][0]['name']) + self.assertEqual("AliPay", result.message['paymentMethods'][0]['name']) self.assertEqual("Credit Card", result.message['paymentMethods'][2]['name']) self.assertEqual("Credit Card via AsiaPay", result.message['paymentMethods'][3]['name']) + + def test_payments_success_mocked(self): + request = {'amount': {"value": "100000", "currency": "EUR"}, + 'reference': "123456", 'paymentMethod': { + "type": "scheme", + "number": "4111111111111111", + "expiryMonth": "08", + "expiryYear": "2018", + "holderName": "John Smith", + "cvc": "737" + }, 'merchantAccount': "YourMerchantAccount", + 'returnUrl': "https://your-company.com/..."} + + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "payments-success" + ".json") + result = self.ady.checkout.payments(request) + self.assertEqual("8535296650153317", result.message['pspReference']) + self.assertEqual("Authorised", result.message['resultCode']) + self.assertEqual("8/2018", + result.message["additionalData"]['expiryDate']) + self.assertEqual("GREEN", + result.message["additionalData"]['fraudResultType']) + + def test_payments_details_success_mocked(self): + request = {'paymentData': "Hee57361f99....", 'details': { + "MD": "sdfsdfsdf...", + "PaRes": "sdkfhskdjfsdf..." + }} + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsdetails" + "-success.json") + result = self.ady.checkout.payments_details(request) + self.assertEqual("8515232733321252", result.message['pspReference']) + self.assertEqual("Authorised", result.message['resultCode']) + self.assertEqual("true", + result.message['additionalData']['liabilityShift']) + self.assertEqual("AUTHORISED", + result.message['additionalData']['refusalReasonRaw']) + + def test_payments_session_success_mocked(self): + request = {"reference": "Your order number", + "shopperReference": "yourShopperId_IOfW3k9G2PvXFu2j", + "channel": "iOS", + "token": "TOKEN_YOU_GET_FROM_CHECKOUT_SDK", + "returnUrl": "app://", "countryCode": "NL", + "shopperLocale": "nl_NL", + "sessionValidity": "2017-04-06T13:09:13Z", + "merchantAccount": "YOUR_MERCHANT_ACCOUNT", + 'amount': {"value": "17408", "currency": "EUR"}} + + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsession" + "-success.json") + result = self.ady.checkout.payment_session(request) + self.assertIsNotNone(result.message['paymentSession']) + + def test_payments_result_success_mocked(self): + request = {"payload": "VALUE_YOU_GET_FROM_CHECKOUT_SDK"} + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsresult" + "-success.json") + result = self.ady.checkout.payment_result(request) + self.assertEqual("8535253563623704", result.message['pspReference']) + self.assertEqual("Authorised", result.message['resultCode']) \ No newline at end of file diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py new file mode 100644 index 00000000..490475bb --- /dev/null +++ b/test/CheckoutUtilityTest.py @@ -0,0 +1,47 @@ +import Adyen +import unittest +from BaseTest import BaseTest +import pprint + + +class TestCheckoutUtility(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.xapikey = "YourXapikey" + client.platform = "test" + client.app_name = "appname" + + def test_origin_keys_success_mocked(self): + request = { + "originDomains": { + "https://www.your-domain1.com", + "https://www.your-domain2.com", + "https://www.your-domain3.com" + } + } + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkoututility/" + "originkeys" + "-success.json") + result = self.ady.checkout.origin_key(request) + + self.assertEqual("pub.v2.7814286629520534.aHR0cHM6Ly93d3cu" + "eW91ci1kb21haW4xLmNvbQ.UEwIBmW9-c_uXo5wS" + "Er2w8Hz8hVIpujXPHjpcEse3xI", + result.message['originKeys'] + ['https://www.your-domain1.com']) + + self.assertEqual("pub.v2.7814286629520534.aHR0cHM6Ly93d3cu" + "eW91ci1kb21haW4zLmNvbQ.fUvflu-YIdZSsLEH8" + "Qqmr7ksE4ag_NYiiMXK0s6aq_4", + result.message['originKeys'] + ['https://www.your-domain3.com']) + + self.assertEqual("pub.v2.7814286629520534.aHR0cHM6Ly93d3cue" + "W91ci1kb21haW4yLmNvbQ.EP6eXBJKk0t7-QIUl6e_" + "b1qMuMHGepxG_SlUqxAYrfY", + result.message['originKeys'] + ['https://www.your-domain2.com']) diff --git a/test/mocks/checkout/paymentsdetails-success.json b/test/mocks/checkout/paymentsdetails-success.json new file mode 100644 index 00000000..e87446a4 --- /dev/null +++ b/test/mocks/checkout/paymentsdetails-success.json @@ -0,0 +1,8 @@ +{ + "pspReference": "8515232733321252", + "resultCode": "Authorised", + "additionalData": { + "liabilityShift": "true", + "refusalReasonRaw": "AUTHORISED" + } +} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsdetails-sucess.json b/test/mocks/checkout/paymentsdetails-sucess.json deleted file mode 100644 index 50d14663..00000000 --- a/test/mocks/checkout/paymentsdetails-sucess.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "pspReference":"8515232733321252", - "resultCode":"Authorised", - "additionalData":{ - "liabilityShift":"true", - "refusalReasonRaw":"AUTHORISED" - } -} \ No newline at end of file diff --git a/test/mocks/checkout/paymentsession-sucess.json b/test/mocks/checkout/paymentsession-success.json similarity index 100% rename from test/mocks/checkout/paymentsession-sucess.json rename to test/mocks/checkout/paymentsession-success.json diff --git a/test/mocks/checkout/paymentsresult-sucess.json b/test/mocks/checkout/paymentsresult-success.json similarity index 100% rename from test/mocks/checkout/paymentsresult-sucess.json rename to test/mocks/checkout/paymentsresult-success.json From b515f7ce28001e4d1701b318126c47f014f284bf Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 15:02:26 +0100 Subject: [PATCH 09/29] format test lines --- test/CheckoutTest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index af35b39f..d1afe1a2 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -98,4 +98,4 @@ def test_payments_result_success_mocked(self): "-success.json") result = self.ady.checkout.payment_result(request) self.assertEqual("8535253563623704", result.message['pspReference']) - self.assertEqual("Authorised", result.message['resultCode']) \ No newline at end of file + self.assertEqual("Authorised", result.message['resultCode']) From a2bfc2cf872ee1a89590e16efecfe9de3e5c192b Mon Sep 17 00:00:00 2001 From: alexandros Date: Fri, 4 Jan 2019 15:46:15 +0100 Subject: [PATCH 10/29] Add checkout test cases for errors --- test/CheckoutTest.py | 94 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index d1afe1a2..8d74a787 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -27,6 +27,20 @@ def test_payment_methods_success_mocked(self): self.assertEqual("Credit Card via AsiaPay", result.message['paymentMethods'][3]['name']) + def test_payment_methods_error_mocked(self): + request = {'merchantAccount': "YourMerchantAccount"} + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentmethods-" + "error-forbidden" + "-403.json") + result = self.ady.checkout.payment_methods(request) + self.assertEqual(403, result.message['status']) + self.assertEqual("901", result.message['errorCode']) + self.assertEqual("Invalid Merchant Account", result.message['message']) + self.assertEqual("security", result.message['errorType']) + def test_payments_success_mocked(self): request = {'amount': {"value": "100000", "currency": "EUR"}, 'reference': "123456", 'paymentMethod': { @@ -52,6 +66,30 @@ def test_payments_success_mocked(self): self.assertEqual("GREEN", result.message["additionalData"]['fraudResultType']) + def test_payments_error_mocked(self): + request = {'amount': {"value": "100000", "currency": "EUR"}, + 'reference': "54431", 'paymentMethod': { + "type": "scheme", + "number": "4111111111111111", + "expiryMonth": "08", + "expiryYear": "2018", + "holderName": "John Smith", + "cvc": "737" + }, 'merchantAccount': "YourMerchantAccount", + 'returnUrl': "https://your-company.com/..."} + + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "payments-error" + "-invalid-data-422" + ".json") + result = self.ady.checkout.payments(request) + self.assertEqual(422, result.message['status']) + self.assertEqual("130", result.message['errorCode']) + self.assertEqual("Reference Missing", result.message['message']) + self.assertEqual("validation", result.message['errorType']) + def test_payments_details_success_mocked(self): request = {'paymentData': "Hee57361f99....", 'details': { "MD": "sdfsdfsdf...", @@ -70,6 +108,23 @@ def test_payments_details_success_mocked(self): self.assertEqual("AUTHORISED", result.message['additionalData']['refusalReasonRaw']) + def test_payments_details_error_mocked(self): + request = {'paymentData': "Hee57361f99....", 'details': { + "MD": "sdfsdfsdf...", + "PaRes": "sdkfhskdjfsdf..." + }} + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsdetails" + "-error-invalid-" + "data-422.json") + result = self.ady.checkout.payments_details(request) + self.assertEqual(422, result.message['status']) + self.assertEqual("101", result.message['errorCode']) + self.assertEqual("Invalid card number", result.message['message']) + self.assertEqual("validation", result.message['errorType']) + def test_payments_session_success_mocked(self): request = {"reference": "Your order number", "shopperReference": "yourShopperId_IOfW3k9G2PvXFu2j", @@ -89,6 +144,30 @@ def test_payments_session_success_mocked(self): result = self.ady.checkout.payment_session(request) self.assertIsNotNone(result.message['paymentSession']) + def test_payments_session_error_mocked(self): + request = {"reference": "Your wro order number", + "shopperReference": "yourShopperId_IOfW3k9G2PvXFu2j", + "channel": "iOS", + "token": "WRONG_TOKEN", + "returnUrl": "app://", "countryCode": "NL", + "shopperLocale": "nl_NL", + "sessionValidity": "2017-04-06T13:09:13Z", + "merchantAccount": "YOUR_MERCHANT_ACCOUNT", + 'amount': {"value": "17408", "currency": "EUR"}} + + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsession" + "-error-invalid-" + "data-422.json") + result = self.ady.checkout.payment_session(request) + self.assertEqual(422, result.message['status']) + self.assertEqual("14_012", result.message['errorCode']) + self.assertEqual("The provided SDK token could not be parsed.", + result.message['message']) + self.assertEqual("validation", result.message['errorType']) + def test_payments_result_success_mocked(self): request = {"payload": "VALUE_YOU_GET_FROM_CHECKOUT_SDK"} self.ady.client = self.test.create_client_from_file(200, request, @@ -99,3 +178,18 @@ def test_payments_result_success_mocked(self): result = self.ady.checkout.payment_result(request) self.assertEqual("8535253563623704", result.message['pspReference']) self.assertEqual("Authorised", result.message['resultCode']) + + def test_payments_result_error_mocked(self): + request = {"payload": "VALUE_YOU_GET_FROM_CHECKOUT_SDK"} + self.ady.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsresult" + "-error-invalid-" + "data-payload-" + "422.json") + result = self.ady.checkout.payment_result(request) + self.assertEqual(422, result.message['status']) + self.assertEqual("14_018", result.message['errorCode']) + self.assertEqual("Invalid payload provided", result.message['message']) + self.assertEqual("validation", result.message['errorType']) From 22fb285a47f61ab8dfc1b740863b8c4f26de3a83 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 8 Jan 2019 15:14:48 +0100 Subject: [PATCH 11/29] Fixes with e2e test --- Adyen/client.py | 15 ++++++++++++++- Adyen/httpclient.py | 14 +++++++++----- Adyen/services.py | 4 ++-- Adyen/validation.py | 8 ++++---- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index dae03791..d89c043b 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -135,6 +135,9 @@ def _determine_checkout_url(self, platform, service, action): action = "payment/details" if action == "paymentResult": action = "payment/result" + if action == "originKey": + action = "v1/originKeys" + base_uri = settings.BASE_CHECKOUT_URL.format(platform) api_version = settings.CHECKOUT_API_VERSION @@ -239,6 +242,17 @@ def call_api(self, request_data, service, action, idempotency=False, You can do this by running 'Adyen.password = 'Your password'""" raise AdyenInvalidRequestError(errorstring) + # xapikey at self object has highest priority. fallback to root module + # and ensure that it is set. + if self.xapikey: + xapikey = self.xapikey + elif 'xapikey' in kwargs: + xapikey = kwargs.pop("xapikey") + if not xapikey: + errorstring = """Please set your webservice xapikey. + You can do this by running 'Adyen.xapikey = 'Your xapikey'""" + raise AdyenInvalidRequestError(errorstring) + # platform at self object has highest priority. fallback to root module # and ensure that it is set to either 'live' or 'test'. if self.platform: @@ -473,7 +487,6 @@ def _handle_response(self, url, raw_response, raw_request, Returns: AdyenResult: Result object if successful. """ - if status_code != 200: response = {} # If the result can't be parsed into json, most likely is raw html. diff --git a/Adyen/httpclient.py b/Adyen/httpclient.py index ceaa39c5..b4a6b3e6 100644 --- a/Adyen/httpclient.py +++ b/Adyen/httpclient.py @@ -142,11 +142,13 @@ def _requests_post(self, url, data=None, username="", password="", + xapikey="", headers=None, timeout=30): + self.pr = """pr""" """This function will POST to the url endpoint using requests. Returning an AdyenResult object on 200 HTTP response. - Either json or data has to be provided. + Either json or data has to be %sovided. If username and password are provided, basic auth will be used. @@ -167,7 +169,7 @@ def _requests_post(self, url, str: Raw request placed int: HTTP status code, eg 200,404,401 dict: Key/Value pairs of the headers received. - """ + """ % self.pr if headers is None: headers = {} @@ -175,6 +177,8 @@ def _requests_post(self, url, auth = None if username and password: auth = requests.auth.HTTPBasicAuth(username, password) + elif xapikey: + headers['x-api-key'] = xapikey # Add User-Agent header to request so that the request # can be identified as coming from the Adyen Python library. @@ -246,12 +250,12 @@ def _urllib_post(self, url, if username and password: if sys.version_info[0] >= 3: basic_authstring = base64.encodebytes(('%s:%s' % - (username, password)) - .encode()).decode().\ + (username, password)) + .encode()).decode(). \ replace('\n', '') else: basic_authstring = base64.encodestring('%s:%s' % (username, - password)).\ + password)). \ replace('\n', '') url_request.add_header("Authorization", "Basic %s" % basic_authstring) diff --git a/Adyen/services.py b/Adyen/services.py index 52e88126..9c1536e7 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -328,7 +328,7 @@ def payments_details(self, request="", **kwargs): action, **kwargs) def payment_session(self, request="", **kwargs): - action = "paymentsSession" + action = "paymentSession" if validation.check_in(request, action): return self.client.call_checkout_api(request, self.service, action, **kwargs) @@ -339,7 +339,7 @@ def payment_result(self, request="", **kwargs): return self.client.call_checkout_api(request, self.service, action, **kwargs) - def origin_key(self, request="", **kwargs): + def origin_keys(self, request="", **kwargs): action = "originKeys" if validation.check_in(request, action): return self.client.call_checkout_api(request, self.service, diff --git a/Adyen/validation.py b/Adyen/validation.py index e9e796cd..13f312e8 100644 --- a/Adyen/validation.py +++ b/Adyen/validation.py @@ -21,10 +21,10 @@ actions['payments'] = ["amount", "reference", "paymentMethod", "merchantAccount", "returnUrl"] actions['paymentsDetails'] = ["paymentData", "details"] -actions['paymentsSession'] = ["amount", "reference", "shopperReference", - "channel", "token", "returnUrl", "countryCode", - "shopperLocale", "sessionValidity", - "merchantAccount"] +actions['paymentSession'] = ["amount", "reference", "shopperReference", + "channel", "returnUrl", "countryCode", + "shopperLocale", "sessionValidity", + "merchantAccount"] actions['paymentResult'] = ["payload"] actions['originKeys'] = ["originDomains"] From 247cbaa8caf02782cb27b525989e5a5e22a8cde6 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 8 Jan 2019 15:19:22 +0100 Subject: [PATCH 12/29] Fixes comment length --- Adyen/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index d89c043b..502d40a4 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -242,7 +242,8 @@ def call_api(self, request_data, service, action, idempotency=False, You can do this by running 'Adyen.password = 'Your password'""" raise AdyenInvalidRequestError(errorstring) - # xapikey at self object has highest priority. fallback to root module + # xapikey at self object has highest priority. + # fallback to root module # and ensure that it is set. if self.xapikey: xapikey = self.xapikey @@ -250,7 +251,8 @@ def call_api(self, request_data, service, action, idempotency=False, xapikey = kwargs.pop("xapikey") if not xapikey: errorstring = """Please set your webservice xapikey. - You can do this by running 'Adyen.xapikey = 'Your xapikey'""" + You can do this by running + 'Adyen.xapikey = 'Your xapikey'""" raise AdyenInvalidRequestError(errorstring) # platform at self object has highest priority. fallback to root module From 1ca76fb0b546d6243f0d7de19370db235c6af08c Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 8 Jan 2019 15:29:54 +0100 Subject: [PATCH 13/29] remove white space --- Adyen/client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 502d40a4..4f56abed 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -241,8 +241,7 @@ def call_api(self, request_data, service, action, idempotency=False, errorstring = """Please set your webservice password. You can do this by running 'Adyen.password = 'Your password'""" raise AdyenInvalidRequestError(errorstring) - - # xapikey at self object has highest priority. + # xapikey at self object has highest priority. # fallback to root module # and ensure that it is set. if self.xapikey: From 8c257eb9c9e46da27f596290613b2ef5a76f2332 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 8 Jan 2019 15:40:44 +0100 Subject: [PATCH 14/29] correct checkout utility --- test/CheckoutUtilityTest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py index 490475bb..6bb42868 100644 --- a/test/CheckoutUtilityTest.py +++ b/test/CheckoutUtilityTest.py @@ -26,7 +26,7 @@ def test_origin_keys_success_mocked(self): "checkoututility/" "originkeys" "-success.json") - result = self.ady.checkout.origin_key(request) + result = self.ady.checkout.origin_keys(request) self.assertEqual("pub.v2.7814286629520534.aHR0cHM6Ly93d3cu" "eW91ci1kb21haW4xLmNvbQ.UEwIBmW9-c_uXo5wS" From 236cd10e183ede659a86af7b80212beadbbda305 Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 10:39:48 +0100 Subject: [PATCH 15/29] add custom endpoint --- Adyen/client.py | 11 ++++++++--- Adyen/services.py | 2 +- Adyen/settings.py | 3 +++ Adyen/validation.py | 2 +- test/CheckoutTest.py | 15 +++++++++++++++ 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 4f56abed..f7eae630 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -122,7 +122,8 @@ def _determine_hpp_url(self, platform, action): result = '/'.join([base_uri, service]) return result - def _determine_checkout_url(self, platform, service, action): + def _determine_checkout_url(self, platform, service, action, + live_endpoint_prefix=None): """This returns the Adyen API endpoint based on the provided platform, service and action. @@ -133,14 +134,18 @@ def _determine_checkout_url(self, platform, service, action): """ if action == "paymentDetails": action = "payment/details" - if action == "paymentResult": + if action == "paymentsResult": action = "payment/result" if action == "originKey": action = "v1/originKeys" base_uri = settings.BASE_CHECKOUT_URL.format(platform) - api_version = settings.CHECKOUT_API_VERSION + if live_endpoint_prefix is not None: + base_uri = settings.ENDPOINT_PROTOCOL + live_endpoint_prefix \ + + settings.CHECKOUT_URL_LIVE_SUFFIX + + api_version = settings.CHECKOUT_API_VERSION return '/'.join([base_uri, api_version, action]) def _review_payout_username(self, **kwargs): diff --git a/Adyen/services.py b/Adyen/services.py index 9c1536e7..da908daf 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -334,7 +334,7 @@ def payment_session(self, request="", **kwargs): action, **kwargs) def payment_result(self, request="", **kwargs): - action = "paymentResult" + action = "paymentsResult" if validation.check_in(request, action): return self.client.call_checkout_api(request, self.service, action, **kwargs) diff --git a/Adyen/settings.py b/Adyen/settings.py index 28c8e1d4..f79265ef 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -2,7 +2,10 @@ BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" +ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" +ENDPOINT_PROTOCOL = "https://" BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com/" +CHECKOUT_URL_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" CHECKOUT_API_VERSION = "v40" API_VERSION = "v30" API_RECURRING_VERSION = "v25" diff --git a/Adyen/validation.py b/Adyen/validation.py index 13f312e8..171fef9c 100644 --- a/Adyen/validation.py +++ b/Adyen/validation.py @@ -25,7 +25,7 @@ "channel", "returnUrl", "countryCode", "shopperLocale", "sessionValidity", "merchantAccount"] -actions['paymentResult'] = ["payload"] +actions['paymentsResult'] = ["payload"] actions['originKeys'] = ["originDomains"] payout_required_fields = { diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 8d74a787..131a6951 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -193,3 +193,18 @@ def test_payments_result_error_mocked(self): self.assertEqual("14_018", result.message['errorCode']) self.assertEqual("Invalid payload provided", result.message['message']) self.assertEqual("validation", result.message['errorType']) + + def test_checkout_api_url(self): + url = self.ady.client._determine_checkout_url("live", "" + , "paymentDetails") + self.assertEqual(url, "https://checkout-live.adyen.com" + "//v40/payment/details") + + def test_checkout_api_url_custom(self): + url = self.ady.client._determine_checkout_url("live", "" + , "payments", + "1797a841fbb37ca7" + "-AdyenDemo") + + self.assertEqual(url, "https://1797a841fbb37ca7-AdyenDemo-checkout-" + "live.adyenpayments.com/checkout/v40/payments") From 4782cb670382aca6757486aee512ec93667fa3d5 Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 10:57:38 +0100 Subject: [PATCH 16/29] Remove white space in unit test --- test/CheckoutTest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 131a6951..ced4be8e 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -195,14 +195,14 @@ def test_payments_result_error_mocked(self): self.assertEqual("validation", result.message['errorType']) def test_checkout_api_url(self): - url = self.ady.client._determine_checkout_url("live", "" - , "paymentDetails") + url = self.ady.client._determine_checkout_url("live", "", + "paymentDetails") self.assertEqual(url, "https://checkout-live.adyen.com" "//v40/payment/details") def test_checkout_api_url_custom(self): - url = self.ady.client._determine_checkout_url("live", "" - , "payments", + url = self.ady.client._determine_checkout_url("live", "", + "payments", "1797a841fbb37ca7" "-AdyenDemo") From 0a134fa687edd4d72cf91fe4b2a84e2261131a6f Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 12:02:19 +0100 Subject: [PATCH 17/29] Add checkout utility url --- Adyen/client.py | 17 ++++++++--------- Adyen/settings.py | 2 +- test/CheckoutTest.py | 2 +- test/CheckoutUtilityTest.py | 6 ++++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index f7eae630..46d8a00a 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -132,20 +132,19 @@ def _determine_checkout_url(self, platform, service, action, service (str): API service to place request through. action (str): the API action to perform. """ - if action == "paymentDetails": - action = "payment/details" - if action == "paymentsResult": - action = "payment/result" - if action == "originKey": - action = "v1/originKeys" - base_uri = settings.BASE_CHECKOUT_URL.format(platform) - + api_version = settings.CHECKOUT_API_VERSION if live_endpoint_prefix is not None: base_uri = settings.ENDPOINT_PROTOCOL + live_endpoint_prefix \ + settings.CHECKOUT_URL_LIVE_SUFFIX - api_version = settings.CHECKOUT_API_VERSION + if action == "paymentDetails": + action = "payment/details" + if action == "paymentsResult": + action = "payment/result" + if action == "originKeys": + api_version = "v1" + return '/'.join([base_uri, api_version, action]) def _review_payout_username(self, **kwargs): diff --git a/Adyen/settings.py b/Adyen/settings.py index f79265ef..12386820 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -4,7 +4,7 @@ BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" ENDPOINT_PROTOCOL = "https://" -BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com/" +BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com" CHECKOUT_URL_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" CHECKOUT_API_VERSION = "v40" API_VERSION = "v30" diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index ced4be8e..968967c6 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -198,7 +198,7 @@ def test_checkout_api_url(self): url = self.ady.client._determine_checkout_url("live", "", "paymentDetails") self.assertEqual(url, "https://checkout-live.adyen.com" - "//v40/payment/details") + "/v40/payment/details") def test_checkout_api_url_custom(self): url = self.ady.client._determine_checkout_url("live", "", diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py index 6bb42868..46162d51 100644 --- a/test/CheckoutUtilityTest.py +++ b/test/CheckoutUtilityTest.py @@ -45,3 +45,9 @@ def test_origin_keys_success_mocked(self): "b1qMuMHGepxG_SlUqxAYrfY", result.message['originKeys'] ['https://www.your-domain2.com']) + + def test_checkout_utility_api_url_custom(self): + url = self.ady.client._determine_checkout_url("test", "", + "originKeys") + + self.assertEqual(url, "https://checkout-test.adyen.com/v1/originKeys") From 2421b542b7a05617e99674b1c5def8ccaac73800 Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 12:08:03 +0100 Subject: [PATCH 18/29] rename to payments details --- Adyen/client.py | 4 ++-- test/CheckoutTest.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 46d8a00a..aa6fdde6 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -138,8 +138,8 @@ def _determine_checkout_url(self, platform, service, action, base_uri = settings.ENDPOINT_PROTOCOL + live_endpoint_prefix \ + settings.CHECKOUT_URL_LIVE_SUFFIX - if action == "paymentDetails": - action = "payment/details" + if action == "paymentsDetails": + action = "payments/details" if action == "paymentsResult": action = "payment/result" if action == "originKeys": diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 968967c6..5d9f72cf 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -196,9 +196,9 @@ def test_payments_result_error_mocked(self): def test_checkout_api_url(self): url = self.ady.client._determine_checkout_url("live", "", - "paymentDetails") + "paymentsDetails") self.assertEqual(url, "https://checkout-live.adyen.com" - "/v40/payment/details") + "/v40/payments/details") def test_checkout_api_url_custom(self): url = self.ady.client._determine_checkout_url("live", "", From 5e7d9c3b0d865ba55d271a6475e14666af659600 Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 12:13:49 +0100 Subject: [PATCH 19/29] remove unused code --- Adyen/httpclient.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Adyen/httpclient.py b/Adyen/httpclient.py index b4a6b3e6..224f7343 100644 --- a/Adyen/httpclient.py +++ b/Adyen/httpclient.py @@ -145,7 +145,6 @@ def _requests_post(self, url, xapikey="", headers=None, timeout=30): - self.pr = """pr""" """This function will POST to the url endpoint using requests. Returning an AdyenResult object on 200 HTTP response. Either json or data has to be %sovided. @@ -169,7 +168,7 @@ def _requests_post(self, url, str: Raw request placed int: HTTP status code, eg 200,404,401 dict: Key/Value pairs of the headers received. - """ % self.pr + """ if headers is None: headers = {} From f3627f7b7d590c25aedaf188cb83d0d989c9ed6f Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 9 Jan 2019 12:22:49 +0100 Subject: [PATCH 20/29] add utility api version --- Adyen/client.py | 2 +- Adyen/settings.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Adyen/client.py b/Adyen/client.py index aa6fdde6..68ed4466 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -143,7 +143,7 @@ def _determine_checkout_url(self, platform, service, action, if action == "paymentsResult": action = "payment/result" if action == "originKeys": - api_version = "v1" + api_version = settings.CHECKOUT_UTILITY_API_VERSION return '/'.join([base_uri, api_version, action]) diff --git a/Adyen/settings.py b/Adyen/settings.py index 12386820..fb12d80b 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -7,5 +7,6 @@ BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com" CHECKOUT_URL_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" CHECKOUT_API_VERSION = "v40" +CHECKOUT_UTILITY_API_VERSION = "v1" API_VERSION = "v30" API_RECURRING_VERSION = "v25" From c397486312f80f202072088db251b4cf50404dff Mon Sep 17 00:00:00 2001 From: alexandros Date: Thu, 10 Jan 2019 13:35:58 +0100 Subject: [PATCH 21/29] Improve settings and client --- Adyen/client.py | 52 ++++++++++++++++++++++---------------------- Adyen/httpclient.py | 2 +- Adyen/settings.py | 10 ++++----- test/CheckoutTest.py | 5 ++--- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 68ed4466..a576dcba 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -72,7 +72,7 @@ def __init__(self, username=None, password=None, xapikey=None, platform="test", merchant_account=None, merchant_specific_url=None, skin_code=None, hmac=None, app_name=None, - http_force=None): + http_force=None, live_endpoint_prefix=None): self.username = username self.password = password self.xapikey = xapikey @@ -91,6 +91,7 @@ def __init__(self, username=None, password=None, xapikey=None, self.USER_AGENT_SUFFIX = "adyen-python-api-library/" self.http_init = False self.http_force = http_force + self.live_endpoint_prefix = live_endpoint_prefix def _determine_api_url(self, platform, service, action): """This returns the Adyen API endpoint based on the provided platform, @@ -105,7 +106,7 @@ def _determine_api_url(self, platform, service, action): if service == "Recurring": api_version = settings.API_RECURRING_VERSION else: - api_version = settings.API_VERSION + api_version = settings.API_PAYOUT_VERSION return '/'.join([base_uri, service, api_version, action]) def _determine_hpp_url(self, platform, action): @@ -122,8 +123,7 @@ def _determine_hpp_url(self, platform, action): result = '/'.join([base_uri, service]) return result - def _determine_checkout_url(self, platform, service, action, - live_endpoint_prefix=None): + def _determine_checkout_url(self, platform, service, action): """This returns the Adyen API endpoint based on the provided platform, service and action. @@ -132,18 +132,18 @@ def _determine_checkout_url(self, platform, service, action, service (str): API service to place request through. action (str): the API action to perform. """ - base_uri = settings.BASE_CHECKOUT_URL.format(platform) - api_version = settings.CHECKOUT_API_VERSION - if live_endpoint_prefix is not None: - base_uri = settings.ENDPOINT_PROTOCOL + live_endpoint_prefix \ - + settings.CHECKOUT_URL_LIVE_SUFFIX + base_uri = settings.ENDPOINT_CHECKOUT_URL.format(platform) + api_version = settings.API_CHECKOUT_VERSION + if self.live_endpoint_prefix is not None: + base_uri = settings.ENDPOINT_PROTOCOL + self.live_endpoint_prefix \ + + settings.ENDPOINT_CHECKOUT_LIVE_SUFFIX if action == "paymentsDetails": action = "payments/details" if action == "paymentsResult": action = "payment/result" if action == "originKeys": - api_version = settings.CHECKOUT_UTILITY_API_VERSION + api_version = settings.API_CHECKOUT_UTILITY_VERSION return '/'.join([base_uri, api_version, action]) @@ -216,47 +216,47 @@ def call_api(self, request_data, service, action, idempotency=False, # username at self object has highest priority. fallback to root module # and ensure that it is set. + if self.xapikey: + xapikey = self.xapikey + elif 'xapikey' in kwargs: + xapikey = kwargs.pop("xapikey") + if self.username: username = self.username elif 'username' in kwargs: username = kwargs.pop("username") elif service == "Payout": - if any(substring in action for substring in ["store", "submit"]): + if any(substring in action for substring in + ["store", "submit"]): username = self._store_payout_username(**kwargs) else: username = self._review_payout_username(**kwargs) if not username: errorstring = """Please set your webservice username. - You can do this by running 'Adyen.username = 'Your username'""" + You can do this by running + 'Adyen.username = 'Your username'""" raise AdyenInvalidRequestError(errorstring) - - # password at self object has highest priority. fallback to root module - # and ensure that it is set. + # password at self object has highest priority. + # fallback to root module + # and ensure that it is set. if self.password: password = self.password elif 'password' in kwargs: password = kwargs.pop("password") elif service == "Payout": - if any(substring in action for substring in ["store", "submit"]): + if any(substring in action for substring in + ["store", "submit"]): password = self._store_payout_pass(**kwargs) else: password = self._review_payout_pass(**kwargs) if not password: errorstring = """Please set your webservice password. - You can do this by running 'Adyen.password = 'Your password'""" + You can do this by running + 'Adyen.password = 'Your password'""" raise AdyenInvalidRequestError(errorstring) # xapikey at self object has highest priority. # fallback to root module # and ensure that it is set. - if self.xapikey: - xapikey = self.xapikey - elif 'xapikey' in kwargs: - xapikey = kwargs.pop("xapikey") - if not xapikey: - errorstring = """Please set your webservice xapikey. - You can do this by running - 'Adyen.xapikey = 'Your xapikey'""" - raise AdyenInvalidRequestError(errorstring) # platform at self object has highest priority. fallback to root module # and ensure that it is set to either 'live' or 'test'. diff --git a/Adyen/httpclient.py b/Adyen/httpclient.py index 224f7343..2379e9c4 100644 --- a/Adyen/httpclient.py +++ b/Adyen/httpclient.py @@ -147,7 +147,7 @@ def _requests_post(self, url, timeout=30): """This function will POST to the url endpoint using requests. Returning an AdyenResult object on 200 HTTP response. - Either json or data has to be %sovided. + Either json or data has to be provided. If username and password are provided, basic auth will be used. diff --git a/Adyen/settings.py b/Adyen/settings.py index fb12d80b..01130cff 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -4,9 +4,9 @@ BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" ENDPOINT_PROTOCOL = "https://" -BASE_CHECKOUT_URL = "https://checkout-{}.adyen.com" -CHECKOUT_URL_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" -CHECKOUT_API_VERSION = "v40" -CHECKOUT_UTILITY_API_VERSION = "v1" -API_VERSION = "v30" +ENDPOINT_CHECKOUT_URL = "https://checkout-{}.adyen.com" +ENDPOINT_CHECKOUT_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" +API_CHECKOUT_VERSION = "v40" +API_CHECKOUT_UTILITY_VERSION = "v1" +API_PAYOUT_VERSION = "v30" API_RECURRING_VERSION = "v25" diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 5d9f72cf..ba55fd2e 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -201,10 +201,9 @@ def test_checkout_api_url(self): "/v40/payments/details") def test_checkout_api_url_custom(self): + self.ady.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" url = self.ady.client._determine_checkout_url("live", "", - "payments", - "1797a841fbb37ca7" - "-AdyenDemo") + "payments") self.assertEqual(url, "https://1797a841fbb37ca7-AdyenDemo-checkout-" "live.adyenpayments.com/checkout/v40/payments") From 4467940302fb2f388fbbf40626340dae722d1845 Mon Sep 17 00:00:00 2001 From: alexandros Date: Thu, 10 Jan 2019 16:20:07 +0100 Subject: [PATCH 22/29] Correct checkout url payments result --- Adyen/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adyen/client.py b/Adyen/client.py index a576dcba..38753dcf 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -141,7 +141,7 @@ def _determine_checkout_url(self, platform, service, action): if action == "paymentsDetails": action = "payments/details" if action == "paymentsResult": - action = "payment/result" + action = "payments/result" if action == "originKeys": api_version = settings.API_CHECKOUT_UTILITY_VERSION From 0aa55af1a4fd920a9abda5621e8d27050cb9cf82 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 15 Jan 2019 12:44:34 +0100 Subject: [PATCH 23/29] imporove determine checkout url --- Adyen/client.py | 29 ++++--- Adyen/exceptions.py | 18 ++-- Adyen/settings.py | 4 +- setup.py | 2 +- test/CheckoutTest.py | 157 ++++++++++++++++------------------ test/DetermineEndpointTest.py | 51 +++++++++++ test/PaymentTest.py | 96 +++++++++++---------- 7 files changed, 202 insertions(+), 155 deletions(-) create mode 100644 test/DetermineEndpointTest.py diff --git a/Adyen/client.py b/Adyen/client.py index 38753dcf..9208d821 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -15,7 +15,7 @@ AdyenInvalidRequestError, AdyenAPIInvalidFormat, AdyenAPIInvalidAmount, -) + AdyenEndpointInvalidFormat) from . import settings @@ -87,7 +87,7 @@ def __init__(self, username=None, password=None, xapikey=None, self.skin_code = skin_code self.psp_list = [] self.app_name = app_name - self.LIB_VERSION = "1.3.0" + self.LIB_VERSION = "1.4.0" self.USER_AGENT_SUFFIX = "adyen-python-api-library/" self.http_init = False self.http_force = http_force @@ -132,12 +132,16 @@ def _determine_checkout_url(self, platform, service, action): service (str): API service to place request through. action (str): the API action to perform. """ - base_uri = settings.ENDPOINT_CHECKOUT_URL.format(platform) api_version = settings.API_CHECKOUT_VERSION - if self.live_endpoint_prefix is not None: - base_uri = settings.ENDPOINT_PROTOCOL + self.live_endpoint_prefix \ - + settings.ENDPOINT_CHECKOUT_LIVE_SUFFIX - + base_uri = settings.ENDPOINT_CHECKOUT_URL.format(platform) + if self.live_endpoint_prefix is not None and platform == "live": + base_uri = settings.ENDPOINT_CHECKOUT_LIVE_SUFFIX.format( + self.live_endpoint_prefix) + if self.live_endpoint_prefix is not None and platform == "test": + errorstring = """Please set your live suffix. You can set it + by running 'settings. + ENDPOINT_CHECKOUT_LIVE_SUFFIX = 'Your live suffix'""" + raise AdyenEndpointInvalidFormat(errorstring) if action == "paymentsDetails": action = "payments/details" if action == "paymentsResult": @@ -415,10 +419,8 @@ def call_checkout_api(self, request_data, service, action, **kwargs): errorstring = "'platform' must be the value of 'live' or 'test'" raise ValueError(errorstring) - message = request_data - - if not message.get('merchantAccount'): - message['merchantAccount'] = self.merchant_account + if not request_data.get('merchantAccount'): + request_data['merchantAccount'] = self.merchant_account # Adyen requires this header to be set and uses the combination of # merchant account and merchant reference to determine uniqueness. @@ -427,13 +429,14 @@ def call_checkout_api(self, request_data, service, action, **kwargs): url = self._determine_checkout_url(platform, service, action) raw_response, raw_request, status_code, headers = \ - self.http_client.request(url, json=message, + self.http_client.request(url, json=request_data, xapikey=xapikey, headers=headers, **kwargs) # Creates AdyenResponse if request was successful, raises error if not. adyen_result = self._handle_response(url, raw_response, raw_request, - status_code, headers, message) + status_code, headers, + request_data) return adyen_result diff --git a/Adyen/exceptions.py b/Adyen/exceptions.py index aa8caa57..331fd764 100644 --- a/Adyen/exceptions.py +++ b/Adyen/exceptions.py @@ -25,16 +25,10 @@ def __str__(self): def debug(self): return ("class: {}\nmessage: {}\nHTTP status_code:{}\nurl: {}" - "request: {}\nresponse: {}\nheaders: {}".format( - self.__class__.__name__, - self.message, - self.status_code, - self.url, - self.raw_request, - self.raw_response, - self.headers - ) - ) + "request: {}\nresponse: {}\nheaders: {}" + .format(self.__class__.__name__, self.message, + self.status_code, self.url, self.raw_request, + self.raw_response, self.headers)) class AdyenInvalidRequestError(AdyenError): @@ -71,3 +65,7 @@ class AdyenAPIInvalidAmount(AdyenAPIResponseError): class AdyenAPIInvalidFormat(AdyenAPIResponseError): pass + + +class AdyenEndpointInvalidFormat(AdyenError): + pass diff --git a/Adyen/settings.py b/Adyen/settings.py index 01130cff..c3fb9df6 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -3,9 +3,9 @@ BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" -ENDPOINT_PROTOCOL = "https://" ENDPOINT_CHECKOUT_URL = "https://checkout-{}.adyen.com" -ENDPOINT_CHECKOUT_LIVE_SUFFIX = "-checkout-live.adyenpayments.com/checkout" +ENDPOINT_CHECKOUT_LIVE_SUFFIX = "https://{}-checkout-live" \ + ".adyenpayments.com/checkout" API_CHECKOUT_VERSION = "v40" API_CHECKOUT_UTILITY_VERSION = "v1" API_PAYOUT_VERSION = "v30" diff --git a/setup.py b/setup.py index bfb3082e..53adcc86 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='Adyen', packages=['Adyen'], - version='1.3.0', + version='1.4.0', maintainer='Adyen', maintainer_email='support@adyen.com', description='Adyen Python Api', diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index ba55fd2e..906a14ad 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -1,26 +1,27 @@ import Adyen import unittest from BaseTest import BaseTest -import pprint + +from Adyen.exceptions import AdyenEndpointInvalidFormat class TestCheckout(unittest.TestCase): - ady = Adyen.Adyen() + adyen = Adyen.Adyen() - client = ady.client - test = BaseTest(ady) + client = adyen.client + test = BaseTest(adyen) client.xapikey = "YourXapikey" client.platform = "test" client.app_name = "appname" def test_payment_methods_success_mocked(self): request = {'merchantAccount': "YourMerchantAccount"} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentmethods" - "-success.json") - result = self.ady.checkout.payment_methods(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentmethods" + "-success.json") + result = self.adyen.checkout.payment_methods(request) self.assertEqual("AliPay", result.message['paymentMethods'][0]['name']) self.assertEqual("Credit Card", result.message['paymentMethods'][2]['name']) @@ -29,13 +30,13 @@ def test_payment_methods_success_mocked(self): def test_payment_methods_error_mocked(self): request = {'merchantAccount': "YourMerchantAccount"} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentmethods-" - "error-forbidden" - "-403.json") - result = self.ady.checkout.payment_methods(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentmethods-" + "error-forbidden" + "-403.json") + result = self.adyen.checkout.payment_methods(request) self.assertEqual(403, result.message['status']) self.assertEqual("901", result.message['errorCode']) self.assertEqual("Invalid Merchant Account", result.message['message']) @@ -53,12 +54,13 @@ def test_payments_success_mocked(self): }, 'merchantAccount': "YourMerchantAccount", 'returnUrl': "https://your-company.com/..."} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "payments-success" - ".json") - result = self.ady.checkout.payments(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "payments" + "-success" + ".json") + result = self.adyen.checkout.payments(request) self.assertEqual("8535296650153317", result.message['pspReference']) self.assertEqual("Authorised", result.message['resultCode']) self.assertEqual("8/2018", @@ -78,13 +80,14 @@ def test_payments_error_mocked(self): }, 'merchantAccount': "YourMerchantAccount", 'returnUrl': "https://your-company.com/..."} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "payments-error" - "-invalid-data-422" - ".json") - result = self.ady.checkout.payments(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "payments-error" + "-invalid" + "-data-422" + ".json") + result = self.adyen.checkout.payments(request) self.assertEqual(422, result.message['status']) self.assertEqual("130", result.message['errorCode']) self.assertEqual("Reference Missing", result.message['message']) @@ -95,12 +98,12 @@ def test_payments_details_success_mocked(self): "MD": "sdfsdfsdf...", "PaRes": "sdkfhskdjfsdf..." }} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsdetails" - "-success.json") - result = self.ady.checkout.payments_details(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsdetails" + "-success.json") + result = self.adyen.checkout.payments_details(request) self.assertEqual("8515232733321252", result.message['pspReference']) self.assertEqual("Authorised", result.message['resultCode']) self.assertEqual("true", @@ -113,13 +116,13 @@ def test_payments_details_error_mocked(self): "MD": "sdfsdfsdf...", "PaRes": "sdkfhskdjfsdf..." }} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsdetails" - "-error-invalid-" - "data-422.json") - result = self.ady.checkout.payments_details(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsdetails" + "-error-invalid-" + "data-422.json") + result = self.adyen.checkout.payments_details(request) self.assertEqual(422, result.message['status']) self.assertEqual("101", result.message['errorCode']) self.assertEqual("Invalid card number", result.message['message']) @@ -136,12 +139,12 @@ def test_payments_session_success_mocked(self): "merchantAccount": "YOUR_MERCHANT_ACCOUNT", 'amount': {"value": "17408", "currency": "EUR"}} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsession" - "-success.json") - result = self.ady.checkout.payment_session(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsession" + "-success.json") + result = self.adyen.checkout.payment_session(request) self.assertIsNotNone(result.message['paymentSession']) def test_payments_session_error_mocked(self): @@ -155,13 +158,13 @@ def test_payments_session_error_mocked(self): "merchantAccount": "YOUR_MERCHANT_ACCOUNT", 'amount': {"value": "17408", "currency": "EUR"}} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsession" - "-error-invalid-" - "data-422.json") - result = self.ady.checkout.payment_session(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsession" + "-error-invalid-" + "data-422.json") + result = self.adyen.checkout.payment_session(request) self.assertEqual(422, result.message['status']) self.assertEqual("14_012", result.message['errorCode']) self.assertEqual("The provided SDK token could not be parsed.", @@ -170,40 +173,26 @@ def test_payments_session_error_mocked(self): def test_payments_result_success_mocked(self): request = {"payload": "VALUE_YOU_GET_FROM_CHECKOUT_SDK"} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsresult" - "-success.json") - result = self.ady.checkout.payment_result(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsresult" + "-success.json") + result = self.adyen.checkout.payment_result(request) self.assertEqual("8535253563623704", result.message['pspReference']) self.assertEqual("Authorised", result.message['resultCode']) def test_payments_result_error_mocked(self): request = {"payload": "VALUE_YOU_GET_FROM_CHECKOUT_SDK"} - self.ady.client = self.test.create_client_from_file(200, request, - "test/mocks/" - "checkout/" - "paymentsresult" - "-error-invalid-" - "data-payload-" - "422.json") - result = self.ady.checkout.payment_result(request) + self.adyen.client = self.test.create_client_from_file(200, request, + "test/mocks/" + "checkout/" + "paymentsresult" + "-error-invalid-" + "data-payload-" + "422.json") + result = self.adyen.checkout.payment_result(request) self.assertEqual(422, result.message['status']) self.assertEqual("14_018", result.message['errorCode']) self.assertEqual("Invalid payload provided", result.message['message']) self.assertEqual("validation", result.message['errorType']) - - def test_checkout_api_url(self): - url = self.ady.client._determine_checkout_url("live", "", - "paymentsDetails") - self.assertEqual(url, "https://checkout-live.adyen.com" - "/v40/payments/details") - - def test_checkout_api_url_custom(self): - self.ady.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" - url = self.ady.client._determine_checkout_url("live", "", - "payments") - - self.assertEqual(url, "https://1797a841fbb37ca7-AdyenDemo-checkout-" - "live.adyenpayments.com/checkout/v40/payments") diff --git a/test/DetermineEndpointTest.py b/test/DetermineEndpointTest.py new file mode 100644 index 00000000..58c916e4 --- /dev/null +++ b/test/DetermineEndpointTest.py @@ -0,0 +1,51 @@ +import Adyen +import unittest +from BaseTest import BaseTest + +from Adyen.exceptions import AdyenEndpointInvalidFormat + + +class TestDetermineUrl(unittest.TestCase): + adyen = Adyen.Adyen() + + client = adyen.client + test = BaseTest(adyen) + client.xapikey = "YourXapikey" + client.app_name = "appname" + + def test_checkout_api_url_custom(self): + self.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" + url = self.adyen.client._determine_checkout_url("live", "", + "payments") + self.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" + self.assertEqual(url, "https://1797a841fbb37ca7-AdyenDemo-checkout-" + "live.adyenpayments.com/checkout/v40/payments") + + def test_payments_invalid_platform(self): + + request = {'amount': {"value": "100000", "currency": "EUR"}, + "reference": "Your order number", + 'paymentMethod': { + "type": "scheme", + "number": "4111111111111111", + "expiryMonth": "08", + "expiryYear": "2018", + "holderName": "John Smith", + "cvc": "737" + }, 'merchantAccount': "YourMerchantAccount", + 'returnUrl': "https://your-company.com/..."} + + self.client.platform = "test" + try: + result = self.adyen.checkout.payments(request) + except AdyenEndpointInvalidFormat as error: + print("the error" + str(error.__class__.__name__)) + self.assertIsNotNone("dfasdf") + + def test_checkout_api_url(self): + + self.client.live_endpoint_prefix = None + url = self.adyen.client._determine_checkout_url("test", "", + "paymentsDetails") + self.assertEqual(url, "https://checkout-test.adyen.com" + "/v40/payments/details") diff --git a/test/PaymentTest.py b/test/PaymentTest.py index d67ad045..fcfb800c 100644 --- a/test/PaymentTest.py +++ b/test/PaymentTest.py @@ -4,10 +4,10 @@ class TestPayments(unittest.TestCase): - ady = Adyen.Adyen() + adyen = Adyen.Adyen() - client = ady.client - test = BaseTest(ady) + client = adyen.client + test = BaseTest(adyen) client.username = "YourWSUser" client.password = "YourWSPassword" client.platform = "test" @@ -25,11 +25,12 @@ def test_authorise_success_mocked(self): "cvc": "737", "holderName": "John Doe" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise-success' - '.json') - result = self.ady.payment.authorise(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise' + '-success' + '.json') + result = self.adyen.payment.authorise(request) self.assertEqual("Authorised", result.message['resultCode']) self.assertEqual("8/2018", result.message['additionalData']['expiryDate']) @@ -64,13 +65,13 @@ def test_authorise_error010_mocked(self): "cvc": "737", "holderName": "John Doe" } - self.ady.client = self.test.create_client_from_file(403, request, - 'test/mocks/' - 'authorise-error' - '-010' - '.json') + self.adyen.client = self.test.create_client_from_file(403, request, + 'test/mocks/' + 'authorise-error' + '-010' + '.json') self.assertRaises(Adyen.AdyenAPIInvalidPermission, - self.ady.payment.authorise, request) + self.adyen.payment.authorise, request) def test_authorise_error_cvc_declined_mocked(self): request = {} @@ -83,12 +84,13 @@ def test_authorise_error_cvc_declined_mocked(self): "cvc": "787", "holderName": "John Doe" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise-error-' - 'cvc-declined' - '.json') - result = self.ady.payment.authorise(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise' + '-error-' + 'cvc-declined' + '.json') + result = self.adyen.payment.authorise(request) self.assertEqual("Refused", result.message['resultCode']) def test_authorise_success_3d_mocked(self): @@ -107,11 +109,12 @@ def test_authorise_success_3d_mocked(self): "userAgent": "YourUserAgent", "acceptHeader": "YourAcceptHeader" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise-success' - '-3d.json') - result = self.ady.payment.authorise(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise' + '-success' + '-3d.json') + result = self.adyen.payment.authorise(request) self.assertEqual("RedirectShopper", result.message['resultCode']) self.assertIsNotNone(result.message['md']) self.assertIsNotNone(result.message['issuerUrl']) @@ -126,11 +129,11 @@ def test_authorise_3d_success_mocked(self): "userAgent": "YourUserAgent", "acceptHeader": "YourAcceptHeader" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise3d-' - 'success.json') - result = self.ady.payment.authorise3d(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise3d-' + 'success.json') + result = self.adyen.payment.authorise3d(request) self.assertEqual("Authorised", result.message['resultCode']) self.assertIsNotNone(result.message['pspReference']) @@ -142,11 +145,12 @@ def test_authorise_cse_success_mocked(self): request['additionalData'] = { "card.encrypted.json": "YourCSEToken" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise-success' - '-cse.json') - result = self.ady.payment.authorise(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise' + '-success' + '-cse.json') + result = self.adyen.payment.authorise(request) self.assertEqual("Authorised", result.message['resultCode']) def test_authorise_cse_error_expired_mocked(self): @@ -158,11 +162,12 @@ def test_authorise_cse_error_expired_mocked(self): "card.encrypted.json": "YourCSEToken" } - self.ady.client = self.test.create_client_from_file(200, request, - 'test/mocks/' - 'authorise-error-' - 'expired.json') - result = self.ady.payment.authorise(request) + self.adyen.client = self.test.create_client_from_file(200, request, + 'test/mocks/' + 'authorise' + '-error-' + 'expired.json') + result = self.adyen.payment.authorise(request) self.assertEqual("Refused", result.message['resultCode']) self.assertEqual("DECLINED Expiry Incorrect", result.message['additionalData']['refusalReasonRaw']) @@ -179,16 +184,17 @@ def test_error_401_mocked(self): "cvc": "787", "holderName": "John Doe" } - self.ady.client = self.test.create_client_from_file(401, request, - 'test/mocks/' - 'authorise-error-' - '010.json') + self.adyen.client = self.test.create_client_from_file(401, request, + 'test/mocks/' + 'authorise' + '-error-' + '010.json') self.assertRaisesRegexp(Adyen.AdyenAPIAuthenticationError, "Unable to authenticate with Adyen's Servers." " Please verify the credentials set with the" " Adyen base class. Please reach out to your" " Adyen Admin if the problem persists", - self.ady.payment.authorise, request) + self.adyen.payment.authorise, request) TestPayments.client.http_force = "requests" From a13dc7efb944c74614e517d6423fb67ebb5a069e Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 15 Jan 2019 14:16:53 +0100 Subject: [PATCH 24/29] fix determine checkout url --- Adyen/client.py | 14 +++++++------- Adyen/services.py | 18 ++++++------------ Adyen/settings.py | 2 +- test/CheckoutUtilityTest.py | 3 +-- test/DetermineEndpointTest.py | 22 +++++++++++----------- 5 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index 9208d821..eefe01b5 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -123,21 +123,21 @@ def _determine_hpp_url(self, platform, action): result = '/'.join([base_uri, service]) return result - def _determine_checkout_url(self, platform, service, action): + def _determine_checkout_url(self, platform, action): """This returns the Adyen API endpoint based on the provided platform, service and action. Args: platform (str): Adyen platform, ie 'live' or 'test'. - service (str): API service to place request through. action (str): the API action to perform. """ api_version = settings.API_CHECKOUT_VERSION - base_uri = settings.ENDPOINT_CHECKOUT_URL.format(platform) - if self.live_endpoint_prefix is not None and platform == "live": + if platform == "test": + base_uri = settings.ENDPOINT_CHECKOUT_TEST + elif self.live_endpoint_prefix is not None and platform == "live": base_uri = settings.ENDPOINT_CHECKOUT_LIVE_SUFFIX.format( self.live_endpoint_prefix) - if self.live_endpoint_prefix is not None and platform == "test": + elif self.live_endpoint_prefix is None and platform == "live": errorstring = """Please set your live suffix. You can set it by running 'settings. ENDPOINT_CHECKOUT_LIVE_SUFFIX = 'Your live suffix'""" @@ -373,7 +373,7 @@ class instance. status_code, headers, message) return adyen_result - def call_checkout_api(self, request_data, service, action, **kwargs): + def call_checkout_api(self, request_data, action, **kwargs): """This will call the checkout adyen api. xapi key merchant_account, and platform are pulled from root module level and or self object. AdyenResult will be returned on 200 response. Otherwise, an exception @@ -426,7 +426,7 @@ def call_checkout_api(self, request_data, service, action, **kwargs): # merchant account and merchant reference to determine uniqueness. headers = {} - url = self._determine_checkout_url(platform, service, action) + url = self._determine_checkout_url(platform, action) raw_response, raw_request, status_code, headers = \ self.http_client.request(url, json=request_data, diff --git a/Adyen/services.py b/Adyen/services.py index da908daf..077f1eb4 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -312,35 +312,29 @@ def payment_methods(self, request="", **kwargs): 'merchantAccount must contain the merchant account' ' when retrieving payment methods.') - return self.client.call_checkout_api(request, self.service, - action, **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) def payments(self, request="", **kwargs): action = "payments" if validation.check_in(request, action): - return self.client.call_checkout_api(request, self.service, - action, **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) def payments_details(self, request="", **kwargs): action = "paymentsDetails" if validation.check_in(request, action): - return self.client.call_checkout_api(request, self.service, - action, **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) def payment_session(self, request="", **kwargs): action = "paymentSession" if validation.check_in(request, action): - return self.client.call_checkout_api(request, self.service, - action, **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) def payment_result(self, request="", **kwargs): action = "paymentsResult" if validation.check_in(request, action): - return self.client.call_checkout_api(request, self.service, action, - **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) def origin_keys(self, request="", **kwargs): action = "originKeys" if validation.check_in(request, action): - return self.client.call_checkout_api(request, self.service, - action, **kwargs) + return self.client.call_checkout_api(request, action, **kwargs) diff --git a/Adyen/settings.py b/Adyen/settings.py index c3fb9df6..d3c73712 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -3,7 +3,7 @@ BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" -ENDPOINT_CHECKOUT_URL = "https://checkout-{}.adyen.com" +ENDPOINT_CHECKOUT_TEST = "https://checkout-test.adyen.com" ENDPOINT_CHECKOUT_LIVE_SUFFIX = "https://{}-checkout-live" \ ".adyenpayments.com/checkout" API_CHECKOUT_VERSION = "v40" diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py index 46162d51..ead4eceb 100644 --- a/test/CheckoutUtilityTest.py +++ b/test/CheckoutUtilityTest.py @@ -47,7 +47,6 @@ def test_origin_keys_success_mocked(self): ['https://www.your-domain2.com']) def test_checkout_utility_api_url_custom(self): - url = self.ady.client._determine_checkout_url("test", "", - "originKeys") + url = self.ady.client._determine_checkout_url("test", "originKeys") self.assertEqual(url, "https://checkout-test.adyen.com/v1/originKeys") diff --git a/test/DetermineEndpointTest.py b/test/DetermineEndpointTest.py index 58c916e4..cba4d6ce 100644 --- a/test/DetermineEndpointTest.py +++ b/test/DetermineEndpointTest.py @@ -15,12 +15,19 @@ class TestDetermineUrl(unittest.TestCase): def test_checkout_api_url_custom(self): self.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" - url = self.adyen.client._determine_checkout_url("live", "", - "payments") + url = self.adyen.client._determine_checkout_url("live", "payments") self.client.live_endpoint_prefix = "1797a841fbb37ca7-AdyenDemo" self.assertEqual(url, "https://1797a841fbb37ca7-AdyenDemo-checkout-" "live.adyenpayments.com/checkout/v40/payments") + def test_checkout_api_url(self): + + self.client.live_endpoint_prefix = None + url = self.adyen.client._determine_checkout_url("test", + "paymentsDetails") + self.assertEqual(url, "https://checkout-test.adyen.com" + "/v40/payments/details") + def test_payments_invalid_platform(self): request = {'amount': {"value": "100000", "currency": "EUR"}, @@ -35,17 +42,10 @@ def test_payments_invalid_platform(self): }, 'merchantAccount': "YourMerchantAccount", 'returnUrl': "https://your-company.com/..."} - self.client.platform = "test" + self.client.platform = "live" + self.client.live_endpoint_prefix = None try: result = self.adyen.checkout.payments(request) except AdyenEndpointInvalidFormat as error: print("the error" + str(error.__class__.__name__)) self.assertIsNotNone("dfasdf") - - def test_checkout_api_url(self): - - self.client.live_endpoint_prefix = None - url = self.adyen.client._determine_checkout_url("test", "", - "paymentsDetails") - self.assertEqual(url, "https://checkout-test.adyen.com" - "/v40/payments/details") From 25afd0cdb117f18036ce8a905323bfda45413d70 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 15 Jan 2019 15:02:10 +0100 Subject: [PATCH 25/29] remove ENDPOINT_LIVE_SUFFIX for pal --- Adyen/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Adyen/settings.py b/Adyen/settings.py index d3c73712..1ad489e7 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -2,7 +2,6 @@ BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" -ENDPOINT_LIVE_SUFFIX = "-pal-live.adyenpayments.com" ENDPOINT_CHECKOUT_TEST = "https://checkout-test.adyen.com" ENDPOINT_CHECKOUT_LIVE_SUFFIX = "https://{}-checkout-live" \ ".adyenpayments.com/checkout" From 768c84b8696d47098025c30390cc46430434f974 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 15 Jan 2019 17:05:52 +0100 Subject: [PATCH 26/29] Deprecate API_VERSION --- Adyen/settings.py | 10 ++++++++-- test/CheckoutTest.py | 2 -- test/CheckoutUtilityTest.py | 1 - test/DetermineEndpointTest.py | 5 +---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Adyen/settings.py b/Adyen/settings.py index 1ad489e7..00b8df96 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -1,5 +1,3 @@ -#!/bin/python - BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_CHECKOUT_TEST = "https://checkout-test.adyen.com" @@ -9,3 +7,11 @@ API_CHECKOUT_UTILITY_VERSION = "v1" API_PAYOUT_VERSION = "v30" API_RECURRING_VERSION = "v25" + + +@property +def API_VERSION(): + import warnings + warnings.warn("this constant is deprecated use API_PAYOUT_VERSION", + DeprecationWarning) + return "v30" diff --git a/test/CheckoutTest.py b/test/CheckoutTest.py index 906a14ad..f93ac940 100644 --- a/test/CheckoutTest.py +++ b/test/CheckoutTest.py @@ -2,8 +2,6 @@ import unittest from BaseTest import BaseTest -from Adyen.exceptions import AdyenEndpointInvalidFormat - class TestCheckout(unittest.TestCase): adyen = Adyen.Adyen() diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py index ead4eceb..1be44b56 100644 --- a/test/CheckoutUtilityTest.py +++ b/test/CheckoutUtilityTest.py @@ -1,7 +1,6 @@ import Adyen import unittest from BaseTest import BaseTest -import pprint class TestCheckoutUtility(unittest.TestCase): diff --git a/test/DetermineEndpointTest.py b/test/DetermineEndpointTest.py index cba4d6ce..9652b7b5 100644 --- a/test/DetermineEndpointTest.py +++ b/test/DetermineEndpointTest.py @@ -1,7 +1,6 @@ import Adyen import unittest from BaseTest import BaseTest - from Adyen.exceptions import AdyenEndpointInvalidFormat @@ -21,7 +20,6 @@ def test_checkout_api_url_custom(self): "live.adyenpayments.com/checkout/v40/payments") def test_checkout_api_url(self): - self.client.live_endpoint_prefix = None url = self.adyen.client._determine_checkout_url("test", "paymentsDetails") @@ -47,5 +45,4 @@ def test_payments_invalid_platform(self): try: result = self.adyen.checkout.payments(request) except AdyenEndpointInvalidFormat as error: - print("the error" + str(error.__class__.__name__)) - self.assertIsNotNone("dfasdf") + self.assertIsNotNone(error) From 42cb7e4c21fe7124994b645ad4f8f377eb6a37e5 Mon Sep 17 00:00:00 2001 From: alexandros Date: Tue, 15 Jan 2019 17:35:24 +0100 Subject: [PATCH 27/29] Intoduce API_PAYMENT_VERSION and API_PAYOUT_VERSION deprecate API_VERSION --- Adyen/client.py | 4 +++- Adyen/settings.py | 12 ++++-------- test/CheckoutUtilityTest.py | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Adyen/client.py b/Adyen/client.py index eefe01b5..2146bc80 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -105,8 +105,10 @@ def _determine_api_url(self, platform, service, action): base_uri = settings.BASE_PAL_URL.format(platform) if service == "Recurring": api_version = settings.API_RECURRING_VERSION - else: + elif service == "Payout": api_version = settings.API_PAYOUT_VERSION + else: + api_version = settings.API_PAYMENT_VERSION return '/'.join([base_uri, service, api_version, action]) def _determine_hpp_url(self, platform, action): diff --git a/Adyen/settings.py b/Adyen/settings.py index 00b8df96..f015e7cc 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -5,13 +5,9 @@ ".adyenpayments.com/checkout" API_CHECKOUT_VERSION = "v40" API_CHECKOUT_UTILITY_VERSION = "v1" -API_PAYOUT_VERSION = "v30" API_RECURRING_VERSION = "v25" +API_PAYMENT_VERSION = "v30" +API_PAYOUT_VERSION = "v30" - -@property -def API_VERSION(): - import warnings - warnings.warn("this constant is deprecated use API_PAYOUT_VERSION", - DeprecationWarning) - return "v30" +# Deprecated +API_VERSION = "v30" diff --git a/test/CheckoutUtilityTest.py b/test/CheckoutUtilityTest.py index 1be44b56..121dc1bb 100644 --- a/test/CheckoutUtilityTest.py +++ b/test/CheckoutUtilityTest.py @@ -2,6 +2,8 @@ import unittest from BaseTest import BaseTest +from Adyen import settings + class TestCheckoutUtility(unittest.TestCase): ady = Adyen.Adyen() @@ -20,6 +22,7 @@ def test_origin_keys_success_mocked(self): "https://www.your-domain3.com" } } + self.ady.client = self.test.create_client_from_file(200, request, "test/mocks/" "checkoututility/" From ec4f563fc0f6892f25ea4515447fb902e9e6ba7c Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 16 Jan 2019 09:27:09 +0100 Subject: [PATCH 28/29] Remove API_VERSION --- Adyen/settings.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Adyen/settings.py b/Adyen/settings.py index f015e7cc..e9e95658 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -1,3 +1,4 @@ +# Those constants are used from the library only BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet" BASE_HPP_URL = "https://{}.adyen.com/hpp" ENDPOINT_CHECKOUT_TEST = "https://checkout-test.adyen.com" @@ -8,6 +9,3 @@ API_RECURRING_VERSION = "v25" API_PAYMENT_VERSION = "v30" API_PAYOUT_VERSION = "v30" - -# Deprecated -API_VERSION = "v30" From a66d3cc2c3cb1f44ce5a3efc66bd80ce1222f72a Mon Sep 17 00:00:00 2001 From: alexandros Date: Wed, 16 Jan 2019 09:32:24 +0100 Subject: [PATCH 29/29] UpdateAPI_PAYMENT_VERSION = v40 --- Adyen/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adyen/settings.py b/Adyen/settings.py index e9e95658..d11759ee 100644 --- a/Adyen/settings.py +++ b/Adyen/settings.py @@ -7,5 +7,5 @@ API_CHECKOUT_VERSION = "v40" API_CHECKOUT_UTILITY_VERSION = "v1" API_RECURRING_VERSION = "v25" -API_PAYMENT_VERSION = "v30" +API_PAYMENT_VERSION = "v40" API_PAYOUT_VERSION = "v30"