From e65cd7c1898f2ede6566fa3c2a9bae27ad385e8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 16 Jan 2020 14:31:18 +0100
Subject: [PATCH] toulouse_axel: endpoint to pay an invoice (#39005)

---
 functests/toulouse_axel/test_toulouse_axel.py |  29 +--
 passerelle/contrib/toulouse_axel/models.py    |  86 +++++++--
 .../xsd/Dui/Q_FormPaiementDui.xsd             |  44 +++++
 .../xsd/Dui/R_FormPaiementDui.xsd             |  36 ++++
 tests/data/toulouse_axel/invoices.xml         |  12 ++
 tests/test_toulouse_axel.py                   | 169 ++++++++++++++++--
 6 files changed, 313 insertions(+), 63 deletions(-)
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.xsd

diff --git a/functests/toulouse_axel/test_toulouse_axel.py b/functests/toulouse_axel/test_toulouse_axel.py
index 7c6e0971..b6214603 100644
--- a/functests/toulouse_axel/test_toulouse_axel.py
+++ b/functests/toulouse_axel/test_toulouse_axel.py
@@ -4,7 +4,7 @@ import requests
 
 def test_link(conn, user):
     print("Get update management dates")
-    url = conn + '/update_management_dates'
+    url = conn + '/management_dates'
     resp = requests.get(url)
     resp.raise_for_status()
     res = resp.json()
@@ -129,33 +129,6 @@ def test_link(conn, user):
         pprint.pprint(res)
         print('\n')
 
-    print("Get invoices")
-    url = conn + '/invoices?NameID=%s' % name_id
-    resp = requests.get(url)
-    resp.raise_for_status()
-    res = resp.json()
-    assert res['err'] == 0
-    pprint.pprint(res)
-    print('\n')
-
-    data = res
-    for invoice in data['data']:
-        print("GET invoice info")
-        url = conn + '/invoice/%s?NameID=%s' % (invoice['id'], name_id)
-        resp = requests.get(url)
-        resp.raise_for_status()
-        res = resp.json()
-        assert res['err'] == 0
-        pprint.pprint(res)
-        print('\n')
-
-        if res['data']['has_pdf']:
-            print("GET invoice PDF")
-            url = conn + '/invoice/%s/pdf?NameID=%s' % (invoice['id'], name_id)
-            resp = requests.get(url)
-            resp.raise_for_status()
-            print('\n')
-
     print("Deleting link")
     url = conn + '/unlink?NameID=%s' % name_id
     resp = requests.post(url)
diff --git a/passerelle/contrib/toulouse_axel/models.py b/passerelle/contrib/toulouse_axel/models.py
index 2eedb105..c5c5c8bb 100644
--- a/passerelle/contrib/toulouse_axel/models.py
+++ b/passerelle/contrib/toulouse_axel/models.py
@@ -17,6 +17,7 @@
 import base64
 import copy
 import datetime
+import json
 import logging
 import os
 import re
@@ -249,6 +250,7 @@ ref_date_gestion_dui = Operation('RefDateGestionDui')
 ref_verif_dui = Operation('RefVerifDui')
 ref_famille_dui = Operation('RefFamilleDui')
 form_maj_famille_dui = Operation('FormMajFamilleDui')
+form_paiement_dui = Operation('FormPaiementDui')
 ref_facture_a_payer = Operation('RefFactureAPayer')
 ref_facture_pdf = Operation('RefFacturePDF', prefix='')
 
@@ -724,7 +726,7 @@ class ToulouseAxel(BaseResource):
             }
         }
 
-    def get_invoices(self, name_id, error_status=200):
+    def get_invoices(self, regie_id, name_id, error_status=200):
         link = self.get_link(name_id, error_status=error_status)
         try:
             result = ref_facture_a_payer(self, {'PORTAIL': {'DUI': {'IDDUI': link.dui}}})
@@ -738,8 +740,10 @@ 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({
-                'id': facture['IDFACTURE'],
+                'id': str(facture['IDFACTURE']),
                 'label': facture['LIBELLE'],
                 'amount': facture['RESTEAPAYER'],
                 'total_amount': facture['MONTANTTOTAL'],
@@ -752,49 +756,58 @@ class ToulouseAxel(BaseResource):
             })
         return result
 
-    def get_invoice(self, name_id, invoice_id, error_status=200):
-        invoices_data = self.get_invoices(name_id, error_status=error_status)
+    def get_invoice(self, regie_id, name_id, invoice_id, error_status=200):
+        invoices_data = self.get_invoices(regie_id, name_id, error_status=error_status)
         for invoice in invoices_data:
-            if str(invoice['id']) == invoice_id:
+            if invoice['id'] == invoice_id:
                 return invoice
 
     @endpoint(
-        description=_("Get invoices to pay"),
+        name='regie',
         perm='can_access',
+        pattern=r'^(?P<regie_id>[\w-]+)/invoices/?$',
+        example_pattern='{regie_id}/invoices/',
+        description=_("Get invoices to pay"),
         parameters={
             'NameID': {'description': _('Publik ID')},
+            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'}
         })
-    def invoices(self, request, NameID):
-        invoices_data = self.get_invoices(NameID)
+    def invoices(self, request, regie_id, NameID):
+        invoices_data = self.get_invoices(regie_id, NameID)
         return {'data': invoices_data}
 
     @endpoint(
+        name='regie',
         perm='can_access',
-        pattern=r'^(?P<invoice_id>\w+)/?$',
+        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\d+)/?$',
+        example_pattern='{regie_id}/invoice/{invoice_id}/',
         description=_('Get invoice details'),
         parameters={
             'NameID': {'description': _('Publik ID')},
-            'invoice_id': {'description': _('Invoice identifier')}
+            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
+            'invoice_id': {'description': _('Invoice identifier'), 'example_value': '42'}
         })
-    def invoice(self, request, invoice_id, NameID):
-        invoice = self.get_invoice(NameID, invoice_id)
+    def invoice(self, request, regie_id, invoice_id, NameID):
+        invoice = self.get_invoice(regie_id, NameID, invoice_id)
         if invoice is None:
             raise APIError('Invoice not found', err_code='not-found')
 
         return {'data': invoice}
 
     @endpoint(
-        name='invoice',
+        name='regie',
         perm='can_access',
-        pattern=r'^(?P<invoice_id>\w+)/pdf/?$',
+        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\d+)/pdf/?$',
+        example_pattern='{regie_id}/invoice/{invoice_id}/pdf/',
         description=_('Get invoice as a PDF file'),
         parameters={
             'NameID': {'description': _('Publik ID')},
-            'invoice_id': {'description': _('Invoice identifier')}
+            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
+            'invoice_id': {'description': _('Invoice identifier'), 'example_value': '42'}
         })
-    def invoice_pdf(self, request, invoice_id, NameID):
+    def invoice_pdf(self, request, regie_id, invoice_id, NameID):
         # check that invoice is related to current user
-        invoice = self.get_invoice(NameID, invoice_id, error_status=404)
+        invoice = self.get_invoice(regie_id, NameID, invoice_id, error_status=404)
         if invoice is None:
             raise APIError('Invoice not found', err_code='not-found', http_status=404)
         # check that PDF is available
@@ -819,6 +832,45 @@ class ToulouseAxel(BaseResource):
         response.write(b64content)
         return response
 
+    @endpoint(
+        name='regie',
+        methods=['post'],
+        perm='can_access',
+        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\d+)/pay/?$',
+        example_pattern='{regie_id}/invoice/{invoice_id}/pay/',
+        description=_('Notify an invoice as paid'),
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
+            'invoice_id': {'description': _('Invoice identifier'), 'example_value': '42'}
+        })
+    def pay_invoice(self, request, regie_id, invoice_id, NameID):
+        # check that invoice is related to current user
+        invoice = self.get_invoice(regie_id, NameID, invoice_id)
+        if invoice is None:
+            raise APIError('Invoice not found', err_code='not-found')
+
+        data = json.loads(request.body)
+        transaction_id = data.get('transaction_id')
+        transaction_date = data.get('transaction_date')
+        t_date = datetime.datetime.strptime(transaction_date, '%Y-%m-%dT%H:%M:%S')
+        post_data = {
+            'IDFACTURE': int(invoice_id),
+            'IDREGIEENCAISSEMENT': '',
+            'MONTANTPAYE': invoice['amount'],
+            'DATEPAIEMENT': t_date.strftime('%d/%m/%Y %H:%M:%S'),
+            'REFERENCE': transaction_id,
+        }
+        try:
+            form_paiement_dui(self, {'PORTAIL': {'DUI': post_data}})
+        except AxelError as e:
+            raise APIError(
+                'Axel error: %s' % e,
+                err_code='error',
+                data={'xml_request': e.xml_request,
+                      'xml_response': e.xml_response})
+        return {'data': True}
+
 
 class Link(models.Model):
     resource = models.ForeignKey(ToulouseAxel, on_delete=models.CASCADE)
diff --git a/passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.xsd b/passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.xsd
new file mode 100644
index 00000000..82157178
--- /dev/null
+++ b/passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.xsd
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
+	
+	<xsd:import schemaLocation="../AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
+	
+	<xsd:complexType name="DUIType">
+		<xsd:sequence>
+			<xsd:element ref="IDFACTURE" />
+			<xsd:element ref="IDREGIEENCAISSEMENT"/>
+			<xsd:element ref="MONTANTPAYE"/>
+			<xsd:element ref="DATEPAIEMENT"/>
+			<xsd:element ref="REFERENCE"/>
+		</xsd:sequence> 
+	</xsd:complexType>
+	
+	<xsd:complexType name="PORTAILType">
+		<xsd:sequence>
+				<xsd:element ref="DUI"/>
+		</xsd:sequence>	
+	</xsd:complexType>
+			
+	<xsd:simpleType name="CHOIXType">
+		<xsd:restriction base="xsd:string">
+			<xsd:enumeration value="1" />
+			<xsd:enumeration value="0" />
+		</xsd:restriction>
+	</xsd:simpleType>
+	
+	<xsd:simpleType name="IDENTREGIEType">
+		<xsd:restriction base="xsd:string">
+			<xsd:maxLength value="10" />
+		</xsd:restriction>
+	</xsd:simpleType>
+	
+	<xsd:element name="IDFACTURE" type="xsd:unsignedInt"/>
+	<xsd:element name="IDREGIEENCAISSEMENT" type="IDENTREGIEType"/>
+	<xsd:element name="MONTANTPAYE" type="all:MONTANTREQUIREDType"/>
+	<xsd:element name="DATEPAIEMENT" type="all:DATETIMEType"/>
+	<xsd:element name="REFERENCE" type="xsd:string"/>
+	
+	<xsd:element name="DUI" type="DUIType"/>
+	
+	<xsd:element name="PORTAIL" type="PORTAILType"/>
+</xsd:schema>
\ No newline at end of file
diff --git a/passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.xsd b/passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.xsd
new file mode 100644
index 00000000..ea5b13b8
--- /dev/null
+++ b/passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.xsd
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
+	
+	<xsd:import schemaLocation="../AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
+
+	<xsd:redefine schemaLocation="../R_ShemaResultat.xsd">
+	    <xsd:simpleType name="TYPEType">
+			<xsd:restriction base="TYPEType">
+				<xsd:enumeration value="FormPaiementDui" />
+			</xsd:restriction>
+	    </xsd:simpleType>
+		
+		<xsd:complexType name="PORTAILType">
+			<xsd:complexContent>
+				<xsd:extension base="PORTAILType">
+					<xsd:sequence>
+						<xsd:element ref="DUI" minOccurs="0"/>
+					</xsd:sequence>	
+				</xsd:extension>
+			 </xsd:complexContent>
+		</xsd:complexType>
+	</xsd:redefine>
+	
+	<xsd:complexType name="DUIType">
+		<xsd:sequence>
+			<xsd:element ref="IDDUI" />
+			<xsd:element ref="CODE" />
+		</xsd:sequence> 
+	</xsd:complexType>
+
+	<xsd:element name="CODE" type="all:unsignedInt-or-empty"/>	
+	<xsd:element name="IDDUI" type="all:IDENTType"/>
+	
+	<xsd:element name="DUI" type="DUIType" />
+	
+</xsd:schema>
\ No newline at end of file
diff --git a/tests/data/toulouse_axel/invoices.xml b/tests/data/toulouse_axel/invoices.xml
index c1830bc8..c18203d8 100644
--- a/tests/data/toulouse_axel/invoices.xml
+++ b/tests/data/toulouse_axel/invoices.xml
@@ -27,5 +27,17 @@
       <EXISTEPDF>0</EXISTEPDF>
       <IDFACTURE>43</IDFACTURE>
     </FACTURES>
+    <FACTURES>
+      <NUMFACTURE>44</NUMFACTURE>
+      <DATEEMISSION>12/01/2020</DATEEMISSION>
+      <DATEECHEANCE>04/02/2020</DATEECHEANCE>
+      <LIBELLE>PRESTATIONS PERISCOLAIRES DECEMBRE 2019</LIBELLE>
+      <IDFACTURATION>4244-35AA</IDFACTURATION>
+      <MONTANTTOTAL>44.94</MONTANTTOTAL>
+      <RESTEAPAYER>44.94</RESTEAPAYER>
+      <IDREGIE>AUTREREGIE</IDREGIE>
+      <EXISTEPDF>1</EXISTEPDF>
+      <IDFACTURE>44</IDFACTURE>
+    </FACTURES>
   </DUI>
 </PORTAIL>
diff --git a/tests/test_toulouse_axel.py b/tests/test_toulouse_axel.py
index e46291ff..d0840293 100644
--- a/tests/test_toulouse_axel.py
+++ b/tests/test_toulouse_axel.py
@@ -17,6 +17,7 @@
 from contextlib import contextmanager
 import copy
 import datetime
+import decimal
 import json
 import mock
 import os
@@ -32,6 +33,7 @@ from passerelle.contrib.toulouse_axel.models import (
     OperationResult,
     ToulouseAxel,
     form_maj_famille_dui,
+    form_paiement_dui,
     ref_date_gestion_dui,
     ref_famille_dui,
     ref_facture_a_payer,
@@ -327,6 +329,25 @@ def test_operation_ref_facture_pdf(resource, content):
             })
 
 
+@pytest.mark.parametrize('content', [
+    '<PORTAIL><DUI/></PORTAIL>',
+])
+def test_operation_form_paiement_dui(resource, content):
+    with mock_getdata(content, 'FormPaiementDui'):
+        with pytest.raises(AxelError):
+            form_paiement_dui(resource, {
+                'PORTAIL': {
+                    'DUI': {
+                        'IDFACTURE': '42',
+                        'IDREGIEENCAISSEMENT': '',
+                        'MONTANTPAYE': '42.42',
+                        'DATEPAIEMENT': '01/01/2020 12:12:12',
+                        'REFERENCE': '42',
+                    }
+                }
+            })
+
+
 def test_management_dates_endpoint_axel_error(app, resource):
     with mock.patch('passerelle.contrib.toulouse_axel.models.ref_date_gestion_dui') as operation:
         operation.side_effect = AxelError('FooBar')
@@ -1195,13 +1216,13 @@ def test_invoices_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.models.ref_facture_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
-        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
 
 
 def test_invoices_endpoint_no_result(app, resource):
-    resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
+    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
     assert resp.json['err_desc'] == "Person not found"
     assert resp.json['err'] == 'not-found'
 
@@ -1216,7 +1237,7 @@ def test_invoices_endpoint_no_invoices(app, resource):
     </DUI>
 </PORTAIL>'''
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
     assert resp.json['err'] == 0
     assert resp.json['data'] == []
 
@@ -1227,11 +1248,11 @@ def test_invoices_endpoint(app, resource):
     with open(filepath) as xml:
         content = xml.read()
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
     assert resp.json['err'] == 0
     assert resp.json['data'] == [
         {
-            'id': 42,
+            'id': '42',
             'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
             'amount': '44.94',
             'total_amount': '44.94',
@@ -1256,7 +1277,7 @@ def test_invoices_endpoint(app, resource):
             }
         },
         {
-            'id': 43,
+            'id': '43',
             'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
             'amount': '44.94',
             'total_amount': '44.94',
@@ -1281,19 +1302,49 @@ def test_invoices_endpoint(app, resource):
             }
         }
     ]
+    with mock_getdata(content, 'RefFactureAPayer'):
+        resp = app.get('/toulouse-axel/test/regie/AUTREREGIE/invoices?NameID=yyy')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {
+            'id': '44',
+            'label': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019',
+            'amount': '44.94',
+            'total_amount': '44.94',
+            'online_payment': True,
+            'created': '2020-01-12',
+            'pay_limit_date': '2020-02-04',
+            'has_pdf': True,
+            'paid': False,
+            'vendor': {
+                'toulouse-axel': {
+                    'IDFACTURATION': '4244-35AA',
+                    'IDFACTURE': 44,
+                    'IDREGIE': 'AUTREREGIE',
+                    'DATEECHEANCE': '2020-02-04',
+                    'DATEEMISSION': '2020-01-12',
+                    'EXISTEPDF': '1',
+                    'LIBELLE': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019',
+                    'MONTANTTOTAL': '44.94',
+                    'NUMFACTURE': 44,
+                    'RESTEAPAYER': '44.94',
+                 }
+            }
+        }
+    ]
 
 
 def test_invoice_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.models.ref_facture_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
-        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/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/invoice/42?NameID=yyy')
+    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42?NameID=yyy')
     assert resp.json['err_desc'] == "Person not found"
     assert resp.json['err'] == 'not-found'
 
@@ -1302,7 +1353,11 @@ def test_invoice_endpoint_no_result(app, resource):
     with open(filepath) as xml:
         content = xml.read()
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoice/35?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/35?NameID=yyy')
+    assert resp.json['err_desc'] == "Invoice not found"
+    assert resp.json['err'] == 'not-found'
+    with mock_getdata(content, 'RefFactureAPayer'):
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/44?NameID=yyy')
     assert resp.json['err_desc'] == "Invoice not found"
     assert resp.json['err'] == 'not-found'
 
@@ -1313,10 +1368,10 @@ def test_invoice_endpoint(app, resource):
     with open(filepath) as xml:
         content = xml.read()
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42?NameID=yyy')
     assert resp.json['err'] == 0
     assert resp.json['data'] == {
-        'id': 42,
+        'id': '42',
         'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
         'amount': '44.94',
         'total_amount': '44.94',
@@ -1346,7 +1401,7 @@ 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.models.ref_facture_a_payer') as operation:
         operation.side_effect = AxelError('FooBar')
-        resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
 
@@ -1356,13 +1411,13 @@ def test_invoice_pdf_endpoint_axel_error(app, resource):
     with mock_getdata(content, 'RefFactureAPayer'):
         with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_pdf') as operation:
             operation.side_effect = AxelError('FooBar')
-            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
+            resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "Axel error: FooBar"
     assert resp.json['err'] == 'error'
 
 
 def test_invoice_pdf_endpoint_no_result(app, resource):
-    resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
+    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "Person not found"
     assert resp.json['err'] == 'not-found'
 
@@ -1371,12 +1426,17 @@ def test_invoice_pdf_endpoint_no_result(app, resource):
     with open(filepath) as xml:
         content = xml.read()
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoice/35/pdf?NameID=yyy', status=404)
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/35/pdf?NameID=yyy', status=404)
+    assert resp.json['err_desc'] == "Invoice not found"
+    assert resp.json['err'] == 'not-found'
+
+    with mock_getdata(content, 'RefFactureAPayer'):
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/44/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "Invoice not found"
     assert resp.json['err'] == 'not-found'
 
     with mock_getdata(content, 'RefFactureAPayer'):
-        resp = app.get('/toulouse-axel/test/invoice/43/pdf?NameID=yyy', status=404)
+        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/43/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "PDF not available"
     assert resp.json['err'] == 'not-available'
 
@@ -1386,7 +1446,7 @@ def test_invoice_pdf_endpoint_no_result(app, resource):
     with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
         invoice.return_value = {'has_pdf': True}
         with mock_getdata(pdf_content, 'RefFacturePDF'):
-            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
+            resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42/pdf?NameID=yyy', status=404)
     assert resp.json['err_desc'] == "PDF error"
     assert resp.json['err'] == 'error'
 
@@ -1399,4 +1459,77 @@ def test_invoice_pdf_endpoint(app, resource):
     with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
         invoice.return_value = {'has_pdf': True}
         with mock_getdata(pdf_content, 'RefFacturePDF'):
-            app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy')
+            app.get('/toulouse-axel/test/regie/MAREGIE/invoice/42/pdf?NameID=yyy')
+
+
+def test_pay_invoice_endpoint_axel_error(app, resource):
+    payload = {
+        'transaction_date': '2020-01-01T12:00:00',
+        'transaction_id': 'foo',
+    }
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
+        operation.side_effect = AxelError('FooBar')
+        resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/42/pay?NameID=yyy', params=payload)
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+    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'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.form_paiement_dui') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/42/pay?NameID=yyy', params=payload)
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+
+def test_pay_invoice_endpoint_no_result(app, resource):
+    payload = {
+        'transaction_date': '2020-01-01T12:00:00',
+        'transaction_id': 'foo',
+    }
+    resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/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', 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.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/35/pay?NameID=yyy', params=payload)
+    assert resp.json['err_desc'] == "Invoice not found"
+    assert resp.json['err'] == 'not-found'
+    with mock_getdata(content, 'RefFactureAPayer'):
+        resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/44/pay?NameID=yyy', params=payload)
+    assert resp.json['err_desc'] == "Invoice not found"
+    assert resp.json['err'] == 'not-found'
+
+
+def test_pay_invoice_endpoint(app, resource):
+    payload = {
+        'transaction_date': '2020-01-01T12:00:00',
+        'transaction_id': 'foo',
+    }
+    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'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.form_paiement_dui') as operation:
+            resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/42/pay?NameID=yyy', params=payload)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] is True
+    assert operation.call_args_list[0][0][1] == {
+        'PORTAIL': {
+            'DUI': {
+                'DATEPAIEMENT': '01/01/2020 12:00:00',
+                'IDFACTURE': 42,
+                'IDREGIEENCAISSEMENT': '',
+                'MONTANTPAYE': decimal.Decimal('44.94'),
+                'REFERENCE': 'foo',
+            }
+        }
+    }
-- 
2.20.1

