From 3ee72e5336d03526c7ab297a5cf09057a6d5d1c2 Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Fri, 26 Nov 2021 10:43:17 +0100 Subject: [PATCH] trivial: apply black (#58937) --- eopayment/__init__.py | 238 ++++++++++++++++------------- eopayment/__main__.py | 3 +- eopayment/common.py | 81 +++++----- eopayment/dummy.py | 108 +++++++++----- eopayment/keyware.py | 27 +++- eopayment/mollie.py | 35 +++-- eopayment/ogone.py | 47 ++++-- eopayment/paybox.py | 138 +++++++++-------- eopayment/payfip_ws.py | 102 ++++++++----- eopayment/saga.py | 63 +++++--- eopayment/sips2.py | 96 +++++++----- eopayment/systempayv2.py | 296 ++++++++++++++++++++++--------------- eopayment/tipi.py | 39 +++-- setup.py | 36 ++--- tests/conftest.py | 5 +- tests/test_base_payment.py | 18 +-- tests/test_dummy.py | 5 +- tests/test_keyware.py | 35 +++-- tests/test_mollie.py | 61 +++----- tests/test_ogone.py | 27 ++-- tests/test_paybox.py | 159 ++++++++++++-------- tests/test_payfip_ws.py | 107 +++++++++----- tests/test_saga.py | 38 +++-- tests/test_sips2.py | 3 +- tests/test_systempayv2.py | 70 ++++----- tests/test_tipi.py | 27 ++-- 26 files changed, 1096 insertions(+), 768 deletions(-) diff --git a/eopayment/__init__.py b/eopayment/__init__.py index 4b964d9..9b82803 100644 --- a/eopayment/__init__.py +++ b/eopayment/__init__.py @@ -20,15 +20,48 @@ import logging import pytz from .common import ( # noqa: F401 - URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED, - CANCELED, CANCELLED, ERROR, WAITING, EXPIRED, force_text, - ResponseError, PaymentException, + URL, + HTML, + FORM, + RECEIVED, + ACCEPTED, + PAID, + DENIED, + CANCELED, + CANCELLED, + ERROR, + WAITING, + EXPIRED, + force_text, + ResponseError, + PaymentException, ) -__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS', 'SYSTEMPAY', - 'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED', 'PAID', - 'DENIED', 'CANCELED', 'CANCELLED', 'ERROR', 'WAITING', - 'EXPIRED', 'get_backends', 'PAYFIP_WS', 'SAGA', 'KEYWARE', 'MOLLIE'] +__all__ = [ + 'Payment', + 'URL', + 'HTML', + 'FORM', + 'SIPS', + 'SYSTEMPAY', + 'TIPI', + 'DUMMY', + 'get_backend', + 'RECEIVED', + 'ACCEPTED', + 'PAID', + 'DENIED', + 'CANCELED', + 'CANCELLED', + 'ERROR', + 'WAITING', + 'EXPIRED', + 'get_backends', + 'PAYFIP_WS', + 'SAGA', + 'KEYWARE', + 'MOLLIE', +] SIPS = 'sips' SIPS2 = 'sips2' @@ -51,86 +84,86 @@ def get_backend(kind): module = importlib.import_module('.' + kind, package='eopayment') return module.Payment -__BACKENDS = [DUMMY, SIPS, SIPS2, SYSTEMPAY, OGONE, PAYBOX, PAYZEN, - TIPI, PAYFIP_WS, KEYWARE, MOLLIE, SAGA] + +__BACKENDS = [DUMMY, SIPS, SIPS2, SYSTEMPAY, OGONE, PAYBOX, PAYZEN, TIPI, PAYFIP_WS, KEYWARE, MOLLIE, SAGA] def get_backends(): - '''Return a dictionnary mapping existing eopayment backends name to their - description. + """Return a dictionnary mapping existing eopayment backends name to their + description. - >>> get_backends()['dummy'].description['caption'] - 'Dummy payment backend' + >>> get_backends()['dummy'].description['caption'] + 'Dummy payment backend' - ''' + """ return {backend: get_backend(backend) for backend in __BACKENDS} class Payment: - ''' - Interface to credit card online payment servers of French banks. The - only use case supported for now is a unique automatic payment. + """ + Interface to credit card online payment servers of French banks. The + only use case supported for now is a unique automatic payment. - >>> options = { - 'numcli': '12345', - } - >>> p = Payment(kind=TIPI, options=options) - >>> transaction_id, kind, data = p.request('10.00', email='bob@example.com') - >>> print (transaction_id, kind, data) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - ('...', 1, 'https://www.payfip.gov.fr/tpa/paiement.web?...') + >>> options = { + 'numcli': '12345', + } + >>> p = Payment(kind=TIPI, options=options) + >>> transaction_id, kind, data = p.request('10.00', email='bob@example.com') + >>> print (transaction_id, kind, data) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ('...', 1, 'https://www.payfip.gov.fr/tpa/paiement.web?...') - Supported backend of French banks are: + Supported backend of French banks are: - - TIPI/PayFiP - - SIPS 2.0, for BNP, Banque Populaire (before 2010), CCF, HSBC, Crédit - Agricole, La Banque Postale, LCL, Société Générale and Crédit du - Nord. - - SystemPay v2/Payzen for Banque Populaire and Caise d'Epargne (Natixis, after 2010) - - Ogone - - Paybox - - Mollie (Belgium) - - Keyware (Belgium) + - TIPI/PayFiP + - SIPS 2.0, for BNP, Banque Populaire (before 2010), CCF, HSBC, Crédit + Agricole, La Banque Postale, LCL, Société Générale and Crédit du + Nord. + - SystemPay v2/Payzen for Banque Populaire and Caise d'Epargne (Natixis, after 2010) + - Ogone + - Paybox + - Mollie (Belgium) + - Keyware (Belgium) - For SIPs you also need the bank provided middleware especially the two - executables, request and response, as the protocol from ATOS/SIPS is not - documented. For the other backends the modules are autonomous. + For SIPs you also need the bank provided middleware especially the two + executables, request and response, as the protocol from ATOS/SIPS is not + documented. For the other backends the modules are autonomous. - Each backend need some configuration parameters to be used, the - description of the backend list those parameters. The description - dictionary can be used to generate configuration forms. + Each backend need some configuration parameters to be used, the + description of the backend list those parameters. The description + dictionary can be used to generate configuration forms. - >>> d = get_backend(SPPLUS).description - >>> print d['caption'] - SPPlus payment service of French bank Caisse d'epargne - >>> print [p['name'] for p in d['parameters']] # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - ['cle', ..., 'moyen'] - >>> print d['parameters'][0]['caption'] - Secret key, a 40 digits hexadecimal number + >>> d = get_backend(SPPLUS).description + >>> print d['caption'] + SPPlus payment service of French bank Caisse d'epargne + >>> print [p['name'] for p in d['parameters']] # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ['cle', ..., 'moyen'] + >>> print d['parameters'][0]['caption'] + Secret key, a 40 digits hexadecimal number - ''' + """ def __init__(self, kind, options, logger=None): self.kind = kind self.backend = get_backend(kind)(options, logger=logger) def request(self, amount, **kwargs): - '''Request a payment to the payment backend. + """Request a payment to the payment backend. - Arguments: - amount -- the amount of money to ask - email -- the email of the customer (optional) - usually redundant with the hardwired settings in the bank - configuration panel. At this url you must use the Payment.response - method to analyze the bank returned values. + Arguments: + amount -- the amount of money to ask + email -- the email of the customer (optional) + usually redundant with the hardwired settings in the bank + configuration panel. At this url you must use the Payment.response + method to analyze the bank returned values. - It returns a triple of values, (transaction_id, kind, data): - - the first gives a string value to later match the payment with - the invoice, - - kind gives the type of the third value, payment.URL or - payment.HTML or payment.FORM, - - the third is the URL or the HTML form to contact the payment - server, which must be sent to the customer browser. - ''' + It returns a triple of values, (transaction_id, kind, data): + - the first gives a string value to later match the payment with + the invoice, + - kind gives the type of the third value, payment.URL or + payment.HTML or payment.FORM, + - the third is the URL or the HTML form to contact the payment + server, which must be sent to the customer browser. + """ logger.debug('%r' % kwargs) if 'capture_date' in kwargs: @@ -151,8 +184,7 @@ class Payment: # backend timezone should come from some backend configuration backend_tz = pytz.timezone('Europe/Paris') utc_tz = pytz.timezone('Etc/UTC') - backend_trans_date = utc_tz.localize( - datetime.datetime.utcnow()).astimezone(backend_tz) + backend_trans_date = utc_tz.localize(datetime.datetime.utcnow()).astimezone(backend_tz) capture_day = (capture_date - backend_trans_date.date()).days if capture_day <= 0: raise ValueError("capture_date needs to be superior to the transaction date.") @@ -162,58 +194,58 @@ class Payment: return self.backend.request(amount, **kwargs) def response(self, query_string, **kwargs): - ''' - Process a response from the Bank API. It must be used on the URL - where the user browser of the payment server is going to post the - result of the payment. Beware it can happen multiple times for the - same payment, so you MUST support multiple notification of the same - event, i.e. it should be idempotent. For example if you already - validated some invoice, receiving a new payment notification for the - same invoice should alter this state change. + """ + Process a response from the Bank API. It must be used on the URL + where the user browser of the payment server is going to post the + result of the payment. Beware it can happen multiple times for the + same payment, so you MUST support multiple notification of the same + event, i.e. it should be idempotent. For example if you already + validated some invoice, receiving a new payment notification for the + same invoice should alter this state change. - Beware that when notified directly by the bank (and not through the - customer browser) no applicative session will exist, so you should - not depend on it in your handler. + Beware that when notified directly by the bank (and not through the + customer browser) no applicative session will exist, so you should + not depend on it in your handler. - Arguments: - query_string -- the URL encoded form-data from a GET or a POST + Arguments: + query_string -- the URL encoded form-data from a GET or a POST - It returns a quadruplet of values: + It returns a quadruplet of values: - (result, transaction_id, bank_data, return_content) + (result, transaction_id, bank_data, return_content) - - result is a boolean stating whether the transaction worked, use it - to decide whether to act on a valid payment, - - the transaction_id return the same id than returned by request - when requesting for the payment, use it to find the invoice or - transaction which is linked to the payment, - - bank_data is a dictionnary of the data sent by the bank, it should - be logged for security reasons, - - return_content, if not None you must return this content as the - result of the HTTP request, it's used when the bank is calling - your site as a web service. + - result is a boolean stating whether the transaction worked, use it + to decide whether to act on a valid payment, + - the transaction_id return the same id than returned by request + when requesting for the payment, use it to find the invoice or + transaction which is linked to the payment, + - bank_data is a dictionnary of the data sent by the bank, it should + be logged for security reasons, + - return_content, if not None you must return this content as the + result of the HTTP request, it's used when the bank is calling + your site as a web service. - ''' + """ return self.backend.response(query_string, **kwargs) def cancel(self, amount, bank_data, **kwargs): - ''' - Cancel or edit the amount of a transaction sent to the bank. + """ + Cancel or edit the amount of a transaction sent to the bank. - Arguments: - - amount -- the amount of money to cancel - - bank_data -- the transaction dictionary received from the bank - ''' + Arguments: + - amount -- the amount of money to cancel + - bank_data -- the transaction dictionary received from the bank + """ return self.backend.cancel(amount, bank_data, **kwargs) def validate(self, amount, bank_data, **kwargs): - ''' - Validate and trigger the transmission of a transaction to the bank. + """ + Validate and trigger the transmission of a transaction to the bank. - Arguments: - - amount -- the amount of money - - bank_data -- the transaction dictionary received from the bank - ''' + Arguments: + - amount -- the amount of money + - bank_data -- the transaction dictionary received from the bank + """ return self.backend.validate(amount, bank_data, **kwargs) def get_parameters(self, scope='global'): diff --git a/eopayment/__main__.py b/eopayment/__main__.py index 077fb61..ebbf158 100644 --- a/eopayment/__main__.py +++ b/eopayment/__main__.py @@ -67,7 +67,7 @@ def main(ctx, backend, debug, option, name): backend = config_backend load = True elif name and backend: - load = (config_backend == backend and config_name == name) + load = config_backend == backend and config_name == name elif name: load = config_name == name elif backend: @@ -123,4 +123,5 @@ def response(backend, query_string, param): for line in formatted_value.splitlines(False): print(' ', line) + main() diff --git a/eopayment/common.py b/eopayment/common.py index 400b66e..750c5f9 100644 --- a/eopayment/common.py +++ b/eopayment/common.py @@ -36,8 +36,7 @@ except ImportError: pass -__all__ = ['PaymentCommon', 'URL', 'HTML', 'RANDOM', 'RECEIVED', 'ACCEPTED', - 'PAID', 'ERROR', 'WAITING'] +__all__ = ['PaymentCommon', 'URL', 'HTML', 'RANDOM', 'RECEIVED', 'ACCEPTED', 'PAID', 'ERROR', 'WAITING'] RANDOM = random.SystemRandom() @@ -94,29 +93,38 @@ class ResponseError(PaymentException): class PaymentResponse: - '''Holds a generic view on the result of payment transaction response. + """Holds a generic view on the result of payment transaction response. - result -- holds the declarative result of the transaction, does not use - it to validate the payment in your backoffice, it's just for informing - the user that all is well. - test -- indicates if the transaction was a test - signed -- holds whether the message was signed - bank_data -- a dictionnary containing some data depending on the bank, - you have to log it for audit purpose. - return_content -- when handling a response in a callback endpoint, i.e. - a response transmitted directly from the bank to the merchant website, - you usually have to confirm good reception of the message by returning a - properly formatted response, this is it. - bank_status -- if result is False, it contains the reason - order_id -- the id given by the merchant in the payment request - transaction_id -- the id assigned by the bank to this transaction, it - could be the one sent by the merchant in the request, but it is usually - an identifier internal to the bank. - ''' + result -- holds the declarative result of the transaction, does not use + it to validate the payment in your backoffice, it's just for informing + the user that all is well. + test -- indicates if the transaction was a test + signed -- holds whether the message was signed + bank_data -- a dictionnary containing some data depending on the bank, + you have to log it for audit purpose. + return_content -- when handling a response in a callback endpoint, i.e. + a response transmitted directly from the bank to the merchant website, + you usually have to confirm good reception of the message by returning a + properly formatted response, this is it. + bank_status -- if result is False, it contains the reason + order_id -- the id given by the merchant in the payment request + transaction_id -- the id assigned by the bank to this transaction, it + could be the one sent by the merchant in the request, but it is usually + an identifier internal to the bank. + """ - def __init__(self, result=None, signed=None, bank_data=dict(), - return_content=None, bank_status='', transaction_id='', - order_id='', test=False, transaction_date=None): + def __init__( + self, + result=None, + signed=None, + bank_data=dict(), + return_content=None, + bank_status='', + transaction_id='', + order_id='', + test=False, + transaction_date=None, + ): self.result = result self.signed = signed self.bank_data = bank_data @@ -163,11 +171,9 @@ class PaymentCommon: while True: parts = [RANDOM.choice(choices) for x in range(length)] id = ''.join(parts) - name = '%s_%s_%s' % (str(date.today()), - '-'.join(prefixes), str(id)) + name = '%s_%s_%s' % (str(date.today()), '-'.join(prefixes), str(id)) try: - fd = os.open(os.path.join(self.PATH, name), - os.O_CREAT | os.O_EXCL) + fd = os.open(os.path.join(self.PATH, name), os.O_CREAT | os.O_EXCL) except Exception: raise else: @@ -179,9 +185,12 @@ class PaymentCommon: try: amount = Decimal(amount) except ValueError: - raise ValueError('invalid amount %s: it must be a decimal integer with two digits ' - 'at most after the decimal point', amount) - if int(amount) < min_amount or (max_amount and int(amount) > max_amount): + raise ValueError( + 'invalid amount %s: it must be a decimal integer with two digits ' + 'at most after the decimal point', + amount, + ) + if int(amount) < min_amount or (max_amount and int(amount) > max_amount): raise ValueError('amount %s is not in range [%s, %s]' % (amount, min_amount, max_amount)) if cents: amount *= Decimal('100') # convert to cents @@ -190,8 +199,7 @@ class PaymentCommon: class Form: - def __init__(self, url, method, fields, encoding='utf-8', - submit_name='Submit', submit_value='Submit'): + def __init__(self, url, method, fields, encoding='utf-8', submit_name='Submit', submit_value='Submit'): self.url = url self.method = method self.fields = fields @@ -211,13 +219,14 @@ class Form: def escape(self, s): return html.escape(force_text(s, self.encoding)) - def __str__(self): s = '
' % (self.method, self.url) for field in self.fields: - s += '\n ' % (self.escape(field['type']), - self.escape(field['name']), - self.escape(field['value'])) + s += '\n ' % ( + self.escape(field['type']), + self.escape(field['name']), + self.escape(field['value']), + ) s += '\n = threshold): - return PaymentResponse( - result=EXPIRED, - signed=True, - order_id=transaction_id) + if e.code == 'P1' or (e.code == 'P5' and delta >= threshold): + return PaymentResponse(result=EXPIRED, signed=True, order_id=transaction_id) if e.code == 'P5' and delta < threshold: - return PaymentResponse( - result=WAITING, - signed=True, - order_id=transaction_id) + return PaymentResponse(result=WAITING, signed=True, order_id=transaction_id) raise e return self.payfip_response_to_eopayment_response(idop, response) @@ -353,7 +374,8 @@ class Payment(PaymentCommon): bank_data={k: response[k] for k in response}, order_id=idop, transaction_id=transaction_id, - test=response.saisie == 'T') + test=response.saisie == 'T', + ) if __name__ == '__main__': @@ -366,6 +388,7 @@ if __name__ == '__main__': return func(*args, **kwargs) except PayFiPError as e: click.echo(click.style('PayFiP ERROR : %s "%s"' % (e.code, e.message), fg='red')) + return f @click.group() @@ -374,6 +397,7 @@ if __name__ == '__main__': @click.pass_context def main(ctx, wsdl_url, service_url): import logging + logging.basicConfig(level=logging.INFO) # hide warning from zeep logging.getLogger('zeep.wsdl.bindings.soap').level = logging.ERROR @@ -407,10 +431,17 @@ if __name__ == '__main__': @click.pass_obj @show_payfip_error def get_idop(payfip, numcli, saisie, exer, montant, refdet, mel, objet, url_notification, url_redirect): - idop = payfip.get_idop(numcli=numcli, saisie=saisie, exer=exer, - montant=montant, refdet=refdet, mel=mel, - objet=objet, url_notification=url_notification, - url_redirect=url_redirect) + idop = payfip.get_idop( + numcli=numcli, + saisie=saisie, + exer=exer, + montant=montant, + refdet=refdet, + mel=mel, + objet=objet, + url_notification=url_notification, + url_redirect=url_redirect, + ) print('idOp:', idop) print(PAYMENT_URL + '?idop=%s' % idop) @@ -422,6 +453,3 @@ if __name__ == '__main__': print(payfip.get_info_paiement(idop)) main() - - - diff --git a/eopayment/saga.py b/eopayment/saga.py index 6709f79..ca8aad9 100644 --- a/eopayment/saga.py +++ b/eopayment/saga.py @@ -23,8 +23,17 @@ import lxml.etree as ET import zeep import zeep.exceptions -from .common import (PaymentException, PaymentCommon, ResponseError, URL, PAID, - DENIED, CANCELLED, ERROR, PaymentResponse) +from .common import ( + PaymentException, + PaymentCommon, + ResponseError, + URL, + PAID, + DENIED, + CANCELLED, + ERROR, + PaymentResponse, +) _zeep_transport = None @@ -60,8 +69,17 @@ class Saga: raise SagaError('Invalid SAGA response "%s"' % content[:1024]) return tree - def transaction(self, num_service, id_tiers, compte, lib_ecriture, montant, - urlretour_asynchrone, email, urlretour_synchrone): + def transaction( + self, + num_service, + id_tiers, + compte, + lib_ecriture, + montant, + urlretour_asynchrone, + email, + urlretour_synchrone, + ): tree = self.soap_call( 'Transaction', 'url', @@ -72,15 +90,13 @@ class Saga: montant=montant, urlretour_asynchrone=urlretour_asynchrone, email=email, - urlretour_synchrone=urlretour_synchrone) + urlretour_synchrone=urlretour_synchrone, + ) # tree == ... return tree.text def page_retour(self, operation, idop): - tree = self.soap_call( - operation, - 'ok', - idop=idop) + tree = self.soap_call(operation, 'ok', idop=idop) # tree == >> gw =Payment(dict(secret_test='xxx', secret_production='yyyy', - site_id=123, ctx_mode='PRODUCTION')) - >>> print gw.request(100) - ('20120525093304_188620', - 'https://paiement.systempay.fr/vads-payment/?vads_url_return=http%3A%2F%2Furl.de.retour%2Fretour.php&vads_cust_country=FR&vads_site_id=&vads_payment_config=SINGLE&vads_trans_id=188620&vads_action_mode=INTERACTIVE&vads_contrib=eopayment&vads_page_action=PAYMENT&vads_trans_date=20120525093304&vads_ctx_mode=TEST&vads_validation_mode=&vads_version=V2&vads_payment_cards=&signature=5d412498ab523627ec5730a09118f75afa602af5&vads_language=fr&vads_capture_delay=&vads_currency=978&vads_amount=100&vads_return_mode=NONE', - {'vads_url_return': 'http://url.de.retour/retour.php', - 'vads_cust_country': 'FR', 'vads_site_id': '', - 'vads_payment_config': 'SINGLE', 'vads_trans_id': '188620', - 'vads_action_mode': 'INTERACTIVE', 'vads_contrib': 'eopayment', - 'vads_page_action': 'PAYMENT', 'vads_trans_date': '20120525093304', - 'vads_ctx_mode': 'TEST', 'vads_validation_mode': '', - 'vads_version': 'V2', 'vads_payment_cards': '', 'signature': - '5d412498ab523627ec5730a09118f75afa602af5', 'vads_language': 'fr', - 'vads_capture_delay': '', 'vads_currency': '978', 'vads_amount': 100, - 'vads_return_mode': 'NONE'}) + >>> gw =Payment(dict(secret_test='xxx', secret_production='yyyy', + site_id=123, ctx_mode='PRODUCTION')) + >>> print gw.request(100) + ('20120525093304_188620', + 'https://paiement.systempay.fr/vads-payment/?vads_url_return=http%3A%2F%2Furl.de.retour%2Fretour.php&vads_cust_country=FR&vads_site_id=&vads_payment_config=SINGLE&vads_trans_id=188620&vads_action_mode=INTERACTIVE&vads_contrib=eopayment&vads_page_action=PAYMENT&vads_trans_date=20120525093304&vads_ctx_mode=TEST&vads_validation_mode=&vads_version=V2&vads_payment_cards=&signature=5d412498ab523627ec5730a09118f75afa602af5&vads_language=fr&vads_capture_delay=&vads_currency=978&vads_amount=100&vads_return_mode=NONE', + {'vads_url_return': 'http://url.de.retour/retour.php', + 'vads_cust_country': 'FR', 'vads_site_id': '', + 'vads_payment_config': 'SINGLE', 'vads_trans_id': '188620', + 'vads_action_mode': 'INTERACTIVE', 'vads_contrib': 'eopayment', + 'vads_page_action': 'PAYMENT', 'vads_trans_date': '20120525093304', + 'vads_ctx_mode': 'TEST', 'vads_validation_mode': '', + 'vads_version': 'V2', 'vads_payment_cards': '', 'signature': + '5d412498ab523627ec5730a09118f75afa602af5', 'vads_language': 'fr', + 'vads_capture_delay': '', 'vads_currency': '978', 'vads_amount': 100, + 'vads_return_mode': 'NONE'}) + + """ - ''' has_free_transaction_id = True service_url = "https://paiement.systempay.fr/vads-payment/" signature_algo = 'sha1' @@ -239,53 +255,71 @@ class Payment(PaymentCommon): 'caption': _('Automatic return URL (ignored, must be set in Payzen/SystemPay backoffice)'), 'required': False, }, - {'name': 'service_url', + { + 'name': 'service_url', 'default': service_url, 'caption': 'URL du service de paiement', 'help_text': 'ne pas modifier si vous ne savez pas', 'validation': lambda x: x.startswith('http'), - 'required': True, }, - {'name': 'secret_test', + 'required': True, + }, + { + 'name': 'secret_test', 'caption': 'Secret pour la configuration de TEST', 'validation': lambda value: str.isalnum(value), - 'required': True, }, - {'name': 'secret_production', + 'required': True, + }, + { + 'name': 'secret_production', 'caption': 'Secret pour la configuration de PRODUCTION', - 'validation': lambda value: str.isalnum(value), }, - {'name': 'signature_algo', + 'validation': lambda value: str.isalnum(value), + }, + { + 'name': 'signature_algo', 'caption': 'Algorithme de signature', 'default': 'sha1', 'choices': ( ('sha1', 'SHA-1'), ('hmac_sha256', 'HMAC-SHA-256'), - )}, + ), + }, { 'name': 'manual_validation', 'caption': 'Validation manuelle', 'type': bool, 'default': False, - 'scope': 'transaction' - } - ] + 'scope': 'transaction', + }, + ], } - for name in ('vads_ctx_mode', VADS_SITE_ID, 'vads_order_info', - 'vads_order_info2', 'vads_order_info3', - 'vads_payment_cards', 'vads_payment_config', 'capture_day'): + for name in ( + 'vads_ctx_mode', + VADS_SITE_ID, + 'vads_order_info', + 'vads_order_info2', + 'vads_order_info3', + 'vads_payment_cards', + 'vads_payment_config', + 'capture_day', + ): parameter = PARAMETER_MAP[name] def check_value(parameter): def validate(value): return parameter.check_value(value) + return validate - x = {'name': name, - 'caption': parameter.description or name, - 'validation': check_value(parameter), - 'default': parameter.default, - 'required': parameter.needed, - 'help_text': parameter.help_text, - 'max_length': parameter.max_length} + x = { + 'name': name, + 'caption': parameter.description or name, + 'validation': check_value(parameter), + 'default': parameter.default, + 'required': parameter.needed, + 'help_text': parameter.help_text, + 'max_length': parameter.max_length, + } description['parameters'].append(x) def __init__(self, options, logger=None): @@ -301,23 +335,45 @@ class Payment(PaymentCommon): alphabet = string.ascii_letters + string.digits first_letter_alphabet = alphabet.replace('9', '') - vads_trans_id = ( - gen.choice(first_letter_alphabet) - + ''.join(gen.choice(alphabet) for i in range(5)) - ) + vads_trans_id = gen.choice(first_letter_alphabet) + ''.join(gen.choice(alphabet) for i in range(5)) return vads_trans_id - def request(self, amount, name=None, first_name=None, last_name=None, - address=None, email=None, phone=None, orderid=None, info1=None, - info2=None, info3=None, next_url=None, manual_validation=None, - transaction_id=None, **kwargs): - ''' - Create the URL string to send a request to SystemPay - ''' - self.logger.debug('%s amount %s name %s address %s email %s phone %s ' - 'next_url %s info1 %s info2 %s info3 %s kwargs: %s', - __name__, amount, name, address, email, phone, info1, - info2, info3, next_url, kwargs) + def request( + self, + amount, + name=None, + first_name=None, + last_name=None, + address=None, + email=None, + phone=None, + orderid=None, + info1=None, + info2=None, + info3=None, + next_url=None, + manual_validation=None, + transaction_id=None, + **kwargs, + ): + """ + Create the URL string to send a request to SystemPay + """ + self.logger.debug( + '%s amount %s name %s address %s email %s phone %s ' + 'next_url %s info1 %s info2 %s info3 %s kwargs: %s', + __name__, + amount, + name, + address, + email, + phone, + info1, + info2, + info3, + next_url, + kwargs, + ) # amount unit is cents amount = '%.0f' % (100 * amount) kwargs.update(add_vads({'amount': force_text(amount)})) @@ -325,8 +381,10 @@ class Payment(PaymentCommon): raise ValueError('amount must be an integer >= 0') normal_return_url = self.normal_return_url if next_url: - warnings.warn("passing next_url to request() is deprecated, " - "set normal_return_url in options", DeprecationWarning) + warnings.warn( + "passing next_url to request() is deprecated, " "set normal_return_url in options", + DeprecationWarning, + ) normal_return_url = next_url if normal_return_url: kwargs[VADS_URL_RETURN] = force_text(normal_return_url) @@ -356,8 +414,7 @@ class Payment(PaymentCommon): ptype = 'an-' p = Parameter(name, ptype, 13, max_length=32) if not p.check_value(orderid): - raise ValueError( - '%s value %s is not of the type %s' % (name, orderid, ptype)) + raise ValueError('%s value %s is not of the type %s' % (name, orderid, ptype)) kwargs[name] = orderid vads_trans_id = self.make_vads_trans_id() @@ -368,8 +425,7 @@ class Payment(PaymentCommon): for parameter in PARAMETERS: name = parameter.name # import default parameters from configuration - if name not in fields \ - and name in self.options: + if name not in fields and name in self.options: fields[name] = force_text(self.options[name]) # import default parameters from module if name not in fields and parameter.default is not None: @@ -399,7 +455,9 @@ class Payment(PaymentCommon): 'name': force_text(field_name), 'value': force_text(field_value), } - for field_name, field_value in fields.items()]) + for field_name, field_value in fields.items() + ], + ) return transaction_id, FORM, form RESULT_MAP = { @@ -416,9 +474,11 @@ class Payment(PaymentCommon): '00': {'message': 'Tous les contrôles se sont déroulés avec succés.'}, '02': {'message': 'La carte a dépassé l\'encours autorisé.'}, '03': {'message': 'La carte appartient à la liste grise du commerçant.'}, - '04': {'messaǵe': 'Le pays d\'émission de la carte appartient à la liste grise du ' - 'commerçant ou le pays d\'émission de la carte n\'appartient pas à la ' - 'liste blanche du commerçant.'}, + '04': { + 'messaǵe': 'Le pays d\'émission de la carte appartient à la liste grise du ' + 'commerçant ou le pays d\'émission de la carte n\'appartient pas à la ' + 'liste blanche du commerçant.' + }, '05': {'message': 'L’adresse IP appartient à la liste grise du marchand.'}, '06': {'message': 'Le code bin appartient à la liste grise du marchand.'}, '07': {'message': 'Détection d’une e-carte bleue.'}, @@ -426,8 +486,10 @@ class Payment(PaymentCommon): '09': {'message': 'Détection d’une carte commerciale étrangère.'}, '14': {'message': 'Détection d’une carte à autorisation systématique.'}, '30': {'message': 'Le pays de l’adresse IP appartient à la liste grise.'}, - '99': {'message': 'Problème technique recontré par le serveur lors du traitement ' - 'd\'un des contrôles locauxi.'}, + '99': { + 'message': 'Problème technique recontré par le serveur lors du traitement ' + 'd\'un des contrôles locauxi.' + }, } @classmethod @@ -471,8 +533,7 @@ class Payment(PaymentCommon): def response(self, query_string, **kwargs): fields = urlparse.parse_qs(query_string, True) if not set(fields) >= {SIGNATURE, VADS_CTX_MODE, VADS_AUTH_RESULT}: - raise ResponseError('missing %s, %s or %s' % (SIGNATURE, VADS_CTX_MODE, - VADS_AUTH_RESULT)) + raise ResponseError('missing %s, %s or %s' % (SIGNATURE, VADS_CTX_MODE, VADS_AUTH_RESULT)) for key, value in fields.items(): fields[key] = value[0] copy = fields.copy() @@ -481,8 +542,7 @@ class Payment(PaymentCommon): self.logger.debug('checking systempay response on: %r', copy) signature_result = signature == fields[SIGNATURE] if not signature_result: - self.logger.debug('signature check: %s %s', signature, - fields[SIGNATURE]) + self.logger.debug('signature check: %s %s', signature, fields[SIGNATURE]) if not signature_result: message += ' signature invalide.' @@ -510,7 +570,8 @@ class Payment(PaymentCommon): transaction_id=transaction_id, bank_status=message, transaction_date=transaction_date, - test=test) + test=test, + ) return response def sha1_sign(self, secret, signed_data): @@ -522,8 +583,7 @@ class Payment(PaymentCommon): def signature(self, fields): self.logger.debug('got fields %s to sign' % fields) - ordered_keys = sorted( - key for key in fields.keys() if key.startswith('vads_')) + ordered_keys = sorted(key for key in fields.keys() if key.startswith('vads_')) self.logger.debug('ordered keys %s' % ordered_keys) ordered_fields = [force_byte(fields[key]) for key in ordered_keys] secret = force_byte(getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower())) diff --git a/eopayment/tipi.py b/eopayment/tipi.py index 403cf2e..a056e82 100644 --- a/eopayment/tipi.py +++ b/eopayment/tipi.py @@ -21,8 +21,7 @@ import random import pytz -from .common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED, - CANCELLED, ERROR, ResponseError, _) +from .common import PaymentCommon, PaymentResponse, URL, PAID, DENIED, CANCELLED, ERROR, ResponseError, _ from six.moves.urllib.parse import urlencode, parse_qs import logging @@ -35,10 +34,10 @@ LOGGER = logging.getLogger(__name__) class Payment(PaymentCommon): - '''Produce requests for and verify response from the TIPI online payment + """Produce requests for and verify response from the TIPI online payment processor from the French Finance Ministry. - ''' + """ description = { 'caption': 'TIPI, Titres Payables par Internet', @@ -81,21 +80,34 @@ class Payment(PaymentCommon): maximal_amount = decimal.Decimal('100000.0') def _generate_refdet(self): - return '%s%010d' % (datetime.datetime.now(pytz.timezone('Europe/Paris')).strftime('%Y%m%d%H%M%S'), - random.randint(1, 1000000000)) + return '%s%010d' % ( + datetime.datetime.now(pytz.timezone('Europe/Paris')).strftime('%Y%m%d%H%M%S'), + random.randint(1, 1000000000), + ) - def request(self, amount, email, next_url=None, exer=None, orderid=None, - refdet=None, objet=None, saisie=None, **kwargs): + def request( + self, + amount, + email, + next_url=None, + exer=None, + orderid=None, + refdet=None, + objet=None, + saisie=None, + **kwargs, + ): montant = self.clean_amount(amount, max_amount=9999.99) automatic_return_url = self.automatic_return_url if next_url and not automatic_return_url: - warnings.warn("passing next_url to request() is deprecated, " - "set automatic_return_url in options", DeprecationWarning) + warnings.warn( + "passing next_url to request() is deprecated, " "set automatic_return_url in options", + DeprecationWarning, + ) automatic_return_url = next_url if automatic_return_url is not None: - if (not isinstance(automatic_return_url, str) - or not automatic_return_url.startswith('http')): + if not isinstance(automatic_return_url, str) or not automatic_return_url.startswith('http'): raise ValueError('URLCL invalid URL format') try: if exer is not None: @@ -189,4 +201,5 @@ class Payment(PaymentCommon): bank_data=fields, order_id=refdet, transaction_id=refdet, - test=test) + test=test, + ) diff --git a/setup.py b/setup.py index 142c827..0c053af 100755 --- a/setup.py +++ b/setup.py @@ -35,25 +35,23 @@ class TestCommand(distutils.core.Command): pass def run(self): - ''' + """ Finds all the tests modules in tests/, and runs them. - ''' + """ testfiles = [] for t in glob(pjoin(self._dir, 'tests', '*.py')): if not t.endswith('__init__.py'): - testfiles.append('.'.join( - ['tests', splitext(basename(t))[0]]) - ) + testfiles.append('.'.join(['tests', splitext(basename(t))[0]])) tests = TestLoader().loadTestsFromNames(testfiles) import eopayment + tests.addTests(doctest.DocTestSuite(eopayment)) t = TextTestRunner(verbosity=4) t.run(tests) class eo_sdist(sdist): - def run(self): print("creating VERSION file") if os.path.exists('VERSION'): @@ -69,16 +67,16 @@ class eo_sdist(sdist): def get_version(): - '''Use the VERSION, if absent generates a version with git describe, if not - tag exists, take 0.0.0- and add the length of the commit log. - ''' + """Use the VERSION, if absent generates a version with git describe, if not + tag exists, take 0.0.0- and add the length of the commit log. + """ if os.path.exists('VERSION'): with open('VERSION') as v: return v.read() if os.path.exists('.git'): - p = subprocess.Popen(['git', 'describe', '--dirty', - '--match=v*'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + p = subprocess.Popen( + ['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) result = p.communicate()[0] if p.returncode == 0: result = result.decode('ascii').strip()[1:] # strip spaces/newlines and initial v @@ -93,9 +91,7 @@ def get_version(): version = result return version else: - return '0.0.post%s' % len( - subprocess.check_output( - ['git', 'rev-list', 'HEAD']).splitlines()) + return '0.0.post%s' % len(subprocess.check_output(['git', 'rev-list', 'HEAD']).splitlines()) return '0.0.0' @@ -131,13 +127,9 @@ setuptools.setup( name='eopayment', version=get_version(), license='GPLv3 or later', - description='Common API to use all French online payment credit card ' - 'processing services', + description='Common API to use all French online payment credit card ' 'processing services', include_package_data=True, - long_description=open( - os.path.join( - os.path.dirname(__file__), - 'README.txt'), encoding='utf-8').read(), + long_description=open(os.path.join(os.path.dirname(__file__), 'README.txt'), encoding='utf-8').read(), long_description_content_type='text/plain', url='http://dev.entrouvert.org/projects/eopayment/', author="Entr'ouvert", @@ -168,5 +160,5 @@ setuptools.setup( 'compile_translations': compile_translations, 'install_lib': install_lib, 'sdist': eo_sdist, - } + }, ) diff --git a/tests/conftest.py b/tests/conftest.py index 5f79977..ec3a2fa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -71,8 +71,8 @@ def record_http_session(request): history = [] for request, response in adapter.history: - request_content = (request.body or b'') - response_content = (response.content or b'') + request_content = request.body or b'' + response_content = response.content or b'' if is_xml_content_type(request): request_content = xmlindent(request_content) @@ -103,6 +103,7 @@ def record_http_session(request): request_content = request_content.decode('utf-8') assert request_content == expected_request_content return response_content + with httmock.HTTMock(Mocker().mock): yield None diff --git a/tests/test_base_payment.py b/tests/test_base_payment.py index 2f33af5..6887ac4 100644 --- a/tests/test_base_payment.py +++ b/tests/test_base_payment.py @@ -37,22 +37,22 @@ def do_mock_backend(monkeypatch): 'caption': 'Validation manuelle', 'type': bool, 'default': False, - 'scope': 'transaction' + 'scope': 'transaction', }, { 'name': 'global_param', 'caption': 'Global Param', 'type': bool, 'default': False, - 'scope': 'global' + 'scope': 'global', }, - ] } def get_backend(*args, **kwargs): def backend(*args, **kwargs): return MockBackend + return backend monkeypatch.setattr(eopayment, 'get_backend', get_backend) @@ -62,14 +62,13 @@ def do_mock_backend(monkeypatch): def test_deferred_payment(monkeypatch): mock_backend, payment = do_mock_backend(monkeypatch) - capture_date = (datetime.now().date() + timedelta(days=3)) + capture_date = datetime.now().date() + timedelta(days=3) payment.request(amount=12.2, capture_date=capture_date) mock_backend.request.assert_called_with(12.2, **{'capture_day': '3'}) # capture date can't be inferior to the transaction date - capture_date = (datetime.now().date() - timedelta(days=3)) - with pytest.raises( - ValueError, match='capture_date needs to be superior to the transaction date.'): + capture_date = datetime.now().date() - timedelta(days=3) + with pytest.raises(ValueError, match='capture_date needs to be superior to the transaction date.'): payment.request(amount=12.2, capture_date=capture_date) # capture date should be a date object @@ -78,7 +77,7 @@ def test_deferred_payment(monkeypatch): payment.request(amount=12.2, capture_date=capture_date) # using capture date on a backend that does not support it raise an error - capture_date = (datetime.now().date() + timedelta(days=3)) + capture_date = datetime.now().date() + timedelta(days=3) mock_backend.description['parameters'] = [] with pytest.raises(ValueError, match='capture_date is not supported by the backend.'): payment.request(amount=12.2, capture_date=capture_date) @@ -89,8 +88,7 @@ def test_paris_timezone(freezer, monkeypatch): _, payment = do_mock_backend(monkeypatch) capture_date = date(year=2018, month=10, day=3) - with pytest.raises( - ValueError, match='capture_date needs to be superior to the transaction date'): + with pytest.raises(ValueError, match='capture_date needs to be superior to the transaction date'): # utcnow will return 2018-10-02 23:50:00, # converted to Europe/Paris it is already 2018-10-03 # so 2018-10-03 for capture_date is invalid diff --git a/tests/test_dummy.py b/tests/test_dummy.py index ec901ae..ad88320 100644 --- a/tests/test_dummy.py +++ b/tests/test_dummy.py @@ -25,7 +25,7 @@ import pytest def backend(): options = { 'automatic_notification_url': 'http://example.com/direct_notification_url', - 'origin': 'Mairie de Perpette-les-oies' + 'origin': 'Mairie de Perpette-les-oies', } return eopayment.Payment('dummy', options) @@ -33,7 +33,8 @@ def backend(): def test_request(backend, freezer): freezer.move_to('2020-01-01 00:00:00+01:00') transaction_id, method, raw_url = backend.request( - '10.10', capture_date=datetime.date(2020, 1, 7), subject='Repas pour 4 personnes') + '10.10', capture_date=datetime.date(2020, 1, 7), subject='Repas pour 4 personnes' + ) assert transaction_id assert method == 1 url = urlparse(raw_url) diff --git a/tests/test_keyware.py b/tests/test_keyware.py index d826558..276e62d 100644 --- a/tests/test_keyware.py +++ b/tests/test_keyware.py @@ -33,9 +33,7 @@ QUERY_STRING = 'order_id=' + ORDER_ID POST_ORDER_RESPONSE = { "amount": 995, - "client": { - "user_agent": "Testing API" - }, + "client": {"user_agent": "Testing API"}, "created": "2016-07-04T11:41:57.121017+00:00", "currency": "EUR", "description": "Example description", @@ -44,14 +42,12 @@ POST_ORDER_RESPONSE = { "modified": "2016-07-04T11:41:57.183822+00:00", "order_url": "https://api.online.emspay.eu/pay/1c969951-f5f1-4290-ae41-6177961fb3cb/", "project_id": "1ef558ed-d77d-470d-b43b-c0f4a131bcef", - "status": "new" + "status": "new", } GET_ORDER_RESPONSE = { "amount": 995, - "client": { - "user_agent": "Testing API" - }, + "client": {"user_agent": "Testing API"}, "created": "2016-07-04T11:41:55.635115+00:00", "currency": "EUR", "description": "Example order #1", @@ -77,7 +73,7 @@ GET_ORDER_RESPONSE = { "id": "0c4bd0cd-f197-446b-b218-39cbeb028290", "noticed": "2016-07-04T11:41:55.987468+00:00", "occurred": "2016-07-04T11:41:55.831655+00:00", - "source": "set_status" + "source": "set_status", } ], "expiration_period": "PT60M", @@ -91,9 +87,9 @@ GET_ORDER_RESPONSE = { }, "payment_url": "https://api.online.emspay.eu/redirect/6c81499c-14e4-4974-99e5-fe72ce019411/to/payment/", "project_id": "1ef558ed-d77d-470d-b43b-c0f4a131bcef", - "status": "completed" + "status": "completed", } - ] + ], } @@ -102,11 +98,13 @@ GET_ORDER_RESPONSE = { def add_order(url, request): return response(200, POST_ORDER_RESPONSE, request=request) + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path='/v1/orders', method='GET') def successful_order(url, request): return response(200, GET_ORDER_RESPONSE, request=request) + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path=r'/v1/orders', method='DELETE') def cancelled_order(url, request): @@ -114,6 +112,7 @@ def cancelled_order(url, request): resp['status'] = 'cancelled' return response(200, resp, request=request) + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path='/v1/orders') def error_order(url, request): @@ -121,29 +120,35 @@ def error_order(url, request): resp['status'] = 'error' return response(200, resp, request=request) + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path='/v1/orders', method='GET') def connection_error(url, request): raise requests.ConnectionError('test msg') + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path='/v1/orders', method='GET') def http_error(url, request): error_payload = {'error': {'status': 400, 'type': 'Bad request', 'value': 'error'}} return response(400, error_payload, request=request) + @remember_called @urlmatch(scheme='https', netloc='api.online.emspay.eu', path='/v1/orders', method='GET') def invalid_json(url, request): return response(200, '{', request=request) + @pytest.fixture def keyware(): - return Payment({ - 'normal_return_url': RETURN_URL, - 'automatic_return_url': WEBHOOK_URL, - 'api_key': API_KEY, - }) + return Payment( + { + 'normal_return_url': RETURN_URL, + 'automatic_return_url': WEBHOOK_URL, + 'api_key': API_KEY, + } + ) @with_httmock(add_order) diff --git a/tests/test_mollie.py b/tests/test_mollie.py index 769b2ab..fb9e41c 100644 --- a/tests/test_mollie.py +++ b/tests/test_mollie.py @@ -36,10 +36,7 @@ POST_PAYMENTS_RESPONSE = { "id": PAYMENT_ID, "mode": "test", "createdAt": "2018-03-20T09:13:37+00:00", - "amount": { - "value": "3.50", - "currency": "EUR" - }, + "amount": {"value": "3.50", "currency": "EUR"}, "description": "Payment #12345", "method": "null", "status": "open", @@ -51,25 +48,16 @@ POST_PAYMENTS_RESPONSE = { "_links": { "checkout": { "href": "https://www.mollie.com/payscreen/select-method/7UhSN1zuXS", - "type": "text/html" + "type": "text/html", }, - } + }, } GET_PAYMENTS_RESPONSE = { - "amount": { - "currency": "EUR", - "value": "3.50" - }, - "amountRefunded": { - "currency": "EUR", - "value": "0.00" - }, - "amountRemaining": { - "currency": "EUR", - "value": "3.50" - }, + "amount": {"currency": "EUR", "value": "3.50"}, + "amountRefunded": {"currency": "EUR", "value": "0.00"}, + "amountRemaining": {"currency": "EUR", "value": "3.50"}, "countryCode": "FR", "createdAt": "2020-05-06T13:04:26+00:00", "description": "Publik", @@ -80,14 +68,10 @@ GET_PAYMENTS_RESPONSE = { "cardLabel": "Mastercard", "cardNumber": "6787", "cardSecurity": "normal", - "feeRegion": "other" + "feeRegion": "other", }, "id": PAYMENT_ID, - "metadata": { - "email": "test@entrouvert.com", - "first_name": "test", - "last_name": "test" - }, + "metadata": {"email": "test@entrouvert.com", "first_name": "test", "last_name": "test"}, "isCancelable": True, "method": "creditcard", "mode": "test", @@ -96,12 +80,9 @@ GET_PAYMENTS_RESPONSE = { "redirectUrl": "https://localhost/lingo/return-payment-backend/3/MTAw.1jWJis.6TbbjwSEurag6v4Z2VCheISBFjw/", "resource": "payment", "sequenceType": "oneoff", - "settlementAmount": { - "currency": "EUR", - "value": "3.50" - }, + "settlementAmount": {"currency": "EUR", "value": "3.50"}, "status": "paid", - "webhookUrl": "https://localhost/lingo/callback-payment-backend/3/" + "webhookUrl": "https://localhost/lingo/callback-payment-backend/3/", } @@ -174,11 +155,13 @@ def invalid_json(url, request): @pytest.fixture def mollie(): - return Payment({ - 'normal_return_url': RETURN_URL, - 'automatic_return_url': WEBHOOK_URL, - 'api_key': API_KEY, - }) + return Payment( + { + 'normal_return_url': RETURN_URL, + 'automatic_return_url': WEBHOOK_URL, + 'api_key': API_KEY, + } + ) @with_httmock(add_payment) @@ -216,8 +199,9 @@ def test_mollie_response(mollie): @with_httmock(successful_payment) def test_mollie_response_on_redirect(mollie): - payment_response = mollie.response(query_string=None, redirect=True, order_id_hint=PAYMENT_ID, - order_status_hint=0) + payment_response = mollie.response( + query_string=None, redirect=True, order_id_hint=PAYMENT_ID, order_status_hint=0 + ) assert payment_response.result == eopayment.PAID request = successful_payment.call['requests'][0] @@ -225,8 +209,9 @@ def test_mollie_response_on_redirect(mollie): def test_mollie_response_on_redirect_final_status(mollie): - payment_response = mollie.response(query_string=None, redirect=True, order_id_hint=PAYMENT_ID, - order_status_hint=eopayment.PAID) + payment_response = mollie.response( + query_string=None, redirect=True, order_id_hint=PAYMENT_ID, order_status_hint=eopayment.PAID + ) assert payment_response.result == eopayment.PAID assert payment_response.order_id == PAYMENT_ID diff --git a/tests/test_ogone.py b/tests/test_ogone.py index 18460c2..c797f3d 100644 --- a/tests/test_ogone.py +++ b/tests/test_ogone.py @@ -33,7 +33,7 @@ def params(request): 'pspid': PSPID, 'sha_in': 'sécret', 'sha_out': 'sécret', - 'automatic_return_url': 'http://example.com/autömatic_réturn_url' + 'automatic_return_url': 'http://example.com/autömatic_réturn_url', } encoding = request.param if encoding: @@ -45,10 +45,7 @@ def test_request(params): ogone_backend = eopayment.Payment('ogone', params) amount = '42.42' order_id = 'my ordér' - reference, kind, what = ogone_backend.request( - amount=amount, - orderid=order_id, - email='foo@example.com') + reference, kind, what = ogone_backend.request(amount=amount, orderid=order_id, email='foo@example.com') assert len(reference) == 32 root = ET.fromstring(str(what)) assert root.tag == 'form' @@ -76,12 +73,18 @@ def test_request(params): def test_response(params): ogone_backend = eopayment.Payment('ogone', params) order_id = 'myorder' - data = {'orderid': 'myorder', 'status': '9', 'payid': '3011229363', - 'cn': 'Usér', 'ncerror': '0', - 'trxdate': '10/24/16', 'acceptance': 'test123', - 'currency': 'eur', 'amount': '7.5'} - data['shasign'] = ogone_backend.backend.sha_sign_out( - data, encoding=params.get('encoding', 'iso-8859-1')) + data = { + 'orderid': 'myorder', + 'status': '9', + 'payid': '3011229363', + 'cn': 'Usér', + 'ncerror': '0', + 'trxdate': '10/24/16', + 'acceptance': 'test123', + 'currency': 'eur', + 'amount': '7.5', + } + data['shasign'] = ogone_backend.backend.sha_sign_out(data, encoding=params.get('encoding', 'iso-8859-1')) # uniformize to utf-8 first for k in data: data[k] = eopayment.common.force_byte(data[k], encoding=params.get('encoding', 'iso-8859-1')) @@ -96,7 +99,7 @@ def test_iso_8859_1_response(): 'pspid': PSPID, 'sha_in': 'sécret', 'sha_out': 'sécret', - 'automatic_return_url': 'http://example.com/autömatic_réturn_url' + 'automatic_return_url': 'http://example.com/autömatic_réturn_url', } ogone_backend = eopayment.Payment('ogone', params) order_id = 'lRXK4Rl1N2yIR3R5z7Kc' diff --git a/tests/test_paybox.py b/tests/test_paybox.py index 79bbf0b..98ef74f 100644 --- a/tests/test_paybox.py +++ b/tests/test_paybox.py @@ -45,25 +45,31 @@ BACKEND_PARAMS = { class PayboxTests(TestCase): - def test_sign(self): - key = (b'0123456789ABCDEF0123456789ABCDEF0123456789' - b'ABCDEF0123456789ABCDEF0123456789ABCDEF0123' - b'456789ABCDEF0123456789ABCDEF0123456789ABCD' - b'EF') + key = ( + b'0123456789ABCDEF0123456789ABCDEF0123456789' + b'ABCDEF0123456789ABCDEF0123456789ABCDEF0123' + b'456789ABCDEF0123456789ABCDEF0123456789ABCD' + b'EF' + ) key = codecs.decode(key, 'hex') - d = dict(paybox.sign([ - ['PBX_SITE', '12345678'], - ['PBX_RANG', '32'], - ['PBX_IDENTIFIANT', '12345678'], - ['PBX_TOTAL', '999'], - ['PBX_DEVISE', '978'], - ['PBX_CMD', 'appel à Paybox'], - ['PBX_PORTEUR', 'test@paybox.com'], - ['PBX_RETOUR', 'Mt:M;Ref:R;Auto:A;Erreur:E'], - ['PBX_HASH', 'SHA512'], - ['PBX_TIME', '2015-06-08T16:21:16+02:00'], - ], key)) + d = dict( + paybox.sign( + [ + ['PBX_SITE', '12345678'], + ['PBX_RANG', '32'], + ['PBX_IDENTIFIANT', '12345678'], + ['PBX_TOTAL', '999'], + ['PBX_DEVISE', '978'], + ['PBX_CMD', 'appel à Paybox'], + ['PBX_PORTEUR', 'test@paybox.com'], + ['PBX_RETOUR', 'Mt:M;Ref:R;Auto:A;Erreur:E'], + ['PBX_HASH', 'SHA512'], + ['PBX_TIME', '2015-06-08T16:21:16+02:00'], + ], + key, + ) + ) result = ( '7E74D8E9A0DBB65AAE51C5C50C2668FD98FC99AED' 'F18244BB1935F602B6C2E953B61FD84364F34FDB8' @@ -81,8 +87,13 @@ class PayboxTests(TestCase): transaction = '1234' amount = '19.99' transaction_id, kind, what = backend.request( - Decimal(amount), email=email, orderid=order_id, - transaction_id=transaction, time=time, manual_validation=False) + Decimal(amount), + email=email, + orderid=order_id, + transaction_id=transaction, + time=time, + manual_validation=False, + ) self.assertEqual(kind, eopayment.FORM) self.assertEqual(transaction_id, '%s!%s' % (transaction, order_id)) root = ET.fromstring(str(what)) @@ -111,7 +122,7 @@ class PayboxTests(TestCase): ), 'PBX_ARCHIVAGE': '20160216', 'PBX_REPONDRE_A': 'http://example.com/callback', - 'PBX_AUTOSEULE': 'N' + 'PBX_AUTOSEULE': 'N', } form_params = {} @@ -137,12 +148,13 @@ class PayboxTests(TestCase): params['capture_day'] = capture_day backend = eopayment.Payment('paybox', params) transaction_id, kind, what = backend.request( - Decimal(amount), email=email, orderid=order_id, - transaction_id=transaction, time=time) + Decimal(amount), email=email, orderid=order_id, transaction_id=transaction, time=time + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertIn('PBX_DIFF', form_params) self.assertEqual(form_params['PBX_DIFF'], '07') @@ -150,13 +162,18 @@ class PayboxTests(TestCase): params = BACKEND_PARAMS.copy() backend = eopayment.Payment('paybox', params) transaction_id, kind, what = backend.request( - Decimal(amount), email=email, orderid=order_id, - transaction_id=transaction, time=time, capture_day='2') + Decimal(amount), + email=email, + orderid=order_id, + transaction_id=transaction, + time=time, + capture_day='2', + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root - if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertIn('PBX_DIFF', form_params) self.assertEqual(form_params['PBX_DIFF'], '02') @@ -166,13 +183,18 @@ class PayboxTests(TestCase): params['capture_day'] = '7' backend = eopayment.Payment('paybox', params) transaction_id, kind, what = backend.request( - Decimal(amount), email=email, orderid=order_id, - transaction_id=transaction, time=time, capture_day='2') + Decimal(amount), + email=email, + orderid=order_id, + transaction_id=transaction, + time=time, + capture_day='2', + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root - if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertIn('PBX_DIFF', form_params) self.assertEqual(form_params['PBX_DIFF'], '02') @@ -187,12 +209,13 @@ class PayboxTests(TestCase): params['capture_mode'] = 'AUTHOR_CAPTURE' backend = eopayment.Payment('paybox', params) transaction_id, kind, what = backend.request( - Decimal(amount), email=email, orderid=order_id, - transaction_id=transaction, time=time) + Decimal(amount), email=email, orderid=order_id, transaction_id=transaction, time=time + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertEqual(form_params['PBX_AUTOSEULE'], 'O') def test_response(self): @@ -206,7 +229,8 @@ class PayboxTests(TestCase): 'code_autorisation': 'A', 'erreur': '00000', 'date_transaction': '20200101', - 'heure_transaction': '01:01:01'} + 'heure_transaction': '01:01:01', + } response = backend.response(urllib.urlencode(data)) self.assertEqual(response.order_id, reference) assert not response.signed @@ -231,16 +255,18 @@ class PayboxTests(TestCase): '&SITE=1999888&RANG=32&AUTORISATION=XXXXXX&CODEREPONSE=00000' '&COMMENTAIRE=Demande traitée avec succès&REFABONNE=&PORTEUR=' ) - backend_expected_response = {"CODEREPONSE": "00000", - "RANG": "32", - "AUTORISATION": "XXXXXX", - "NUMTRANS": "0013989865", - "PORTEUR": "", - "COMMENTAIRE": "Demande traitée avec succès", - "SITE": "1999888", - "NUMAPPEL": "0030378572", - "REFABONNE": "", - "NUMQUESTION": "0013989862"} + backend_expected_response = { + "CODEREPONSE": "00000", + "RANG": "32", + "AUTORISATION": "XXXXXX", + "NUMTRANS": "0013989865", + "PORTEUR": "", + "COMMENTAIRE": "Demande traitée avec succès", + "SITE": "1999888", + "NUMAPPEL": "0030378572", + "REFABONNE": "", + "NUMQUESTION": "0013989862", + } with mock.patch('eopayment.paybox.requests.post') as requests_post: response = mock.Mock(status_code=200, text=backend_raw_response) @@ -263,7 +289,7 @@ class PayboxTests(TestCase): 'REFERENCE': '830657461681', 'RANG': backend.backend.rang, 'SITE': backend.backend.site, - 'DEVISE': backend.backend.devise + 'DEVISE': backend.backend.devise, } self.assertEqual(params_sent, expected_params) self.assertEqual(backend_response, backend_expected_response) @@ -285,7 +311,8 @@ class PayboxTests(TestCase): 'Transaction non trouvée', getattr(backend, operation_name), Decimal('10'), - bank_data) + bank_data, + ) def test_validate_payment(self): params = BACKEND_PARAMS.copy() @@ -294,7 +321,7 @@ class PayboxTests(TestCase): bank_data = { 'numero_transaction': ['13957441'], 'numero_appel': ['30310733'], - 'reference': ['830657461681'] + 'reference': ['830657461681'], } backend_raw_response = ( 'NUMTRANS=0013989865&NUMAPPEL=0030378572&NUMQUESTION=0013989862' @@ -331,15 +358,12 @@ FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4=''' backend = eopayment.Payment('paybox', params) transaction_id, kind, what = backend.request( - Decimal(amount), - email=email, - orderid=order_id, - transaction_id=transaction, - time=time) + Decimal(amount), email=email, orderid=order_id, transaction_id=transaction, time=time + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root - if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertIn('PBX_AUTOSEULE', form_params) self.assertEqual(form_params['PBX_AUTOSEULE'], 'N') @@ -349,11 +373,12 @@ FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4=''' orderid=order_id, transaction_id=transaction, time=time, - manual_validation=True) + manual_validation=True, + ) root = ET.fromstring(str(what)) form_params = { - node.attrib['name']: node.attrib['value'] for node in root - if node.attrib['type'] == 'hidden'} + node.attrib['name']: node.attrib['value'] for node in root if node.attrib['type'] == 'hidden' + } self.assertIn('PBX_AUTOSEULE', form_params) self.assertEqual(form_params['PBX_AUTOSEULE'], 'O') @@ -369,17 +394,21 @@ FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4=''' 'erreur': '00000', 'date_transaction': '20200101', 'heure_transaction': '01:01:01', - 'signature': 'a'} + 'signature': 'a', + } with pytest.raises(eopayment.ResponseError, match='invalid signature'): backend.response(urllib.urlencode(data)) -@pytest.mark.parametrize('name,value,result', [ - ('shared_secret', '1f', True), - ('shared_secret', '1fxx', False), - ('shared_secret', '1fa', False), - ('shared_secret', '1fa2', True), -]) +@pytest.mark.parametrize( + 'name,value,result', + [ + ('shared_secret', '1f', True), + ('shared_secret', '1fxx', False), + ('shared_secret', '1fa', False), + ('shared_secret', '1fa2', True), + ], +) def test_param_validation(name, value, result): for param in paybox.Payment.description['parameters']: if param['name'] == name: diff --git a/tests/test_payfip_ws.py b/tests/test_payfip_ws.py index e5d4952..87c29f0 100644 --- a/tests/test_payfip_ws.py +++ b/tests/test_payfip_ws.py @@ -84,8 +84,7 @@ def history(history_name, request, zeep_history_plugin): yield None history_path = 'tests/data/payfip-%s.json' % history_name d = [ - (xmlindent(exchange['sent']['envelope']), - xmlindent(exchange['received']['envelope'])) + (xmlindent(exchange['sent']['envelope']), xmlindent(exchange['received']['envelope'])) for exchange in zeep_history_plugin._buffer ] content = json.dumps(d) @@ -104,17 +103,21 @@ def get_idop(): def backend(request): with mock.patch('eopayment.payfip_ws.Payment._generate_refdet') as _generate_refdet: _generate_refdet.return_value = REFDET_GEN - yield eopayment.Payment('payfip_ws', { - 'numcli': '090909', - 'automatic_return_url': NOTIF_URL, - 'normal_return_url': REDIRECT_URL, - }) + yield eopayment.Payment( + 'payfip_ws', + { + 'numcli': '090909', + 'automatic_return_url': NOTIF_URL, + 'normal_return_url': REDIRECT_URL, + }, + ) @httmock.urlmatch() def raise_on_request(url, request): # ensure we do not access network from requests.exceptions import RequestException + raise RequestException('huhu') @@ -126,8 +129,10 @@ def zeep_history_plugin(): @pytest.fixture def payfip(zeep_history_plugin): with httmock.HTTMock(raise_on_request): - payfip = PayFiP(wsdl_url='./eopayment/resource/PaiementSecuriseService.wsdl', - zeep_client_kwargs={'plugins': [zeep_history_plugin]}) + payfip = PayFiP( + wsdl_url='./eopayment/resource/PaiementSecuriseService.wsdl', + zeep_client_kwargs={'plugins': [zeep_history_plugin]}, + ) yield payfip @@ -141,8 +146,10 @@ def set_history_name(name): def decorator(func): func.history_name = name return func + return decorator + # pytestmark = pytest.mark.update_data @@ -162,7 +169,8 @@ def test_get_idop_ok(history, payfip): objet='coucou', url_notification=NOTIF_URL, url_redirect=REDIRECT_URL, - saisie='T') + saisie='T', + ) assert result == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103' @@ -177,7 +185,8 @@ def test_get_idop_refdet_error(history, payfip): objet='coucou', url_notification='https://notif.payfip.example.com/', url_redirect='https://redirect.payfip.example.com/', - saisie='T') + saisie='T', + ) def test_get_idop_adresse_mel_incorrect(payfip, payfip_history): @@ -191,7 +200,8 @@ def test_get_idop_adresse_mel_incorrect(payfip, payfip_history): objet='coucou', url_notification='https://notif.payfip.example.com/', url_redirect='https://redirect.payfip.example.com/', - saisie='T') + saisie='T', + ) def test_get_info_paiement_ok(history, payfip): @@ -208,7 +218,7 @@ def test_get_info_paiement_ok(history, payfip): 'objet': 'coucou', 'refdet': 'EFEFAEFG', 'resultrans': 'V', - 'saisie': 'T' + 'saisie': 'T', } @@ -228,14 +238,18 @@ def test_P1_and_payment_status(history, backend): @set_history_name('test_get_info_paiement_P1') def test_P1_and_payment_status_utc_aware_now(history, backend): utc_now = datetime.datetime.now(pytz.utc) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now + ) assert response.result == eopayment.EXPIRED @set_history_name('test_get_info_paiement_P1') def test_P1_and_payment_status_utc_naive_now(history, backend): now = datetime.datetime.now() - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.EXPIRED @@ -243,7 +257,9 @@ def test_P1_and_payment_status_utc_naive_now(history, backend): def test_P1_and_payment_status_utc_aware_now_later(history, backend, freezer): utc_now = datetime.datetime.now(pytz.utc) freezer.move_to(datetime.timedelta(minutes=25)) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now + ) assert response.result == eopayment.EXPIRED @@ -251,7 +267,9 @@ def test_P1_and_payment_status_utc_aware_now_later(history, backend, freezer): def test_P1_and_payment_status_utc_naive_now_later(history, payfip, backend, freezer): now = datetime.datetime.now() freezer.move_to(datetime.timedelta(minutes=25)) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.EXPIRED @@ -270,14 +288,18 @@ def test_P5_and_payment_status(history, payfip, backend, freezer): @set_history_name('test_get_info_paiement_P5') def test_P5_and_payment_status_utc_aware_now(history, payfip, backend, freezer): utc_now = datetime.datetime.now(pytz.utc) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now + ) assert response.result == eopayment.WAITING @set_history_name('test_get_info_paiement_P5') def test_P5_and_payment_status_utc_naive_now(history, payfip, backend, freezer): now = datetime.datetime.now() - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.WAITING @@ -285,7 +307,9 @@ def test_P5_and_payment_status_utc_naive_now(history, payfip, backend, freezer): def test_P5_and_payment_status_utc_aware_now_later(history, payfip, backend, freezer): utc_now = datetime.datetime.now(pytz.utc) freezer.move_to(datetime.timedelta(minutes=25)) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=utc_now + ) assert response.result == eopayment.EXPIRED @@ -293,7 +317,9 @@ def test_P5_and_payment_status_utc_aware_now_later(history, payfip, backend, fre def test_P5_and_payment_status_utc_naive_now_later(history, payfip, backend, freezer): now = datetime.datetime.now() freezer.move_to(datetime.timedelta(minutes=25)) - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.EXPIRED @@ -302,7 +328,8 @@ def test_payment_ok(history, payfip, backend): amount='10.00', email=MEL, # make test deterministic - refdet='201912261758460053903194') + refdet='201912261758460053903194', + ) assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103' assert kind == eopayment.URL @@ -313,14 +340,17 @@ def test_payment_ok(history, payfip, backend): assert response.bank_status == 'paid CB' assert response.order_id == payment_id assert response.transaction_id == ( - '201912261758460053903194 cc0cb210-1cd4-11ea-8cca-0213ad91a103 112233445566-tip') + '201912261758460053903194 cc0cb210-1cd4-11ea-8cca-0213ad91a103 112233445566-tip' + ) @set_history_name('test_payment_ok') def test_payment_status_ok(history, backend, freezer): history.counter = 1 # only the response now = datetime.datetime.now() - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.PAID @@ -329,7 +359,8 @@ def test_payment_denied(history, backend): amount='10.00', email=MEL, # make test deterministic - refdet='201912261758460053903194') + refdet='201912261758460053903194', + ) assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103' assert kind == eopayment.URL @@ -346,7 +377,9 @@ def test_payment_denied(history, backend): def test_payment_status_denied(history, backend, freezer): history.counter = 1 # only the response now = datetime.datetime.now() - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.DENIED @@ -355,7 +388,8 @@ def test_payment_cancelled(history, backend): amount='10.00', email=MEL, # make test deterministic - refdet='201912261758460053903194') + refdet='201912261758460053903194', + ) assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103' assert kind == eopayment.URL @@ -372,7 +406,9 @@ def test_payment_cancelled(history, backend): def test_payment_status_cancelled(history, backend, freezer): history.counter = 1 # only the response now = datetime.datetime.now() - response = backend.payment_status(transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now) + response = backend.payment_status( + transaction_id='cc0cb210-1cd4-11ea-8cca-0213ad91a103', transaction_date=now + ) assert response.result == eopayment.CANCELLED @@ -390,7 +426,8 @@ def test_refdet_exer(get_idop, backend): email=MEL, # make test deterministic exer=EXER, - refdet=REFDET) + refdet=REFDET, + ) assert payment_id == 'idop-1234' kwargs = get_idop.call_args[1] @@ -416,7 +453,8 @@ def test_transaction_id_orderid_subject(get_idop, backend): exer=EXER, transaction_id='TR12345', orderid='F20190003', - subject='Précompte famille #1234') + subject='Précompte famille #1234', + ) assert payment_id == 'idop-1234' kwargs = get_idop.call_args[1] @@ -442,7 +480,8 @@ def test_invalid_transaction_id_valid_orderid(get_idop, backend): exer=EXER, transaction_id='TR-12345', orderid='F20190003', - subject='Précompte famille #1234') + subject='Précompte famille #1234', + ) assert payment_id == 'idop-1234' kwargs = get_idop.call_args[1] @@ -468,7 +507,8 @@ def test_invalid_transaction_id_invalid_orderid(get_idop, backend): exer=EXER, transaction_id='TR-12345', orderid='F/20190003', - subject='Précompte famille #1234') + subject='Précompte famille #1234', + ) assert payment_id == 'idop-1234' kwargs = get_idop.call_args[1] @@ -505,4 +545,5 @@ def test_request_error(payfip, backend): amount='10.00', email=MEL, # make test deterministic - refdet='201912261758460053903194') + refdet='201912261758460053903194', + ) diff --git a/tests/test_saga.py b/tests/test_saga.py index 62b651c..055d150 100644 --- a/tests/test_saga.py +++ b/tests/test_saga.py @@ -42,13 +42,20 @@ def saga(record_http_session): @pytest.fixture def backend_factory(saga, target_url): def factory(**kwargs): - return eopayment.Payment('saga', dict({ - 'base_url': target_url, - 'num_service': '868', - 'compte': '70688', - 'automatic_return_url': 'https://automatic.notif.url/automatic/', - 'normal_return_url': 'https://normal.notif.url/normal/', - }, **kwargs)) + return eopayment.Payment( + 'saga', + dict( + { + 'base_url': target_url, + 'num_service': '868', + 'compte': '70688', + 'automatic_return_url': 'https://automatic.notif.url/automatic/', + 'normal_return_url': 'https://normal.notif.url/normal/', + }, + **kwargs, + ), + ) + return factory @@ -56,19 +63,19 @@ def test_error_parametrage(backend_factory): payment = backend_factory(num_service='1', compte='1') with pytest.raises(eopayment.PaymentException, match='Impossible de déterminer le paramétrage'): transaction_id, kind, url = payment.request( - amount='10.00', - email='john.doe@example.com', - subject='Réservation concert XYZ numéro 1234') + amount='10.00', email='john.doe@example.com', subject='Réservation concert XYZ numéro 1234' + ) def test_request(backend_factory): transaction_id, kind, url = backend_factory().request( - amount='10.00', - email='john.doe@example.com', - subject='Réservation concert XYZ numéro 1234') + amount='10.00', email='john.doe@example.com', subject='Réservation concert XYZ numéro 1234' + ) assert transaction_id == '347b2060-1a37-11eb-af92-0213ad91a103' assert kind == eopayment.URL - assert url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=347b2060-1a37-11eb-af92-0213ad91a103' + assert ( + url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=347b2060-1a37-11eb-af92-0213ad91a103' + ) def test_response(backend_factory): @@ -81,7 +88,7 @@ def test_response(backend_factory): 'montant': '10.00', 'num_service': '868', 'numcp': '70688', - 'numcpt_lib_ecriture': 'COUCOU' + 'numcpt_lib_ecriture': 'COUCOU', }, 'bank_status': 'paid', 'order_id': '28b52f40-1ace-11eb-8ce3-0213ad91a104', @@ -94,4 +101,3 @@ def test_response(backend_factory): } # Check bank_data is JSON serializable json.dumps(response.bank_data) - diff --git a/tests/test_sips2.py b/tests/test_sips2.py index a982f79..f5386bd 100644 --- a/tests/test_sips2.py +++ b/tests/test_sips2.py @@ -21,8 +21,7 @@ import pytest def test_build_request(): backend = eopayment.Payment('sips2', {}) - transaction, f, form = backend.request(amount='12', last_name='Foo', - first_name='Félix000000') + transaction, f, form = backend.request(amount='12', last_name='Foo', first_name='Félix000000') data = [f for f in form.fields if f['name'] == 'Data'] assert 'lix000000' not in data[0]['value'] diff --git a/tests/test_systempayv2.py b/tests/test_systempayv2.py index dc91afd..af1d46a 100644 --- a/tests/test_systempayv2.py +++ b/tests/test_systempayv2.py @@ -21,8 +21,7 @@ import pytest from six.moves.urllib import parse as urlparse import eopayment -from eopayment.systempayv2 import Payment, VADS_CUST_FIRST_NAME, \ - VADS_CUST_LAST_NAME, PAID +from eopayment.systempayv2 import Payment, VADS_CUST_FIRST_NAME, VADS_CUST_LAST_NAME, PAID from eopayment import ResponseError PARAMS = { @@ -30,7 +29,7 @@ PARAMS = { 'vads_site_id': '12345678', 'vads_ctx_mode': 'TEST', 'vads_trans_date': '20090501193530', - 'signature_algo': 'sha1' + 'signature_algo': 'sha1', } @@ -48,12 +47,7 @@ def get_field(form, field_name): def test_systempayv2(caplog): caplog.set_level(0) p = Payment(PARAMS) - data = { - 'amount': 15.24, - 'orderid': '654321', - 'first_name': 'Jean Michél', - 'last_name': 'Mihaï' - } + data = {'amount': 15.24, 'orderid': '654321', 'first_name': 'Jean Michél', 'last_name': 'Mihaï'} qs = ( 'vads_version=V2&vads_page_action=PAYMENT&vads_action_mode=INTERACTIV' 'E&vads_payment_config=SINGLE&vads_site_id=12345678&vads_ctx_mode=TES' @@ -71,16 +65,18 @@ def test_systempayv2(caplog): if field['name'] in (VADS_CUST_FIRST_NAME, VADS_CUST_LAST_NAME): assert field['value'] in ('Jean Michél', 'Mihaï') - response_qs = 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' \ - '&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' \ - '&vads_result=00' \ - '&vads_card_number=497010XXXXXX0000' \ - '&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' \ - '&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' \ - '&vads_site_id=70168983&vads_trans_date=20161013101355' \ - '&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' \ - '&vads_effective_creation_date=20200330162530' \ - '&signature=c17fab393f94dc027dc029510c85d5fc46c4710f' + response_qs = ( + 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' + '&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' + '&vads_result=00' + '&vads_card_number=497010XXXXXX0000' + '&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' + '&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' + '&vads_site_id=70168983&vads_trans_date=20161013101355' + '&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' + '&vads_effective_creation_date=20200330162530' + '&signature=c17fab393f94dc027dc029510c85d5fc46c4710f' + ) response = p.response(response_qs) assert response.result == PAID assert response.signed @@ -90,16 +86,18 @@ def test_systempayv2(caplog): PARAMS['signature_algo'] = 'hmac_sha256' p = Payment(PARAMS) assert p.signature(qs) == 'aHrJ7IzSGFa4pcYA8kh99+M/xBzoQ4Odnu3f4BUrpIA=' - response_qs = 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' \ - '&vads_result=00' \ - '&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' \ - '&vads_card_number=497010XXXXXX0000' \ - '&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' \ - '&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' \ - '&vads_site_id=70168983&vads_trans_date=20161013101355' \ - '&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' \ - '&vads_effective_creation_date=20200330162530' \ - '&signature=Wbz3bP6R6wDvAwb2HnSiH9%2FiUUoRVCxK7mdLtCMz8Xw%3D' + response_qs = ( + 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' + '&vads_result=00' + '&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' + '&vads_card_number=497010XXXXXX0000' + '&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' + '&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' + '&vads_site_id=70168983&vads_trans_date=20161013101355' + '&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' + '&vads_effective_creation_date=20200330162530' + '&signature=Wbz3bP6R6wDvAwb2HnSiH9%2FiUUoRVCxK7mdLtCMz8Xw%3D' + ) response = p.response(response_qs) assert response.result == PAID assert response.signed @@ -115,10 +113,7 @@ def test_systempayv2_deferred_payment(): 'vads_site_id': '12345678', 'vads_ctx_mode': 'TEST', } - default_data = { - 'amount': 15.24, 'orderid': '654321', 'first_name': 'John', - 'last_name': 'Doe' - } + default_data = {'amount': 15.24, 'orderid': '654321', 'first_name': 'John', 'last_name': 'Doe'} # default vads_capture_delay used params = default_params.copy() @@ -144,7 +139,7 @@ def test_systempayv2_deferred_payment(): params['vads_capture_delay'] = 1 p = eopayment.Payment('systempayv2', params) data = default_data.copy() - data['capture_date'] = (datetime.now().date() + timedelta(days=4)) + data['capture_date'] = datetime.now().date() + timedelta(days=4) transaction_id, f, form = p.request(**data) assert get_field(form, 'vads_capture_delay')['value'] == '4' @@ -155,10 +150,7 @@ def test_manual_validation(): 'vads_site_id': '12345678', 'vads_ctx_mode': 'TEST', } - data = { - 'amount': 15.24, 'orderid': '654321', 'first_name': 'John', - 'last_name': 'Doe' - } + data = {'amount': 15.24, 'orderid': '654321', 'first_name': 'John', 'last_name': 'Doe'} backend = eopayment.Payment('systempayv2', params) transaction_id, f, form = backend.request(**data.copy()) @@ -172,8 +164,10 @@ def test_manual_validation(): transaction_id, f, form = backend.request(**data.copy()) assert get_field(form, 'vads_validation_mode')['value'] == '' + FIXED_TRANSACTION_ID = '1234' + def test_transaction_id_request(backend): transaction_id, kind, form = backend.request(10.0, transaction_id=FIXED_TRANSACTION_ID) assert transaction_id == FIXED_TRANSACTION_ID diff --git a/tests/test_tipi.py b/tests/test_tipi.py index 84cd906..a92d92e 100644 --- a/tests/test_tipi.py +++ b/tests/test_tipi.py @@ -34,7 +34,8 @@ def test_tipi(): objet='tout a fait', email='info@entrouvert.com', urlcl='http://example.com/tipi/test', - saisie='T') + saisie='T', + ) assert eopayment.tipi.Payment.REFDET_RE.match(payment_id) is not None parsed_qs = parse_qs(urlparse(url).query) assert parsed_qs['objet'][0].startswith('tout a fait') @@ -47,7 +48,8 @@ def test_tipi(): response = p.response( 'objet=tout+a+fait&montant=12312&saisie=T&mel=info%40entrouvert.com' - '&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P') + '&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P' + ) assert response.signed # ... assert response.order_id == '999900000000999999' assert response.transaction_id == '999900000000999999' @@ -60,10 +62,8 @@ def test_tipi(): def test_tipi_no_orderid_no_refdet(): p = eopayment.Payment('tipi', {'numcli': '12345'}) payment_id, kind, url = p.request( - amount=Decimal('123.12'), - exer=9999, - email='info@entrouvert.com', - saisie='T') + amount=Decimal('123.12'), exer=9999, email='info@entrouvert.com', saisie='T' + ) assert eopayment.tipi.Payment.REFDET_RE.match(payment_id) is not None parsed_qs = parse_qs(urlparse(url).query) assert 'objet' not in parsed_qs @@ -72,15 +72,16 @@ def test_tipi_no_orderid_no_refdet(): assert parsed_qs['mel'] == ['info@entrouvert.com'] assert parsed_qs['numcli'] == ['12345'] assert parsed_qs['exer'] == ['9999'] - assert parsed_qs['refdet'][0].startswith(datetime.datetime.now(pytz.timezone('Europe/Paris')).strftime('%Y%m%d')) + assert parsed_qs['refdet'][0].startswith( + datetime.datetime.now(pytz.timezone('Europe/Paris')).strftime('%Y%m%d') + ) def test_tipi_orderid_refdef_compatible(): p = eopayment.Payment('tipi', {'numcli': '12345', 'saisie': 'A'}) payment_id, kind, url = p.request( - amount=Decimal('123.12'), - email='info@entrouvert.com', - orderid='F121212') + amount=Decimal('123.12'), email='info@entrouvert.com', orderid='F121212' + ) assert eopayment.tipi.Payment.REFDET_RE.match(payment_id) expected_url = urlparse(eopayment.tipi.TIPI_URL) parsed_url = urlparse(url) @@ -98,10 +99,8 @@ def test_tipi_orderid_refdef_compatible(): def test_tipi_orderid_not_refdef_compatible(): p = eopayment.Payment('tipi', {'numcli': '12345', 'saisie': 'A'}) payment_id, kind, url = p.request( - amount=Decimal('123.12'), - email='info@entrouvert.com', - objet='coucou', - orderid='F12-12-12') + amount=Decimal('123.12'), email='info@entrouvert.com', objet='coucou', orderid='F12-12-12' + ) assert eopayment.tipi.Payment.REFDET_RE.match(payment_id) is not None expected_url = urlparse(eopayment.tipi.TIPI_URL) parsed_url = urlparse(url)