diff --git a/eopayment/__init__.py b/eopayment/__init__.py index 1d5dade..39441c8 100644 --- a/eopayment/__init__.py +++ b/eopayment/__init__.py @@ -45,8 +45,7 @@ class Payment(object): 'siret': '00000000000001-01', \ } >>> p = Payment(kind=SPPLUS, options=spplus_options) - >>> transaction_id, kind, data = p.request('10.00', email='bob@example.com', \ - next_url='https://my-site.com') + >>> transaction_id, kind, data = p.request('10.00', email='bob@example.com') >>> print (transaction_id, kind, data) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ('...', 1, 'https://www.spplus.net/paiement/init.do?...') @@ -86,7 +85,6 @@ class Payment(object): Arguments: amount -- the amount of money to ask email -- the email of the customer (optional) - next_url -- the URL where the customer will be returned (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. diff --git a/eopayment/dummy.py b/eopayment/dummy.py index 11d1d63..7e62b3b 100644 --- a/eopayment/dummy.py +++ b/eopayment/dummy.py @@ -1,6 +1,7 @@ import urllib import string import logging +import warnings try: from cgi import parse_qs @@ -27,26 +28,33 @@ class Payment(PaymentCommon): You must pass the following keys inside the options dictionnary: - dummy_service_url, the URL of the dummy payment service, it defaults to the one operated by Entr'ouvert. - - direct_notification_url: where to POST to notify the service of a + - automatic_return_url: where to POST to notify the service of a payment - origin: a human string to display to the user about the origin of the request. - siret: an identifier for the eCommerce site, fake. - - next_url: the return URL for the user (can be overriden on a per - request basis). + - normal_return_url: the return URL for the user (can be overriden on a + per request basis). ''' description = { 'caption': 'Dummy payment backend', 'parameters': [ + { + 'name': 'normal_return_url', + 'caption': _('Normal return URL'), + 'default': '', + 'required': True, + }, + { + 'name': 'automatic_return_url', + 'caption': _('Automatic return URL'), + 'required': False, + }, { 'name': 'dummy_service_url', 'caption': 'URL of the dummy payment service', 'default': SERVICE_URL, 'type': str, }, - { 'name': 'direct_notification_url', - 'caption': 'direct notification url', - 'type': str, - }, { 'name': 'origin', 'caption': 'name of the requesting service, ' 'to present in the user interface', @@ -57,10 +65,6 @@ class Payment(PaymentCommon): 'caption': 'dummy siret parameter', 'type': str, }, - { 'name': 'next_url', - 'caption': 'Return URL for the user', - 'type': str, - }, { 'name': 'consider_all_response_signed', 'caption': 'All response will be considered as signed ' '(to test payment locally for example, as you ' @@ -68,6 +72,16 @@ class Payment(PaymentCommon): '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, + }, ], } @@ -77,15 +91,23 @@ class Payment(PaymentCommon): ' 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) - if self.next_url: - next_url = self.next_url + normal_return_url = self.normal_return_url + if next_url and not normal_return_url: + warnings.warn("passing next_url to request() is deprecated, " + "set normal_return_url in options", DeprecationWarning) + normal_return_url = next_url + automatic_return_url = self.automatic_return_url + if self.direct_notification_url and not automatic_return_url: + warnings.warn("direct_notification_url option is deprecated, " + "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': next_url or '', - 'direct_notification_url': self.direct_notification_url, + '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, diff --git a/eopayment/ogone.py b/eopayment/ogone.py index 2a72d7c..e6a65e4 100644 --- a/eopayment/ogone.py +++ b/eopayment/ogone.py @@ -407,6 +407,17 @@ class Payment(PaymentCommon): description = { 'caption': N_('Système de paiement Ogone / Ingenico Payment System e-Commerce'), 'parameters': [ + { + 'name': 'normal_return_url', + 'caption': N_('Normal return URL'), + 'default': '', + 'required': True, + }, + { + 'name': 'automatic_return_url', + 'caption': N_('Automatic return URL (ignored, must be set in Ogone backoffice)'), + 'required': False, + }, {'name': 'environment', 'default': ENVIRONMENT_TEST, 'caption': N_(u'Environnement'), @@ -487,6 +498,12 @@ class Payment(PaymentCommon): 'LANGUAGE': language, 'CURRENCY': self.currency, } + if self.normal_return_url: + params['ACCEPTURL'] = self.normal_return_url + params['BACKURL'] = self.normal_return_url + params['CANCELURL'] = self.normal_return_url + params['DECLINEURL'] = self.normal_return_url + params['EXCEPTIONURL'] = self.normal_return_url if name: params['CN'] = name if email: diff --git a/eopayment/paybox.py b/eopayment/paybox.py index 31a90f1..a6973ae 100644 --- a/eopayment/paybox.py +++ b/eopayment/paybox.py @@ -14,6 +14,7 @@ import urllib import base64 from gettext import gettext as _ import string +import warnings from common import (PaymentCommon, PaymentResponse, FORM, PAID, ERROR, Form, ORDERID_TRANSACTION_SEPARATOR) @@ -127,8 +128,8 @@ class Payment(PaymentCommon): '''Paybox backend for eopayment. If you want to handle Instant Payment Notification, you must pass - a callback parameter to the request() method specifying the URL of - the callback endpoint. + provide a automatic_return_url option specifying the URL of the + callback endpoint. Email is mandatory to emit payment requests with paybox. @@ -143,6 +144,17 @@ class Payment(PaymentCommon): description = { 'caption': _('Paybox'), 'parameters': [ + { + 'name': 'normal_return_url', + 'caption': _('Normal return URL'), + 'default': '', + 'required': False, + }, + { + 'name': 'automatic_return_url', + 'caption': _('Automatic return URL'), + 'required': False, + }, { 'name': 'platform', 'caption': _('Plateforme cible'), @@ -189,6 +201,7 @@ class Payment(PaymentCommon): { 'name': 'callback', 'caption': _('Callback URL'), + 'deprecated': True, }, ] } @@ -212,8 +225,18 @@ class Payment(PaymentCommon): d['PBX_HASH'] = 'SHA512' d['PBX_TIME'] = kwargs.get('time') or (unicode(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00') d['PBX_ARCHIVAGE'] = transaction_id - if self.callback: - d['PBX_REPONDRE_A'] = unicode(self.callback) + if self.normal_return_url: + d['PBX_EFFECTUE'] = self.normal_return_url + d['PBX_REFUSE'] = self.normal_return_url + d['PBX_ANNULE'] = self.normal_return_url + d['PBX_ATTENTE'] = self.normal_return_url + automatic_return_url = self.automatic_return_url + if not automatic_return_url and self.callback: + warnings.warn("callback option is deprecated, " + "use automatic_return_url", DeprecationWarning) + automatic_return_url = self.callback + if automatic_return_url: + d['PBX_REPONDRE_A'] = unicode(automatic_return_url) d = d.items() d = sign(d, self.shared_secret.decode('hex')) url = URLS[self.platform] diff --git a/eopayment/sips.py b/eopayment/sips.py index 73c79d5..47b6d20 100644 --- a/eopayment/sips.py +++ b/eopayment/sips.py @@ -7,6 +7,7 @@ import logging import os import os.path import uuid +import warnings from common import PaymentCommon, HTML, PaymentResponse from cb import CB_RESPONSE_CODES @@ -143,8 +144,13 @@ class Payment(PaymentCommon): params['amount'] = str(int(Decimal(amount) * 100)) if email: params['customer_email'] = email - if next_url: - params['normal_return_url'] = next_url + normal_return_url = self.normal_return_url + if next_url and not normal_return_url: + 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: + params['normal_return_url'] = normal_return_url code, error, form = self.execute('request', params) if int(code) == 0: return params[ORDER_ID], HTML, form diff --git a/eopayment/sips2.py b/eopayment/sips2.py index 2522028..0b72be0 100644 --- a/eopayment/sips2.py +++ b/eopayment/sips2.py @@ -5,6 +5,7 @@ from decimal import Decimal import uuid import hashlib from gettext import gettext as _ +import warnings from common import PaymentCommon, FORM, Form, PaymentResponse, PAID, ERROR, CANCELED @@ -92,7 +93,7 @@ class Payment(PaymentCommon): { 'name': 'normal_return_url', 'caption': _('Normal return URL'), - 'default': 'http://www.example.com/', + 'default': '', 'required': True, }, { @@ -129,6 +130,8 @@ class Payment(PaymentCommon): data['merchantId'] = self.merchand_id data['keyVersion'] = self.key_version data['normalReturnUrl'] = self.normal_return_url + if self.automatic_return_url: + date['automaticReturnUrl'] = self.automatic_return_url data['currencyCode'] = self.currency_code return data @@ -144,7 +147,12 @@ class Payment(PaymentCommon): data['amount'] = unicode(int(Decimal(amount) * 100)) if email: data['billingContact.email'] = email - if next_url: + normal_return_url = self.normal_return_url + if next_url and not normal_return_url: + 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: data['normalReturnUrl'] = next_url form = Form( url=self.get_url(), diff --git a/eopayment/spplus.py b/eopayment/spplus.py index 1e9b11c..fcf7586 100644 --- a/eopayment/spplus.py +++ b/eopayment/spplus.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from decimal import Decimal import binascii +from gettext import gettext as _ import hmac import hashlib import urlparse @@ -9,6 +10,7 @@ import string import datetime as dt import logging import re +import warnings import Crypto.Cipher.DES from common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED, @@ -92,6 +94,17 @@ class Payment(PaymentCommon): description = { 'caption': "SPPlus payment service of French bank Caisse d'epargne", 'parameters': [ + { + 'name': 'normal_return_url', + 'caption': _('Normal return URL'), + 'default': '', + 'required': True, + }, + { + 'name': 'automatic_return_url', + 'caption': _('Automatic return URL'), + 'required': False, + }, { 'name': 'cle', 'caption': 'Secret key, a 40 digits hexadecimal number', 'regexp': re.compile('^ *((?:[a-fA-F0-9] *){40}) *$') @@ -125,8 +138,7 @@ class Payment(PaymentCommon): 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): - logger.debug('requesting spplus payment with montant %s email=%s and \ -next_url=%s' % (amount, email, next_url)) + 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') @@ -142,12 +154,17 @@ next_url=%s' % (amount, email, next_url)) 'moyen': self.moyen } if email: fields['email'] = email - if next_url: - if (not next_url.startswith('http://') \ - and not next_url.startswith('https://')) \ - or '?' in next_url: - raise ValueError('next_url must be an absolute URL without parameters') - fields['urlretour'] = next_url + normal_return_url = self.normal_return_url + if next_url and not normal_return_url: + 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: + 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, diff --git a/eopayment/systempayv2.py b/eopayment/systempayv2.py index 90bb822..fb36b4c 100644 --- a/eopayment/systempayv2.py +++ b/eopayment/systempayv2.py @@ -5,6 +5,7 @@ import hashlib import logging import string import urlparse +import warnings from gettext import gettext as _ from common import PaymentCommon, PaymentResponse, PAID, ERROR, FORM, Form @@ -214,6 +215,17 @@ class Payment(PaymentCommon): description = { 'caption': 'SystemPay, système de paiment du groupe BPCE', 'parameters': [ + { + 'name': 'normal_return_url', + 'caption': _('Normal return URL'), + 'default': '', + 'required': True, + }, + { + 'name': 'automatic_return_url', + 'caption': _('Automatic return URL (ignored, must be set in Payzen/SystemPay backoffice)'), + 'required': False, + }, {'name': 'service_url', 'default': service_url, 'caption': _(u'URL du service de paiment'), @@ -266,8 +278,13 @@ class Payment(PaymentCommon): kwargs.update(add_vads({'amount': unicode(amount)})) if amount < 0: raise ValueError('amount must be an integer >= 0') + normal_return_url = self.normal_return_url if next_url: - kwargs[VADS_URL_RETURN] = unicode(next_url) + 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] = unicode(normal_return_url) if name is not None: kwargs['vads_cust_name'] = unicode(name) if address is not None: diff --git a/eopayment/tipi.py b/eopayment/tipi.py index 763cfa8..2534649 100644 --- a/eopayment/tipi.py +++ b/eopayment/tipi.py @@ -7,6 +7,7 @@ from urllib import urlencode from urlparse import parse_qs from gettext import gettext as _ import logging +import warnings from systempayv2 import isonow @@ -39,7 +40,17 @@ class Payment(PaymentCommon): 'help_text': _(u'ne pas modifier si vous ne savez pas'), 'validation': lambda x: x.startswith('http'), 'required': True, - } + }, + { + 'name': 'normal_return_url', + 'caption': _('Normal return URL (unused by TIPI)'), + 'required': False, + }, + { + 'name': 'automatic_return_url', + 'caption': _('Automatic return URL'), + 'required': True, + }, ], } @@ -61,9 +72,15 @@ class Payment(PaymentCommon): 'a decimal integer with less than 4 digits ' 'before and 2 digits after the decimal point ' ', here it is %s' % repr(amount)) - if next_url is not None: - if not isinstance(next_url, str) or \ - not next_url.startswith('http'): + + 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) + 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'): raise ValueError('URLCL invalid URL format') try: if exer is not None: @@ -117,8 +134,8 @@ class Payment(PaymentCommon): } if exer: params['exer'] = exer - if next_url: - params['urlcl'] = next_url + if automatic_return_url: + params['urlcl'] = automatic_return_url url = '%s?%s' % (self.service_url, urlencode(params)) return transaction_id, URL, url