Code Monkey home page Code Monkey logo

adyen-python-api-library's Introduction

Python

Adyen APIs Library for Python

version

This is the officially supported Python library for using Adyen's APIs.

Supported API versions

API Description Service Name Supported version
BIN lookup API The BIN Lookup API provides endpoints for retrieving information based on a given BIN. binLookup v54
Balance Platform API The Balance Platform API enables you to create a platform where you can onboard your users as account holders and create balance accounts, cards, and business accounts. balancePlatform v2
Checkout API Our latest integration for accepting online payments. checkout v71
Data Protection API Endpoint for requesting data erasure. dataProtection v1
Legal Entity Management API Endpoint to manage legal entities legalEntityManagement v3
Management API Configure and manage your Adyen company and merchant accounts, stores, and payment terminals. management v3
Payments API Our classic integration for online payments. payments v68
Payouts API Endpoints for sending funds to your customers. payouts v68
POS Terminal Management API Endpoints for managing your point-of-sale payment terminals. terminal v1
Recurring API Endpoints for managing saved payment details. recurring v68
Stored Value API Endpoints for managing gift cards. storedValue v46
Transfers API Endpoints for managing transfers, getting information about transactions or moving fund transfers v4
Disputes API You can use the Disputes API to automate the dispute handling process so that you can respond to disputes and chargebacks as soon as they are initiated. The Disputes API lets you retrieve defense reasons, supply and delete defense documents, and accept or defend disputes. disputes v30

For more information, refer to our documentation or the API Explorer.

Prerequisites

Installation

For development purpose

Clone this repository and run

make install

For usage purpose

Use pip command:

pip install Adyen

Using the library

General use with API key

import Adyen

adyen = Adyen.Adyen()

adyen.payment.client.xapikey = "YourXapikey"
adyen.payment.client.hmac = "YourHMACkey"
adyen.payment.client.platform = "test" # Environment to use the library in.

Consuming Services

Every API the library supports is represented by a service object. The name of the service matching the corresponding API is listed in the Integrations section of this document.

Using all services

import Adyen

adyen = Adyen.Adyen()
adyen.payment.client.xapikey = "YourXapikey"
adyen.payment.client.platform = "test"  # change to live for production
request = {
    "amount": {
        "currency": "USD",
        "value": 1000  # value in minor units
    },
    "reference": "Your order number",
    "paymentMethod": {
        "type": "visa",
        "encryptedCardNumber": "test_4111111111111111",
        "encryptedExpiryMonth": "test_03",
        "encryptedExpiryYear": "test_2030",
        "encryptedSecurityCode": "test_737"
    },
    "shopperReference": "YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j",
    "returnUrl": "https://your-company.com/...",
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT"
}
result = adyen.checkout.payments_api.payments(request)

Using one of the services

from Adyen import checkout

checkout.client.xapikey = "YourXapikey"
checkout.client.platform = "test"  # change to live for production
request = {
    "amount": {
        "currency": "USD",
        "value": 1000  # value in minor units
    },
    "reference": "Your order number",
    "paymentMethod": {
        "type": "visa",
        "encryptedCardNumber": "test_4111111111111111",
        "encryptedExpiryMonth": "test_03",
        "encryptedExpiryYear": "test_2030",
        "encryptedSecurityCode": "test_737"
    },
    "shopperReference": "YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j",
    "returnUrl": "https://your-company.com/...",
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT"
}
result = checkout.payments_api.payments(request)

Force HTTP library

import Adyen

adyen = Adyen.Adyen()
adyen.client.http_force = 'requests' # or 'pycurl'

Using query parameters (management API only)

Define a dictionary with query parameters that you want to use.

query_parameters = {
    'pageSize': 10,
    'pageNumber': 3
}

pass the dictionary to the method as an additional argument.

adyen.management.account_company_level_api.get_companies(query_parameters=query_parameters)

Using Header Parameters

Define a dictionary containing the headers you want to include in your request.

    headers = {
        "Var1": "Var2",
        "Var2": "Var1"
    }

Pass the dictionary as an additional argument to the method where you make the API call.

    adyen.checkout.payments_api.payments(header_parameters=headers)

Customizing Base URL

Instantiate the service and replace the baseUrl with your own URL

    service = adyen.checkout.payments_api
    service.baseUrl = "localhost:8080"

Handling exceptions

Adyen service exceptions extend the AdyenError class. After you catch this exception, you can access the class arguments for the specifics around this error or use the debug method which prints all the arguments.

try:
    adyen.checkout.payments_api.payments(request)
except Adyen.exceptions.AdyenError as error:
    print(error.debug())
List of exceptions

AdyenInvalidRequestError

AdyenAPIResponseError

AdyenAPIAuthenticationError

AdyenAPIInvalidPermission

AdyenAPICommunicationError

AdyenAPIValidationError

AdyenAPIUnprocessableEntity

AdyenAPIInvalidFormat

AdyenEndpointInvalidFormat

Example integration

For a closer look at how our Python library works, clone our example integration. This includes commented code, highlighting key features and concepts, and examples of API calls that can be made using the library.

Feedback

We value your input! Help us enhance our API Libraries and improve the integration experience by providing your feedback. Please take a moment to fill out our feedback form to share your thoughts, suggestions or ideas.

Contributing

We encourage you to contribute to this repository, so everyone can benefit from new features, bug fixes, and any other improvements.

Have a look at our contributing guidelines to find out how to raise a pull request.

Support

If you have a feature request, or spotted a bug or a technical problem, create an issue here.

For other questions, contact our Support Team.

Licence

This repository is available under the MIT license.

See also

adyen-python-api-library's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adyen-python-api-library's Issues

Code breaks if provided with wrong test password

Hi,
when trying to make a payment with a wrong password I am getting the following errors:

Traceback (most recent call last):
...
  File "..../helpers/adyen.py", line 61, in create_payment
    'card.encrypted.json': encrypted_card
  File ".../.virtualenvs/luuna_api/lib/python3.6/site-packages/Adyen/services.py", line 146, in authorise
    return self.client.call_api(request, self.service, action, **kwargs)
  File ".../lib/python3.6/site-packages/Adyen/client.py", line 280, in call_api
    status_code, headers, message)
  File "..../lib/python3.6/site-packages/Adyen/client.py", line 413, in _handle_response
    response = json_lib.loads(raw_response)
  File "/usr/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

The reason for this can be the content returned by the adyen post request, which is b''; afterwards the library is trying to convert the data using "response = json_lib.loads(raw_response)" call.

Python 3 compatibility

Current api version was only tested with Python 2.7, to cover more ground with developers and environments, Python 3 needs to be tested for as well.

Possibly the api does not many Python 2 specific features and so adaptation to Python 3 should not be complicated.

Some things unknown to me:

  • Can there be 1 module that is both compatible with Python 2 and 3?
  • If not, how can we easily 'convert' the current module to be Python 3 compatible?

Ability to pin API versions

Python version: all
Library version: 2.1.0
Description
It should be possible to ensure that the client is using the Adyen service version of the integration the user is using. For example, currently the settings.py pins the Payment service version to v49, though the latest version is v50. It is unclear when this client will bumped. This could lead to unexpected behaviour, for example a new user writing their integration for v50 only to discover later on that the python client only targets v49.

My suggestion is to ensure the client is compatible with all versions, and allow the user to set what version they are targeting. Update documentation explicitly stating the supported versions.

Logging options

Add Adyen base class boolean attribute to turn on/off logging to file. The Python library then logs activity directly to file. The resulting log files then include only Adyen information, which may be useful when debugging an app with Adyen.

Otherwise, the merchant is always possible to generate a log in their own app based on values returned by the Adyen library.

  • log all library requests and responses ( info )
  • log requests and responses in case of exceptions ( debug )
  • boolean attribute with Adyen class to enable/disable logging
  • specify path were to store log files with Adyen class
  • test that logging does not interfere with logging in other packages or user's own module

Keep a CHANGELOG

Python version: any
Library version: any
Description

Would be awesome to keep a CHANGELOG file with changes between releases so we don't need to compare tags with github (like in 1.1.0...1.2.0)

Extended validation

Implemented validation for all api calls to detect missing values to immediately raise a Value/Type Error. This allows for quicker debugging and pre-emptively avoiding common mistakes.

challenges:

  • avoiding breaking valid requests by wrongly validating data
  • defining limits of validation, to what extend the data is checked
    • my suggestion is to only check for existence and type of properties
  • making validation fast by checking against list of property names, not writing endless if/else statements.

Where

validation is best done in services.py and possibly moved to validation.py

Forces Payout Role Required

Python version: 3.7.2
Library version: 2.1.0
Description
When using the checkout API, making a payment, and attempting to store the payment details, an error is raised:

File "/Users/x/Documents/x/payments/service-payments/venv/lib/python3.7/site-packages/Adyen/services.py", line 320, in payments
return self.client.call_checkout_api(request, action, **kwargs)
File "/Users/x/Documents/x/payments/service-payments/venv/lib/python3.7/site-packages/Adyen/client.py", line 459, in call_checkout_api
request_data)
File "/Users/x/Documents/x/payments/service-payments/venv/lib/python3.7/site-packages/Adyen/client.py", line 528, in _handle_response
headers, request_dict)
File "/Users/x/Documents/x/payments/service-payments/venv/lib/python3.7/site-packages/Adyen/client.py", line 653, in _handle_http_error
"errorCode"))
Adyen.exceptions.AdyenAPIInvalidPermission: 'AdyenAPIInvalidPermission:Unable to perform the requested action. message: Not allowed to store Payout Details. If you think your webservice user: [email protected] might not have the necessary permissions to perform this request. Please reach out to [email protected], providing the PSP reference: xxxx'

I am not trying to use Payout, and have enablePayout set to False.

If I make the same request using requests directly, the payment works as expected.

I confirmed with Adyen support that when the backend receives my request enablePayout is set to true

Hosted Payment Pages

Right now, following the documentation a developer uses a 'hidden' html form element with a POST action.

<form method="post" id="adyenForm" action="https://test.adyen.com/hpp/skipDetails.shtml" name="adyenForm" target="_parent" style="display:none">
     <input type="hidden" id="merchantSig" name="merchantSig"/>
     <input type="hidden" id="sessionValidity" name="sessionValidity"/>
     <input type="hidden" id="shopperLocale" name="shopperLocale"/>
     <input type="hidden" id="merchantAccount" name="merchantAccount"/>
     <input type="hidden" id="paymentAmount" name="paymentAmount"/>
     <input type="hidden" id="currencyCode" name="currencyCode"/>
     <input type="hidden" id="skinCode" name="skinCode"/>
     <input type="hidden" id="merchantReference" name="merchantReference"/>
     <input type="hidden" id="brandCode" name="brandCode"/>
     <input type="hidden" id="issuerId" name="issuerId"/>
     <input type="hidden" id="merchantReturnData" name="merchantReturnData"/>
     <!-- for recurring hpp -->
     <input type="hidden" name="shopperEmail" value="[email protected]" />
     <input type="hidden" name="shopperReference" value="Simon Hopper" />
     <input type="hidden" name="recurringContract" value="RECURRING" />

     <input type="submit" value="Send"/>
     <input type="reset"/>
  </form>

An option would be that the Adyen library sends this post request and redirects the page on calling a 'HPP payment' method. This would make it easy, except for the fact that redirects are handled in the Python server's request handler, which Adyen Api users need to program themselves.

Still trying to find a clean solution for this, if not found, the POST with form data is the best option available for websites/apps.

Recurring:

What to do with the recurring form fields if not used?

No build script in repo

Hi,

Is it intentional that the build script for this python package is maintained elsewhere? It would be great if it was part of the repository because then one could directly install Adyen from the git repo using pip. For this project it was decided to remove it some time ago.

UnboundLocalError: local variable 'xapikey' referenced before assignment

Python version: 3.7
Library version: 2.2.0
Description

if you don't set the api key you get an unbound error

  File "/home/patrick/PycharmProjects/fpo-api/fpo/payment/api/views/adyen.py", line 28, in payment_methods
    pm = adyen.checkout.payment_methods()
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/Adyen/services.py", line 297, in payment_methods
    return self.client.call_checkout_api(request, action, **kwargs)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/Adyen/client.py", line 424, in call_checkout_api
    if not xapikey:
UnboundLocalError: local variable 'xapikey' referenced before assignment
        if self.xapikey:
            xapikey = self.xapikey
        elif 'xapikey' in kwargs:
            xapikey = kwargs.pop("xapikey")

        if not xapikey:

Allow customer handle error codes

Here you raise an error with text mnessage

raise AdyenAPIValidationError(erstr)

Instead of doing this we need to raise custom error that contains not only text but the errorCode too.
This is needed to handle custom validation messages on Customer side (for example with translation).
for example

class MyException(Exception):
    def __init__(self,*args,**kwargs):
        self.code = kwargs.pop('error_code',None)
        super().__init__(*args,**kwargs)

Compatibility issue with Python3

Python version: 3.6.9
Library version: 2.2.0
Description
I tried to test the adyen library on python3 and it kept giving me this error
Traceback (most recent call last): File "adyenTest.py", line 20, in <module> result = adyen.checkout.payment_methods(request) File "/home/dchen/.local/lib/python3.6/site-packages/Adyen/services.py", line 297, in payment_methods return self.client.call_checkout_api(request, action, **kwargs) File "/home/dchen/.local/lib/python3.6/site-packages/Adyen/client.py", line 461, in call_checkout_api **kwargs) File "/home/dchen/.local/lib/python3.6/site-packages/Adyen/httpclient.py", line 196, in _requests_post headers=headers, timeout=timeout) File "/home/dchen/.local/lib/python3.6/site-packages/requests/api.py", line 116, in post return request('post', url, data=data, json=json, **kwargs) File "/home/dchen/.local/lib/python3.6/site-packages/requests/api.py", line 60, in request return session.request(method=method, url=url, **kwargs) File "/home/dchen/.local/lib/python3.6/site-packages/requests/sessions.py", line 519, in request prep = self.prepare_request(req) File "/home/dchen/.local/lib/python3.6/site-packages/requests/sessions.py", line 462, in prepare_request hooks=merge_hooks(request.hooks, self.hooks), File "/home/dchen/.local/lib/python3.6/site-packages/requests/models.py", line 314, in prepare self.prepare_headers(headers) File "/home/dchen/.local/lib/python3.6/site-packages/requests/models.py", line 448, in prepare_headers check_header_validity(header) File "/home/dchen/.local/lib/python3.6/site-packages/requests/utils.py", line 942, in check_header_validity raise InvalidHeader("Invalid return character or leading space in header: %s" % name) requests.exceptions.InvalidHeader: Invalid return character or leading space in header: User-Agent

my code is the following:
Selection_039

I then tested the same code on python 2 which was totally fine, I'm wondering if it's a compatibility issue with python 3?

Recurring payments

Not sure if recurring payments are implemented yet:

When sending a request to Adyen directly, the following additional properties are included:

recurring create:
request['shopperEmail'] = headers['shopperEmail'].lower()
request['shopperReference'] = headers['shopperReference']
request['recurring'] = {}
request['recurring']['contract'] = 'RECURRING'

recurring payment:
request["reference"] = reference
request["merchantAccount"] = "SupportAdyenTest"
request["shopperEmail"] = headers['shopperEmail'].lower()
request["shopperReference"] = headers['shopperReference']
request["selectedRecurringDetailReference"] = "LATEST"
request["shopperInteraction"] = "ContAuth"
request['recurring'] = {}
request["recurring"]['contract'] = "RECURRING"

I sent them with the authorize request with 'AdyenPayment' but didn't note a recurring created response.

The Adyen.recurring child class doesn't seem to contain methods for creating recurring contracts and paying with them.

Is this still in development or are they available in some other part?

HTTPClient interface

Python version: 3.7.2
Library version: 2.0.0

HTTPClient:
Interface between requests (line 140), pycurl (line 57), and urllib (line 196) should be the same. 'Requests' has xapikey as a parameter while pycurl, and urllib do not.

Invalid return character or leading space in header: User-Agent

Python version: 3.7.7
Library version: 2.2.0

requests: requests==2.23.0

Description
Invalid return character or leading space in header: User-Agent

Which is ' adyen-python-api-library/2.2.0'

** Trace **

  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/Adyen/services.py", line 297, in payment_methods
    return self.client.call_checkout_api(request, action, **kwargs)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/Adyen/client.py", line 461, in call_checkout_api
    **kwargs)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/Adyen/httpclient.py", line 196, in _requests_post
    headers=headers, timeout=timeout)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/api.py", line 119, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/sessions.py", line 516, in request
    prep = self.prepare_request(req)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/sessions.py", line 459, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/models.py", line 315, in prepare
    self.prepare_headers(headers)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/models.py", line 449, in prepare_headers
    check_header_validity(header)
  File "/home/patrick/PycharmProjects/fpo-api/venv/lib/python3.7/site-packages/requests/utils.py", line 947, in check_header_validity
    raise InvalidHeader("Invalid return character or leading space in header: %s" % name)
requests.exceptions.InvalidHeader: Invalid return character or leading space in header: User-Agent

TypeError/ValueError: Provide Info on what arguments to pass

file: Validation.py
error: TypeError

raise TypeError("You need to provide a valid dictionary request"

TypeError: You need to provide a valid dictionary request object. 
This could contain information in the currency, amount, card details and so on.
Please reach out to support@adyen.com if you have more questions.

Unclear to user of API what arguments or kind of dictionary to provide.
Suggested solution:

  • Refer to documentation ( when sufficiently updated )
  • Print required arguments and their types in the log

Same for:

file: util.py
error: ValueError
line 64

line 64, in generate_hpp_sig
    raise ValueError("Must Provide dictionary object")
ValueError: Must Provide dictionary object

Logging to file

Api logging to file

Useful for sharing api reports, errors and general debugging information with other developers and with Adyen support.

Features:

  • Create a daily log file
  • Logs errors, exceptions

Format:

  • input
  • error / reason
  • correction/solution if known

Questions:

What to put in logs?:

  • All requests and responses may be too much, so my suggestion is to keep logs to errors only, and include the requests and response in the log.
    Where to create log entry?:
    • Because logging on every raised exception may create incoherent logs, which are hard to search.
    • Log entry needs to include input, error, reason and response data ( response is optional, as some errors raised from validation before sending the request )

Update Aug 2 2016:

About logging:

  • Raised exceptions are sent upwards were they can be handled and logged including request data

Open Issues with logging to file:

  • Only urllib is currently logging to file. Test why/how other logs are not entered.

Library installation and usage documentation

Finalise the Python API documentation.

  • installation instructions
  • api configuration
  • how-to and code examples for all api requests and features

Python API docs will initially be released through Github Pages.

Method _handle_response returns multiple object types

return string

return raw_response

and here return object
return AdyenResult(message=response, status_code=status_code,

This method should not return multiple object types, it should return AdyenResponse only or raise an exception
Use case:
if you will try to authorize this card: 3569 9900 1009 5841
then method will return string
if you will try to authorize 2223 0000 4841 0010 with cvc 7371
then method will raise an exception
if you will try to authorize 2223 0000 4841 0010 with valid cvc (737)
then AdyenResponse object will be returned.

User-Agent Header Error

Python version: 3.7.2
Library version: 2.0.0
Description

While following the API Integration guide, the suggested instantiation of the Adyen class is:

adyen = Adyen.Adyen()
adyen.client.xapikey = 'YOUR X-API-KEY'

This will result in the following error.

Traceback (most recent call last):
  ...
  File ".../venv/lib/python3.7/site-packages/Adyen/httpclient.py", line 41, in __init__
    self.user_agent = app_name + " " + user_agent_suffix + lib_version
  TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

Because the default for app_name is None instead of an empty string, or another string type default value.

To get around this error, a user needs to read through the code here on github and discover that you can init the Adyen class by passing

adyen = Adyen.Adyen(app_name="some arbitrary app name")

or

adyen = Adyen.Adyen()
adyen.client.app_name = "some arbitrary app name"

My suggestion is to either change your documentation, fail with a more reasonable error message if an app_name is required, or update the code to have string type default value.

for example change line 74 of adyen/client.py from:

                 hmac=None, app_name=None,

to:

                 hmac=None, app_name="",

I have supplied code snippets bellow with links to code as well as line numbers for your reference.

https://github.com/Adyen/adyen-python-api-library/blob/develop/Adyen/__init__.py (line 29)

class Adyen(AdyenBase):
    def __init__(self, **kwargs):
        self.client = AdyenClient(**kwargs)
        self.payment = AdyenPayment(client=self.client)
        self.payout = AdyenThirdPartyPayout(client=self.client)
        self.hpp = AdyenHPP(client=self.client)
        self.recurring = AdyenRecurring(client=self.client)
        self.checkout = AdyenCheckoutApi(client=self.client)

https://github.com/Adyen/adyen-python-api-library/blob/develop/Adyen/client.py (line 74, line 89, and any call to HTTPClient, such as line 217)

class AdyenClient(object):
    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,
                 merchant_specific_url=None, skin_code=None,
                 hmac=None, app_name=None,
                 http_force=None, live_endpoint_prefix=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
        self.store_payout_password = store_payout_password
        self.platform = platform
        self.merchant_specific_url = merchant_specific_url
        self.hmac = hmac
        self.merchant_account = merchant_account
        self.skin_code = skin_code
        self.psp_list = []
        self.app_name = app_name
        self.LIB_VERSION = settings.LIB_VERSION
        self.USER_AGENT_SUFFIX = settings.LIB_NAME + "/"
        self.http_init = False
        self.http_force = http_force
        self.live_endpoint_prefix = live_endpoint_prefix

        # any call to HTTPClient will fail because app_name is None

https://github.com/Adyen/adyen-python-api-library/blob/develop/Adyen/httpclient.py (line 41)

class HTTPClient(object):
    def __init__(self, app_name, user_agent_suffix,
                 lib_version, force_request=None):

        self.user_agent = app_name + " " + user_agent_suffix + lib_version

Mutable types as default values

Python version: 3+
Library version: 2.1.0
Description
Default values in functions should not be mutable types in python. The value set will be maintained between function calls

This is well known behaviour in python.

>>> def mutable_default_test(default={}):
...     print(default)
...     default["key"] = "value"
...
>>> mutable_default_test()
{}
>>> mutable_default_test()
{'key': 'value'}
>>> mutable_default_test({"something": "some value"})
{'something': 'some value'}
>>> mutable_default_test()
{'key': 'value'}

Changing the API endpoints

Python version: 2.7
Library version: x.y.z
Description
We are using the Adyen pyhton library to connect to Barclaycard smartpay. The library calls the Adyen test endpoints. Is there an option to change the endpoints being called by the python library as we need to call barclaycard smartpay endpoints

User-Agent Header missing

User-Agent header is created from the app name, library version and library type ( python ):

self.user_agent = self.app_name + " " + self.USER_AGENT_SUFFIX + self.LIB_VERSION

However, when adding the 'User-Agent' header to a request it isn't sent ( or received ):

headers['User-Agent'] = self.user_agent
request = requests.post(url, auth=auth, data=data, json = json,headers=headers, timeout=timeout)
print request.headers # < 'User-Agent' header is not in here.

The User-Agent header defaults to "Apache-HttpClient/4.4.1 (Java/1.8.0_92)" on our servers. Thus it is either changed somewhere, set to default or it is not sent. The header not being sent should not result in it being "Apache-HttpClient/4.4.1 (Java/1.8.0_92)" so I think that can be ruled out as the issue.

Util generate_hpp_sig() value and hmac do not correspond

Python version: 2.7.16
Library version: 2.1.0 (and tested too with future 2.2.0)
Description
TEST ENVIRONMENT

Implemented webhook for Adyen notifications (https://docs.adyen.com/development-resources/notifications) and using Test Configuration form in Adyen backend.

Passed JSON received data from Adyen to generate_hpp_sig() function according to test here : https://github.com/Adyen/adyen-python-api-library/blob/develop/test/UtilTest.py#L13

The generated hmac does not correspond to the addtionnalData['hmacSignature'].

Even tested with future 2.2.0 function is_valid_hmac, returns False.

Update Readme: More detailed guide on installing/using the Api in readme.md

Update Readme

Should contain clear explanations on:

  • where to put merchantAccount, Web Service user info to initialize the API.
  • How/which class instance to create and which attributes to set
  • What methods to call and which arguments are required for payments, hpp, recurring

Note:

  • Working on the 'gh-pages' branch to create a full installation and usage tutorial.

Merchant Signature

As of now I don't see where this is available, or how for HPP a merchant signature can be easily calculated with a single call to the Adyen API.

I found a method under the AdyenAPIClient class but can not find how it should be accessed by the end user of this API.

def call_hpp(self, request_data, action, hmac_key="", **kwargs):

Travis Build Failing on pycurl

Python version: 2 and 3
Library version: 2.1.0
Description

Travis is failing to build pycurl from setup.py


Failed building wheel for pycurl
Running setup.py clean for pycurl
Building wheel for docopt (setup.py) ... done
Stored in directory: /home/travis/.cache/pip/wheels/9b/04/dd/7daf4150b6d9b12949298737de9431a324d4b797ffd63f526e
Building wheel for wrapt (setup.py) ... done
Stored in directory: /home/travis/.cache/pip/wheels/d7/de/2e/efa132238792efb6459a96e85916ef8597fcb3d2ae51590dfd
Successfully built docopt wrapt
Failed to build pycurl
Installing collected packages: idna, urllib3, chardet, requests, pycurl, coverage, docopt, coveralls, isort, mccabe, lazy-object-proxy, wrapt, typed-ast, astroid, pylint, pycodestyle
Running setup.py install for pycurl ... error
Complete output from command /home/travis/virtualenv/python3.6.7/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-install-11_hg_43/pycurl/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-record-6v9198mt/install-record.txt --single-version-externally-managed --compile --install-headers /home/travis/virtualenv/python3.6.7/include/site/python3.6/pycurl:
Using curl-config (libcurl 7.47.0)
Using SSL library: GnuTLS
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.6
creating build/lib.linux-x86_64-3.6/curl
copying python/curl/init.py -> build/lib.linux-x86_64-3.6/curl
running build_ext
building 'pycurl' extension
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/src
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fPIC -DPYCURL_VERSION="7.43.0.3" -DHAVE_CURL_SSL=1 -DHAVE_CURL_GNUTLS=1 -DHAVE_CURL_SSL=1 -I/opt/python/3.6.7/include/python3.6m -c src/docstrings.c -o build/temp.linux-x86_64-3.6/src/docstrings.o
In file included from src/docstrings.c:4:0:
src/pycurl.h:168:30: fatal error: gnutls/gnutls.h: No such file or directory
compilation terminated.
error: command 'gcc' failed with exit status 1

----------------------------------------

Command "/home/travis/virtualenv/python3.6.7/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-install-11_hg_43/pycurl/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-record-6v9198mt/install-record.txt --single-version-externally-managed --compile --install-headers /home/travis/virtualenv/python3.6.7/include/site/python3.6/pycurl" failed with error code 1 in /tmp/pip-install-11_hg_43/pycurl/
The command "pip install requests pycurl mock coveralls pylint pycodestyle" failed and exited with 1 during .

Code clean up

All library features are tested, but a clean up/review is needed:

  • make code more readable
  • improve exception handling with more clear descriptions
  • raise exceptions were possible instead of just returning false

PEP-8 style guide can provide a good guideline for code readability: https://www.python.org/dev/peps/pep-0008/

Hopefully someone can take a look and fix/provide feedback were needed.

Adyen v40

Python version: 3.6
Library version: 1.3.0
Description
Good day.
I see that this library is based on the Adyen v30, right?
Is there any chance that this library will be using v40 version of Adyen API soon?
What are the main differences between v30 and v40?

Cheers
Justinas

Disabled X-API-KEY Authorization from `call_api`

Python version: 2.7.16
Library version: 2.1.0
Description

When using the library to access functions on classes such as adyen.recurring, the underlying call_api function is used to actually make the api call. However, it doesn't allow for X-API-KEY as a valid authentication method as it pops it from the kwargs, and never passes it in as a potential named argument to the self.http_client.request call.

here is where it's popped

and then here is the call to request where it never gets passed back in

self.http_client.request(url, json=message, username=username,

in contrast, here is the call to request from the different call_checkout_api function where X-API-KEY authentication does work

self.http_client.request(url, json=request_data,

Unhandled exceptions on json.loads give no clues on connection errors to Adyen

Python version: 2.7.12
Library version: 1.1.0, 1.2.0, development
Description

Sometimes we have big periods of time that we get following error from Adyen client:

ValueError('No JSON could be decoded')

To make the problem worse this exception tell us nothing about what we are sending and receiving to Adyen servers, and so we can't investigate the problem because we have no clues about it.

We need that devs handle the json_lib.loads call at https://github.com/Adyen/adyen-python-api-library/blob/1.1.0/Adyen/client.py#L413 and instead ValueError return an AdyenInvalidRequestError with request information so we can investigate the problem.

Cheers!

Convert AdyenResult object to dict

Python version: 3.6.9
Library version: 2.2.0
Description

I am getting the list of the payment methods using the library. I found a worky bug bulky solution to convert an AdyenResult instance to a python dict.

I want to know if any method on this object exist to convert it to a dict.

The goal is to provide my framework (Odoo) the response in order to it to convert it to JSON for my client side JS code.

Here is the workaround I found to turn this object into a dict:

@http.route("/adyen/payment-methods", type="json", auth="public")
  # ...
  response = adyen.checkout.payment_methods(parameters)
  payment_methods = ast.literal_eval(str(response)) # AdyenResult -> dict

  return payment_methods

Client Side Encryption (CSE)

Python version: 3.7.4
Library version: 2.1.0
Description

Is there any way of encrypting card data similar to other SDK's CSE implementations?

Cancel request sent from library returns 401

When sending a cancel request with the library passing the 'originalReference' and 'merchantAccount' properties, only get a returned status code 401, but no response text returned.

Currently have not found if the Python Api contains a formatting mistake for these requests as all seems to be according to the documentation: https://docs.adyen.com/developers/api-manual#cancel

So far checked that:

Checking the psp reference and web service user in the server logs do not show any request for 'cancel' coming.

Because the request is not seen in the server logs, I think it is not sent past the server request handler, which directly returns a 401 status.

The web service user and password are correct as I am able to use the same for authorising, recurring payments.

Update:

Might the following additional properties be required?

  • originalReference string
  • reference string
  • merchantAccount string
  • modificationAmount.currency string
  • modificationAmount.value long
  • authorisationCode string
  • additionalData.*

Make Adyen Python package available on PIP

For easier installation and updating in a Python environment. In case there are any dependencies from PIP these can then be automatically detected as well in the installation procedure.

API - HPP Post / redirect

Validate properties, create merchantSignature and send a POST request to Adyen.

Return the resulting url, so that the end user of the api can redirect their user
towards the hpp page with Adyen at another point in time.

This method may give API users more control, besides posting a hidden html form.

Return normal Python dicts

I see that the dictionary is converted to use dot notation for dict keys.
In AdyenResult Class definition.

Dot notation is reserved in Python for methods and attributes, not for dictionary keys. This is unexpected behaviour of a Python package, it will confuse developers and cause unnecessary problems with their implementation.

Accessing a dictionary key causes:

response = Adyen.payment.authorise(request=request)

return response['raw_response']

TypeError: 'AdyenResult' object has no attribute '__getitem__'
  • AdyenResult class is not convertible to a dict using the python dict() method and not JSON serializable
  • It is not iterable:
for idx in result:
            print result[idx]

TypeError: 'AdyenResult' object is not iterable

Suggestion:

  • Return normal dictionaries, don't override Python language standards

Python Test Script

Python test scripts for developers, should cover all library features.

Dev needs to enter test credentials locally, otherwise all tests fail with missing credentials and tests won't be of much use.

To avoid having credentials in source code, maybe it's useful to add function to load credentials from JSON file? This way a path can be given to credentials file which can easily be added to .gitignore.

TypeError: _urllib_post() got an unexpected keyword argument 'xapikey'

Python version: 3.7.2
Library version: 2.0.0
Description

I followed the docs and ran into issue #66 .I tried adding the app_name workaround but I got this error instead.

Error: TypeError: _urllib_post() got an unexpected keyword argument 'xapikey'
    at PythonShell.parseError (/Users/Jibo/Documents/Experiments/stripe_client/node_modules/python-shell/index.js:246:21)
    at terminateIfNeeded (/Users/Jibo/Documents/Experiments/stripe_client/node_modules/python-shell/index.js:129:32)
    at ChildProcess.<anonymous> (/Users/Jibo/Documents/Experiments/stripe_client/node_modules/python-shell/index.js:121:13)
    at emitTwo (events.js:126:13)
    at ChildProcess.emit (events.js:214:7)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:198:12)
    ----- Python Traceback -----
    File "/Users/Jibo/Documents/Experiments/stripe_client/python/adyen.py", line 57, in <module>
      get_list()
    File "/Users/Jibo/Documents/Experiments/stripe_client/python/adyen.py", line 25, in get_list
      'channel': 'Web',
    File "/usr/local/lib/python3.7/site-packages/Adyen/services.py", line 315, in payment_methods
      return self.client.call_checkout_api(request, action, **kwargs)
    File "/usr/local/lib/python3.7/site-packages/Adyen/client.py", line 448, in call_checkout_api
      **kwargs)

'raw_request' encoded to invalid json with single speech marks ''

Because this dict is encoded to json with single speech marks '', it causes problems when decoding in _handle_http_error

Decoding this JSON string causes:

ValueError: Expecting property name: line 1 column 2 (char 1)

I'm trying to determine where this JSON is encoded, and if it is possible to return a regular dict, so no JSON encoding/decoding is required.

Update:

I see there are 3 different request methods in httpclient.py.

  • verify the JSON encoding methods used in each one
  • find where the raw_request is set and returned and if possible, return a regular dict instead of JSON
  • JSON is not required for dicts used within the library so not using JSON for these avoids any encoding errors.

Remove unnecessary validation code

Some validation is done server side with Adyen, it is not needed to implement this in the library as the Adyen server returns a correct error message.

Find and remove these statements in validation.py.

InvalidHeader when getting payment_methods

Python version: 3.7
Library version: 2.1.0
Description
Sending a request through .checkout.payment_methods causes an exception from requests.
Full traceback:

2019-09-20T10:17:46.634599+00:00 app[web.1]: Traceback (most recent call last):
2019-09-20T10:17:46.634601+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
2019-09-20T10:17:46.634602+00:00 app[web.1]: response = self.full_dispatch_request()
2019-09-20T10:17:46.634604+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
2019-09-20T10:17:46.634606+00:00 app[web.1]: rv = self.handle_user_exception(e)
2019-09-20T10:17:46.634607+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
2019-09-20T10:17:46.634609+00:00 app[web.1]: reraise(exc_type, exc_value, tb)
2019-09-20T10:17:46.634610+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
2019-09-20T10:17:46.634612+00:00 app[web.1]: raise value
2019-09-20T10:17:46.634613+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
2019-09-20T10:17:46.634614+00:00 app[web.1]: rv = self.dispatch_request()
2019-09-20T10:17:46.634615+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
2019-09-20T10:17:46.634618+00:00 app[web.1]: return self.view_functions[rule.endpoint](**req.view_args)
2019-09-20T10:17:46.634621+00:00 app[web.1]: File "/app/app/blueprints/api/routes.py", line 84, in _get_adyen_data
2019-09-20T10:17:46.634622+00:00 app[web.1]: config = adyen.checkout.payment_methods(data)
2019-09-20T10:17:46.634624+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/Adyen/services.py", line 315, in payment_methods
2019-09-20T10:17:46.634625+00:00 app[web.1]: return self.client.call_checkout_api(request, action, **kwargs)
2019-09-20T10:17:46.634626+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/Adyen/client.py", line 454, in call_checkout_api
2019-09-20T10:17:46.634628+00:00 app[web.1]: **kwargs)
2019-09-20T10:17:46.634629+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/Adyen/httpclient.py", line 192, in _requests_post
2019-09-20T10:17:46.634630+00:00 app[web.1]: headers=headers, timeout=timeout)
2019-09-20T10:17:46.634632+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/api.py", line 116, in post
2019-09-20T10:17:46.634633+00:00 app[web.1]: return request('post', url, data=data, json=json, **kwargs)
2019-09-20T10:17:46.634635+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/api.py", line 60, in request
2019-09-20T10:17:46.634636+00:00 app[web.1]: return session.request(method=method, url=url, **kwargs)
2019-09-20T10:17:46.634637+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/sessions.py", line 519, in request
2019-09-20T10:17:46.634638+00:00 app[web.1]: prep = self.prepare_request(req)
2019-09-20T10:17:46.634639+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/sessions.py", line 462, in prepare_request
2019-09-20T10:17:46.634640+00:00 app[web.1]: hooks=merge_hooks(request.hooks, self.hooks),
2019-09-20T10:17:46.634641+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/models.py", line 314, in prepare
2019-09-20T10:17:46.634642+00:00 app[web.1]: self.prepare_headers(headers)
2019-09-20T10:17:46.634643+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/models.py", line 448, in prepare_headers
2019-09-20T10:17:46.634644+00:00 app[web.1]: check_header_validity(header)
2019-09-20T10:17:46.634645+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/requests/utils.py", line 942, in check_header_validity
2019-09-20T10:17:46.634647+00:00 app[web.1]: raise InvalidHeader("Invalid return character or leading space in header: %s" % name)
2019-09-20T10:17:46.634648+00:00 app[web.1]: requests.exceptions.InvalidHeader: Invalid return character or leading space in header: User-Agent

Test Authorise 3D

Test an Authorise3D with the api.

Test:

  • browser info, time stamp from client
  • API request, validation
  • redirect to URL returned by Authorise3D request.
  • catch final state

Open PR's

Merge PR open, approved, and passing PR's into develop

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.