0002-allow-arbitrary-date-for-deferred-payment-26992.patch
eopayment/__init__.py | ||
---|---|---|
1 | 1 |
# -*- coding: utf-8 -*- |
2 | 2 | |
3 |
import datetime |
|
3 | 4 |
import importlib |
4 | 5 |
import logging |
6 |
import pytz |
|
7 | ||
5 | 8 | |
6 | 9 |
from .common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED, |
7 | 10 |
CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text) |
... | ... | |
102 | 105 |
- the third is the URL or the HTML form to contact the payment |
103 | 106 |
server, which must be sent to the customer browser. |
104 | 107 |
''' |
105 |
logger.debug(u'%r' % kwargs) |
|
108 |
logger.debug(u'%r' % kwargs) |
|
109 | ||
110 |
if 'capture_date' in kwargs: |
|
111 |
capture_date = kwargs.pop('capture_date') |
|
112 | ||
113 |
delay_param = False |
|
114 |
for parameter in self.backend.description['parameters']: |
|
115 |
if parameter['name'] == 'capture_day': |
|
116 |
delay_param = True |
|
117 |
break |
|
118 | ||
119 |
if not delay_param: |
|
120 |
raise ValueError('capture_date is not supported by the backend.') |
|
121 | ||
122 |
if not isinstance(capture_date, datetime.date): |
|
123 |
raise ValueError('capture_date should be a datetime.date object.') |
|
124 | ||
125 |
# backend timezone should come from some backend configuration |
|
126 |
backend_tz = pytz.timezone('Europe/Paris') |
|
127 |
utc_tz = pytz.timezone('Etc/UTC') |
|
128 |
backend_trans_date = utc_tz.localize( |
|
129 |
datetime.datetime.utcnow()).astimezone(backend_tz) |
|
130 |
capture_day = (capture_date - backend_trans_date.date()).days |
|
131 |
if capture_day <= 0: |
|
132 |
raise ValueError("capture_date needs to be superior to the transaction date.") |
|
133 | ||
134 |
kwargs['capture_day'] = capture_day |
|
135 | ||
106 | 136 |
for param in kwargs: |
107 | 137 |
# encode all input params to unicode |
108 | 138 |
kwargs[param] = force_text(kwargs[param]) |
eopayment/paybox.py | ||
---|---|---|
279 | 279 |
warnings.warn("callback option is deprecated, " |
280 | 280 |
"use automatic_return_url", DeprecationWarning) |
281 | 281 |
automatic_return_url = self.callback |
282 |
if self.capture_day: |
|
283 |
d['PBX_DIFF'] = self.capture_day.zfill(2) |
|
282 |
capture_day = capture_day = kwargs.get('capture_day', self.capture_day) |
|
283 |
if capture_day: |
|
284 |
d['PBX_DIFF'] = capture_day.zfill(2) |
|
284 | 285 |
d['PBX_AUTOSEULE'] = PAYMENT_MODES[self.capture_mode] |
285 | 286 |
if automatic_return_url: |
286 | 287 |
d['PBX_REPONDRE_A'] = force_text(automatic_return_url) |
eopayment/sips2.py | ||
---|---|---|
181 | 181 |
data['amount'] = force_text(int(Decimal(amount) * 100)) |
182 | 182 |
if email: |
183 | 183 |
data['billingContact.email'] = email |
184 |
if 'captureDay' in kwargs:
|
|
185 |
data['captureDay'] == kwargs.get('captureDay')
|
|
184 |
if 'capture_day' in kwargs:
|
|
185 |
data['captureDay'] = kwargs.get('capture_day')
|
|
186 | 186 |
normal_return_url = self.normal_return_url |
187 | 187 |
if next_url and not normal_return_url: |
188 | 188 |
warnings.warn("passing next_url to request() is deprecated, " |
eopayment/systempayv2.py | ||
---|---|---|
82 | 82 |
choices=('SILENT', 'INTERACTIVE')), |
83 | 83 |
Parameter('vads_amount', 'n', 9, max_length=12, needed=True), |
84 | 84 |
Parameter('vads_capture_delay', 'n', 6, max_length=3, default=''), |
85 |
# Same as 'vads_capture_delay' but matches other backend naming for |
|
86 |
# deferred payment |
|
87 |
Parameter('capture_day', 'n', 6, max_length=3, default=''), |
|
85 | 88 |
Parameter('vads_contrib', 'ans', 31, max_length=255, default='eopayment'), |
86 | 89 |
# defaut currency = EURO, norme ISO4217 |
87 | 90 |
Parameter('vads_currency', 'n', 10, length=3, default='978', needed=True), |
... | ... | |
248 | 251 | |
249 | 252 |
for name in ('vads_ctx_mode', VADS_SITE_ID, 'vads_order_info', |
250 | 253 |
'vads_order_info2', 'vads_order_info3', |
251 |
'vads_payment_cards', 'vads_payment_config'): |
|
254 |
'vads_payment_cards', 'vads_payment_config', 'capture_day'):
|
|
252 | 255 |
parameter = PARAMETER_MAP[name] |
253 | 256 |
x = {'name': name, |
254 | 257 |
'caption': parameter.description or name, |
... | ... | |
332 | 335 |
fields[name] = parameter.default() |
333 | 336 |
else: |
334 | 337 |
fields[name] = parameter.default |
338 |
capture_day = fields.pop('capture_day') |
|
339 |
if capture_day: |
|
340 |
fields['vads_capture_delay'] = capture_day |
|
335 | 341 |
check_vads(fields) |
336 | 342 |
fields[SIGNATURE] = force_text(self.signature(fields)) |
337 | 343 |
self.logger.debug('%s request contains fields: %s', __name__, fields) |
tests/test_base_payment.py | ||
---|---|---|
1 |
from datetime import date, datetime, timedelta |
|
2 | ||
3 |
import mock |
|
4 |
import pytest |
|
5 | ||
6 | ||
7 |
def do_mock_backend(monkeypatch): |
|
8 | ||
9 |
class MockBackend(object): |
|
10 | ||
11 |
request = mock.Mock() |
|
12 | ||
13 |
description = { |
|
14 |
'parameters': [ |
|
15 |
{ |
|
16 |
'name': 'capture_day', |
|
17 |
} |
|
18 |
] |
|
19 |
} |
|
20 | ||
21 |
def get_backend(*args, **kwargs): |
|
22 |
def backend(*args, **kwargs): |
|
23 |
return MockBackend |
|
24 |
return backend |
|
25 | ||
26 |
import eopayment |
|
27 |
monkeypatch.setattr(eopayment, 'get_backend', get_backend) |
|
28 |
return MockBackend, eopayment.Payment('kind', None) |
|
29 | ||
30 | ||
31 |
def test_deferred_payment(monkeypatch): |
|
32 |
mock_backend, payment = do_mock_backend(monkeypatch) |
|
33 | ||
34 |
capture_date = (datetime.now().date() + timedelta(days=3)) |
|
35 |
payment.request(amount=12.2, capture_date=capture_date) |
|
36 |
mock_backend.request.assert_called_with(12.2, **{'capture_day': u'3'}) |
|
37 | ||
38 |
# capture date can't be inferior to the transaction date |
|
39 |
capture_date = (datetime.now().date() - timedelta(days=3)) |
|
40 |
with pytest.raises( |
|
41 |
ValueError, match='capture_date needs to be superior to the transaction date.'): |
|
42 |
payment.request(amount=12.2, capture_date=capture_date) |
|
43 | ||
44 |
# capture date should be a date object |
|
45 |
capture_date = 'not a date' |
|
46 |
with pytest.raises(ValueError, match='capture_date should be a datetime.date object.'): |
|
47 |
payment.request(amount=12.2, capture_date=capture_date) |
|
48 | ||
49 |
# using capture date on a backend that does not support it raise an error |
|
50 |
capture_date = (datetime.now().date() + timedelta(days=3)) |
|
51 |
mock_backend.description['parameters'] = [] |
|
52 |
with pytest.raises(ValueError, match='capture_date is not supported by the backend.'): |
|
53 |
payment.request(amount=12.2, capture_date=capture_date) |
|
54 | ||
55 | ||
56 |
def test_paris_timezone(freezer, monkeypatch): |
|
57 |
freezer.move_to('2018-10-02 23:50:00') |
|
58 |
_, payment = do_mock_backend(monkeypatch) |
|
59 |
capture_date = date(year=2018, month=10, day=3) |
|
60 | ||
61 |
with pytest.raises( |
|
62 |
ValueError, match='capture_date needs to be superior to the transaction date'): |
|
63 |
# utcnow will return 2018-10-02 23:50:00, |
|
64 |
# converted to Europe/Paris it is already 2018-10-03 |
|
65 |
# so 2018-10-03 for capture_date is invalid |
|
66 |
payment.request(amount=12.2, capture_date=capture_date) |
tests/test_paybox.py | ||
---|---|---|
105 | 105 |
self.assertIn('PBX_DIFF', form_params) |
106 | 106 |
self.assertEqual(form_params['PBX_DIFF'], '07') |
107 | 107 | |
108 |
# capture_day can be used as a request argument |
|
109 |
params = BACKEND_PARAMS.copy() |
|
110 |
backend = eopayment.Payment('paybox', params) |
|
111 |
transaction_id, kind, what = backend.request( |
|
112 |
Decimal(amount), email=email, orderid=order_id, |
|
113 |
transaction_id=transaction, time=time, capture_day=2) |
|
114 |
root = ET.fromstring(str(what)) |
|
115 | ||
116 |
form_params = dict((( |
|
117 |
node.attrib['name'], node.attrib['value']) for node in root |
|
118 |
if node.attrib['type'] == 'hidden')) |
|
119 |
self.assertIn('PBX_DIFF', form_params) |
|
120 |
self.assertEqual(form_params['PBX_DIFF'], '02') |
|
121 | ||
122 |
# capture_day passed as a request argument |
|
123 |
# overrides capture_day from backend params |
|
124 |
params = BACKEND_PARAMS.copy() |
|
125 |
params['capture_day'] = '7' |
|
126 |
backend = eopayment.Payment('paybox', params) |
|
127 |
transaction_id, kind, what = backend.request( |
|
128 |
Decimal(amount), email=email, orderid=order_id, |
|
129 |
transaction_id=transaction, time=time, capture_day=2) |
|
130 |
root = ET.fromstring(str(what)) |
|
131 | ||
132 |
form_params = dict((( |
|
133 |
node.attrib['name'], node.attrib['value']) for node in root |
|
134 |
if node.attrib['type'] == 'hidden')) |
|
135 |
self.assertIn('PBX_DIFF', form_params) |
|
136 |
self.assertEqual(form_params['PBX_DIFF'], '02') |
|
137 | ||
138 | ||
108 | 139 |
def test_request_with_authorization_only(self): |
109 | 140 |
params = BACKEND_PARAMS.copy() |
110 | 141 |
time = '2018-08-21T10:26:32+02:00' |
tests/test_sips2.py | ||
---|---|---|
19 | 19 |
data = [f for f in form.fields if f['name'] == 'Data'] |
20 | 20 |
assert 'statementReference=foobar' in data[0]['value'] |
21 | 21 | |
22 |
transaction, f, form = backend.request(amount=u'12', info1='foobar', capture_day=u'1') |
|
23 |
data = [f for f in form.fields if f['name'] == 'Data'] |
|
24 |
assert 'captureDay=1' in data[0]['value'] |
|
25 | ||
26 | ||
22 | 27 |
def test_options(): |
23 | 28 |
payment = eopayment.Payment('sips2', {'capture_mode': u'VALIDATION'}) |
24 | 29 |
assert payment.backend.get_data()['captureMode'] == 'VALIDATION' |
tests/test_systempayv2.py | ||
---|---|---|
1 | 1 |
# -*- coding: utf-8 -*- |
2 |
from datetime import datetime, timedelta |
|
2 | 3 | |
3 | 4 |
import pytest |
4 | 5 |
from six.moves.urllib import parse as urlparse |
5 | 6 | |
7 |
import eopayment |
|
6 | 8 |
from eopayment.systempayv2 import Payment, VADS_CUST_FIRST_NAME, \ |
7 | 9 |
VADS_CUST_LAST_NAME, PAID |
8 | 10 |
from eopayment import ResponseError |
... | ... | |
14 | 16 |
'vads_trans_date': u'20090501193530', |
15 | 17 |
} |
16 | 18 | |
19 | ||
20 |
def get_field(form, field_name): |
|
21 |
for field in form.fields: |
|
22 |
if field['name'] == field_name: |
|
23 |
return field |
|
24 | ||
25 | ||
17 | 26 |
def test_systempayv2(): |
18 | 27 |
p = Payment(PARAMS) |
19 | 28 |
data = {'amount': 15.24, 'orderid': '654321', |
... | ... | |
49 | 58 |
# bad response |
50 | 59 |
with pytest.raises(ResponseError, match='missing signature, vads_ctx_mode or vads_auth_result'): |
51 | 60 |
p.response('foo=bar') |
61 | ||
62 | ||
63 |
def test_systempayv2_deferred_payment(): |
|
64 |
default_params = { |
|
65 |
'secret_test': u'1122334455667788', |
|
66 |
'vads_site_id': u'12345678', |
|
67 |
'vads_ctx_mode': u'TEST', |
|
68 |
} |
|
69 |
default_data = { |
|
70 |
'amount': 15.24, 'orderid': '654321', 'first_name': u'John', |
|
71 |
'last_name': u'Doe' |
|
72 |
} |
|
73 | ||
74 |
# default vads_capture_delay used |
|
75 |
params = default_params.copy() |
|
76 |
params['vads_capture_delay'] = 1 |
|
77 | ||
78 |
backend = eopayment.Payment('systempayv2', params) |
|
79 |
data = default_data.copy() |
|
80 |
transaction_id, f, form = backend.request(**data) |
|
81 |
assert get_field(form, 'vads_capture_delay')['value'] == '1' |
|
82 | ||
83 |
# vads_capture_delay can used in request and |
|
84 |
# override default vads_capture_delay |
|
85 |
params = default_params.copy() |
|
86 |
params['vads_capture_delay'] = 1 |
|
87 |
p = eopayment.Payment('systempayv2', params) |
|
88 |
data = default_data.copy() |
|
89 |
data['vads_capture_delay'] = '3' |
|
90 |
transaction_id, f, form = p.request(**data) |
|
91 |
assert get_field(form, 'vads_capture_delay')['value'] == '3' |
|
92 | ||
93 |
# capture_date can be used for deferred_payment |
|
94 |
params = default_params.copy() |
|
95 |
params['vads_capture_delay'] = 1 |
|
96 |
p = eopayment.Payment('systempayv2', params) |
|
97 |
data = default_data.copy() |
|
98 |
data['capture_date'] = (datetime.now().date() + timedelta(days=4)) |
|
99 |
transaction_id, f, form = p.request(**data) |
|
100 |
assert get_field(form, 'vads_capture_delay')['value'] == '4' |
tox.ini | ||
---|---|---|
16 | 16 |
usedevelop = True |
17 | 17 |
deps = coverage |
18 | 18 |
pytest |
19 |
pytest-freezegun |
|
19 | 20 |
py2: pytest-cov |
20 | 21 |
mock |
21 |
- |