From 5d331dfaf1741a84db83e94f1140b4e6f8d63f21 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 13 Dec 2022 19:26:12 +0100
Subject: [PATCH 2/3] toulouse-maelis: add endpoint for invoice debit order
 (#72288)

---
 .../toulouse_maelis/invoice_schemas.py        | 106 ++++++++++++++
 passerelle/contrib/toulouse_maelis/models.py  |  34 ++++-
 .../R_add_direct_debit_order.xml              |   5 +
 .../R_direct_debit_order_soap_error.xml       |  13 ++
 .../R_get_direct_debit_order.xml              |  16 +++
 tests/test_toulouse_maelis.py                 | 131 ++++++++++++++++++
 6 files changed, 304 insertions(+), 1 deletion(-)
 create mode 100644 passerelle/contrib/toulouse_maelis/invoice_schemas.py
 create mode 100644 tests/data/toulouse_maelis/R_add_direct_debit_order.xml
 create mode 100644 tests/data/toulouse_maelis/R_direct_debit_order_soap_error.xml
 create mode 100644 tests/data/toulouse_maelis/R_get_direct_debit_order.xml

diff --git a/passerelle/contrib/toulouse_maelis/invoice_schemas.py b/passerelle/contrib/toulouse_maelis/invoice_schemas.py
new file mode 100644
index 00000000..01d38e75
--- /dev/null
+++ b/passerelle/contrib/toulouse_maelis/invoice_schemas.py
@@ -0,0 +1,106 @@
+# Copyright (C) 2022 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+PERSON_BANK_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-04/schema#',
+    'title': 'Person bank',
+    'description': "Coordonnées du compte à débiter (coordonnées bancaires)",
+    'type': 'object',
+    'required': ['bankBIC', 'bankIBAN', 'bankRUM', 'dateStart', 'bankAddress', 'lastName', 'firstName'],
+    'properties': {
+        'bankBIC': {
+            'description': 'BIC',
+            'type': 'string',
+        },
+        'bankIBAN': {
+            'description': 'IBAN',
+            'type': 'string',
+        },
+        'bankRUM': {
+            'description': 'RUM',
+            'type': 'string',
+        },
+        'dateStart': {
+            'description': 'date de début',
+            'type': 'string',
+            'pattern': '^[0-9]{4}-[0-9]{2}-[0-9]{2}$',
+        },
+        'bankAddress': {
+            'description': 'Adresse de la banque',
+            'type': 'string',
+        },
+        'civility': {
+            'description': 'civility',
+            'oneOf': [{'type': 'string'}, {'type': 'null'}],
+        },
+        'lastName': {
+            'description': 'Nom',
+            'type': 'string',
+        },
+        'firstName': {
+            'description': 'Prénom',
+            'type': 'string',
+        },
+    },
+}
+
+
+ADD_DIRECT_DEBIT_ORDER_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-04/schema#',
+    'title': 'Add direct debit order',
+    'description': "Ajout d'autorisation de prélèvement",
+    'type': 'object',
+    'required': ['numPerson', 'bank', 'codeRegie'],
+    'properties': {
+        'numPerson': {
+            'description': 'Numéro MAELIS de la personne',
+            'type': 'string',
+        },
+        'bank': PERSON_BANK_SCHEMA,
+        'codeRegie': {
+            'description': 'Code de la régie',
+            'type': 'string',
+        },
+    },
+    'additionalProperties': False,
+    'unflatten': True,
+}
+
+
+GET_DIRECT_DEBIT_ORDER_SCHEMA = {
+    '$schema': 'http://json-schema.org/draft-04/schema#',
+    'title': 'Get direct debit order',
+    'description': "Lecture des informations relatives à l'autorisation de prélèvement en cours à la date de référence",
+    'type': 'object',
+    'required': ['numPerson', 'codeRegie', 'dateRef'],
+    'properties': {
+        'numPerson': {
+            'description': 'Numéro MAELIS de la personne',
+            'type': 'string',
+        },
+        'codeRegie': {
+            'description': 'Code de la régie',
+            'type': 'string',
+        },
+        'dateRef': {
+            'description': 'Date de référence ',
+            'type': 'string',
+            'pattern': '^[0-9]{4}-[0-9]{2}-[0-9]{2}$',
+        },
+    },
+    'additionalProperties': False,
+    'unflatten': True,
+}
diff --git a/passerelle/contrib/toulouse_maelis/models.py b/passerelle/contrib/toulouse_maelis/models.py
index 2b9430ce..8ad03e46 100644
--- a/passerelle/contrib/toulouse_maelis/models.py
+++ b/passerelle/contrib/toulouse_maelis/models.py
@@ -22,17 +22,17 @@ from django.utils.timezone import now
 from zeep.helpers import serialize_object
 from zeep.wsse.username import UsernameToken
 
 from passerelle.base.models import BaseResource, HTTPResource
 from passerelle.utils.api import endpoint
 from passerelle.utils.conversion import simplify
 from passerelle.utils.jsonresponse import APIError
 
-from . import family_schemas, schemas
+from . import family_schemas, invoice_schemas, schemas
 
 
 class UpdateError(Exception):
     pass
 
 
 class ToulouseMaelis(BaseResource, HTTPResource):
     # noqa pylint: disable=too-many-public-methods
@@ -1399,16 +1399,48 @@ class ToulouseMaelis(BaseResource, HTTPResource):
     )
     def update_child_indicator(self, request, NameID, child_id, post_data):
         self.get_link(NameID)
         self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data)
 
         self.call('Family', 'updatePersonIndicatorList', numPerson=child_id, **post_data)
         return {'data': 'ok'}
 
+    @endpoint(
+        display_category='Facture',
+        description="Ajout d'autorisation de prélèvement",
+        name='add-direct-debit-order',
+        perm='can_access',
+        parameters={'NameID': {'description': 'Publik NameID'}},
+        post={
+            'request_body': {'schema': {'application/json': invoice_schemas.ADD_DIRECT_DEBIT_ORDER_SCHEMA}}
+        },
+    )
+    def add_direct_debit_order(self, request, NameID, post_data):
+        family_id = self.get_link(NameID).family_id
+        self.call('Invoice', 'addDirectDebitOrder', dossierNumber=family_id, **post_data)
+        return {'data': 'ok'}
+
+    @endpoint(
+        display_category='Facture',
+        description="Lecture des informations relatives à l'autorisation de prélèvement en cours à la date de référence",
+        name='get-direct-debit-order',
+        perm='can_access',
+        parameters={'NameID': {'description': 'Publik NameID'}},
+        post={
+            'request_body': {'schema': {'application/json': invoice_schemas.GET_DIRECT_DEBIT_ORDER_SCHEMA}}
+        },
+    )
+    def get_direct_debit_order(self, request, NameID, post_data):
+        family_id = self.get_link(NameID).family_id
+
+        response = self.call('Invoice', 'getDirectDebitOrder', dossierNumber=family_id, **post_data)
+        data = serialize_object(response)
+        return {'data': data}
+
 
 class Link(models.Model):
     resource = models.ForeignKey(ToulouseMaelis, on_delete=models.CASCADE)
     name_id = models.CharField(blank=False, max_length=256)
     family_id = models.CharField(blank=False, max_length=128)
     created = models.DateTimeField(auto_now_add=True)
     updated = models.DateTimeField(auto_now=True)
 
diff --git a/tests/data/toulouse_maelis/R_add_direct_debit_order.xml b/tests/data/toulouse_maelis/R_add_direct_debit_order.xml
new file mode 100644
index 00000000..860a8ba9
--- /dev/null
+++ b/tests/data/toulouse_maelis/R_add_direct_debit_order.xml
@@ -0,0 +1,5 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+  <soap:Body>
+    <ns2:addDirectDebitOrderResponse xmlns:ns2="ws.maelis.sigec.com"/>
+  </soap:Body>
+</soap:Envelope>
diff --git a/tests/data/toulouse_maelis/R_direct_debit_order_soap_error.xml b/tests/data/toulouse_maelis/R_direct_debit_order_soap_error.xml
new file mode 100644
index 00000000..b04460f5
--- /dev/null
+++ b/tests/data/toulouse_maelis/R_direct_debit_order_soap_error.xml
@@ -0,0 +1,13 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+  <soap:Body>
+    <soap:Fault>
+      <faultcode>soap:Server</faultcode>
+      <faultstring>E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis</faultstring>
+      <detail>
+        <ns1:MaelisAccountException xmlns:ns1="ws.maelis.sigec.com">
+          <message xmlns:ns2="ws.maelis.sigec.com">E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis</message>
+        </ns1:MaelisAccountException>
+      </detail>
+    </soap:Fault>
+  </soap:Body>
+</soap:Envelope>
diff --git a/tests/data/toulouse_maelis/R_get_direct_debit_order.xml b/tests/data/toulouse_maelis/R_get_direct_debit_order.xml
new file mode 100644
index 00000000..771ed7b7
--- /dev/null
+++ b/tests/data/toulouse_maelis/R_get_direct_debit_order.xml
@@ -0,0 +1,16 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+  <soap:Body>
+    <ns2:getDirectDebitOrderResponse xmlns:ns2="ws.maelis.sigec.com">
+      <return>
+        <bankBIC>BDFEFR2T</bankBIC>
+        <bankIBAN>FR7630001007941234567890185</bankIBAN>
+        <bankRUM>xxx</bankRUM>
+        <dateStart>2023-01-01T00:00:00+01:00</dateStart>
+        <bankAddress>75049 PARIS cedex 01</bankAddress>
+        <civility>x</civility>
+        <lastName>Ewing</lastName>
+        <firstName>John Ross</firstName>
+      </return>
+    </ns2:getDirectDebitOrderResponse>
+  </soap:Body>
+</soap:Envelope>
diff --git a/tests/test_toulouse_maelis.py b/tests/test_toulouse_maelis.py
index 0f5ef10c..314e7e2e 100644
--- a/tests/test_toulouse_maelis.py
+++ b/tests/test_toulouse_maelis.py
@@ -3026,8 +3026,139 @@ def test_update_child_indicator_wrong_referential_key_error(con, app):
 
     Link.objects.create(resource=con, family_id='1312', name_id='local')
     resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
     assert resp.json['err'] == 'wrong-key'
     assert (
         resp.json['err_desc']
         == "indicatorList/0/code key value 'plop' do not belong to 'ChildIndicator' required referential"
     )
+
+
+def test_add_direct_debit_order(invoice_service, con, app):
+    def request_check(request):
+        assert request.dossierNumber == 1312
+
+    invoice_service.add_soap_response(
+        'addDirectDebitOrder', get_xml_file('R_add_direct_debit_order.xml'), request_check=request_check
+    )
+    url = get_endpoint('add-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '22',
+        'bank/bankBIC': 'BDFEFR2T',
+        'bank/bankIBAN': 'FR7630001007941234567890185',
+        'bank/bankRUM': 'xxx',
+        'bank/dateStart': '2023-01-01',
+        'bank/bankAddress': '75049 PARIS cedex 01',
+        'bank/civility': 'x',
+        'bank/lastName': 'Ewing',
+        'bank/firstName': 'John Ross',
+    }
+
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == 'ok'
+
+
+def test_add_direct_debit_order_not_linked_error(con, app):
+    url = get_endpoint('add-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '22',
+        'bank/bankBIC': 'BDFEFR2T',
+        'bank/bankIBAN': 'FR7630001007941234567890185',
+        'bank/bankRUM': 'xxx',
+        'bank/dateStart': '2023-01-01',
+        'bank/bankAddress': '75049 PARIS cedex 01',
+        'bank/civility': 'x',
+        'bank/lastName': 'Ewing',
+        'bank/firstName': 'John Ross',
+    }
+
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 'not-linked'
+    assert resp.json['err_desc'] == 'User not linked to family'
+
+
+def test_add_direct_debit_order_soap_error(invoice_service, con, app):
+    invoice_service.add_soap_response(
+        'addDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500
+    )
+
+    url = get_endpoint('add-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '12345',
+        'bank/bankBIC': 'BDFEFR2T',
+        'bank/bankIBAN': 'FR7630001007941234567890185',
+        'bank/bankRUM': 'xxx',
+        'bank/dateStart': '2023-01-01',
+        'bank/bankAddress': '75049 PARIS cedex 01',
+        'bank/civility': 'x',
+        'bank/lastName': 'Ewing',
+        'bank/firstName': 'John Ross',
+    }
+
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 'Invoice-addDirectDebitOrder-soap:Server'
+    assert resp.json['err_desc'] == "E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis"
+
+
+def test_get_direct_debit_order(invoice_service, con, app):
+    def request_check(request):
+        assert request.dossierNumber == 1312
+
+    invoice_service.add_soap_response(
+        'getDirectDebitOrder', get_xml_file('R_get_direct_debit_order.xml'), request_check=request_check
+    )
+    url = get_endpoint('get-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '22',
+        'dateRef': '2023-01-01',
+    }
+
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == {
+        'bankBIC': 'BDFEFR2T',
+        'bankIBAN': 'FR7630001007941234567890185',
+        'bankRUM': 'xxx',
+        'dateStart': '2023-01-01T00:00:00+01:00',
+        'bankAddress': '75049 PARIS cedex 01',
+        'civility': 'x',
+        'lastName': 'Ewing',
+        'firstName': 'John Ross',
+    }
+
+
+def test_get_direct_debit_order_not_linked_error(con, app):
+    url = get_endpoint('get-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '22',
+        'dateRef': '2023-01-01',
+    }
+
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 'not-linked'
+    assert resp.json['err_desc'] == 'User not linked to family'
+
+
+def test_get_direct_debit_order_soap_error(invoice_service, con, app):
+    invoice_service.add_soap_response(
+        'getDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500
+    )
+    url = get_endpoint('get-direct-debit-order')
+    params = {
+        'numPerson': '613878',
+        'codeRegie': '12345',
+        'dateRef': '2023-01-01',
+    }
+
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+    resp = app.post_json(url + '?NameID=local', params=params)
+    assert resp.json['err'] == 'Invoice-getDirectDebitOrder-soap:Server'
+    assert resp.json['err_desc'] == "E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis"
-- 
2.30.2

