Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
72c24d8
PW-781: Code optimizations (#53)
Aleffio Nov 26, 2018
26cccd9
Add payment methods with mock test
AlexandrosMor Jan 3, 2019
e6986a7
Format lines
AlexandrosMor Jan 4, 2019
40b60b0
Format lines for client
AlexandrosMor Jan 4, 2019
2e834fb
Format lines for client long lines
AlexandrosMor Jan 4, 2019
25ca3f2
Format lines for checkout
AlexandrosMor Jan 4, 2019
bee6945
Format lines for checkout again
AlexandrosMor Jan 4, 2019
1b50cad
Add all checkout components
AlexandrosMor Jan 4, 2019
b515f7c
format test lines
AlexandrosMor Jan 4, 2019
a2bfc2c
Add checkout test cases for errors
AlexandrosMor Jan 4, 2019
22fb285
Fixes with e2e test
AlexandrosMor Jan 8, 2019
247cbaa
Fixes comment length
AlexandrosMor Jan 8, 2019
1ca76fb
remove white space
AlexandrosMor Jan 8, 2019
8c257eb
correct checkout utility
AlexandrosMor Jan 8, 2019
236cd10
add custom endpoint
AlexandrosMor Jan 9, 2019
4782cb6
Remove white space in unit test
AlexandrosMor Jan 9, 2019
0a134fa
Add checkout utility url
AlexandrosMor Jan 9, 2019
2421b54
rename to payments details
AlexandrosMor Jan 9, 2019
5e7d9c3
remove unused code
AlexandrosMor Jan 9, 2019
f3627f7
add utility api version
AlexandrosMor Jan 9, 2019
c397486
Improve settings and client
AlexandrosMor Jan 10, 2019
4467940
Correct checkout url payments result
AlexandrosMor Jan 10, 2019
0aa55af
imporove determine checkout url
AlexandrosMor Jan 15, 2019
a13dc7e
fix determine checkout url
AlexandrosMor Jan 15, 2019
25afd0c
remove ENDPOINT_LIVE_SUFFIX for pal
AlexandrosMor Jan 15, 2019
768c84b
Deprecate API_VERSION
AlexandrosMor Jan 15, 2019
42cb7e4
Intoduce API_PAYMENT_VERSION and API_PAYOUT_VERSION deprecate API_VER…
AlexandrosMor Jan 15, 2019
ec4f563
Remove API_VERSION
AlexandrosMor Jan 16, 2019
a66d3cc
UpdateAPI_PAYMENT_VERSION = v40
AlexandrosMor Jan 16, 2019
1d94500
Merge pull request #56 from Adyen/feature/checkoutv40
AlexandrosMor Jan 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Adyen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
AdyenRecurring,
AdyenPayment,
AdyenThirdPartyPayout,
AdyenHPP)
AdyenHPP,
AdyenCheckoutApi)

from .httpclient import HTTPClient

Expand All @@ -30,10 +31,12 @@ 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()
recurring = _base_adyen_obj.recurring
hpp = _base_adyen_obj.hpp
payment = _base_adyen_obj.payment
payout = _base_adyen_obj.payout
checkout = _base_adyen_obj.checkout
197 changes: 165 additions & 32 deletions Adyen/client.py

Large diffs are not rendered by default.

26 changes: 11 additions & 15 deletions Adyen/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,26 @@ 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
self.url = url
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))

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):
Expand All @@ -42,13 +38,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):
Expand All @@ -73,3 +65,7 @@ class AdyenAPIInvalidAmount(AdyenAPIResponseError):

class AdyenAPIInvalidFormat(AdyenAPIResponseError):
pass


class AdyenEndpointInvalidFormat(AdyenError):
pass
9 changes: 6 additions & 3 deletions Adyen/httpclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def _requests_post(self, url,
data=None,
username="",
password="",
xapikey="",
headers=None,
timeout=30):
"""This function will POST to the url endpoint using requests.
Expand Down Expand Up @@ -175,6 +176,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.
Expand Down Expand Up @@ -246,12 +249,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)
Expand Down
69 changes: 64 additions & 5 deletions Adyen/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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. "
Expand All @@ -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, "
Expand Down Expand Up @@ -279,3 +279,62 @@ 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, action, **kwargs)

def payments(self, request="", **kwargs):
action = "payments"
if validation.check_in(request, action):
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, action, **kwargs)

def payment_session(self, request="", **kwargs):
action = "paymentSession"
if validation.check_in(request, action):
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, action, **kwargs)

def origin_keys(self, request="", **kwargs):
action = "originKeys"
if validation.check_in(request, action):
return self.client.call_checkout_api(request, action, **kwargs)
11 changes: 8 additions & 3 deletions Adyen/settings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/bin/python

# Those constants are used from the library only
BASE_PAL_URL = "https://pal-{}.adyen.com/pal/servlet"
BASE_HPP_URL = "https://{}.adyen.com/hpp"
API_VERSION = "v30"
ENDPOINT_CHECKOUT_TEST = "https://checkout-test.adyen.com"
ENDPOINT_CHECKOUT_LIVE_SUFFIX = "https://{}-checkout-live" \
".adyenpayments.com/checkout"
API_CHECKOUT_VERSION = "v40"
API_CHECKOUT_UTILITY_VERSION = "v1"
API_RECURRING_VERSION = "v25"
API_PAYMENT_VERSION = "v40"
API_PAYOUT_VERSION = "v30"
11 changes: 11 additions & 0 deletions Adyen/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@
actions['refund'] = ["modificationAmount", "originalReference"]
actions['cancelOrRefund'] = ["originalReference"]

actions['paymentMethods'] = ["merchantAccount"]
actions['payments'] = ["amount", "reference", "paymentMethod",
"merchantAccount", "returnUrl"]
actions['paymentsDetails'] = ["paymentData", "details"]
actions['paymentSession'] = ["amount", "reference", "shopperReference",
"channel", "returnUrl", "countryCode",
"shopperLocale", "sessionValidity",
"merchantAccount"]
actions['paymentsResult'] = ["payload"]
actions['originKeys'] = ["originDomains"]

payout_required_fields = {
'confirmThirdParty': (
'merchantAccount',
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Loading