From ae792f767cb556e885c77deeff73c8bbd6df723a Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 26 Aug 2021 12:35:17 +0200
Subject: [PATCH] caluire-axel: allow to call invoice endpoint anonymously
 (#56006)

---
 passerelle/contrib/caluire_axel/models.py | 14 +++-
 tests/test_caluire_axel.py                | 82 +++++++++++++++++++++++
 2 files changed, 93 insertions(+), 3 deletions(-)

diff --git a/passerelle/contrib/caluire_axel/models.py b/passerelle/contrib/caluire_axel/models.py
index ce934fd5..36407c3c 100644
--- a/passerelle/contrib/caluire_axel/models.py
+++ b/passerelle/contrib/caluire_axel/models.py
@@ -1103,24 +1103,32 @@ class CaluireAxel(BaseResource):
         description=_('Get invoice details'),
         parameters={
             'NameID': {'description': _('Publik ID')},
             'regie_id': {'description': _('Regie identifier'), 'example_value': 'ENF'},
             'invoice_id': {'description': _('Invoice identifier'), 'example_value': 'IDFAM-42'},
             'nb_mounts_limit': {'description': _('Number of months of history'), 'example_value': '12'},
         },
     )
-    def invoice(self, request, regie_id, invoice_id, NameID, nb_mounts_limit='12'):
-        link = self.get_link(NameID)
+    def invoice(self, request, regie_id, invoice_id, NameID=None, nb_mounts_limit='12'):
         real_invoice_id = invoice_id.split('-')[-1]
         historical = invoice_id.startswith('historical-')
+        if historical:
+            invoice_id = invoice_id[len('historical-') :]
+        family_id, real_invoice_id = invoice_id.split('-')
+        if NameID:
+            link = self.get_link(NameID)
+            if link.family_id != family_id:
+                raise APIError(
+                    'Invoice does not belongs to linked family', err_code='bad-request', http_status=400
+                )
         invoice = self.get_invoice(
             regie_id=regie_id,
             invoice_id=real_invoice_id,
-            family_id=link.family_id,
+            family_id=family_id,
             historical=historical,
             nb_mounts_limit=nb_mounts_limit,
         )
         if invoice is None:
             raise APIError('Invoice not found', err_code='not-found')
 
         return {'data': invoice}
 
diff --git a/tests/test_caluire_axel.py b/tests/test_caluire_axel.py
index d62f6c1d..d1429973 100644
--- a/tests/test_caluire_axel.py
+++ b/tests/test_caluire_axel.py
@@ -3010,16 +3010,20 @@ def test_invoice_endpoint_axel_error(app, resource):
         operation.side_effect = AxelError('FooBar')
         resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
 
 
 def test_invoice_endpoint_bad_request(app, resource):
     Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
+    resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-ZZZ-42?NameID=yyy', status=400)
+    assert resp.json['err_desc'] == "Invoice does not belongs to linked family"
+    assert resp.json['err'] == 'bad-request'
+
     with mock_data(None, 'GetListFactures'):
         resp = app.get(
             '/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42?NameID=yyy&nb_mounts_limit=not_a_number',
             status=400,
         )
     assert resp.json['err_desc'] == "nb_mounts_limit must be an integer"
     assert resp.json['err'] == 'bad-request'
 
@@ -3164,16 +3168,94 @@ def test_invoice_endpoint(app, resource):
                 'ECHEANCE': '2019-12-04',
                 'EMISSION': '2019-11-12',
                 'EXISTEPDF': True,
             },
         },
     }
 
 
+@freezegun.freeze_time('2019-12-04')
+def test_invoice_endpoint_anonymously(app, resource):
+    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:
+        invoices = xml.read()
+    content = (
+        '''<PORTAIL>
+  <GETFACTURESAPAYER>
+    %s
+  </GETFACTURESAPAYER>
+</PORTAIL>'''
+        % invoices
+    )
+    with mock_data(content, 'GetFacturesaPayer'):
+        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == {
+        'id': 'XXX-42',
+        'display_id': '42',
+        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
+        'amount': '4.94',
+        'total_amount': '44.94',
+        'amount_paid': '40.00',
+        'online_payment': True,
+        'created': '2019-11-12',
+        'pay_limit_date': '2019-12-04',
+        'has_pdf': True,
+        'paid': False,
+        'vendor': {
+            'caluire-axel': {
+                'IDFACTURE': 42,
+                'MONTANT': '44.94',
+                'ENCAISSE': '40.00',
+                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
+                'ECHEANCE': '2019-12-04',
+                'EMISSION': '2019-11-12',
+                'EXISTEPDF': True,
+            }
+        },
+    }
+
+    content = (
+        '''<PORTAIL>
+    <GETLISTFACTURES>
+        %s
+    </GETLISTFACTURES>
+</PORTAIL>'''
+        % invoices
+    )
+    with mock_data(content, 'GetListFactures'):
+        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == {
+        'id': 'historical-XXX-42',
+        'display_id': '42',
+        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
+        'amount': 0,
+        'total_amount': '44.94',
+        'online_payment': False,
+        'created': '2019-11-12',
+        'pay_limit_date': '',
+        'has_pdf': True,
+        'paid': False,
+        'vendor': {
+            'caluire-axel': {
+                'IDFACTURE': 42,
+                'MONTANT': '44.94',
+                'ENCAISSE': '40.00',
+                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
+                'ECHEANCE': '2019-12-04',
+                'EMISSION': '2019-11-12',
+                'EXISTEPDF': True,
+            },
+        },
+    }
+
+
 def test_invoice_pdf_endpoint_axel_error(app, resource):
     Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
     with mock.patch('passerelle.contrib.caluire_axel.schemas.get_factures_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
         resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
 
-- 
2.30.2

