Projet

Général

Profil

0001-dpark-accept-UTC-datetime-in-payment-notification-41.patch

Benjamin Dauvergne, 07 avril 2020 15:05

Télécharger (6,03 ko)

Voir les différences:

Subject: [PATCH] dpark: accept UTC datetime in payment notification (#41373)

 passerelle/contrib/dpark/models.py | 31 ++++++++++++++++++++++++++++--
 setup.py                           |  1 +
 tests/test_dpark.py                | 26 +++++++++++++++++--------
 3 files changed, 48 insertions(+), 10 deletions(-)
passerelle/contrib/dpark/models.py
16 16

  
17 17
from __future__ import unicode_literals
18 18

  
19
import datetime
19 20
import base64
20 21

  
22
import pytz
23

  
21 24
from django.conf import settings
22 25
from django.db import models
23 26
from django.utils import six, timezone
......
115 118
    if not idate:
116 119
        return None
117 120
    try:
118
        return timezone.datetime.strptime(idate, '%Y%m%d').date().isoformat()
121
        return datetime.datetime.strptime(idate, '%Y%m%d').date().isoformat()
119 122
    except (ValueError,):
120 123
        return idate
121 124

  
122 125

  
126
def date_or_datetime_to_local_date(value):
127
    try:
128
        dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S')
129
    except ValueError:
130
        pass
131
    else:
132
        dt = pytz.utc.localize(dt)
133
        dt = dt.astimezone(pytz.timezone('Europe/Paris'))
134
        return dt.date()
135

  
136
    try:
137
        dt = datetime.datetime.strptime(value, '%Y%m%d')
138
    except ValueError:
139
        pass
140
    else:
141
        return dt.date()
142

  
143
    return None
144

  
145

  
123 146
def normalize_reply(reply):
124 147
    excluded = ('CodeRetour', 'MessageRetour')
125 148
    serialized_reply = serialize_object(reply)
......
414 437
             'transaction_datetime', 'total_amount',
415 438
             'application_external_id')
416 439
        )
440
        # We accept a simple date or a datetime using UTC, we convert it to Europe/Paris timezone on exit
441
        transaction_date = date_or_datetime_to_local_date(data['transaction_datetime'])
442
        if transaction_date is None:
443
            raise APIError(_('Invalid value for transaction datetime'))
417 444
        pairings = Pairing.objects.filter(resource=self,
418 445
                                          nameid=data['nameid'],
419 446
                                          filenumber=data['filenumber'])
......
427 454
            data['application_id'],
428 455
            data.get('applicaiton_payment_type', 10),
429 456
            total_amount,
430
            data['transaction_datetime'],
457
            transaction_date.strftime('%Y%m%d'),
431 458
            data['transaction_id'])
432 459
        for pairing in pairings:
433 460
            pairing.clear_cache()
setup.py
110 110
            'pdfrw',
111 111
            'httplib2',
112 112
            'xmlschema',
113
            'pytz',
113 114
        ],
114 115
        cmdclass={
115 116
            'build': build,
tests/test_dpark.py
73 73

  
74 74

  
75 75
class ReplyDataClass(dict):
76

  
77 76
    def __init__(self, **kwargs):
78 77
        self.__dict__.update(kwargs)
79 78
        super(ReplyDataClass, self).__init__(**kwargs)
......
110 109

  
111 110

  
112 111
def get_client(success=True, error_class=None, replydata=None):
112
    service = MockedService(success, error_class, replydata)
113 113

  
114 114
    def create_service(binging, operation_endpoint):
115
        return MockedService(success, error_class, replydata)
115
        return service
116 116

  
117
    return mock.Mock(create_service=create_service)
117
    return mock.Mock(create_service=create_service, service=service)
118 118

  
119 119

  
120 120
def test_call_service_error(dpark, app):
......
492 492
        assert data['numerodemande'] == '55555'
493 493

  
494 494

  
495
def test_payment_notification(dpark, app):
496
    with mock.patch('passerelle.contrib.dpark.models.get_client') as client:
495
@pytest.mark.parametrize('transaction_datetime,expected_date', [
496
    ('20180611', '20180611'),
497
    # UTC datetime should be converted to Europe/Paris date
498
    ('2018-06-11T23:59:00', '20180612')
499
])
500
def test_payment_notification(dpark, app, transaction_datetime, expected_date):
501
    operation = mock.Mock(name='PLS_NOTIFCB')
502
    service = mock.Mock(spec=['PLS_NOTIFCB'], PLS_NOTIFCB=operation)
503
    create_service = mock.Mock(spec=[], return_value=service)
504
    client = mock.NonCallableMock(spec=['create_service'], create_service=create_service)
505
    with mock.patch('passerelle.contrib.dpark.models.get_client', return_value=client):
497 506
        nameid = 'abcd' * 8
498 507
        filenumber = '1' * 9
499 508
        params = {
500 509
            'nameid': nameid, 'filenumber': filenumber, 'transaction_id': 'I123456789',
501
            'transaction_datetime': '2018-06-11T10:23', 'total_amount': '125',
510
            'transaction_datetime': transaction_datetime, 'total_amount': '125',
502 511
            'application_id': '61718', 'application_external_id': 'E-8-N5UTAK6P'
503 512
        }
504 513
        url = '/dpark/test/notify-payment/'
......
509 518
            'nameid': nameid, 'firstnames': 'spam eggs', 'lastname': 'bar',
510 519
            'filenumber': filenumber, 'badgenumber': '2' * 9}
511 520
        )
512
        client.return_value = get_client(replydata={'CodeRetour': '02', 'MessageRetour': u'Dossier inconnu'})
521
        operation.return_value = mock.Mock(CodeRetour='02', MessageRetour=u'Dossier inconnu')
513 522
        resp = app.post_json(url, params=params)
523
        assert operation.call_args_list[-1].args[5] == expected_date
514 524
        assert resp.json['err'] == 1
515 525
        assert resp.json['err_desc'] == 'Dossier inconnu'
516
        client.return_value = get_client(replydata={'CodeRetour': '01'})
526
        operation.return_value = mock.Mock(CodeRetour='01')
517 527
        resp = app.post_json(url, params=params)
518 528
        assert resp.json['data'] is True
519 529

  
520
-