diff --git a/.gitignore b/.gitignore index c2dbae8f..5eaad933 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,5 @@ *.log *.DS_Store *.pypirc -MANIFEST.in releaseguide.md -setup.cfg -setup.py + diff --git a/.travis.yml b/.travis.yml index 553b3c6a..04997e1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,15 @@ sudo: true language: python python: - - "2.6" - "2.7" - - "3.2" - - "3.3" - - "3.4" - - "3.5" -cache: - pip: false + - "3.6" +cache: pip install: - pip install requests + - pip install pycurl + - pip install mock + - pip install coveralls script: - - python runtests.py + - coverage run -m unittest discover -s test -p '*Test.py' +after_success: + coveralls diff --git a/Adyen/__init__.py b/Adyen/__init__.py index 9faad46d..854b2c27 100644 --- a/Adyen/__init__.py +++ b/Adyen/__init__.py @@ -1,4 +1,7 @@ #!/bin/python + +from __future__ import absolute_import, division, print_function, unicode_literals + from . import util from .util import generate_hpp_sig from .exceptions import ( @@ -16,9 +19,9 @@ AdyenPayment, AdyenHPP) +from .httpclient import HTTPClient + import datetime -from adyen_log import logname,getlogger -logger = getlogger() username = "" password = "" @@ -34,7 +37,6 @@ def __init__(self, **kwargs): self.hpp = AdyenHPP(client=self.client) self.recurring = AdyenRecurring(client=self.client) - _base_adyen_obj = Adyen() recurring = _base_adyen_obj.recurring hpp = _base_adyen_obj.hpp diff --git a/Adyen/adyen_log.py b/Adyen/adyen_log.py deleted file mode 100644 index baa91192..00000000 --- a/Adyen/adyen_log.py +++ /dev/null @@ -1,28 +0,0 @@ -import logging -import datetime - -# Create current date string for log file name -log_now = datetime.datetime.now() -log_now = log_now.strftime('%m_%d_%Y') - -LOG_FILENAME = 'Adyen %s.log' % log_now - -logger = logging.getLogger(LOG_FILENAME) -logger.setLevel(logging.DEBUG) - - -# TODO: Make logging optional based on Adyen class instance attribute 'create_log'. -# TODO: Define a clear logging structure. - -# fh = logging.FileHandler(LOG_FILENAME) -# formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(message)s") -# fh.setFormatter(formatter) -# fh.setLevel(logging.DEBUG) -# logger.addHandler(fh) -# logger.info('Adyen Log of %s' % log_now) - -def logname(): - return LOG_FILENAME - -def getlogger(): - return logger diff --git a/Adyen/client.py b/Adyen/client.py index 75fdedc2..2c532865 100644 --- a/Adyen/client.py +++ b/Adyen/client.py @@ -1,4 +1,7 @@ #!/bin/python + +from __future__ import absolute_import, division, print_function, unicode_literals + import json as json_lib import re @@ -15,10 +18,6 @@ import datetime from datetime import timedelta -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) - HMAC_TEST_url = "https://ca-test.adyen.com/ca/ca/skin/checkhmac.shtml" @@ -77,7 +76,7 @@ class AdyenClient(object): def __init__(self, username=None, password=None, review_payout_username=None, review_payout_password=None, store_payout_username=None, store_payout_password=None, platform=None, - merchant_account=None, merchant_specific_url=None, skin_code=None, hmac=None,app_name=None,create_log=None): + merchant_account=None, merchant_specific_url=None, skin_code=None, hmac=None, app_name=None, http_force = None): self.username = username self.password = password self.review_payout_username = review_payout_username @@ -91,10 +90,10 @@ def __init__(self, username=None, password=None, review_payout_username=None, self.skin_code = skin_code self.psp_list = [] self.app_name = app_name - self.create_log = create_log - self.LIB_VERSION = "1.0.0"; + self.LIB_VERSION = "1.1.0"; self.USER_AGENT_SUFFIX = "adyen-python-api-library/"; self.http_init = False + self.http_force = http_force def _determine_api_url(self, platform, service, action): """This returns the Adyen API endpoint based on the provided platform, @@ -123,7 +122,7 @@ def _determine_hpp_url(self, platform, action): return result def _review_payout_username(self,**kwargs): - from Adyen import review_payout_username + from . import review_payout_username if 'username' in kwargs: review_payout_username = kwargs['username'] elif self.review_payout_username: @@ -132,13 +131,12 @@ def _review_payout_username(self,**kwargs): errorstring = """AdyenInvalidRequestError: Please set your review payout webservice username. You can do this by running 'Adyen.review_payout_username = 'Your payout username' """ - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) return review_payout_username def _review_payout_pass(self,**kwargs): - from Adyen import review_payout_password + from . import review_payout_password if 'password' in kwargs: review_payout_password = kwargs["password"] elif self.review_payout_password: @@ -147,13 +145,12 @@ def _review_payout_pass(self,**kwargs): errorstring = """AdyenInvalidRequestError: Please set your review payout webservice password. You can do this by running 'Adyen.review_payout_password = 'Your payout password'""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) return review_payout_password def _store_payout_username(self,**kwargs): - from Adyen import store_payout_username + from . import store_payout_username if 'username' in kwargs: store_payout_username = kwargs['username'] elif self.store_payout_username: @@ -162,13 +159,12 @@ def _store_payout_username(self,**kwargs): errorstring = """AdyenInvalidRequestError: Please set your store payout webservice username. You can do this by running 'Adyen.store_payout_username = 'Your payout username'""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) return store_payout_username def _store_payout_pass(self,**kwargs): - from Adyen import store_payout_password + from . import store_payout_password if 'password' in kwargs: store_payout_password = kwargs["password"] elif self.store_payout_password: @@ -177,7 +173,6 @@ def _store_payout_pass(self,**kwargs): errorstring = """AdyenInvalidRequestError: Please set your store payout webservice password. You can do this by running 'Adyen.store_payout_password = 'Your payout password'""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) return store_payout_password @@ -202,10 +197,10 @@ def call_api(self, request_data, service, action, idempotency=False, AdyenResult: The AdyenResult is returned when a request was succesful. """ - from Adyen import username, password, merchant_account, platform - + from . import username, password, merchant_account, platform + # if self.http_init == False: - self.http_client = HTTPClient(self.app_name,self.LIB_VERSION,self.USER_AGENT_SUFFIX) + self.http_client = HTTPClient(self.app_name,self.USER_AGENT_SUFFIX,self.LIB_VERSION,self.http_force) self.http_init = True #username at self object has highest priority. fallback to root module @@ -222,7 +217,6 @@ def call_api(self, request_data, service, action, idempotency=False, if not username: errorstring = """AdyenInvalidRequestError: Please set your webservice username." You can do this by running 'Adyen.username = 'Your username'""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) #Ensure that username has been removed so as not to be passed to adyen. if 'username' in kwargs: @@ -242,7 +236,6 @@ def call_api(self, request_data, service, action, idempotency=False, if not password: errorstring = """AdyenInvalidRequestError: Please set your webservice password. You can do this by running 'Adyen.password = 'Your password'""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) #Ensure that password has been removed so as not to be passed to adyen. if 'password' in kwargs: @@ -306,10 +299,10 @@ def call_hpp(self, message, action, hmac_key="", **kwargs): AdyenResult: The AdyenResult is returned when a request was succesful. """ - from Adyen import hmac, platform - + from . import hmac, platform + # if self.http_init == False: - self.http_client = HTTPClient(self.app_name,self.LIB_VERSION,self.USER_AGENT_SUFFIX) + self.http_client = HTTPClient(self.app_name,self.USER_AGENT_SUFFIX,self.LIB_VERSION,self.http_force) self.http_init = True #hmac provided in function has highest priority. fallback to self then @@ -324,7 +317,6 @@ def call_hpp(self, message, action, hmac_key="", **kwargs): parameter in the function call ie. 'Adyen.hpp.directory_lookup(hmac=\"!WR#F@...\"'. Please reach out to support@Adyen.com if the issue persists.""" - # logger.error(errorstring) raise AdyenInvalidRequestError(errorstring) #platform provided in self has highest priority, fallback to root module @@ -333,11 +325,9 @@ def call_hpp(self, message, action, hmac_key="", **kwargs): platform = self.platform if platform.lower() not in ['live','test']: errorstring = " 'platform' must be the value of 'live' or 'test' " - # logger.error(errorstring) raise ValueError(errorstring) elif not isinstance(platform, str): errorstring = "'platform' must be type string" - # logger.error(errorstring) raise TypeError(errorstring) if 'skinCode' not in message: @@ -362,21 +352,19 @@ def call_hpp(self, message, action, hmac_key="", **kwargs): def hpp_payment(self,request_data, action, hmac_key="", **kwargs): - from Adyen import hmac, platform - + from . import hmac, platform + # if self.http_init == False: - self.http_client = HTTPClient(self.app_name,self.LIB_VERSION,self.USER_AGENT_SUFFIX) + self.http_client = HTTPClient(self.app_name,self.USER_AGENT_SUFFIX,self.LIB_VERSION,self.http_force) self.http_init = True if self.platform: platform = self.platform if platform.lower() not in ['live','test']: errorstring = " 'platform' must be the value of 'live' or 'test' " - # logger.error(errorstring) raise ValueError(errorstring) elif not isinstance(platform, str): errorstring = "'platform' must be type string" - # logger.error(errorstring) raise TypeError(errorstring) if 'skinCode' not in request_data: @@ -421,25 +409,18 @@ def _handle_response(self, url, raw_response, raw_request, status_code, headers, response = {} # If the result can't be parsed into json, most likely is raw html. # Some response are neither json or raw html, handle them here: - try: - response = json_lib.loads(raw_result) - - self._handle_http_error(url, response, status_code, - headers.get('pspReference'), raw_request, raw_response, headers) - except: - response = json_lib.loads(raw_response) + response = json_lib.loads(raw_response) - # Pass raised error to error handler. - self._handle_http_error(url,response,status_code,headers.get('pspReference'),raw_request,raw_response,headers,request_dict) + # Pass raised error to error handler. + self._handle_http_error(url,response,status_code,headers.get('pspReference'),raw_request,raw_response,headers,request_dict) - try: - if response['errorCode']: - return raw_response - except KeyError: - errstr = 'KeyError: errorCode' - # logger.error('Key Error: errorCode') - pass + try: + if response['errorCode']: + return raw_response + except KeyError: + errstr = 'KeyError: errorCode' + pass else: try: response = json_lib.loads(raw_response) @@ -465,8 +446,6 @@ def _handle_response(self, url, raw_response, raw_request, status_code, headers, raw_response=raw_response, url=url - # logger.error(errorstring) - raise AdyenInvalidRequestError(errorstring) def _handle_http_error(self, url, response_obj, status_code, psp_ref, @@ -489,14 +468,12 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, """ if status_code == 404: - from Adyen import merchant_specific_url + from . import merchant_specific_url if url == merchant_specific_url: erstr = "Received a 404 for url:'{}'. Please ensure that the custom merchant specific url is correct".format(url) - # logger.error(erstr) raise AdyenAPICommunicationError(erstr) else: erstr = "Unexpected error while communicating with Adyen. Please reach out to support@adyen.com if the problem persists" - # logger.error(erstr) raise AdyenAPICommunicationError(erstr, raw_request=raw_request, raw_response=raw_response, @@ -506,15 +483,12 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, elif status_code in [400, 422]: erstr = "Received validation error with errorCode: %s, message: %s, HTTP Code: %s. Please verify the values provided. Please reach out to support@adyen.com if the problem persists, providing the PSP reference: %s" % (response_obj["errorCode"],response_obj["message"], status_code, psp_ref) - # logger.error(erstr) - raise ValueError(erstr) 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" - # logger.error(erstr) raise ValueError(erstr) elif status_code == 403: - from Adyen import username + from . import username ma = raw_request['merchantAccount'] @@ -522,10 +496,9 @@ def _handle_http_error(self, url, response_obj, status_code, psp_ref, erstr = ("You provided the merchant account:'%s' that doesn't exist or you don't have access to it.\n" "Please verify the merchant account provided. \n" "Reach out to support@adyen.com if the issue persists") % raw_request['merchantAccount'] - # logger.error(erstr) raise AdyenAPIInvalidPermission(erstr) - erstr = "Unable to perform the requested action. message: %s. If you think your webservice user: %s might not have the necessary permissions to perform this request. Please reach out to support@adyen.com, providing the PSP reference: %s" % response_obj["message"],self.username,psp_ref + erstr = "Unable to perform the requested action. message: %s. If you think your webservice user: %s might not have the necessary permissions to perform this request. Please reach out to support@adyen.com, providing the PSP reference: %s" % (response_obj["message"],self.username,psp_ref) raise AdyenAPIInvalidPermission(erstr,username,psp_ref,raw_request=raw_request,raw_response=raw_response,url=url,psp=psp_ref,headers=headers) elif status_code == 422: diff --git a/Adyen/exceptions.py b/Adyen/exceptions.py index 141f626c..0294b738 100644 --- a/Adyen/exceptions.py +++ b/Adyen/exceptions.py @@ -1,6 +1,4 @@ -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) +from __future__ import absolute_import, division, print_function, unicode_literals class AdyenError(Exception): diff --git a/Adyen/httpclient.py b/Adyen/httpclient.py index e388c1da..85c5ea5f 100644 --- a/Adyen/httpclient.py +++ b/Adyen/httpclient.py @@ -1,4 +1,8 @@ #!/bin/python + +from __future__ import absolute_import, division, print_function, unicode_literals +import sys + try: import requests except ImportError: @@ -9,16 +13,26 @@ except ImportError: pycurl = None -import urllib2 +try: + # Python 3 + from urllib.parse import urlencode + from urllib.request import Request, urlopen + from urllib.error import HTTPError +except ImportError: + # Python 2 + from urllib import urlencode + from urllib2 import Request, urlopen, HTTPError + +try: + # Python 2 + from StringIO import StringIO +except ImportError: + # Python 3 + from io import BytesIO -from urllib import urlencode -from StringIO import StringIO import json as json_lib import re import base64 -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) #Could be used instead of the large tuple response from request function @@ -27,19 +41,26 @@ # ['raw_response','raw_request','status_code','headers']) class HTTPClient(object): - def __init__(self,app_name,LIB_VERSION,USER_AGENT_SUFFIX): + def __init__(self,app_name,USER_AGENT_SUFFIX,LIB_VERSION,force_request = None): #Check if requests already available, default to urllib - self.app_name = app_name - self.LIB_VERSION = LIB_VERSION - self.USER_AGENT_SUFFIX = USER_AGENT_SUFFIX - self.user_agent = self.app_name + " " + self.USER_AGENT_SUFFIX + self.LIB_VERSION - - if requests: - self.request = self._requests_post - elif pycurl: - self.request = self._pycurl_post + # self.app_name = app_name + # self.LIB_VERSION = LIB_VERSION + # self.USER_AGENT_SUFFIX = USER_AGENT_SUFFIX + self.user_agent = app_name + " " + USER_AGENT_SUFFIX + LIB_VERSION + if not force_request: + if requests: + self.request = self._requests_post + elif pycurl: + self.request = self._pycurl_post + else: + self.request = self._urllib_post else: - self.request = self._urllib_post + if force_request == 'requests': + self.request = self._requests_post + elif force_request == 'pycurl': + self.request = self._pycurl_post + else: + self.request = self._urllib_post def _pycurl_post(self, url, @@ -86,7 +107,11 @@ def handle_header(header_line): curl = pycurl.Curl() curl.setopt(curl.URL, url) - stringbuffer = StringIO() + if sys.version_info[0] >= 3: + stringbuffer = BytesIO() + else: + stringbuffer = StringIO() + #stringbuffer = StringIO() curl.setopt(curl.WRITEDATA, stringbuffer) # Add User-Agent header to request so that the request can be identified as coming @@ -94,7 +119,10 @@ def handle_header(header_line): headers['User-Agent'] = self.user_agent # Convert the header dict to formatted array as pycurl needs. - header_list = ["%s:%s" % (k,v) for k,v in headers.iteritems()] + if sys.version_info[0] >= 3: + header_list = ["%s:%s" % (k, v) for k, v in headers.items()] + else: + header_list = ["%s:%s" % (k, v) for k, v in headers.iteritems()] #Ensure proper content-type when adding headers if json: header_list.append("Content-Type:application/json") @@ -185,6 +213,7 @@ def _urllib_post(self, url, password="", headers={}, timeout=30): + """This function will POST to the url endpoint using urllib2. returning an AdyenResult object on 200 HTTP responce. Either json or data has to be provided. If username and password are provided, basic auth will be @@ -214,7 +243,7 @@ def _urllib_post(self, url, raw_store = json raw_request = json_lib.dumps(json) if json else urlencode(data) - url_request = urllib2.Request(url,data=raw_request) + url_request = Request(url,data=raw_request.encode('utf8')) if json: url_request.add_header('Content-Type','application/json') elif not data: @@ -229,8 +258,12 @@ def _urllib_post(self, url, #Adding basic auth is username and password provided. if username and password: - basicAuthstring = base64.encodestring('%s:%s' % (username, - password)).replace('\n', '') + if sys.version_info[0] >= 3: + basicAuthstring = base64.encodebytes(('%s:%s' % (username, + password)).encode()).decode().replace('\n', '') + else: + basicAuthstring = base64.encodestring('%s:%s' % (username, + password)).replace('\n', '') url_request.add_header("Authorization", "Basic %s" % basicAuthstring) #Adding the headers to the request. @@ -239,11 +272,11 @@ def _urllib_post(self, url, #URLlib raises all non 200 responses as en error. try: - response = urllib2.urlopen(url_request, timeout=timeout) - except urllib2.HTTPError as e: + response = urlopen(url_request, timeout=timeout) + except HTTPError as e: raw_response = e.read() - return raw_response, raw_request, e.getcode, e.headers + return raw_response, raw_request, e.getcode(), e.headers else: raw_response = response.read() response.close() diff --git a/Adyen/services.py b/Adyen/services.py index 6ad11bf1..bba8a5bd 100644 --- a/Adyen/services.py +++ b/Adyen/services.py @@ -1,14 +1,14 @@ + +from __future__ import absolute_import, division, print_function, unicode_literals + import datetime -import util +from . import util from .client import AdyenClient -import validation -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) +from . import validation class AdyenBase(object): def __setattr__(self, attr, value): - client_attr = ["username","password","platform"] + client_attr = ["username","password","platform","app_name"] if attr in client_attr: if value: self.client[attr] = value diff --git a/Adyen/util.py b/Adyen/util.py index ffd9e482..750f8ade 100644 --- a/Adyen/util.py +++ b/Adyen/util.py @@ -1,13 +1,14 @@ + +from __future__ import absolute_import, division, print_function, unicode_literals + import re from functools import wraps +from itertools import chain from collections import OrderedDict import base64 import hmac import hashlib import binascii -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) def _generate_signing_string(dict_object,hmac_key): @@ -25,7 +26,7 @@ def escapeVal(val): #for k,v in ordered_request.items(): # signing_string.append(':'.join(k,escapeVal(v))) - signing_string = ':'.join(map(escapeVal, map(str,ordered_request.keys()) + map(str,ordered_request.values()))) + signing_string = ':'.join(map(escapeVal, chain(map(str,ordered_request.keys()), map(str,ordered_request.values())))) return signing_string @@ -47,8 +48,7 @@ def escapeVal(val): ordered_request = OrderedDict(sorted(dict_object.items(), key=lambda t: t[0])) - signing_string = ':'.join(map(escapeVal, map(str,ordered_request.keys()) + map(str,ordered_request.values()))) - + signing_string = ':'.join(map(escapeVal, chain(map(str,ordered_request.keys()), map(str,ordered_request.values())))) - hm = hmac.new(hmac_key, signing_string, hashlib.sha256) + hm = hmac.new(hmac_key, signing_string.encode('utf-8'), hashlib.sha256) return base64.b64encode(hm.digest()) diff --git a/Adyen/validation.py b/Adyen/validation.py index e890ba26..a7c41868 100644 --- a/Adyen/validation.py +++ b/Adyen/validation.py @@ -1,14 +1,13 @@ + +from __future__ import absolute_import, division, print_function, unicode_literals + from .exceptions import AdyenInvalidRequestError from functools import wraps -# from .util import under_to_camel_dict -import logging -from adyen_log import logname,getlogger -logger = logging.getLogger(logname()) actions = {} actions['listRecurringDetails'] = ["shopperReference"] actions['disable'] = ["shopperReference"] -actions['directory'] = ["currencyCode","paymentAmount","merchantReference","sessionValidity","shipBeforeDate"] +actions['directory'] = ["currencyCode","paymentAmount","merchantReference","sessionValidity"] actions['skipDetails'] = ["sessionValidity","currencyCode","paymentAmount","merchantReference","brandCode","issuerId"] actions['select'] = ["sessionValidity","currencyCode","paymentAmount","merchantReference"] actions['authorise'] = ["amount","reference"] diff --git a/README.md b/README.md index 83feaa97..825f9f8b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![Build Status](https://travis-ci.org/Adyen/adyen-python-api-library.svg?branch=master)](https://travis-ci.org/Adyen/adyen-python-api-library) +[![Coverage Status](https://coveralls.io/repos/github/Adyen/adyen-python-api-library/badge.svg?branch=master)](https://coveralls.io/github/Adyen/adyen-python-api-library?branch=master) + # Adyen APIs Library for Python This library simplifies working with Adyen APIs and allows you to integrate Adyen @@ -5,7 +8,7 @@ payments within any Python application. ## Requirements -- Python 2.7 +- Python 2.7 or 3.6 - Packages: requests or pycurl ( optional ) - Adyen account. If you don't have this you can request it here: https://www.adyen.com/home/discover/test-account-signup#form @@ -33,7 +36,7 @@ ady.payment.client.app_name = "your app name" ## Documentation -Follow the rest our guides from the documentation on how to use this library. [ Insert documentation link here ] +Follow the rest of our guides from the [documentation](http://adyen.github.io/adyen-python-api-library/index.html) on how to use this library. ## Licence diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..b1a1ddb7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[bdist_wheel] + +[metadata] +description-file = README.md + +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..e4257fde --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +from setuptools import setup,find_packages + +setup( + name = 'Adyen', + packages = ['Adyen'], + version = '1.1.0', + description = 'Adyen Python Api', + long_description = "Adyen Python Api to build ecommerce and reconciliation apps with Python. Connects to Adyen backend. Requires a 'test' or 'live' account with Adyen.", + author = 'Adyen', + author_email = 'support@adyen.com', + url = 'https://github.com/Adyen/adyen-python-api-library', + download_url = 'https://github.com/Adyen/adyen-python-api-library/archive/1.1.0.tar.gz', + keywords = ['payments', 'adyen', 'fintech'], + classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Libraries', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.6' + ] +) diff --git a/test/BaseTest.py b/test/BaseTest.py new file mode 100644 index 00000000..7fb17e98 --- /dev/null +++ b/test/BaseTest.py @@ -0,0 +1,29 @@ +import mock +import json +from Adyen import httpclient + + +class BaseTest(): + def __init__(self, adyen): + self.ady = adyen + + def create_client_from_file(self, status, request, filename = None): + if filename: + with open(filename) as data_file: + data = json.load(data_file) + st = open(filename) + strjson = st.read() + else: + data = "" + st = "" + strjson = "" + + self.ady.client.http_client = httpclient.HTTPClient + self.ady.client.http_init = True + self.ady.client.http_client.request = mock.MagicMock(return_value=[strjson, request, status, data]) + + mockclient = self.ady.client + if st: + st.close() + return mockclient + diff --git a/test/DirectoryLookupTest.py b/test/DirectoryLookupTest.py new file mode 100644 index 00000000..b54701d4 --- /dev/null +++ b/test/DirectoryLookupTest.py @@ -0,0 +1,67 @@ +import Adyen +import unittest +from BaseTest import BaseTest +import time +import pprint + +class TestDirectoryLookup(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.username = "YourWSUser" + client.password = "YourWSPassword" + client.platform = "test" + client.hmac = "DFB1EB5485895CFA84146406857104ABB4CBCABDC8AAF103A624C8F6A3EAAB00" + client.app_name = "appname" + + def test_get_post_parameters(self): + request = {} + request['merchantAccount'] = "testmerchantaccount" + request['paymentAmount'] = "1000" + request['currencyCode'] = "EUR" + request['merchantReference'] = "Get Payment methods" + request['skinCode'] = "testskincode" + request['countryCode'] = "NL" + request['shopperLocale'] = "nl_NL" + request['sessionValidity'] = time.strftime('%Y-%m-%dT%H:%M:%SZ') + self.test.create_client_from_file(200, request, None) + result = self.ady.hpp.hpp_payment(request) + self.assertEqual("EUR", result["message"]["currencyCode"]) + self.assertEqual(44, len(result["message"]["merchantSig"])) + + def test_get_payment_methods(self): + request = {} + request['merchantAccount'] = "testmerchantaccount" + request['paymentAmount'] = "1000" + request['currencyCode'] = "EUR" + request['merchantReference'] = "Get Payment methods" + request['skinCode'] = "testskincode" + request['countryCode'] = "NL" + request['shopperLocale'] = "nl_NL" + request['sessionValidity'] = time.strftime('%Y-%m-%dT%H:%M:%SZ') + self.test.create_client_from_file(200, request, 'test/mocks/hpp/directoryLookup-success.json') + result = self.ady.hpp.directory_lookup(request) + self.assertEqual(8, len(result.message['paymentMethods'])) + ideal = result.message['paymentMethods'][0] + self.assertEqual("ideal", ideal['brandCode']) + self.assertEqual("iDEAL", ideal['name']) + self.assertEqual(3, len(ideal['issuers'])) + issuer1 = ideal['issuers'][0] + self.assertEqual("1121", issuer1['issuerId']) + self.assertEqual("Test Issuer", issuer1['name']) + visa = result.message['paymentMethods'][1] + self.assertEqual("visa", visa['brandCode']) + + +TestDirectoryLookup.client.http_force = "requests" +suite = unittest.TestLoader().loadTestsFromTestCase(TestDirectoryLookup) +unittest.TextTestRunner(verbosity=2).run(suite) +TestDirectoryLookup.client.http_force = "pycurl" +TestDirectoryLookup.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestDirectoryLookup) +unittest.TextTestRunner(verbosity=2).run(suite) +TestDirectoryLookup.client.http_force = "other" +TestDirectoryLookup.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestDirectoryLookup) +unittest.TextTestRunner(verbosity=2).run(suite) \ No newline at end of file diff --git a/test/ModificationTest.py b/test/ModificationTest.py new file mode 100644 index 00000000..f2d78f50 --- /dev/null +++ b/test/ModificationTest.py @@ -0,0 +1,75 @@ +import Adyen +import unittest +from BaseTest import BaseTest + +class TestModifications(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.username = "YourWSUser" + client.password = "YourWSPassword" + client.platform = "test" + client.app_name = "appname" + + def test_capture_success(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['modificationAmount'] = {"value": "1234", "currency": "EUR"} + request['originalReference'] = "YourOriginalReference" + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/capture-success.json') + result = self.ady.payment.capture(request) + self.assertEqual("[capture-received]",result.message['response']) + + def test_capture_error_167(self): + #This test is not needed since validation.py already checks the 'originalReference' value in case it is missing + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['modificationAmount'] = {"value": "1234", "currency": "EUR"} + request['originalReference'] = "YourOriginalReference" + self.ady.client = self.test.create_client_from_file(422, request, 'test/mocks/capture-error-167.json') + self.assertRaisesRegexp(ValueError,"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) + + def test_cancel_or_refund_received(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['originalReference'] = "YourOriginalReference" + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/cancelOrRefund-received.json') + result = self.ady.payment.cancel_or_refund(request) + self.assertEqual("[cancelOrRefund-received]", result.message['response']) + + def test_refund_received(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['originalReference'] = "YourOriginalReference" + request['modificationAmount'] = {"value": "1234", "currency": "EUR"} + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/refund-received.json') + result = self.ady.payment.refund(request) + self.assertEqual("[refund-received]", result.message['response']) + + def test_cancel_received(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['originalReference'] = "YourOriginalReference" + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/cancel-received.json') + result = self.ady.payment.cancel(request) + self.assertEqual("[cancel-received]", result.message['response']) + +TestModifications.client.http_force = "requests" +suite = unittest.TestLoader().loadTestsFromTestCase(TestModifications) +unittest.TextTestRunner(verbosity=2).run(suite) +TestModifications.client.http_force = "pycurl" +TestModifications.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestModifications) +unittest.TextTestRunner(verbosity=2).run(suite) +TestModifications.client.http_force = "other" +TestModifications.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestModifications) +unittest.TextTestRunner(verbosity=2).run(suite) \ No newline at end of file diff --git a/test/PaymentTest.py b/test/PaymentTest.py new file mode 100644 index 00000000..b078779e --- /dev/null +++ b/test/PaymentTest.py @@ -0,0 +1,163 @@ +import Adyen +import unittest +from BaseTest import BaseTest + + +class TestPayments(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.username = "YourWSUser" + client.password = "YourWSPassword" + client.platform = "test" + client.app_name = "appname" + + def test_authorise_success_mocked(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['amount'] = {"value": "100000", "currency": "EUR"} + request['reference'] = "123456" + request['card'] = { + "number": "5136333333333335", + "expiryMonth": "08", + "expiryYear": "2018", + "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.assertEqual("Authorised", result.message['resultCode']) + self.assertEqual("8/2018", result.message['additionalData']['expiryDate']) + self.assertEqual("411111", result.message['additionalData']['cardBin']) + self.assertEqual("1111", result.message['additionalData']['cardSummary']) + self.assertEqual("Holder", result.message['additionalData']['cardHolderName']) + self.assertEqual("true", result.message['additionalData']['threeDOffered']) + self.assertEqual("false", result.message['additionalData']['threeDAuthenticated']) + self.assertEqual("69746", result.message['authCode']) + self.assertEqual(11, len(result.message['fraudResult']['results'])) + fraudCheckResult = result.message['fraudResult']['results'][0]['FraudCheckResult'] + self.assertEqual("CardChunkUsage", fraudCheckResult['name']) + self.assertEqual(8, fraudCheckResult['accountScore']) + self.assertEqual(2, fraudCheckResult['checkId']) + + def test_authorise_error010_mocked(self): + request = {} + request['merchantAccount'] = "testaccount" + request['amount'] = {"value": "100000", "currency": "EUR"} + request['reference'] = "123456" + request['card'] = { + "number": "5136333333333335", + "expiryMonth": "08", + "expiryYear": "2018", + "cvc": "737", + "holderName": "John Doe" + } + self.ady.client = self.test.create_client_from_file(403,request, 'test/mocks/authorise-error-010.json') + self.assertRaises(Adyen.AdyenAPIInvalidPermission,self.ady.payment.authorise,request) + + def test_authorise_error_cvc_declined_mocked(self): + request = {} + request['amount'] = {"value": "100000", "currency": "EUR"} + request['reference'] = "123456" + request['card'] = { + "number": "5136333333333335", + "expiryMonth": "08", + "expiryYear": "2018", + "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.assertEqual("Refused", result.message['resultCode']) + + def test_authorise_success_3d_mocked(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['amount'] = {"value": "100000", "currency": "EUR"} + request['reference'] = "123456" + request['card'] = { + "number": "5136333333333335", + "expiryMonth": "08", + "expiryYear": "2018", + "cvc": "787", + "holderName": "John Doe" + } + request['browserInfo'] = { + "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.assertEqual("RedirectShopper", result.message['resultCode']) + self.assertIsNotNone(result.message['md']) + self.assertIsNotNone(result.message['issuerUrl']) + self.assertIsNotNone(result.message['paRequest']) + + def test_authorise_3d_success_mocked(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['md'] = "testMD" + request['paResponse'] = "paresponsetest" + request['browserInfo'] = { + "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.assertEqual("Authorised", result.message['resultCode']) + self.assertIsNotNone(result.message['pspReference']) + + def test_authorise_cse_success_mocked(self): + request = {} + request['amount'] = {"value": "1234", "currency": "EUR"} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + 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.assertEqual("Authorised", result.message['resultCode']) + + def test_authorise_cse_error_expired_mocked(self): + request = {} + request['amount'] = {"value": "1234", "currency": "EUR"} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request['additionalData'] = { + "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.assertEqual("Refused", result.message['resultCode']) + self.assertEqual("DECLINED Expiry Incorrect", result.message['additionalData']['refusalReasonRaw']) + + def test_error_401_mocked(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['amount'] = {"value": "100000", "currency": "EUR"} + request['reference'] = "123456" + request['card'] = { + "number": "5136333333333335", + "expiryMonth": "08", + "expiryYear": "2018", + "cvc": "787", + "holderName": "John Doe" + } + self.ady.client = self.test.create_client_from_file(401, request, 'test/mocks/authorise-error-010.json') + self.assertRaisesRegexp(ValueError, "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) + + +TestPayments.client.http_force = "requests" +suite = unittest.TestLoader().loadTestsFromTestCase(TestPayments) +unittest.TextTestRunner(verbosity=2).run(suite) +TestPayments.client.http_force = "pycurl" +TestPayments.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestPayments) +unittest.TextTestRunner(verbosity=2).run(suite) +TestPayments.client.http_force = "other" +TestPayments.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestPayments) +unittest.TextTestRunner(verbosity=2).run(suite) \ No newline at end of file diff --git a/test/RecurringTest.py b/test/RecurringTest.py new file mode 100644 index 00000000..a54e89cb --- /dev/null +++ b/test/RecurringTest.py @@ -0,0 +1,63 @@ +import Adyen +import unittest +from BaseTest import BaseTest + +class TestRecurring(unittest.TestCase): + ady = Adyen.Adyen() + + client = ady.client + test = BaseTest(ady) + client.username = "YourWSUser" + client.password = "YourWSPassword" + client.platform = "test" + client.app_name = "appname" + + def test_list_recurring_details(self): + request = {} + request['merchantAccount'] = "YourMerchantAccount" + request['reference'] = "YourReference" + request["shopperEmail"] = "ref@email.com" + request["shopperReference"] = "ref" + request['recurring'] = {} + request["recurring"]['contract'] = "RECURRING" + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/recurring/listRecurringDetails-success.json') + result = self.ady.recurring.list_recurring_details(request) + self.assertEqual(1, len(result.message['details'])) + self.assertEqual(1, len(result.message['details'][0])) + recurringDetail = result.message['details'][0]['RecurringDetail'] + self.assertEqual("recurringReference", recurringDetail['recurringDetailReference']) + self.assertEqual("cardAlias", recurringDetail['alias']) + self.assertEqual("1111", recurringDetail['card']['number']) + + def test_disable(self): + request = {} + request["shopperEmail"] = "ref@email.com" + request["shopperReference"] = "ref" + request["recurringDetailReference"] = "12345678889" + self.ady.client = self.test.create_client_from_file(200, request, 'test/mocks/recurring/disable-success.json') + result = self.ady.recurring.disable(request) + self.assertEqual(1, len(result.message['details'])) + self.assertEqual("[detail-successfully-disabled]", result.message['response']) + + def test_disable_803(self): + request = {} + request["shopperEmail"] = "ref@email.com" + request["shopperReference"] = "ref" + request["recurringDetailReference"] = "12345678889" + self.ady.client = self.test.create_client_from_file(422, request, 'test/mocks/recurring/disable-error-803.json') + self.assertRaisesRegexp(ValueError, + "Received validation error with errorCode: 803, message: PaymentDetail not found, HTTP Code: 422.*", + self.ady.recurring.disable, request) + +TestRecurring.client.http_force = "requests" +suite = unittest.TestLoader().loadTestsFromTestCase(TestRecurring) +unittest.TextTestRunner(verbosity=2).run(suite) +TestRecurring.client.http_force = "pycurl" +TestRecurring.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestRecurring) +unittest.TextTestRunner(verbosity=2).run(suite) +TestRecurring.client.http_force = "other" +TestRecurring.client.http_init = False +suite = unittest.TestLoader().loadTestsFromTestCase(TestRecurring) +unittest.TextTestRunner(verbosity=2).run(suite) + diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/mocks/authorise-error-010.json b/test/mocks/authorise-error-010.json new file mode 100644 index 00000000..1bed6e13 --- /dev/null +++ b/test/mocks/authorise-error-010.json @@ -0,0 +1,7 @@ +{ + "status": 403, + "errorCode": "010", + "message": "Not allowed", + "errorType": "security", + "pspReference": "8514836072314693" +} diff --git a/test/mocks/authorise-error-cvc-declined.json b/test/mocks/authorise-error-cvc-declined.json new file mode 100644 index 00000000..ab2d0cca --- /dev/null +++ b/test/mocks/authorise-error-cvc-declined.json @@ -0,0 +1,85 @@ +{ + "additionalData": { + "fraudResultType": "GREEN", + "aliasType": "Default", + "alias": "H167852639363479" + }, + "fraudResult": { + "accountScore": 50, + "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": 50, + "checkId": 41, + "name": "PaymentDetailNonFraudRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + } + ] + }, + "pspReference": "7924836078655376", + "refusalReason": "CVC Declined", + "resultCode": "Refused" +} \ No newline at end of file diff --git a/test/mocks/authorise-error-expired.json b/test/mocks/authorise-error-expired.json new file mode 100644 index 00000000..c551112e --- /dev/null +++ b/test/mocks/authorise-error-expired.json @@ -0,0 +1,89 @@ +{ + "additionalData": { + "cvcResult": "1 Matches", + "fraudResultType": "GREEN", + "avsResult": "4 AVS not supported for this card type", + "avsResultRaw": "4", + "cvcResultRaw": "1", + "refusalReasonRaw": "DECLINED Expiry Incorrect", + "acquirerCode": "TestPmmAcquirer" + }, + "fraudResult": { + "accountScore": 51, + "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": 50, + "checkId": 41, + "name": "PaymentDetailNonFraudRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, + { + "FraudCheckResult": { + "accountScore": 1, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + } + ] + }, + "pspReference": "7924836277951659", + "refusalReason": "Refused", + "resultCode": "Refused" +} \ No newline at end of file diff --git a/test/mocks/authorise-success-3d.json b/test/mocks/authorise-success-3d.json new file mode 100644 index 00000000..d859e138 --- /dev/null +++ b/test/mocks/authorise-success-3d.json @@ -0,0 +1,87 @@ +{ + "additionalData": { + "fraudResultType": "GREEN", + "aliasType": "Default", + "alias": "E840075550837688" + }, + "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": 41, + "name": "PaymentDetailNonFraudRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + } + ] + }, + "pspReference": "7924836133944997", + "resultCode": "RedirectShopper", + "issuerUrl": "https://test.adyen.com/hpp/3d/validate.shtml", + "md": "qeQbxBB3pYYM+ggR0rXKb9Bdng0p0WRtFU206k+2+tpjnN/q2Jvlvr5GowN8bLHYuXa67otJ5LP10s0000ULw6tVLYFsQDR6JGL5+f7S3HajWtVe/q6LfZRce7x04Fo813aDftvSFW+hFmjTZWHu4guKZrC7GBUYnEmjcHrhMXQbLgC23asFr/Cg7FPMz7DAJBh2Frc/WluZ5/5DD6PN5XXGQvLOWxmVszT8rd0x05AiZTGq2evPWQTeB1qOkNxmA0KGEznTaXakHYpFAIN69GQOSnrx9Ys4f4/H9gechsdGGi/5jA3e0jeQvVJ5J74vAdD+0MRv1VyeX6g0CIupbgfm4L90zoWMBgG2SeeKRgc=", + "paRequest": "eNpVUttygjAQ/RXrB5CEi1xmzQwVZ+qDjGP1ucOEjFJK0BCK8PVNUGqbp3N2s5uzZwOHs+Q8eeeslZzCljdNduKzIl/OIz+03cBZEMcJXTcM/TmFXbznVwrfX000LSixsGUDmqgul+ycCUUhY9fXTUqJ7bjeAtCDQsXlJqEH3qhdVcXs2haSS0D3MIis4vQYf8Srl2irZQhVTx33RQlozAOrW6FkTz07ADQRaOUXPSt1iRDqus7K8p4Li9UVAmRSgJ7adq1BjW51K3KaDmWfJqch/VwP26HEaVJ6aRebswRkbkCeKU5tTHxMsDcjOHLDyHMBjXHIKqOBro/7GfEsjPW09whczEPxnRDPZP5GQFsuuWA9DX0zycSA3y610MNTbe0vBvSUvXozBjOlPXPtu8V+EGKNfGP1mDBdCm0MCXAwtjEEkClFjy2ix7Y1+vcLfgBLma8C" +} \ No newline at end of file diff --git a/test/mocks/authorise-success-cse.json b/test/mocks/authorise-success-cse.json new file mode 100644 index 00000000..8da8efe9 --- /dev/null +++ b/test/mocks/authorise-success-cse.json @@ -0,0 +1,99 @@ +{ + "additionalData": { + "cvcResult": "1 Matches", + "fraudResultType": "GREEN", + "authCode": "78224", + "avsResult": "4 AVS not supported for this card type", + "fraudManualReview": "false", + "avsResultRaw": "4", + "cvcResultRaw": "1", + "refusalReasonRaw": "AUTHORISED", + "acquirerCode": "TestPmmAcquirer", + "acquirerReference": "7F57UVGV1H6" + }, + "fraudResult": { + "accountScore": 51, + "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": 50, + "checkId": 41, + "name": "PaymentDetailNonFraudRefCheck" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, + { + "FraudCheckResult": { + "accountScore": 1, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 25, + "name": "CVCAuthResultCheck" + } + } + ] + }, + "pspReference": "8624836275772397", + "resultCode": "Authorised", + "authCode": "78224" +} \ No newline at end of file diff --git a/test/mocks/authorise-success.json b/test/mocks/authorise-success.json new file mode 100644 index 00000000..ff4f3a57 --- /dev/null +++ b/test/mocks/authorise-success.json @@ -0,0 +1,95 @@ +{ + "additionalData": { + "liabilityShift": "true", + "fraudResultType": "GREEN", + "authCode": "43733", + "avsResult": "4 AVS not supported for this card type", + "cardHolderName": "Holder", + "cardSummary": "1111", + "fraudManualReview": "false", + "threeDOffered": "true", + "refusalReasonRaw": "AUTHORISED", + "expiryDate": "8/2018", + "cvcResult": "1 Matches", + "cardBin": "411111", + "avsResultRaw": "4", + "threeDAuthenticated": "false", + "paymentMethod": "visa", + "cvcResultRaw": "1", + "acquirerCode": "TestPmmAcquirer", + "acquirerReference": "7F59FSE1M6K" + }, + "fraudResult": { + "accountScore": 25, + "results": [{ + "FraudCheckResult": { + "accountScore": 8, + "checkId": 2, + "name": "CardChunkUsage" + } + }, { + "FraudCheckResult": { + "accountScore": 5, + "checkId": 3, + "name": "PaymentDetailUsage" + } + }, { + "FraudCheckResult": { + "accountScore": 12, + "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": 41, + "name": "PaymentDetailNonFraudRefCheck" + } + }, { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 10, + "name": "HolderNameContainsNumber" + } + }, { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 11, + "name": "HolderNameIsOneWord" + } + }, { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 25, + "name": "CVCAuthResultCheck" + } + }] + }, + "pspReference": "7924835492819808", + "resultCode": "Authorised", + "authCode": "69746" +} \ No newline at end of file diff --git a/test/mocks/authorise3d-success.json b/test/mocks/authorise3d-success.json new file mode 100644 index 00000000..9af6fd65 --- /dev/null +++ b/test/mocks/authorise3d-success.json @@ -0,0 +1,30 @@ +{ + "additionalData": { + "fraudResultType": "GREEN", + "fraudManualReview": "false", + "aliasType": "Default", + "alias": "E840075550837688" + }, + "fraudResult": { + "accountScore": 12, + "results": [ + { + "FraudCheckResult": { + "accountScore": 12, + "checkId": -1, + "name": "Pre-Auth-Risk-Total" + } + }, + { + "FraudCheckResult": { + "accountScore": 0, + "checkId": 25, + "name": "CVCAuthResultCheck" + } + } + ] + }, + "pspReference": "8524836146572696", + "resultCode": "Authorised", + "authCode": "90473" +} \ No newline at end of file diff --git a/test/mocks/cancel-received.json b/test/mocks/cancel-received.json new file mode 100644 index 00000000..8555ff66 --- /dev/null +++ b/test/mocks/cancel-received.json @@ -0,0 +1,4 @@ +{ + "pspReference": "PSP_REFERENCE", + "response": "[cancel-received]" +} \ No newline at end of file diff --git a/test/mocks/cancelOrRefund-received.json b/test/mocks/cancelOrRefund-received.json new file mode 100644 index 00000000..f5bd6bc4 --- /dev/null +++ b/test/mocks/cancelOrRefund-received.json @@ -0,0 +1,4 @@ +{ + "pspReference": "PSP_REFERENCE", + "response": "[cancelOrRefund-received]" +} \ No newline at end of file diff --git a/test/mocks/capture-error-167.json b/test/mocks/capture-error-167.json new file mode 100644 index 00000000..b609a676 --- /dev/null +++ b/test/mocks/capture-error-167.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "167", + "message": "Original pspReference required for this operation", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/capture-success.json b/test/mocks/capture-success.json new file mode 100644 index 00000000..61499edd --- /dev/null +++ b/test/mocks/capture-success.json @@ -0,0 +1,4 @@ +{ + "pspReference": "8524840434233409", + "response": "[capture-received]" +} \ No newline at end of file diff --git a/test/mocks/hpp/directoryLookup-success.json b/test/mocks/hpp/directoryLookup-success.json new file mode 100644 index 00000000..e25de125 --- /dev/null +++ b/test/mocks/hpp/directoryLookup-success.json @@ -0,0 +1,50 @@ +{ + "paymentMethods":[ + { + "brandCode":"ideal", + "name":"iDEAL", + "issuers":[ + { + "issuerId":"1121", + "name":"Test Issuer" + }, + { + "issuerId":"1152", + "name":"Test Issuer 3" + }, + { + "issuerId":"1151", + "name":"Test Issuer 2" + } + ] + }, + { + "brandCode":"visa", + "name":"VISA" + }, + { + "brandCode":"sepadirectdebit", + "name":"SEPA Direct Debit" + }, + { + "brandCode":"moneybookers", + "name":"Moneybookers" + }, + { + "brandCode":"klarna", + "name":"Klarna Invoice" + }, + { + "brandCode":"afterpay_default", + "name":"AfterPay Invoice" + }, + { + "brandCode":"boku", + "name":"Boku" + }, + { + "brandCode":"paypal", + "name":"PayPal" + } + ] +} \ No newline at end of file diff --git a/test/mocks/recurring/disable-error-803.json b/test/mocks/recurring/disable-error-803.json new file mode 100644 index 00000000..dcf442b6 --- /dev/null +++ b/test/mocks/recurring/disable-error-803.json @@ -0,0 +1,6 @@ +{ + "status": 422, + "errorCode": "803", + "message": "PaymentDetail not found", + "errorType": "validation" +} \ No newline at end of file diff --git a/test/mocks/recurring/disable-success.json b/test/mocks/recurring/disable-success.json new file mode 100644 index 00000000..75761fff --- /dev/null +++ b/test/mocks/recurring/disable-success.json @@ -0,0 +1,30 @@ +{ + "details": [ + { + "RecurringDetail": { + "acquirer": "TestPmmAcquirer", + "acquirerAccount": "TestPmmAcquirerAccount", + "additionalData": { + "cardBin": "411111" + }, + "alias": "ALIAS", + "aliasType": "Default", + "card": { + "expiryMonth": "8", + "expiryYear": "2018", + "holderName": "Holder", + "number": "1111" + }, + "contractTypes": [ + "ONECLICK" + ], + "creationDate": "2017-03-07T09:43:33+01:00", + "firstPspReference": "PSP_REF", + "paymentMethodVariant": "visa", + "recurringDetailReference": "RECURRING_REFERENCE", + "variant": "visa" + } + } + ], + "response": "[detail-successfully-disabled]" +} \ No newline at end of file diff --git a/test/mocks/recurring/listRecurringDetails-success.json b/test/mocks/recurring/listRecurringDetails-success.json new file mode 100644 index 00000000..ef12a54b --- /dev/null +++ b/test/mocks/recurring/listRecurringDetails-success.json @@ -0,0 +1,32 @@ +{ + "creationDate": "2017-03-01T11:53:11+01:00", + "details": [ + { + "RecurringDetail": { + "acquirer": "TestPmmAcquirer", + "acquirerAccount": "TestPmmAcquirerAccount", + "additionalData": { + "cardBin": "411111" + }, + "alias": "cardAlias", + "aliasType": "Default", + "card": { + "expiryMonth": "8", + "expiryYear": "2018", + "holderName": "Holder", + "number": "1111" + }, + "contractTypes": [ + "ONECLICK" + ], + "creationDate": "2017-03-07T09:43:33+01:00", + "firstPspReference": "8524888762135795", + "paymentMethodVariant": "visa", + "recurringDetailReference": "recurringReference", + "variant": "visa" + } + } + ], + "shopperReference": "test-123", + "invalidOneclickContracts": "false" +} \ No newline at end of file diff --git a/test/mocks/refund-received.json b/test/mocks/refund-received.json new file mode 100644 index 00000000..46effc64 --- /dev/null +++ b/test/mocks/refund-received.json @@ -0,0 +1,4 @@ +{ + "pspReference": "8524873258461343", + "response": "[refund-received]" +} \ No newline at end of file