Projet

Général

Profil

0002-allow-arbitrary-date-for-deferred-payment-26992.patch

Emmanuel Cazenave, 08 novembre 2018 12:44

Télécharger (13,3 ko)

Voir les différences:

Subject: [PATCH 2/2] allow arbitrary date for deferred payment (#26992)

 eopayment/__init__.py      | 32 +++++++++++++++++-
 eopayment/paybox.py        |  5 +--
 eopayment/sips2.py         |  4 +--
 eopayment/systempayv2.py   |  8 ++++-
 tests/test_base_payment.py | 66 ++++++++++++++++++++++++++++++++++++++
 tests/test_paybox.py       | 31 ++++++++++++++++++
 tests/test_sips2.py        |  5 +++
 tests/test_systempayv2.py  | 49 ++++++++++++++++++++++++++++
 tox.ini                    |  1 +
 9 files changed, 195 insertions(+), 6 deletions(-)
 create mode 100644 tests/test_base_payment.py
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
@pytest.mark.freeze_time('2018-10-02 23:50:00')
57
def test_paris_timezone(monkeypatch):
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
-