dpark: accept UTC datetime in payment notification (#41373)

This commit is contained in:
Benjamin Dauvergne 2020-04-07 15:04:38 +02:00
parent 555aa3c49d
commit f2b06c9a08
3 changed files with 48 additions and 10 deletions

View File

@ -16,8 +16,11 @@
from __future__ import unicode_literals
import datetime
import base64
import pytz
from django.conf import settings
from django.db import models
from django.utils import six, timezone
@ -115,11 +118,31 @@ def date_to_isoformat(idate):
if not idate:
return None
try:
return timezone.datetime.strptime(idate, '%Y%m%d').date().isoformat()
return datetime.datetime.strptime(idate, '%Y%m%d').date().isoformat()
except (ValueError,):
return idate
def date_or_datetime_to_local_date(value):
try:
dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S')
except ValueError:
pass
else:
dt = pytz.utc.localize(dt)
dt = dt.astimezone(pytz.timezone('Europe/Paris'))
return dt.date()
try:
dt = datetime.datetime.strptime(value, '%Y%m%d')
except ValueError:
pass
else:
return dt.date()
return None
def normalize_reply(reply):
excluded = ('CodeRetour', 'MessageRetour')
serialized_reply = serialize_object(reply)
@ -414,6 +437,10 @@ class DPark(BaseResource):
'transaction_datetime', 'total_amount',
'application_external_id')
)
# We accept a simple date or a datetime using UTC, we convert it to Europe/Paris timezone on exit
transaction_date = date_or_datetime_to_local_date(data['transaction_datetime'])
if transaction_date is None:
raise APIError(_('Invalid value for transaction datetime'))
pairings = Pairing.objects.filter(resource=self,
nameid=data['nameid'],
filenumber=data['filenumber'])
@ -427,7 +454,7 @@ class DPark(BaseResource):
data['application_id'],
data.get('applicaiton_payment_type', 10),
total_amount,
data['transaction_datetime'],
transaction_date.strftime('%Y%m%d'),
data['transaction_id'])
for pairing in pairings:
pairing.clear_cache()

View File

@ -110,6 +110,7 @@ setup(name='passerelle',
'pdfrw',
'httplib2',
'xmlschema',
'pytz',
],
cmdclass={
'build': build,

View File

@ -73,7 +73,6 @@ def dpark(db):
class ReplyDataClass(dict):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
super(ReplyDataClass, self).__init__(**kwargs)
@ -110,11 +109,12 @@ class MockedService(object):
def get_client(success=True, error_class=None, replydata=None):
service = MockedService(success, error_class, replydata)
def create_service(binging, operation_endpoint):
return MockedService(success, error_class, replydata)
return service
return mock.Mock(create_service=create_service)
return mock.Mock(create_service=create_service, service=service)
def test_call_service_error(dpark, app):
@ -492,13 +492,22 @@ def test_get_payment_infos(dpark, app):
assert data['numerodemande'] == '55555'
def test_payment_notification(dpark, app):
with mock.patch('passerelle.contrib.dpark.models.get_client') as client:
@pytest.mark.parametrize('transaction_datetime,expected_date', [
('20180611', '20180611'),
# UTC datetime should be converted to Europe/Paris date
('2018-06-11T23:59:00', '20180612')
])
def test_payment_notification(dpark, app, transaction_datetime, expected_date):
operation = mock.Mock(name='PLS_NOTIFCB')
service = mock.Mock(spec=['PLS_NOTIFCB'], PLS_NOTIFCB=operation)
create_service = mock.Mock(spec=[], return_value=service)
client = mock.NonCallableMock(spec=['create_service'], create_service=create_service)
with mock.patch('passerelle.contrib.dpark.models.get_client', return_value=client):
nameid = 'abcd' * 8
filenumber = '1' * 9
params = {
'nameid': nameid, 'filenumber': filenumber, 'transaction_id': 'I123456789',
'transaction_datetime': '2018-06-11T10:23', 'total_amount': '125',
'transaction_datetime': transaction_datetime, 'total_amount': '125',
'application_id': '61718', 'application_external_id': 'E-8-N5UTAK6P'
}
url = '/dpark/test/notify-payment/'
@ -509,11 +518,12 @@ def test_payment_notification(dpark, app):
'nameid': nameid, 'firstnames': 'spam eggs', 'lastname': 'bar',
'filenumber': filenumber, 'badgenumber': '2' * 9}
)
client.return_value = get_client(replydata={'CodeRetour': '02', 'MessageRetour': u'Dossier inconnu'})
operation.return_value = mock.Mock(CodeRetour='02', MessageRetour=u'Dossier inconnu')
resp = app.post_json(url, params=params)
assert operation.call_args_list[-1].args[5] == expected_date
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Dossier inconnu'
client.return_value = get_client(replydata={'CodeRetour': '01'})
operation.return_value = mock.Mock(CodeRetour='01')
resp = app.post_json(url, params=params)
assert resp.json['data'] is True