From 335513b34bfa0f642bd6d3440e9f65e1e9d9a830 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Fri, 6 Aug 2021 12:33:15 +0200
Subject: [PATCH] caluire-axel: check DUI on pay_invoice endpoint (#56006)

---
 passerelle/contrib/caluire_axel/models.py | 28 +++++++++++--------
 tests/test_caluire_axel.py                | 34 +++++++++++++++++++++--
 2 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/passerelle/contrib/caluire_axel/models.py b/passerelle/contrib/caluire_axel/models.py
index ce934fd5..2946eebf 100644
--- a/passerelle/contrib/caluire_axel/models.py
+++ b/passerelle/contrib/caluire_axel/models.py
@@ -1198,58 +1198,62 @@ class CaluireAxel(BaseResource):
         post={
             'request_body': {
                 'schema': {
                     'application/json': schemas.PAYMENT_SCHEMA,
                 }
             }
         },
     )
-    def pay_invoice(self, request, regie_id, invoice_id, **kwargs):
-        family_id, invoice_id = invoice_id.split('-')
+    def pay_invoice(self, request, regie_id, invoice_id, NameID, post_data):
+        family_id, real_invoice_id = invoice_id.split('-')
+        link = self.get_link(NameID)
+        assert link.family_id == family_id, 'invoice does not belongs to linked family'
 
-        invoice = self.get_invoice(regie_id=regie_id, family_id=family_id, invoice_id=invoice_id)
+        invoice = self.get_invoice(regie_id=regie_id, family_id=family_id, invoice_id=real_invoice_id)
         if invoice is None:
             raise APIError('Invoice not found', err_code='not-found')
 
         transaction_amount = invoice['amount']
-        post_data = {
-            'IDFACTURE': int(invoice_id),
+        payload = {
+            'IDFACTURE': int(real_invoice_id),
             'IDENTREGIEENC': regie_id,
             'MONTANT': transaction_amount,
             'IDENTMODEREGLEMENT': 'INCB',
         }
         try:
-            result = schemas.set_paiement(self, {'PORTAIL': {'SETPAIEMENT': post_data}})
+            result = schemas.set_paiement(self, {'PORTAIL': {'SETPAIEMENT': payload}})
         except axel.AxelError as e:
             raise APIError(
                 'Axel error: %s' % e,
                 err_code='error',
                 data={
                     'xml_request': e.xml_request,
                     'xml_response': e.xml_response,
                     'regie_id': regie_id,
-                    'family_id': family_id,
-                    'invoice': invoice,
+                    'invoice_id': invoice_id,
+                    'NameID': NameID,
                     'post_data': post_data,
-                    'kwargs': kwargs,
+                    'invoice': invoice,
+                    'payload': payload,
                 },
             )
         try:
             code = int(result.json_response['DATA']['PORTAIL']['SETPAIEMENT']['CODE'])
         except (KeyError, ValueError):
             raise APIError(
                 'Wrong pay-invoice response',
                 err_code='pay-invoice-code-response-error',
                 data={
                     'regie_id': regie_id,
-                    'family_id': family_id,
-                    'invoice': invoice,
+                    'invoice_id': invoice_id,
+                    'NameID': NameID,
                     'post_data': post_data,
-                    'kwargs': kwargs,
+                    'invoice': invoice,
+                    'payload': payload,
                     'result': result.json_response,
                 },
                 http_status=500,
             )
 
         if code < 0:
             raise APIError('Wrong pay-invoice status', err_code='pay-invoice-code-error-%s' % code)
 
diff --git a/tests/test_caluire_axel.py b/tests/test_caluire_axel.py
index d62f6c1d..196dc4b0 100644
--- a/tests/test_caluire_axel.py
+++ b/tests/test_caluire_axel.py
@@ -3298,17 +3298,26 @@ def test_pay_invoice_endpoint_axel_error(app, resource):
     with mock_data(content, 'GetFacturesaPayer'):
         with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
             operation.side_effect = AxelError('FooBar')
             resp = app.post_json(
                 '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload
             )
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
-    for key in ('xml_request', 'xml_response', 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs'):
+    for key in (
+        'xml_request',
+        'xml_response',
+        'regie_id',
+        'invoice_id',
+        'NameID',
+        'post_data',
+        'invoice',
+        'payload',
+    ):
         assert key in resp.json['data'].keys()
 
     content2 = '''
 <PORTAIL>
   <SETPAIEMENT>
     <CODE>-3</CODE>
   </SETPAIEMENT>
 </PORTAIL>'''
@@ -3324,23 +3333,40 @@ def test_pay_invoice_endpoint_axel_error(app, resource):
 
 
 def test_pay_invoice_endpoint_bad_request(app, resource):
     resp = app.post_json(
         '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params={}, status=400
     )
     assert resp.json['err_desc'] == "'transaction_date' is a required property"
 
+    payload = {
+        'transaction_date': '2021-06-15T12:00:00',
+        'transaction_id': 'foo',
+    }
+    resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
+    assert resp.json['err_desc'] == "Person not found"
+    assert resp.json['err'] == 'not-found'
+
+    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
+    resp = app.post_json(
+        '/caluire-axel/test/regie/MAREGIE/invoice/ZZZ-42/pay?NameID=yyy', params=payload, status=500
+    )
+    assert resp.json['err'] == 1
+    assert resp.json['err_class'] == 'AssertionError'
+    assert resp.json['err_desc'] == 'invoice does not belongs to linked family'
+
 
 @freezegun.freeze_time('2019-12-04')
 def test_pay_invoice_endpoint_no_result(app, resource):
     payload = {
         'transaction_date': '2021-06-15T12:00:00',
         'transaction_id': 'foo',
     }
+    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
     filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
     with open(filepath) as xml:
         content = (
             '''<PORTAIL>
   <GETFACTURESAPAYER>
     %s
   </GETFACTURESAPAYER>
 </PORTAIL>'''
@@ -3357,16 +3383,17 @@ def test_pay_invoice_endpoint_no_result(app, resource):
     assert resp.json['err'] == 'not-found'
 
 
 def test_pay_invoice_endpoint_wrong_response(app, resource):
     payload = {
         'transaction_date': '2021-06-15T12:00:00',
         'transaction_id': 'foo',
     }
+    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
     with mock.patch(
         'passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice',
         return_value={'amount': '44.9'},
     ):
         with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
             operation.return_value = OperationResult(
                 json_response={'DATA': {'PORTAIL': {}}},
                 xml_request='',
@@ -3374,33 +3401,33 @@ def test_pay_invoice_endpoint_wrong_response(app, resource):
             )
             resp = app.post_json(
                 '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy',
                 params=payload,
                 status=500,
             )
         assert resp.json['err'] == 'pay-invoice-code-response-error'
         assert resp.json['err_desc'] == 'Wrong pay-invoice response'
-        for key in 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs', 'result':
+        for key in 'regie_id', 'invoice_id', 'NameID', 'post_data', 'invoice', 'payload', 'result':
             assert key in resp.json['data'].keys()
 
         with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
             operation.return_value = OperationResult(
                 json_response={'DATA': {'PORTAIL': {'SETPAIEMENT': {'CODE': 'oups'}}}},
                 xml_request='',
                 xml_response='',
             )
             resp = app.post_json(
                 '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy',
                 params=payload,
                 status=500,
             )
         assert resp.json['err'] == 'pay-invoice-code-response-error'
         assert resp.json['err_desc'] == 'Wrong pay-invoice response'
-        for key in 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs', 'result':
+        for key in 'regie_id', 'invoice_id', 'NameID', 'post_data', 'invoice', 'payload', 'result':
             assert key in resp.json['data'].keys()
 
 
 def test_pay_invoice_endpoint(app, resource):
     payload = {
         'transaction_date': '2021-06-15T12:00:00',
         'transaction_id': 'foo',
     }
@@ -3433,16 +3460,17 @@ def test_pay_invoice_endpoint(app, resource):
     assert resp.json['created'] is True
 
 
 def test_pay_invoice_providing_mode_reglement(app, resource):
     payload = {
         'transaction_date': '2021-06-15T12:00:00',
         'transaction_id': 'foo',
     }
+    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
     with mock.patch(
         'passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice',
         return_value={'amount': '44.9'},
     ):
         with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
             operation.return_value = OperationResult(
                 json_response={'DATA': {'PORTAIL': {'SETPAIEMENT': {'CODE': 0}}}},
                 xml_request='',
-- 
2.30.2

