diff --git a/eopayment/__init__.py b/eopayment/__init__.py
index 17c9038..11dc254 100644
--- a/eopayment/__init__.py
+++ b/eopayment/__init__.py
@@ -1,18 +1,35 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
import datetime
import importlib
import logging
import pytz
+from .common import ( # noqa: F401
+ URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
+ CANCELED, CANCELLED, ERROR, WAITING, force_text,
+ ResponseError,
+)
-from .common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
- CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text,
- PaymentException)
-
-__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS',
-'SYSTEMPAY', 'SPPLUS', 'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED',
-'PAID', 'DENIED', 'CANCELED', 'CANCELLED', 'ERROR', 'WAITING', 'get_backends', 'PAYFIP_WS']
+__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS', 'SYSTEMPAY', 'SPPLUS',
+ 'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED', 'PAID',
+ 'DENIED', 'CANCELED', 'CANCELLED', 'ERROR', 'WAITING',
+ 'get_backends', 'PAYFIP_WS']
SIPS = 'sips'
SIPS2 = 'sips2'
@@ -27,12 +44,15 @@ PAYFIP_WS = 'payfip_ws'
logger = logging.getLogger(__name__)
+
def get_backend(kind):
'''Resolve a backend name into a module object'''
module = importlib.import_module('.' + kind, package='eopayment')
return module.Payment
-__BACKENDS = [ DUMMY, SIPS, SIPS2, SYSTEMPAY, SPPLUS, OGONE, PAYBOX, PAYZEN, TIPI, PAYFIP_WS ]
+__BACKENDS = [DUMMY, SIPS, SIPS2, SYSTEMPAY, SPPLUS, OGONE, PAYBOX, PAYZEN,
+ TIPI, PAYFIP_WS]
+
def get_backends():
'''Return a dictionnary mapping existing eopayment backends name to their
@@ -44,6 +64,7 @@ def get_backends():
'''
return dict((backend, get_backend(backend)) for backend in __BACKENDS)
+
class Payment(object):
'''
Interface to credit card online payment servers of French banks. The
diff --git a/eopayment/cb.py b/eopayment/cb.py
index 7b0443f..ccd7f69 100644
--- a/eopayment/cb.py
+++ b/eopayment/cb.py
@@ -1,4 +1,19 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
'''Responses codes emitted by EMV Card or 'Carte Bleu' in France'''
diff --git a/eopayment/common.py b/eopayment/common.py
index 66578e7..b79d9d4 100644
--- a/eopayment/common.py
+++ b/eopayment/common.py
@@ -1,3 +1,19 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import os.path
import os
import random
@@ -54,6 +70,7 @@ def force_text(s, encoding='utf-8'):
return six.text_type(s, encoding, 'ignore')
return s
+
def force_byte(s, encoding='utf-8'):
if isinstance(s, bytes):
return s
@@ -144,7 +161,7 @@ class PaymentCommon(object):
try:
fd = os.open(os.path.join(self.PATH, name),
os.O_CREAT | os.O_EXCL)
- except:
+ except Exception:
raise
else:
os.close(fd)
diff --git a/eopayment/dummy.py b/eopayment/dummy.py
index 98c63e0..6a4ede9 100644
--- a/eopayment/dummy.py
+++ b/eopayment/dummy.py
@@ -1,20 +1,46 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import string
import logging
import warnings
-def N_(message): return message
-
from six.moves.urllib.parse import parse_qs, urlencode
-from .common import (PaymentCommon, URL, PaymentResponse, PAID, ERROR, WAITING,
- ResponseError, force_text)
+from .common import (
+ PaymentCommon,
+ PaymentResponse,
+ ResponseError,
+ URL,
+ PAID, ERROR, WAITING,
+ force_text
+)
+
+__all__ = ['Payment']
+
+
+def N_(message):
+ return message
-__all__ = [ 'Payment' ]
SERVICE_URL = 'http://dummy-payment.demo.entrouvert.com/'
ALPHANUM = string.ascii_letters + string.digits
LOGGER = logging.getLogger(__name__)
+
class Payment(PaymentCommon):
'''
Dummy implementation of the payment interface.
@@ -36,59 +62,68 @@ class Payment(PaymentCommon):
per request basis).
'''
description = {
- 'caption': 'Dummy payment backend',
- 'parameters': [
- {
- 'name': 'normal_return_url',
- 'caption': N_('Normal return URL'),
- 'default': '',
- 'required': True,
- },
- {
- 'name': 'automatic_return_url',
- 'caption': N_('Automatic return URL'),
- 'required': False,
- },
- { 'name': 'dummy_service_url',
- 'caption': 'URL of the dummy payment service',
- 'default': SERVICE_URL,
- 'type': str,
- },
- { 'name': 'origin',
- 'caption': 'name of the requesting service, '
- 'to present in the user interface',
- 'type': str,
-
- },
- { 'name': 'siret',
- 'caption': 'dummy siret parameter',
- 'type': str,
- },
- { 'name': 'consider_all_response_signed',
- 'caption': 'All response will be considered as signed '
- '(to test payment locally for example, as you '
- 'cannot received the signed callback)',
- 'type': bool,
- 'default': False,
- },
- { 'name': 'direct_notification_url',
- 'caption': 'direct notification url (replaced by automatic_return_url)',
- 'type': str,
- 'deprecated': True,
- },
- { 'name': 'next_url (replaced by normal_return_url)',
- 'caption': 'Return URL for the user',
- 'type': str,
- 'deprecated': True,
- },
- ],
+ 'caption': 'Dummy payment backend',
+ 'parameters': [
+ {
+ 'name': 'normal_return_url',
+ 'caption': N_('Normal return URL'),
+ 'default': '',
+ 'required': True,
+ },
+ {
+ 'name': 'automatic_return_url',
+ 'caption': N_('Automatic return URL'),
+ 'required': False,
+ },
+ {
+ 'name': 'dummy_service_url',
+ 'caption': 'URL of the dummy payment service',
+ 'default': SERVICE_URL,
+ 'type': str,
+ },
+ {
+ 'name': 'origin',
+ 'caption': 'name of the requesting service, '
+ 'to present in the user interface',
+ 'type': str,
+ },
+ {
+ 'name': 'siret',
+ 'caption': 'dummy siret parameter',
+ 'type': str,
+ },
+ {
+ 'name': 'consider_all_response_signed',
+ 'caption': (
+ 'All response will be considered as signed '
+ '(to test payment locally for example, as you '
+ 'cannot received the signed callback)'
+ ),
+ 'type': bool,
+ 'default': False,
+ },
+ {
+ 'name': 'direct_notification_url',
+ 'caption': 'direct notification url (replaced by automatic_return_url)',
+ 'type': str,
+ 'deprecated': True,
+ },
+ {
+ 'name': 'next_url (replaced by normal_return_url)',
+ 'caption': 'Return URL for the user',
+ 'type': str,
+ 'deprecated': True,
+ },
+ ],
}
def request(self, amount, name=None, address=None, email=None, phone=None,
- orderid=None, info1=None, info2=None, info3=None, next_url=None, **kwargs):
- 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)
+ orderid=None, info1=None, info2=None, info3=None,
+ next_url=None, **kwargs):
+ 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)
transaction_id = self.transaction_id(30, ALPHANUM, 'dummy', self.siret)
normal_return_url = self.normal_return_url
if next_url and not normal_return_url:
@@ -101,16 +136,17 @@ class Payment(PaymentCommon):
"use automatic_return_url", DeprecationWarning)
automatic_return_url = self.direct_notification_url
query = {
- 'transaction_id': transaction_id,
- 'siret': self.siret,
- 'amount': amount,
- 'email': email,
- 'return_url': normal_return_url or '',
- 'direct_notification_url': automatic_return_url or '',
- 'origin': self.origin
+ 'transaction_id': transaction_id,
+ 'siret': self.siret,
+ 'amount': amount,
+ 'email': email,
+ 'return_url': normal_return_url or '',
+ 'direct_notification_url': automatic_return_url or '',
+ 'origin': self.origin
}
- query.update(dict(name=name, address=address, email=email, phone=phone,
- orderid=orderid, info1=info1, info2=info2, info3=info3))
+ query.update(
+ dict(name=name, address=address, email=email, phone=phone,
+ orderid=orderid, info1=info1, info2=info2, info3=info3))
for key in list(query.keys()):
if query[key] is None:
del query[key]
@@ -119,9 +155,9 @@ class Payment(PaymentCommon):
def response(self, query_string, logger=LOGGER, **kwargs):
form = parse_qs(force_text(query_string))
- if not 'transaction_id' in form:
+ if 'transaction_id' not in form:
raise ResponseError('missing transaction_id')
- transaction_id = form.get('transaction_id',[''])[0]
+ transaction_id = form.get('transaction_id', [''])[0]
form[self.BANK_ID] = transaction_id
signed = 'signed' in form
@@ -134,14 +170,15 @@ class Payment(PaymentCommon):
if 'waiting' in form:
result = WAITING
- response = PaymentResponse(result=result,
- signed=signed,
- bank_data=form,
- return_content=content,
- order_id=transaction_id,
- transaction_id=transaction_id,
- bank_status=form.get('reason'),
- test=True)
+ response = PaymentResponse(
+ result=result,
+ signed=signed,
+ bank_data=form,
+ return_content=content,
+ order_id=transaction_id,
+ transaction_id=transaction_id,
+ bank_status=form.get('reason'),
+ test=True)
return response
def validate(self, amount, bank_data, **kwargs):
diff --git a/eopayment/ogone.py b/eopayment/ogone.py
index f2788ec..dc304b3 100644
--- a/eopayment/ogone.py
+++ b/eopayment/ogone.py
@@ -1,14 +1,35 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import hashlib
import string
import six
from six.moves.urllib import parse as urlparse
from decimal import Decimal, ROUND_HALF_UP
-from .common import (PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
- ERROR, Form, DENIED, ACCEPTED, ORDERID_TRANSACTION_SEPARATOR,
- WAITING, ResponseError, force_byte, force_text)
-def N_(message): return message
+from .common import (
+ PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
+ ERROR, Form, DENIED, ACCEPTED, ORDERID_TRANSACTION_SEPARATOR,
+ WAITING, ResponseError, force_byte, force_text
+)
+
+
+def N_(message):
+ return message
ENVIRONMENT_TEST = 'TEST'
ENVIRONMENT_TEST_URL = 'https://secure.ogone.com/ncol/test/orderstandard.asp'
@@ -409,6 +430,7 @@ TRXDATE
VC
""".split()
+
class Payment(PaymentCommon):
# See http://payment-services.ingenico.com/fr/fr/ogone/support/guides/integration%20guides/e-commerce
description = {
@@ -425,33 +447,40 @@ class Payment(PaymentCommon):
'caption': N_('Automatic return URL (ignored, must be set in Ogone backoffice)'),
'required': False,
},
- {'name': 'environment',
+ {
+ 'name': 'environment',
'default': ENVIRONMENT_TEST,
'caption': N_(u'Environnement'),
'choices': ENVIRONMENT,
},
- {'name': 'pspid',
+ {
+ 'name': 'pspid',
'caption': N_(u"Nom d'affiliation dans le système"),
'required': True,
},
- {'name': 'language',
+ {
+ 'name': 'language',
'caption': N_(u'Langage'),
'default': 'fr_FR',
'choices': (('fr_FR', N_('français')),),
},
- {'name': 'hash_algorithm',
+ {
+ 'name': 'hash_algorithm',
'caption': N_(u'Algorithme de hachage'),
'default': 'sha1',
},
- {'name': 'sha_in',
+ {
+ 'name': 'sha_in',
'caption': N_(u'Clé SHA-IN'),
'required': True,
},
- {'name': 'sha_out',
+ {
+ 'name': 'sha_out',
'caption': N_(u'Clé SHA-OUT'),
'required': True,
},
- {'name': 'currency',
+ {
+ 'name': 'currency',
'caption': N_(u'Monnaie'),
'default': 'EUR',
'choices': ('EUR',),
@@ -485,7 +514,7 @@ class Payment(PaymentCommon):
raise NotImplementedError('unknown environment %s' % self.environment)
def request(self, amount, orderid=None, name=None, email=None,
- language=None, description=None, **kwargs):
+ language=None, description=None, **kwargs):
reference = self.transaction_id(20, string.digits + string.ascii_letters)
@@ -493,18 +522,22 @@ class Payment(PaymentCommon):
if orderid:
if len(orderid) > 24:
raise ValueError('orderid length exceeds 25 characters')
- reference = orderid + ORDERID_TRANSACTION_SEPARATOR + self.transaction_id(29-len(orderid), string.digits + string.ascii_letters)
+ reference = (
+ orderid
+ + ORDERID_TRANSACTION_SEPARATOR
+ + self.transaction_id(29 - len(orderid),
+ string.digits + string.ascii_letters))
language = language or self.language
# convertir en centimes
amount = Decimal(amount) * 100
# arrondi comptable francais
amount = amount.quantize(Decimal('1.'), rounding=ROUND_HALF_UP)
params = {
- 'AMOUNT': force_text(amount),
- 'ORDERID': reference,
- 'PSPID': self.pspid,
- 'LANGUAGE': language,
- 'CURRENCY': self.currency,
+ 'AMOUNT': force_text(amount),
+ 'ORDERID': reference,
+ 'PSPID': self.pspid,
+ 'LANGUAGE': language,
+ 'CURRENCY': self.currency,
}
if self.normal_return_url:
params['ACCEPTURL'] = self.normal_return_url
@@ -526,11 +559,11 @@ class Payment(PaymentCommon):
params[key] = force_text(params[key])
url = self.get_request_url()
form = Form(
- url=url,
- method='POST',
- fields=[{'type': 'hidden',
- 'name': key,
- 'value': params[key]} for key in params])
+ url=url,
+ method='POST',
+ fields=[{'type': 'hidden',
+ 'name': key,
+ 'value': params[key]} for key in params])
return reference, FORM, form
def response(self, query_string, **kwargs):
@@ -570,14 +603,14 @@ class Payment(PaymentCommon):
result = WAITING
else:
self.logger.error('response STATUS=%s NCERROR=%s NCERRORPLUS=%s',
- status, error, params.get('NCERRORPLUS', ''))
+ status, error, params.get('NCERRORPLUS', ''))
result = ERROR
# extract reference from received order id
if ORDERID_TRANSACTION_SEPARATOR in reference:
reference, transaction_id = reference.split(ORDERID_TRANSACTION_SEPARATOR, 1)
return PaymentResponse(
- result=result,
- signed=signed,
- bank_data=params,
- order_id=reference,
- transaction_id=transaction_id)
+ result=result,
+ signed=signed,
+ bank_data=params,
+ order_id=reference,
+ transaction_id=transaction_id)
diff --git a/eopayment/paybox.py b/eopayment/paybox.py
index 130925e..c629f68 100644
--- a/eopayment/paybox.py
+++ b/eopayment/paybox.py
@@ -1,4 +1,19 @@
# -*- coding: utf-8
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
import codecs
from collections import OrderedDict
@@ -289,7 +304,9 @@ class Payment(PaymentCommon):
'signature:K'
)
d['PBX_HASH'] = 'SHA512'
- d['PBX_TIME'] = kwargs.get('time') or (force_text(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00')
+ d['PBX_TIME'] = kwargs.get('time') or (
+ force_text(datetime.datetime.utcnow().isoformat('T')).split('.')[0]
+ + '+00:00')
d['PBX_ARCHIVAGE'] = transaction_id
if self.normal_return_url:
d['PBX_EFFECTUE'] = self.normal_return_url
diff --git a/eopayment/payfip_ws.py b/eopayment/payfip_ws.py
index 2b6e2c1..4446f8a 100644
--- a/eopayment/payfip_ws.py
+++ b/eopayment/payfip_ws.py
@@ -1,5 +1,5 @@
# eopayment - online payment library
-# Copyright (C) 2011-2019 Entr'ouvert
+# Copyright (C) 2011-2020 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
diff --git a/eopayment/payzen.py b/eopayment/payzen.py
index 9d9cdb9..3059bb4 100644
--- a/eopayment/payzen.py
+++ b/eopayment/payzen.py
@@ -1,9 +1,26 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
from copy import deepcopy
from . import systempayv2
__all__ = ['Payment']
+
class Payment(systempayv2.Payment):
service_url = 'https://secure.payzen.eu/vads-payment/'
diff --git a/eopayment/sips.py b/eopayment/sips.py
index 9c06d83..669264a 100644
--- a/eopayment/sips.py
+++ b/eopayment/sips.py
@@ -1,4 +1,20 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
from six.moves.urllib import parse as urlparse
import string
import subprocess
@@ -34,23 +50,25 @@ __all__ = ['Payment']
BINPATH = 'binpath'
PATHFILE = 'pathfile'
AUTHORISATION_ID = 'authorisation_id'
-REQUEST_VALID_PARAMS = ['merchant_id', 'merchant_country', 'amount',
- 'currency_code', 'pathfile', 'normal_return_url', 'cancel_return_url',
- 'automatic_response_url', 'language', 'payment_means', 'header_flag',
- 'capture_day', 'capture_mode', 'bgcolor', 'block_align', 'block_order',
- 'textcolor', 'receipt_complement', 'caddie', 'customer_id',
- 'customer_email', 'customer_ip_address', 'data', 'return_context',
- 'target', 'order_id']
+REQUEST_VALID_PARAMS = [
+ 'merchant_id', 'merchant_country', 'amount', 'currency_code', 'pathfile',
+ 'normal_return_url', 'cancel_return_url', 'automatic_response_url',
+ 'language', 'payment_means', 'header_flag', 'capture_day', 'capture_mode',
+ 'bgcolor', 'block_align', 'block_order', 'textcolor', 'receipt_complement',
+ 'caddie', 'customer_id', 'customer_email', 'customer_ip_address', 'data',
+ 'return_context', 'target', 'order_id',
+]
-RESPONSE_PARAMS = ['code', 'error', 'merchant_id', 'merchant_country',
- 'amount', 'transaction_id', 'payment_means', 'transmission_date',
- 'payment_time', 'payment_date', 'response_code', 'payment_certificate',
- AUTHORISATION_ID, 'currency_code', 'card_number', 'cvv_flag',
- 'cvv_response_code', 'bank_response_code', 'complementary_code',
- 'complementary_info', 'return_context', 'caddie', 'receipt_complement',
- 'merchant_language', 'language', 'customer_id', 'order_id',
- 'customer_email', 'customer_ip_address', 'capture_day', 'capture_mode',
- 'data', ]
+RESPONSE_PARAMS = [
+ 'code', 'error', 'merchant_id', 'merchant_country', 'amount',
+ 'transaction_id', 'payment_means', 'transmission_date', 'payment_time',
+ 'payment_date', 'response_code', 'payment_certificate', AUTHORISATION_ID,
+ 'currency_code', 'card_number', 'cvv_flag', 'cvv_response_code',
+ 'bank_response_code', 'complementary_code', 'complementary_info',
+ 'return_context', 'caddie', 'receipt_complement', 'merchant_language',
+ 'language', 'customer_id', 'order_id', 'customer_email',
+ 'customer_ip_address', 'capture_day', 'capture_mode', 'data',
+]
DATA = 'DATA'
PARAMS = 'params'
@@ -69,37 +87,38 @@ LOGGER = logging.getLogger(__name__)
CB_BANK_RESPONSE_CODES = CB_RESPONSE_CODES
AMEX_BANK_RESPONSE_CODE = {
-'00': 'Transaction approuvée ou traitée avec succès',
-'02': 'Dépassement de plafond',
-'04': 'Conserver la carte',
-'05': 'Ne pas honorer',
-'97': 'Échéance de la temporisation de surveillance globale',
+ '00': 'Transaction approuvée ou traitée avec succès',
+ '02': 'Dépassement de plafond',
+ '04': 'Conserver la carte',
+ '05': 'Ne pas honorer',
+ '97': 'Échéance de la temporisation de surveillance globale',
}
FINAREF_BANK_RESPONSE_CODE = {
-'00': 'Transaction approuvée',
-'03': 'Commerçant inconnu - Identifiant de commerçant incorrect',
-'05': 'Compte / Porteur avec statut bloqué ou invalide',
-'11': 'Compte / porteur inconnu',
-'16': 'Provision insuffisante',
-'20': 'Commerçant invalide - Code monnaie incorrect - ' + \
- 'Opération commerciale inconnue - Opération commerciale invalide',
-'80': 'Transaction approuvée avec dépassement',
-'81': 'Transaction approuvée avec augmentation capital',
-'82': 'Transaction approuvée NPAI',
-'83': 'Compte / porteur invalide',
+ '00': 'Transaction approuvée',
+ '03': 'Commerçant inconnu - Identifiant de commerçant incorrect',
+ '05': 'Compte / Porteur avec statut bloqué ou invalide',
+ '11': 'Compte / porteur inconnu',
+ '16': 'Provision insuffisante',
+ '20': (
+ 'Commerçant invalide - Code monnaie incorrect - '
+ 'Opération commerciale inconnue - Opération commerciale invalide'
+ ),
+ '80': 'Transaction approuvée avec dépassement',
+ '81': 'Transaction approuvée avec augmentation capital',
+ '82': 'Transaction approuvée NPAI',
+ '83': 'Compte / porteur invalide',
}
class Payment(PaymentCommon):
description = {
- 'caption': 'SIPS',
- 'parameters': [{
- 'name': 'merchand_id',
- },
- {'name': 'merchant_country', },
- {'name': 'currency_code', }
- ],
+ 'caption': 'SIPS',
+ 'parameters': [
+ {'name': 'merchand_id'},
+ {'name': 'merchant_country', },
+ {'name': 'currency_code', }
+ ],
}
def __init__(self, options, logger=None):
@@ -114,8 +133,11 @@ class Payment(PaymentCommon):
executable = os.path.join(self.binpath, executable)
args = [executable] + ["%s=%s" % p for p in params.items()]
self.logger.debug('executing %s' % args)
- result,_ = subprocess.Popen(' '.join(args),
- stdout=subprocess.PIPE, shell=True).communicate()
+ result, _ = subprocess.Popen(
+ ' '.join(args),
+ stdout=subprocess.PIPE,
+ shell=True
+ ).communicate()
try:
if result[0] == '!':
result = result[1:]
@@ -133,11 +155,11 @@ class Payment(PaymentCommon):
params.update(self.options)
return params
- def request(self, amount, name=None, address=None, email=None, phone=None, orderid=None,
- info1=None, info2=None, info3=None, next_url=None, **kwargs):
+ def request(self, amount, name=None, address=None, email=None, phone=None,
+ orderid=None, info1=None, info2=None, info3=None,
+ next_url=None, **kwargs):
params = self.get_request_params()
- transaction_id = self.transaction_id(6, string.digits, 'sips',
- params[MERCHANT_ID])
+ transaction_id = self.transaction_id(6, string.digits, 'sips', params[MERCHANT_ID])
params[TRANSACTION_ID] = transaction_id
params[ORDER_ID] = orderid or str(uuid.uuid4())
params[ORDER_ID] = params[ORDER_ID].replace('-', '')
@@ -159,7 +181,7 @@ class Payment(PaymentCommon):
def response(self, query_string, **kwargs):
form = urlparse.parse_qs(query_string)
- if not DATA in form:
+ if DATA not in form:
raise ResponseError('missing %s' % DATA)
params = {'message': form[DATA][0]}
result = self.execute('response', params)
@@ -170,10 +192,10 @@ class Payment(PaymentCommon):
response_result = d.get(RESPONSE_CODE) == '00'
response_code_msg = CB_BANK_RESPONSE_CODES.get(d.get(RESPONSE_CODE))
response = PaymentResponse(
- result=response_result,
- signed=response_result,
- bank_data=d,
- order_id=d.get(ORDER_ID),
- transaction_id=d.get(AUTHORISATION_ID),
- bank_status=response_code_msg)
+ result=response_result,
+ signed=response_result,
+ bank_data=d,
+ order_id=d.get(ORDER_ID),
+ transaction_id=d.get(AUTHORISATION_ID),
+ bank_status=response_code_msg)
return response
diff --git a/eopayment/sips2.py b/eopayment/sips2.py
index 80dfd2b..f84f5a6 100644
--- a/eopayment/sips2.py
+++ b/eopayment/sips2.py
@@ -1,4 +1,19 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
import datetime
from decimal import Decimal
diff --git a/eopayment/spplus.py b/eopayment/spplus.py
index 771a672..1b8e6db 100644
--- a/eopayment/spplus.py
+++ b/eopayment/spplus.py
@@ -1,7 +1,22 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
from decimal import Decimal
import binascii
-from gettext import gettext as _
import hmac
import hashlib
from six.moves.urllib import parse as urlparse
@@ -13,10 +28,14 @@ import re
import warnings
import Crypto.Cipher.DES
-from .common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
- PAID, ERROR, ResponseError, force_byte)
+from .common import (
+ PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
+ PAID, ERROR, ResponseError, force_byte
+)
-def N_(message): return message
+
+def N_(message):
+ return message
__all__ = ['Payment']
@@ -39,7 +58,7 @@ SPPLUS_RESPONSE_CODES = {
'8': 'Chèque encaissé',
'10': 'Paiement terminé',
'11': 'Echéance du paiement annulée par le commerçant',
- '12': 'Abandon de l\’internaute',
+ '12': 'Abandon de l’internaute',
'15': 'Remboursement enregistré',
'16': 'Remboursement annulé',
'17': 'Remboursement accepté',
@@ -59,10 +78,12 @@ def decrypt_ntkey(ntkey):
key = binascii.unhexlify(ntkey.replace(b' ', b''))
return decrypt_key(key)
+
def decrypt_key(key):
CIPHER = Crypto.Cipher.DES.new(KEY_DES_KEY, Crypto.Cipher.DES.MODE_CBC, IV)
return CIPHER.decrypt(key)
+
def extract_values(query_string):
kvs = query_string.split('&')
result = []
@@ -72,88 +93,104 @@ def extract_values(query_string):
result.append(v)
return force_byte(''.join(result))
+
def sign_ntkey_query(ntkey, query):
key = decrypt_ntkey(ntkey)
data_to_sign = extract_values(query)
return hmac.new(key[:20], data_to_sign, hashlib.sha1).hexdigest().upper()
-PAIEMENT_FIELDS = [ 'siret', REFERENCE, 'langue', 'devise', 'montant',
- 'taxe', 'validite' ]
+PAIEMENT_FIELDS = [
+ 'siret', REFERENCE, 'langue', 'devise', 'montant', 'taxe', 'validite'
+]
+
def sign_url_paiement(ntkey, query):
if '?' in query:
- query = query[query.index('?')+1:]
+ query = query[query.index('?') + 1:]
key = decrypt_ntkey(ntkey)
data = urlparse.parse_qs(query, True)
- fields = [data.get(field,[''])[0] for field in PAIEMENT_FIELDS]
+ fields = [data.get(field, [''])[0] for field in PAIEMENT_FIELDS]
data_to_sign = ''.join(fields)
return hmac.new(key[:20], data_to_sign, hashlib.sha1).hexdigest().upper()
ALPHANUM = string.ascii_letters + string.digits
SERVICE_URL = "https://www.spplus.net/paiement/init.do"
+
class Payment(PaymentCommon):
description = {
- 'caption': "SPPlus payment service of French bank Caisse d'epargne",
- 'parameters': [
- {
- 'name': 'normal_return_url',
- 'caption': N_('Normal return URL'),
- 'default': '',
- 'required': True,
- },
- {
- 'name': 'automatic_return_url',
- 'caption': N_('Automatic return URL'),
- 'required': False,
- },
- { 'name': 'cle',
- 'caption': 'Secret key, a 40 digits hexadecimal number',
- 'regexp': re.compile('^ *((?:[a-fA-F0-9] *){40}) *$')
- },
- { 'name': 'siret',
- 'caption': 'Siret of the entreprise augmented with the '
- 'site number, example: 00000000000001-01',
- 'regexp': re.compile('^ *(\d{14}-\d{2}) *$')
- },
- { 'name': 'langue',
- 'caption': 'Language of the customers',
- 'default': 'FR',
- },
- { 'name': 'taxe',
- 'caption': 'Taxes',
- 'default': '0.00'
- },
- { 'name': 'modalite',
- 'caption': '1x, 2x, 3x, xx, nx (if multiple separated by "/")',
- 'default': '1x',
- },
- { 'name': 'moyen',
- 'caption': 'AUR, AMX, CBS, CGA, '
- 'CHK, DIN, PRE (if multiple separate by "/")',
- 'default': 'CBS',
- },
- ]
+ 'caption': "SPPlus payment service of French bank Caisse d'epargne",
+ 'parameters': [
+ {
+ 'name': 'normal_return_url',
+ 'caption': N_('Normal return URL'),
+ 'default': '',
+ 'required': True,
+ },
+ {
+ 'name': 'automatic_return_url',
+ 'caption': N_('Automatic return URL'),
+ 'required': False,
+ },
+ {
+ 'name': 'cle',
+ 'caption': 'Secret key, a 40 digits hexadecimal number',
+ 'regexp': re.compile('^ *((?:[a-fA-F0-9] *){40}) *$')
+ },
+ {
+ 'name': 'siret',
+ 'caption': (
+ 'Siret of the entreprise augmented with the '
+ 'site number, example: 00000000000001-01'
+ ),
+ 'regexp': re.compile(r'^ *(\d{14}-\d{2}) *$')
+ },
+ {
+ 'name': 'langue',
+ 'caption': 'Language of the customers',
+ 'default': 'FR',
+ },
+ {
+ 'name': 'taxe',
+ 'caption': 'Taxes',
+ 'default': '0.00'
+ },
+ {
+ 'name': 'modalite',
+ 'caption': '1x, 2x, 3x, xx, nx (if multiple separated by "/")',
+ 'default': '1x',
+ },
+ {
+ 'name': 'moyen',
+ 'caption': (
+ 'AUR, AMX, CBS, CGA, '
+ 'CHK, DIN, PRE (if multiple separate by "/")'
+ ),
+ 'default': 'CBS',
+ },
+ ]
}
devise = '978'
def request(self, amount, name=None, address=None, email=None, phone=None,
- orderid=None, info1=None, info2=None, info3=None, next_url=None,
- logger=LOGGER, **kwargs):
+ orderid=None, info1=None, info2=None, info3=None,
+ next_url=None, logger=LOGGER, **kwargs):
logger.debug('requesting spplus payment with montant %s email=%s' % (amount, email))
reference = self.transaction_id(20, ALPHANUM, 'spplus', self.siret)
validite = dt.date.today()+dt.timedelta(days=1)
validite = validite.strftime('%d/%m/%Y')
- fields = { 'siret': self.siret,
- 'devise': self.devise,
- 'langue': self.langue,
- 'taxe': self.taxe,
- 'montant': str(Decimal(amount)),
- REFERENCE: orderid or reference,
- 'validite': validite,
- 'version': '1',
- 'modalite': self.modalite,
- 'moyen': self.moyen }
+ fields = {
+ 'siret': self.siret,
+ 'devise': self.devise,
+ 'langue': self.langue,
+ 'taxe': self.taxe,
+ 'montant': str(Decimal(amount)),
+ REFERENCE: orderid or reference,
+ 'validite': validite,
+ 'version': '1',
+ 'modalite': self.modalite,
+ 'moyen': self.moyen,
+ }
if email:
fields['email'] = email
normal_return_url = self.normal_return_url
@@ -162,15 +199,14 @@ class Payment(PaymentCommon):
"set normal_return_url in options", DeprecationWarning)
normal_return_url = next_url
if normal_return_url:
- if (not normal_return_url.startswith('http://') \
- and not normal_return_url.startswith('https://')) \
- or '?' in normal_return_url:
- raise ValueError('normal_return_url must be an absolute URL without parameters')
+ if ((not normal_return_url.startswith('http://')
+ and not normal_return_url.startswith('https://'))
+ or '?' in normal_return_url):
+ raise ValueError('normal_return_url must be an absolute URL without parameters')
fields['urlretour'] = normal_return_url
logger.debug('sending fields %s' % fields)
query = urllib.urlencode(fields)
- url = '%s?%s&hmac=%s' % (SERVICE_URL, query, sign_url_paiement(self.cle,
- query))
+ url = '%s?%s&hmac=%s' % (SERVICE_URL, query, sign_url_paiement(self.cle, query))
logger.debug('full url %s' % url)
return reference, URL, url
@@ -211,20 +247,20 @@ class Payment(PaymentCommon):
elif etat in VALID_STATE:
result = RECEIVED
elif etat in TEST_STATE:
- result = RECEIVED # what else ?
+ result = RECEIVED # what else ?
test = True
else:
result = ERROR
response = PaymentResponse(
- result=result,
- signed=signed,
- bank_data=form,
- order_id=reference,
- transaction_id=form[self.BANK_ID],
- bank_status=' - '.join(bank_status),
- return_content=SPCHECKOK,
- test=test)
+ result=result,
+ signed=signed,
+ bank_data=form,
+ order_id=reference,
+ transaction_id=form[self.BANK_ID],
+ bank_status=' - '.join(bank_status),
+ return_content=SPCHECKOK,
+ test=test)
return response
diff --git a/eopayment/systempayv2.py b/eopayment/systempayv2.py
index 705d33d..49ff6fb 100644
--- a/eopayment/systempayv2.py
+++ b/eopayment/systempayv2.py
@@ -1,4 +1,19 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
import pytz
import datetime as dt
@@ -286,7 +301,8 @@ class Payment(PaymentCommon):
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, **kwargs):
+ info2=None, info3=None, next_url=None, manual_validation=None,
+ **kwargs):
'''
Create the URL string to send a request to SystemPay
'''
@@ -332,8 +348,8 @@ 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
transaction_id = self.transaction_id(6, string.digits, 'systempay',
diff --git a/eopayment/tipi.py b/eopayment/tipi.py
index 9a7e75b..ee30c50 100644
--- a/eopayment/tipi.py
+++ b/eopayment/tipi.py
@@ -1,3 +1,19 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import re
import random
from decimal import Decimal, ROUND_DOWN
diff --git a/tests/test_base_payment.py b/tests/test_base_payment.py
index bb23959..d96f99f 100644
--- a/tests/test_base_payment.py
+++ b/tests/test_base_payment.py
@@ -1,13 +1,29 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
from datetime import date, datetime, timedelta
import mock
import pytest
+import eopayment
+
def do_mock_backend(monkeypatch):
-
class MockBackend(object):
-
request = mock.Mock()
description = {
@@ -38,7 +54,6 @@ def do_mock_backend(monkeypatch):
return MockBackend
return backend
- import eopayment
monkeypatch.setattr(eopayment, 'get_backend', get_backend)
return MockBackend, eopayment.Payment('kind', None)
diff --git a/tests/test_dummy.py b/tests/test_dummy.py
index 1725673..b46b1d8 100644
--- a/tests/test_dummy.py
+++ b/tests/test_dummy.py
@@ -1,24 +1,56 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+
import eopayment
import pytest
+
def test_dummy():
options = {
- 'direct_notification_url': 'http://example.com/direct_notification_url',
- 'siret': '1234',
- 'origin': 'Mairie de Perpette-les-oies'
+ 'direct_notification_url': 'http://example.com/direct_notification_url',
+ 'siret': '1234',
+ 'origin': 'Mairie de Perpette-les-oies'
}
p = eopayment.Payment('dummy', options)
- retour = 'http://example.com/retour?amount=10.0&direct_notification_url=http%3A%2F%2Fexample.com%2Fdirect_notification_url&email=toto%40example.com&transaction_id=6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T&return_url=http%3A%2F%2Fexample.com%2Fretour&nok=1'
- r = p.response(retour.split('?',1)[1])
+ retour = (
+ 'http://example.com/retour?amount=10.0'
+ '&direct_notification_url=http%3A%2F%2Fexample.com%2Fdirect_notification_url'
+ '&email=toto%40example.com'
+ '&transaction_id=6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T'
+ '&return_url=http%3A%2F%2Fexample.com%2Fretour'
+ '&nok=1'
+ )
+ r = p.response(retour.split('?', 1)[1])
assert not r.signed
assert r.transaction_id == '6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T'
assert r.return_content is None
- retour = 'http://example.com/retour?amount=10.0&direct_notification_url=http%3A%2F%2Fexample.com%2Fdirect_notification_url&email=toto%40example.com&transaction_id=6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T&return_url=http%3A%2F%2Fexample.com%2Fretour&ok=1&signed=1'
- r = p.response(retour.split('?',1)[1])
+ retour = (
+ 'http://example.com/retour'
+ '?amount=10.0'
+ '&direct_notification_url=http%3A%2F%2Fexample.com%2Fdirect_notification_url'
+ '&email=toto%40example.com'
+ '&transaction_id=6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T'
+ '&return_url=http%3A%2F%2Fexample.com%2Fretour'
+ '&ok=1&signed=1'
+ )
+ r = p.response(retour.split('?', 1)[1])
assert r.signed
assert r.transaction_id == '6Tfw2e1bPyYnz7CedZqvdHt7T9XX6T'
assert r.return_content == 'signature ok'
- data = {'foo': 'bar'}
with pytest.raises(eopayment.ResponseError, match='missing transaction_id'):
p.response('foo=bar')
diff --git a/tests/test_ogone.py b/tests/test_ogone.py
index c44596d..abf472a 100644
--- a/tests/test_ogone.py
+++ b/tests/test_ogone.py
@@ -1,6 +1,23 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
from unittest import TestCase
+from xml.etree import ElementTree as ET
+
from six.moves.urllib import parse as urllib
import eopayment
@@ -17,17 +34,18 @@ BACKEND_PARAMS = {
'automatic_return_url': u'http://example.com/autömatic_réturn_url'
}
-class OgoneTests(TestCase):
+class OgoneTests(TestCase):
def test_request(self):
ogone_backend = eopayment.Payment('ogone', BACKEND_PARAMS)
amount = '42.42'
order_id = u'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')
self.assertEqual(len(reference), 30)
assert reference.startswith(order_id)
- from xml.etree import ElementTree as ET
root = ET.fromstring(str(what))
self.assertEqual(root.tag, 'form')
self.assertEqual(root.attrib['method'], 'POST')
@@ -67,27 +85,39 @@ class OgoneTests(TestCase):
def test_iso_8859_1_response(self):
ogone_backend = eopayment.Payment('ogone', BACKEND_PARAMS)
order_id = 'lRXK4Rl1N2yIR3R5z7Kc'
- backend_response = 'orderID=lRXK4Rl1N2yIR3R5z7Kc¤cy=EUR&amount=7%2E5&PM=CreditCard&ACCEPTANCE=test123&STATUS=9&CARDNO=XXXXXXXXXXXX9999&ED=0118&CN=Miha%EF+Serghe%EF&TRXDATE=10%2F24%2F16&PAYID=3011228911&NCERROR=0&BRAND=MasterCard&IP=80%2E12%2E92%2E47&SHASIGN=435D5E36E1F4B17739C1054FFD204218E65C15AB'
+ backend_response = (
+ 'orderID=lRXK4Rl1N2yIR3R5z7Kc¤cy=EUR&amount=7%2E5'
+ '&PM=CreditCard&ACCEPTANCE=test123&STATUS=9'
+ '&CARDNO=XXXXXXXXXXXX9999&ED=0118'
+ '&CN=Miha%EF+Serghe%EF&TRXDATE=10%2F24%2F16'
+ '&PAYID=3011228911&NCERROR=0&BRAND=MasterCard'
+ '&IP=80%2E12%2E92%2E47&SHASIGN=435D5E36E1F4B17739C1054FFD204218E65C15AB'
+ )
response = ogone_backend.response(backend_response)
assert response.signed
self.assertEqual(response.order_id, order_id)
def test_bad_response(self):
ogone_backend = eopayment.Payment('ogone', BACKEND_PARAMS)
- order_id = 'myorder'
data = {'payid': '32100123', 'status': 9, 'ncerror': 0}
with self.assertRaisesRegexp(ResponseError, 'missing ORDERID, PAYID, STATUS or NCERROR'):
- response = ogone_backend.response(urllib.urlencode(data))
+ ogone_backend.response(urllib.urlencode(data))
def test_bank_transfer_response(self):
ogone_backend = eopayment.Payment('ogone', BACKEND_PARAMS)
- order_id = 'myorder'
- data = {'orderid': u'myorder', 'status': u'41', 'payid': u'3011229363',
- 'cn': u'User', 'ncerror': u'0',
- 'trxdate': u'10/24/16',
- 'brand': 'Bank transfer', 'pm': 'bank transfer',
- 'currency': u'eur', 'amount': u'7.5',
- 'shasign': u'0E35F687ACBEAA6CA769E0ADDBD0863EB6C1678A'}
+ data = {
+ 'orderid': u'myorder',
+ 'status': u'41',
+ 'payid': u'3011229363',
+ 'cn': u'User',
+ 'ncerror': u'0',
+ 'trxdate': u'10/24/16',
+ 'brand': 'Bank transfer',
+ 'pm': 'bank transfer',
+ 'currency': u'eur',
+ 'amount': u'7.5',
+ 'shasign': u'0E35F687ACBEAA6CA769E0ADDBD0863EB6C1678A'
+ }
# uniformize to utf-8 first
for k in data:
data[k] = eopayment.common.force_byte(data[k])
diff --git a/tests/test_paybox.py b/tests/test_paybox.py
index e87b0b2..b504e04 100644
--- a/tests/test_paybox.py
+++ b/tests/test_paybox.py
@@ -1,4 +1,20 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import codecs
from unittest import TestCase
@@ -12,32 +28,45 @@ import eopayment.paybox as paybox
import eopayment
BACKEND_PARAMS = {
- 'platform': u'test',
- 'site': u'12345678',
- 'rang': u'001',
- 'identifiant': u'12345678',
- 'shared_secret': u'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF',
- 'callback': u'http://example.com/callback',
+ 'platform': u'test',
+ 'site': u'12345678',
+ 'rang': u'001',
+ 'identifiant': u'12345678',
+ 'shared_secret': (
+ u'0123456789ABCDEF0123456789ABCDEF01234'
+ u'56789ABCDEF0123456789ABCDEF0123456789'
+ u'ABCDEF0123456789ABCDEF0123456789ABCDE'
+ u'F0123456789ABCDEF'
+ ),
+ 'callback': u'http://example.com/callback',
}
+
class PayboxTests(TestCase):
def test_sign(self):
- key = b'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'
+ key = (b'0123456789ABCDEF0123456789ABCDEF0123456789'
+ b'ABCDEF0123456789ABCDEF0123456789ABCDEF0123'
+ b'456789ABCDEF0123456789ABCDEF0123456789ABCD'
+ b'EF')
key = codecs.decode(key, 'hex')
d = dict(paybox.sign([
- ['PBX_SITE', u'12345678'],
- ['PBX_RANG', u'32'],
- ['PBX_IDENTIFIANT', u'12345678'],
- ['PBX_TOTAL', u'999'],
- ['PBX_DEVISE', u'978'],
- ['PBX_CMD', u'appel à Paybox'],
- ['PBX_PORTEUR', u'test@paybox.com'],
- ['PBX_RETOUR', u'Mt:M;Ref:R;Auto:A;Erreur:E'],
- ['PBX_HASH', u'SHA512'],
- ['PBX_TIME', u'2015-06-08T16:21:16+02:00'],
- ],
- key))
- result = '7E74D8E9A0DBB65AAE51C5C50C2668FD98FC99AEDF18244BB1935F602B6C2E953B61FD84364F34FDB88B049901C0A07F6040AF446BBF5589113F48A733D551D4'
+ ['PBX_SITE', u'12345678'],
+ ['PBX_RANG', u'32'],
+ ['PBX_IDENTIFIANT', u'12345678'],
+ ['PBX_TOTAL', u'999'],
+ ['PBX_DEVISE', u'978'],
+ ['PBX_CMD', u'appel à Paybox'],
+ ['PBX_PORTEUR', u'test@paybox.com'],
+ ['PBX_RETOUR', u'Mt:M;Ref:R;Auto:A;Erreur:E'],
+ ['PBX_HASH', u'SHA512'],
+ ['PBX_TIME', u'2015-06-08T16:21:16+02:00'],
+ ], key))
+ result = (
+ '7E74D8E9A0DBB65AAE51C5C50C2668FD98FC99AED'
+ 'F18244BB1935F602B6C2E953B61FD84364F34FDB8'
+ '8B049901C0A07F6040AF446BBF5589113F48A733D'
+ '551D4'
+ )
self.assertIn('PBX_HMAC', d)
self.assertEqual(d['PBX_HMAC'], result)
@@ -61,14 +90,23 @@ class PayboxTests(TestCase):
'PBX_RANG': '01',
'PBX_SITE': '12345678',
'PBX_IDENTIFIANT': '12345678',
- 'PBX_RETOUR': 'montant:M;reference:R;code_autorisation:A;erreur:E;numero_appel:T;numero_transaction:S;date_transaction:W;heure_transaction:Q;signature:K',
+ 'PBX_RETOUR': (
+ 'montant:M;reference:R;code_autorisation:A;'
+ 'erreur:E;numero_appel:T;numero_transaction:S;'
+ 'date_transaction:W;heure_transaction:Q;signature:K'
+ ),
'PBX_TIME': time,
'PBX_PORTEUR': email,
'PBX_CMD': order_id + eopayment.common.ORDERID_TRANSACTION_SEPARATOR + transaction,
'PBX_TOTAL': amount.replace('.', ''),
'PBX_DEVISE': '978',
'PBX_HASH': 'SHA512',
- 'PBX_HMAC': 'CE29AB421D9FF5E22B52A0F0D31BB881E6D3040B7A0B390AC3F335292A75D2389253A3ED6B3E430A90D30088F6AC29F792B484A2ECFC36A1B73771796A5FD15C',
+ 'PBX_HMAC': (
+ 'CE29AB421D9FF5E22B52A0F0D31BB881E6D'
+ '3040B7A0B390AC3F335292A75D2389253A3'
+ 'ED6B3E430A90D30088F6AC29F792B484A2E'
+ 'CFC36A1B73771796A5FD15C'
+ ),
'PBX_ARCHIVAGE': '1234',
'PBX_REPONDRE_A': 'http://example.com/callback',
'PBX_AUTOSEULE': 'N'
@@ -101,7 +139,8 @@ class PayboxTests(TestCase):
transaction_id=transaction, time=time)
root = ET.fromstring(str(what))
- form_params = dict(((node.attrib['name'], node.attrib['value']) for node in root if node.attrib['type'] == 'hidden'))
+ form_params = dict(
+ ((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')
@@ -109,13 +148,13 @@ 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 = dict(((
node.attrib['name'], node.attrib['value']) for node in root
- if node.attrib['type'] == 'hidden'))
+ if node.attrib['type'] == 'hidden'))
self.assertIn('PBX_DIFF', form_params)
self.assertEqual(form_params['PBX_DIFF'], '02')
@@ -125,17 +164,16 @@ 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 = dict(((
node.attrib['name'], node.attrib['value']) for node in root
- if node.attrib['type'] == 'hidden'))
+ if node.attrib['type'] == 'hidden'))
self.assertIn('PBX_DIFF', form_params)
self.assertEqual(form_params['PBX_DIFF'], '02')
-
def test_request_with_authorization_only(self):
params = BACKEND_PARAMS.copy()
time = '2018-08-21T10:26:32+02:00'
@@ -151,7 +189,8 @@ class PayboxTests(TestCase):
transaction_id=transaction, time=time)
root = ET.fromstring(str(what))
- form_params = dict(((node.attrib['name'], node.attrib['value']) for node in root if node.attrib['type'] == 'hidden'))
+ form_params = dict(
+ ((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):
@@ -180,11 +219,16 @@ class PayboxTests(TestCase):
params = BACKEND_PARAMS.copy()
params['cle'] = 'cancelling_key'
backend = eopayment.Payment('paybox', params)
- bank_data = {'numero_transaction': ['13957441'],
- 'numero_appel': ['30310733'],
- 'reference': ['830657461681']
+ bank_data = {
+ 'numero_transaction': ['13957441'],
+ 'numero_appel': ['30310733'],
+ 'reference': ['830657461681'],
}
- backend_raw_response = u"""NUMTRANS=0013989865&NUMAPPEL=0030378572&NUMQUESTION=0013989862&SITE=1999888&RANG=32&AUTORISATION=XXXXXX&CODEREPONSE=00000&COMMENTAIRE=Demande traitée avec succès&REFABONNE=&PORTEUR="""
+ backend_raw_response = (
+ u'NUMTRANS=0013989865&NUMAPPEL=0030378572&NUMQUESTION=0013989862'
+ u'&SITE=1999888&RANG=32&AUTORISATION=XXXXXX&CODEREPONSE=00000'
+ u'&COMMENTAIRE=Demande traitée avec succès&REFABONNE=&PORTEUR='
+ )
backend_expected_response = {"CODEREPONSE": "00000",
"RANG": "32",
"AUTORISATION": "XXXXXX",
@@ -206,17 +250,18 @@ class PayboxTests(TestCase):
assert 'DATEQ' in params_sent
# don't care about its value
params_sent.pop('DATEQ')
- expected_params = {'CLE': 'cancelling_key',
- 'VERSION': '00103',
- 'TYPE': operation_code,
- 'MONTANT': Decimal('1000'),
- 'NUMAPPEL': '30310733',
- 'NUMTRANS': '13957441',
- 'NUMQUESTION': '0013957441',
- 'REFERENCE': '830657461681',
- 'RANG': backend.backend.rang,
- 'SITE': backend.backend.site,
- 'DEVISE': backend.backend.devise
+ expected_params = {
+ 'CLE': 'cancelling_key',
+ 'VERSION': '00103',
+ 'TYPE': operation_code,
+ 'MONTANT': Decimal('1000'),
+ 'NUMAPPEL': '30310733',
+ 'NUMTRANS': '13957441',
+ 'NUMQUESTION': '0013957441',
+ 'REFERENCE': '830657461681',
+ 'RANG': backend.backend.rang,
+ 'SITE': backend.backend.site,
+ 'DEVISE': backend.backend.devise
}
self.assertEqual(params_sent, expected_params)
self.assertEqual(backend_response, backend_expected_response)
@@ -233,26 +278,33 @@ class PayboxTests(TestCase):
error_response = u"""CODEREPONSE=00015&COMMENTAIRE=PAYBOX : Transaction non trouvée"""
response = mock.Mock(status_code=200, text=error_response)
requests_post.return_value = response
- self.assertRaisesRegexp(eopayment.ResponseError, 'Transaction non trouvée', getattr(backend, operation_name),
- Decimal('10'), bank_data)
-
+ self.assertRaisesRegexp(
+ eopayment.ResponseError,
+ 'Transaction non trouvée',
+ getattr(backend, operation_name),
+ Decimal('10'),
+ bank_data)
def test_validate_payment(self):
params = BACKEND_PARAMS.copy()
params['cle'] = 'cancelling_key'
backend = eopayment.Payment('paybox', params)
- bank_data = {'numero_transaction': ['13957441'],
- 'numero_appel': ['30310733'],
- 'reference': ['830657461681']
+ bank_data = {
+ 'numero_transaction': ['13957441'],
+ 'numero_appel': ['30310733'],
+ 'reference': ['830657461681']
}
- backend_raw_response = u"""NUMTRANS=0013989865&NUMAPPEL=0030378572&NUMQUESTION=0013989862&SITE=1999888&RANG=32&AUTORISATION=XXXXXX&CODEREPONSE=00000&COMMENTAIRE=Demande traitée avec succès&REFABONNE=&PORTEUR="""
+ backend_raw_response = (
+ u'NUMTRANS=0013989865&NUMAPPEL=0030378572&NUMQUESTION=0013989862'
+ u'&SITE=1999888&RANG=32&AUTORISATION=XXXXXX&CODEREPONSE=00000'
+ u'&COMMENTAIRE=Demande traitée avec succès&REFABONNE=&PORTEUR='
+ )
with mock.patch('eopayment.paybox.requests.post') as requests_post:
response = mock.Mock(status_code=200, text=backend_raw_response)
requests_post.return_value = response
backend.validate(Decimal(12), bank_data)
-
def test_rsa_signature_validation(self):
pkey = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUgYufHuheMztK1LhQSG6xsOzb
@@ -277,8 +329,11 @@ 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 = dict((
(node.attrib['name'], node.attrib['value']) for node in root
@@ -287,8 +342,12 @@ FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4='''
self.assertEqual(form_params['PBX_AUTOSEULE'], 'N')
transaction_id, kind, what = backend.request(
- Decimal(amount), email=email, orderid=order_id,
- transaction_id=transaction, time=time, manual_validation=True)
+ Decimal(amount),
+ email=email,
+ orderid=order_id,
+ transaction_id=transaction,
+ time=time,
+ manual_validation=True)
root = ET.fromstring(str(what))
form_params = dict((
(node.attrib['name'], node.attrib['value']) for node in root
diff --git a/tests/test_payfip_ws.py b/tests/test_payfip_ws.py
index 5580081..d6909de 100644
--- a/tests/test_payfip_ws.py
+++ b/tests/test_payfip_ws.py
@@ -1,7 +1,7 @@
# coding: utf-8
#
# eopayment - online payment library
-# Copyright (C) 2011-2019 Entr'ouvert
+# Copyright (C) 2011-2020 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
diff --git a/tests/test_sips2.py b/tests/test_sips2.py
index fe8c4d5..2c70882 100644
--- a/tests/test_sips2.py
+++ b/tests/test_sips2.py
@@ -1,4 +1,20 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import eopayment
import pytest
@@ -9,7 +25,7 @@ def test_build_request():
transaction, f, form = backend.request(amount=u'12', last_name=u'Foo',
first_name=u'Félix000000')
data = [f for f in form.fields if f['name'] == 'Data']
- assert not u'lix000000' in data[0]['value']
+ assert u'lix000000' not in data[0]['value']
transaction, f, form = backend.request(amount=u'12')
data = [f for f in form.fields if f['name'] == 'Data']
@@ -29,19 +45,20 @@ def test_options():
assert payment.backend.get_data()['captureMode'] == 'VALIDATION'
payment = eopayment.Payment('sips2', {})
- assert not 'captureDay' in payment.backend.get_data()
+ assert 'captureDay' not in payment.backend.get_data()
payment = eopayment.Payment('sips2', {'capture_day': '10'})
assert 'captureDay' in payment.backend.get_data()
+
def test_parse_response():
- qs = '''Data=captureDay%3D0%7CcaptureMode%3DAUTHOR_CAPTURE%7CcurrencyCode%3D978%7CmerchantId%3D002001000000001%7CorderChannel%3DINTERNET%7CresponseCode%3D00%7CtransactionDateTime%3D2016-02-01T17%3A44%3A20%2B01%3A00%7CtransactionReference%3D668930%7CkeyVersion%3D1%7CacquirerResponseCode%3D00%7Camount%3D1200%7CauthorisationId%3D12345%7CcardCSCResultCode%3D4E%7CpanExpiryDate%3D201605%7CpaymentMeanBrand%3DMASTERCARD%7CpaymentMeanType%3DCARD%7CcustomerIpAddress%3D82.244.203.243%7CmaskedPan%3D5100%23%23%23%23%23%23%23%23%23%23%23%2300%7CorderId%3Dd4903de7027f4d56ac01634fd7ab9526%7CholderAuthentRelegation%3DN%7CholderAuthentStatus%3D3D_ERROR%7CtransactionOrigin%3DINTERNET%7CpaymentPattern%3DONE_SHOT&Seal=6ca3247765a19b45d25ad54ef4076483e7d55583166bd5ac9c64357aac097602&InterfaceVersion=HP_2.0&Encode='''
+ qs = '''Data=captureDay%3D0%7CcaptureMode%3DAUTHOR_CAPTURE%7CcurrencyCode%3D978%7CmerchantId%3D002001000000001%7CorderChannel%3DINTERNET%7CresponseCode%3D00%7CtransactionDateTime%3D2016-02-01T17%3A44%3A20%2B01%3A00%7CtransactionReference%3D668930%7CkeyVersion%3D1%7CacquirerResponseCode%3D00%7Camount%3D1200%7CauthorisationId%3D12345%7CcardCSCResultCode%3D4E%7CpanExpiryDate%3D201605%7CpaymentMeanBrand%3DMASTERCARD%7CpaymentMeanType%3DCARD%7CcustomerIpAddress%3D82.244.203.243%7CmaskedPan%3D5100%23%23%23%23%23%23%23%23%23%23%23%2300%7CorderId%3Dd4903de7027f4d56ac01634fd7ab9526%7CholderAuthentRelegation%3DN%7CholderAuthentStatus%3D3D_ERROR%7CtransactionOrigin%3DINTERNET%7CpaymentPattern%3DONE_SHOT&Seal=6ca3247765a19b45d25ad54ef4076483e7d55583166bd5ac9c64357aac097602&InterfaceVersion=HP_2.0&Encode=''' # noqa: E501
backend = eopayment.Payment('sips2', {})
response = backend.response(qs)
assert response.signed
assert response.transaction_date is None
- qs = '''Data=captureDay%3D0%7CcaptureMode%3DAUTHOR_CAPTURE%7CcurrencyCode%3D978%7CmerchantId%3D002001000000001%7CorderChannel%3DINTERNET%7CresponseCode%3D00%7CtransactionDateTime%3D2016-02-01T17%3A44%3A20%2B01%3A00%7CtransactionReference%3D668930%7CkeyVersion%3D1%7CacquirerResponseCode%3D00%7Camount%3D1200%7CauthorisationId%3D12345%7CcardCSCResultCode%3D4E%7CpanExpiryDate%3D201605%7CpaymentMeanBrand%3DMASTERCARD%7CpaymentMeanType%3DCARD%7CcustomerIpAddress%3D82.244.203.243%7CmaskedPan%3D5100%23%23%23%23%23%23%23%23%23%23%23%2300%7CorderId%3Dd4903de7027f4d56ac01634fd7ab9526%7CholderAuthentRelegation%3DN%7CholderAuthentStatus%3D3D_ERROR%7CtransactionOrigin%3DINTERNET%7CpaymentPattern%3DONE_SHOT%7CtransactionDateTime%3D2020-01-01%2001:01:01&Seal=6ca3247765a19b45d25ad54ef4076483e7d55583166bd5ac9c64357aac097602&InterfaceVersion=HP_2.0&Encode='''
+ qs = '''Data=captureDay%3D0%7CcaptureMode%3DAUTHOR_CAPTURE%7CcurrencyCode%3D978%7CmerchantId%3D002001000000001%7CorderChannel%3DINTERNET%7CresponseCode%3D00%7CtransactionDateTime%3D2016-02-01T17%3A44%3A20%2B01%3A00%7CtransactionReference%3D668930%7CkeyVersion%3D1%7CacquirerResponseCode%3D00%7Camount%3D1200%7CauthorisationId%3D12345%7CcardCSCResultCode%3D4E%7CpanExpiryDate%3D201605%7CpaymentMeanBrand%3DMASTERCARD%7CpaymentMeanType%3DCARD%7CcustomerIpAddress%3D82.244.203.243%7CmaskedPan%3D5100%23%23%23%23%23%23%23%23%23%23%23%2300%7CorderId%3Dd4903de7027f4d56ac01634fd7ab9526%7CholderAuthentRelegation%3DN%7CholderAuthentStatus%3D3D_ERROR%7CtransactionOrigin%3DINTERNET%7CpaymentPattern%3DONE_SHOT%7CtransactionDateTime%3D2020-01-01%2001:01:01&Seal=6ca3247765a19b45d25ad54ef4076483e7d55583166bd5ac9c64357aac097602&InterfaceVersion=HP_2.0&Encode=''' # noqa: E501
response = backend.response(qs)
assert not response.signed
assert response.transaction_date.isoformat() == '2020-01-01T01:01:01+01:00'
diff --git a/tests/test_spplus.py b/tests/test_spplus.py
index ba047e9..970a5db 100644
--- a/tests/test_spplus.py
+++ b/tests/test_spplus.py
@@ -1,14 +1,36 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
from unittest import TestCase
import eopayment.spplus as spplus
from eopayment import ResponseError
+
class SPPlustTest(TestCase):
ntkey = b'58 6d fc 9c 34 91 9b 86 3f ' \
b'fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
- tests = [('x=coin', 'c04f8266d6ae3ce37551cce996c751be4a95d10a'),
- ('x=coin&y=toto', 'ef008e02f8dbf5e70e83da416b0b3a345db203de'),
- ('x=wdwd%20%3Fdfgfdgd&z=343&hmac=04233b78bb5aff332d920d4e89394f505ec58a2a', '04233b78bb5aff332d920d4e89394f505ec58a2a')]
+ tests = [
+ ('x=coin',
+ 'c04f8266d6ae3ce37551cce996c751be4a95d10a'),
+ ('x=coin&y=toto',
+ 'ef008e02f8dbf5e70e83da416b0b3a345db203de'),
+ ('x=wdwd%20%3Fdfgfdgd&z=343&hmac=04233b78bb5aff332d920d4e89394f505ec58a2a',
+ '04233b78bb5aff332d920d4e89394f505ec58a2a')
+ ]
def test_spplus(self):
payment = spplus.Payment({'cle': self.ntkey, 'siret': '00000000000001-01'})
diff --git a/tests/test_systempayv2.py b/tests/test_systempayv2.py
index 248356e..6dcb29f 100644
--- a/tests/test_systempayv2.py
+++ b/tests/test_systempayv2.py
@@ -1,4 +1,21 @@
# -*- coding: utf-8 -*-
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+
from datetime import datetime, timedelta
import pytest
@@ -25,14 +42,18 @@ def get_field(form, field_name):
def test_systempayv2():
p = Payment(PARAMS)
- data = {'amount': 15.24, 'orderid': '654321',
- 'first_name': u'Jean Michél',
- 'last_name': u'Mihaï'
+ data = {
+ 'amount': 15.24,
+ 'orderid': '654321',
+ 'first_name': u'Jean Michél',
+ 'last_name': u'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' \
- 'T&vads_trans_id=654321&vads_trans_date=20090501193530&vads_amount=15' \
- '24&vads_currency=978&vads_cust_first_name=Jean+Mich%C3%A9l&vads_cust_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'
+ 'T&vads_trans_id=654321&vads_trans_date=20090501193530&vads_amount=15'
+ '24&vads_currency=978&vads_cust_first_name=Jean+Mich%C3%A9l&vads_cust_last_name=Mihaï'
+ )
qs = urlparse.parse_qs(qs)
for key in qs.keys():
qs[key] = qs[key][0]
diff --git a/tests/test_tipi.py b/tests/test_tipi.py
index 9e2660c..c0f194f 100644
--- a/tests/test_tipi.py
+++ b/tests/test_tipi.py
@@ -1,3 +1,19 @@
+# eopayment - online payment library
+# Copyright (C) 2011-2020 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
import datetime
from decimal import Decimal
from six.moves.urllib.parse import urlparse, parse_qs