From 442c5b95c70d1af1d278b995848cfa60e655e5ba Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 26 Aug 2021 17:53:07 +0200
Subject: [PATCH] toulouse-axel: allow to call invoice endpoint anonymously
 (#56412)

---
 passerelle/contrib/toulouse_axel/models.py | 24 ++++---
 tests/test_toulouse_axel.py                | 76 ++++++++++++++++++++--
 2 files changed, 86 insertions(+), 14 deletions(-)

diff --git a/passerelle/contrib/toulouse_axel/models.py b/passerelle/contrib/toulouse_axel/models.py
index dd7c3231..027e2828 100644
--- a/passerelle/contrib/toulouse_axel/models.py
+++ b/passerelle/contrib/toulouse_axel/models.py
@@ -690,50 +690,51 @@ class ToulouseAxel(BaseResource):
         data = result.json_response['DATA']['PORTAIL']['DUI']
         result = []
         for facture in data.get('FACTURES', []):
             if facture['IDREGIE'] != regie_id:
                 continue
             result.append(utils.normalize_invoice(facture, dui))
         return result
 
-    def get_historical_invoices(self, name_id):
-        link = self.get_link(name_id)
+    def get_historical_invoices(self, dui=None, name_id=None):
+        assert name_id or dui
+        if name_id:
+            dui = self.get_link(name_id).dui
+
         try:
-            result = schemas.list_dui_factures(
-                self, {'LISTFACTURE': {'NUMDUI': link.dui, 'DEBUT': '1970-01-01'}}
-            )
+            result = schemas.list_dui_factures(self, {'LISTFACTURE': {'NUMDUI': dui, 'DEBUT': '1970-01-01'}})
         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},
             )
 
         data = result.json_response['DATA']['PORTAIL']['LISTFACTURE']
         result = []
         for direction in data.get('DIRECTION', []):
             for facture in direction.get('FACTURE', []):
                 result.append(
                     utils.normalize_invoice(
                         facture,
-                        link.dui,
+                        dui,
                         historical=True,
                         vendor_base={
                             'NUMDIRECTION': direction['NUMDIRECTION'],
                             'IDDIRECTION': direction['IDDIRECTION'],
                             'LIBDIRECTION': direction['LIBDIRECTION'],
                         },
                     )
                 )
         return result
 
     def get_invoice(self, regie_id, invoice_id, dui=None, name_id=None, historical=None):
         if historical:
-            invoices_data = self.get_historical_invoices(name_id=name_id)
+            invoices_data = self.get_historical_invoices(dui=dui, name_id=name_id)
         else:
             invoices_data = self.get_invoices(regie_id=regie_id, dui=dui, name_id=name_id)
         for invoice in invoices_data:
             if invoice['display_id'] == invoice_id:
                 return invoice
 
     @endpoint(
         display_category=_('Invoices'),
@@ -778,21 +779,24 @@ class ToulouseAxel(BaseResource):
         example_pattern='{regie_id}/invoice/{invoice_id}',
         description=_('Get invoice details'),
         parameters={
             'NameID': {'description': _('Publik ID')},
             'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
             'invoice_id': {'description': _('Invoice identifier'), 'example_value': 'DUI-42'},
         },
     )
-    def invoice(self, request, regie_id, invoice_id, NameID):
-        real_invoice_id = invoice_id.split('-')[-1]
+    def invoice(self, request, regie_id, invoice_id, NameID=None):
         historical = invoice_id.startswith('historical-')
+        if historical:
+            invoice_id = invoice_id[len('historical-') :]
+        real_invoice_id = invoice_id.split('-')[-1]
+        dui = invoice_id[: -(len(real_invoice_id) + 1)]
         invoice = self.get_invoice(
-            regie_id=regie_id, name_id=NameID, invoice_id=real_invoice_id, historical=historical
+            regie_id=regie_id, dui=dui, invoice_id=real_invoice_id, historical=historical
         )
         if invoice is None:
             raise APIError('Invoice not found', err_code='not-found')
 
         return {'data': invoice}
 
     @endpoint(
         display_category=_('Invoices'),
diff --git a/tests/test_toulouse_axel.py b/tests/test_toulouse_axel.py
index c97accae..5c731a8d 100644
--- a/tests/test_toulouse_axel.py
+++ b/tests/test_toulouse_axel.py
@@ -2273,20 +2273,16 @@ def test_invoice_endpoint_axel_error(app, resource):
     with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
         resp = app.get('/toulouse-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_no_result(app, resource):
-    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
-    assert resp.json['err_desc'] == "Person not found"
-    assert resp.json['err'] == 'not-found'
-
     Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
     filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
     with open(filepath) as xml:
         content = xml.read()
     with mock_getdata(content, 'RefFactureAPayer'):
         resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35?NameID=yyy')
     assert resp.json['err_desc'] == "Invoice not found"
     assert resp.json['err'] == 'not-found'
@@ -2363,16 +2359,88 @@ def test_invoice_endpoint(app, resource, dui):
                 'MONTANT': '28.98',
                 'NOFACTURE': 42,
                 'NUMDIRECTION': 10,
             }
         },
     }
 
 
+@pytest.mark.parametrize('dui', ['XXX', 'S-XXX'])
+def test_invoice_endpoint_anonymous(app, resource, dui):
+    Link.objects.create(resource=resource, name_id='yyy', dui=dui, person_id='42')
+    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
+    with open(filepath) as xml:
+        content = xml.read().replace('XXX', dui)
+    with mock_getdata(content, 'RefFactureAPayer'):
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/%s-42' % dui)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == {
+        'id': '%s-42' % dui,
+        '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': {
+            'toulouse-axel': {
+                'IDFACTURATION': '4242-35AA',
+                'IDFACTURE': 42,
+                'IDREGIE': 'MAREGIE',
+                'DATEECHEANCE': '2019-12-04',
+                'DATEEMISSION': '2019-11-12',
+                'EXISTEPDF': '1',
+                'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
+                'MONTANTTOTAL': '44.94',
+                'NUMFACTURE': 42,
+                'RESTEAPAYER': '4.94',
+            }
+        },
+    }
+
+    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices_history.xml')
+    with open(filepath) as xml:
+        content = xml.read().replace('XXX', dui)
+    with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'):
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/historical-%s-42' % dui)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == {
+        'amount': 0,
+        'created': '2017-03-23',
+        'display_id': '42',
+        'has_pdf': True,
+        'id': 'historical-%s-42' % dui,
+        'label': 'PRESTATIONS SEPTEMBRE 2015',
+        'online_payment': False,
+        'paid': False,
+        'pay_limit_date': '',
+        'total_amount': '28.98',
+        'vendor': {
+            'toulouse-axel': {
+                'EMISSION': '2017-03-23',
+                'IDAXEL': 'AXEL',
+                'IDDIRECTION': 'DIR-A',
+                'IDFACTURE': 42,
+                'IDFAMILLE': dui,
+                'IPDF': 'O',
+                'LIBDIRECTION': 'DIRECTION A',
+                'LIBELLE': 'PRESTATIONS SEPTEMBRE 2015',
+                'MONTANT': '28.98',
+                'NOFACTURE': 42,
+                'NUMDIRECTION': 10,
+            }
+        },
+    }
+
+
 def test_invoice_pdf_endpoint_axel_error(app, resource):
     Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
     with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
         resp = app.get('/toulouse-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

