From a2fc7a0c0e888be3b12adf190a8045dba46cd1d5 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Fri, 25 Nov 2022 15:47:46 +0100
Subject: [PATCH 2/2] toulouse-maelis: add quotient year filter on read-family
 (#71698)

---
 functests/toulouse_maelis/read_family.py      |   2 +-
 functests/toulouse_maelis/test_family.py      |   8 +
 passerelle/contrib/toulouse_maelis/models.py  |  30 +--
 .../R_read_family_with_income_year.xml        | 211 ++++++++++++++++++
 tests/test_toulouse_maelis.py                 |  26 +++
 5 files changed, 263 insertions(+), 14 deletions(-)
 create mode 100644 tests/data/toulouse_maelis/R_read_family_with_income_year.xml

diff --git a/functests/toulouse_maelis/read_family.py b/functests/toulouse_maelis/read_family.py
index 7ab6ae1e..fabd7e03 100755
--- a/functests/toulouse_maelis/read_family.py
+++ b/functests/toulouse_maelis/read_family.py
@@ -16,17 +16,17 @@ def read_family(family_id, verbose):
     session.verify = False
     transport = Transport(session=session)
     settings = zeep.Settings(strict=False, xsd_ignore_sequence_order=True)
     client = zeep.Client(WSDL_URL, transport=transport, wsse=WSSE, settings=settings)
 
     result = client.service.readFamily(
         dossierNumber=family_id,
         # schoolYear=
-        # incomeYear=2020,  # <-- pour avoir les quotients
+        # incomeYear=2022,  # <-- pour filtrer les quotients sur cette année
         # referenceYear=2020,
     )
     print(result)
 
 
 if __name__ == "__main__":
     parser = argparse.ArgumentParser()
     parser.add_argument('--verbose', '-v', type=int, default=2, help='display errors')
diff --git a/functests/toulouse_maelis/test_family.py b/functests/toulouse_maelis/test_family.py
index f561a1d7..dc8d448f 100644
--- a/functests/toulouse_maelis/test_family.py
+++ b/functests/toulouse_maelis/test_family.py
@@ -793,8 +793,16 @@ def test_update_quotient(conn, create_data):
 
     # add quotient on another income year
     payload['yearRev'] = '2020'
     resp = requests.post(url, json=payload)
     resp.raise_for_status()
     assert resp.json()['err'] == 0
     data = diff_rlg(conn, create_data['name_id'], 1, 'test_update_quotient.json', 'quotientList')
     assert len(data['RL1']['quotientList']) == 3
+
+    # test read-family with reference year
+    url = conn + '/read-family?NameID=%s&income_year=%s' % (create_data['name_id'], '2020')
+    resp = requests.get(url)
+    resp.raise_for_status()
+    res = resp.json()
+    assert res['err'] == 0
+    return len(res['data']['RL1']['quotientList']) == 1
diff --git a/passerelle/contrib/toulouse_maelis/models.py b/passerelle/contrib/toulouse_maelis/models.py
index 68a95203..5eb636aa 100644
--- a/passerelle/contrib/toulouse_maelis/models.py
+++ b/passerelle/contrib/toulouse_maelis/models.py
@@ -182,23 +182,23 @@ class ToulouseMaelis(BaseResource, HTTPResource):
             return key
 
     def get_link(self, NameID):
         try:
             return self.link_set.get(name_id=NameID)
         except Link.DoesNotExist:
             raise APIError('User not linked to family', err_code='not-linked')
 
-    def get_family_raw(self, family_id):
-        response = self.call('Family', 'readFamily', dossierNumber=family_id)
+    def get_family_raw(self, family_id, **kwargs):
+        response = self.call('Family', 'readFamily', dossierNumber=family_id, **kwargs)
         data = serialize_object(response)
         return data
 
-    def get_rl_raw(self, family_id, rl_id):
-        data = self.get_family_raw(family_id)
+    def get_rl_raw(self, family_id, rl_id, **kwargs):
+        data = self.get_family_raw(family_id, **kwargs)
         if data['RL1']['num'] == rl_id:
             return data['RL1']
         elif data['RL2'] and data['RL2']['num'] == rl_id:
             return data['RL2']
         raise APIError("no '%s' RL on '%s' family" % (rl_id, family_id), err_code='not-found')
 
     def get_person_raw(self, family_id, person_id):
         data = self.get_family_raw(family_id)
@@ -304,23 +304,23 @@ class ToulouseMaelis(BaseResource, HTTPResource):
         self.add_text_value_to_child(data)
         return data
 
     def get_person(self, family_id, person_id):
         data = self.get_person_raw(family_id, person_id)
         self.add_text_value_to_person(data)
         return data
 
-    def get_rl(self, family_id, rl_id):
-        data = self.get_rl_raw(family_id, rl_id)
+    def get_rl(self, family_id, rl_id, **kwargs):
+        data = self.get_rl_raw(family_id, rl_id, **kwargs)
         self.add_text_value_to_rl(data)
         return data
 
-    def get_family(self, family_id):
-        data = self.get_family_raw(family_id)
+    def get_family(self, family_id, **kwargs):
+        data = self.get_family_raw(family_id, **kwargs)
         self.add_text_value_to_family(data)
         return data
 
     def assert_key_in_referential(self, referential_name, key_value, keys_text, required=True):
         if not key_value:
             if required:
                 raise APIError("%s is required and could not be None" % keys_text, err_code='field-required')
             return
@@ -724,36 +724,40 @@ class ToulouseMaelis(BaseResource, HTTPResource):
         link.delete()
         return {'data': 'ok'}
 
     @endpoint(
         display_category='Famille',
         description='Informations sur la famille',
         perm='can_access',
         name='read-family',
-        parameters={'NameID': {'description': 'Publik NameID'}},
+        parameters={
+            'NameID': {'description': 'Publik NameID'},
+            'income_year': {'description': 'Année de revenu pour filtrer les quotients'},
+        },
     )
-    def read_family(self, request, NameID):
+    def read_family(self, request, NameID, income_year=None):
         family_id = self.get_link(NameID).family_id
-        data = self.get_family(family_id)
+        data = self.get_family(family_id, incomeYear=income_year)
         return {'data': data}
 
     @endpoint(
         display_category='Famille',
         description="Informations sur un responsable légal",
         perm='can_access',
         name='read-rl',
         parameters={
             'NameID': {'description': 'Publik NameID'},
             'rl_id': {'description': 'Numéro du représentant légal'},
+            'income_year': {'description': 'Année de revenu pour filtrer les quotients'},
         },
     )
-    def read_rl(self, request, NameID, rl_id):
+    def read_rl(self, request, NameID, rl_id, income_year=None):
         family_id = self.get_link(NameID).family_id
-        data = self.get_rl(family_id, rl_id)
+        data = self.get_rl(family_id, rl_id, incomeYear=income_year)
         return {'data': data}
 
     @endpoint(
         display_category='Famille',
         description="Informations sur une personne autorisée à récupérer les enfants ou à prévenir en cas d'urgence",
         perm='can_access',
         name='read-person',
         parameters={
diff --git a/tests/data/toulouse_maelis/R_read_family_with_income_year.xml b/tests/data/toulouse_maelis/R_read_family_with_income_year.xml
new file mode 100644
index 00000000..c7d708e0
--- /dev/null
+++ b/tests/data/toulouse_maelis/R_read_family_with_income_year.xml
@@ -0,0 +1,211 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+  <soap:Body>
+    <ns2:readFamilyResponse xmlns:ns2="family.ws.maelis.sigec.com">
+      <familyResult>
+        <number>1312</number>
+        <category>BI</category>
+        <situation>M</situation>
+        <flagCom>true</flagCom>
+        <nbChild>2</nbChild>
+        <RL1>
+          <num>613878</num>
+          <lastname>DOE</lastname>
+          <firstname>JHON</firstname>
+          <quality>PERE</quality>
+          <civility>M.</civility>
+          <birth>
+            <dateBirth>1938-07-26T00:00:00+01:00</dateBirth>
+            <place>Rabbat</place>
+            <countryCode>99350</countryCode>
+          </birth>
+          <adresse>
+            <idStreet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
+            <num>170</num>
+            <street1>Chateau d'eau</street1>
+            <town>Paris</town>
+            <zipcode>75014</zipcode>
+          </adresse>
+          <contact>
+            <phone>non</phone>
+            <mobile>0777777777</mobile>
+            <mail>djhon@example.org</mail>
+            <isContactMail>true</isContactMail>
+            <isContactSms>true</isContactSms>
+            <isInvoicePdf>true</isInvoicePdf>
+          </contact>
+          <profession>
+            <addressPro/>
+          </profession>
+          <quotientList>
+            <yearRev>2020</yearRev>
+            <dateStart>2021-01-01T00:00:00+01:00</dateStart>
+            <dateEnd>2021-12-31T00:00:00+01:00</dateEnd>
+            <mtt>1500.33</mtt>
+            <cdquo>QS</cdquo>
+          </quotientList>
+        </RL1>
+        <RL2>
+          <num>613879</num>
+          <lastname>DOE</lastname>
+          <firstname>JANE</firstname>
+          <maidenName>SMITH</maidenName>
+          <quality>MERE</quality>
+          <civility>MME</civility>
+          <birth>
+            <dateBirth>1940-06-22T00:00:00+02:00</dateBirth>
+            <place>Bardot</place>
+            <countryCode>99351</countryCode>
+          </birth>
+          <adresse>
+            <idStreet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
+            <num>170</num>
+            <street1>Chateau d'eau</street1>
+            <town>Paris</town>
+            <zipcode>75014</zipcode>
+          </adresse>
+          <contact>
+            <isContactMail>false</isContactMail>
+            <isContactSms>false</isContactSms>
+            <isInvoicePdf>false</isInvoicePdf>
+          </contact>
+          <profession>
+            <codeCSP>ART</codeCSP>
+            <profession>informaticien</profession>
+            <employerName>EO</employerName>
+            <phone>0123456789</phone>
+            <addressPro>
+              <town>Orl&#233;ans</town>
+            </addressPro>
+          </profession>
+          <CAFInfo>
+            <number>789</number>
+            <organ>A10007752822</organ>
+          </CAFInfo>
+        </RL2>
+        <emergencyPersonList>
+          <numPerson>614059</numPerson>
+          <civility>MME</civility>
+          <firstname>KENY</firstname>
+          <lastname>ARKANA</lastname>
+          <dateBirth>1982-12-20T00:00:00+01:00</dateBirth>
+          <quality>T</quality>
+          <contact>
+            <phone>0123456789</phone>
+            <mail>pueblo@example.org</mail>
+          </contact>
+        </emergencyPersonList>
+        <childList>
+          <num>613880</num>
+          <lastname>DOE</lastname>
+          <firstname>JANNIS</firstname>
+          <sexe>F</sexe>
+          <birth>
+            <dateBirth>1943-01-19T00:00:00+01:00</dateBirth>
+            <place>Saint-louis</place>
+            <communeCode>91122</communeCode>
+            <countryCode>99100</countryCode>
+          </birth>
+          <dietcode>RSV</dietcode>
+          <bPhoto>true</bPhoto>
+          <bLeaveAlone>false</bLeaveAlone>
+          <authorizedPersonList>
+            <personInfo>
+              <num>614719</num>
+              <lastname>BENT</lastname>
+              <firstname>AMEL</firstname>
+              <dateBirth>1985-06-21T00:00:00+02:00</dateBirth>
+              <civility>MME</civility>
+              <sexe>F</sexe>
+              <contact>
+                <phone>0123456789</phone>
+                <mobile>0623456789</mobile>
+                <mail>abent@example.org</mail>
+              </contact>
+            </personInfo>
+            <personQuality>
+              <code>T</code>
+              <libelle>TANTE</libelle>
+            </personQuality>
+          </authorizedPersonList>
+          <medicalRecord>
+            <familyDoctor>
+              <name>DRE</name>
+              <phone>0612341234</phone>
+              <address>
+                <street1>Alameda</street1>
+                <zipcode>90220</zipcode>
+                <town>Compton</town>
+              </address>
+            </familyDoctor>
+            <allergy1>butterscotch, imitation butterscotch, glow-in-the-dark monster make-up</allergy1>
+            <allergy2>shrimp and cauliflower</allergy2>
+            <comment1>the shrimp allergy isn't fully identified</comment1>
+            <observ1>Ay Caramba!</observ1>
+            <observ2>Eat my shorts!</observ2>
+            <isAuthHospital>true</isAuthHospital>
+            <hospital>Springfield General Hospital</hospital>
+            <vaccinList>
+              <code>ROR</code>
+              <label>ROUGEOLE-OREILLONS-RUBEOLE</label>
+              <vaccinationDate>2012-02-22T00:00:00+01:00</vaccinationDate>
+            </vaccinList>
+            <vaccinList>
+              <code>DTC</code>
+              <label>DIPHTERIE TETANOS COQUELUCHE</label>
+              <vaccinationDate>2011-01-11T00:00:00+01:00</vaccinationDate>
+            </vaccinList>
+            <vaccinList>
+              <code>ROR</code>
+              <label>ROUGEOLE-OREILLONS-RUBEOLE</label>
+              <vaccinationDate>1970-01-11T00:00:00+01:00</vaccinationDate>
+            </vaccinList>
+          </medicalRecord>
+          <mother>
+            <num>613963</num>
+            <civility>MME</civility>
+            <firstname>JANE</firstname>
+            <lastname>DOE</lastname>
+          </mother>
+          <father>
+            <num>613878</num>
+            <civility>M.</civility>
+            <firstname>JHON</firstname>
+            <lastname>DOE</lastname>
+          </father>
+          <paiInfoBean>
+            <code>PAIALI</code>
+            <dateDeb>2022-01-01T00:00:00+01:00</dateDeb>
+            <dateFin>2022-12-31T00:00:00+01:00</dateFin>
+            <description>bla bla PAI</description>
+          </paiInfoBean>
+        </childList>
+        <childList>
+          <num>613987</num>
+          <lastname>DOE</lastname>
+          <firstname>JOHNNY ALLEN</firstname>
+          <sexe>M</sexe>
+          <birth>
+            <dateBirth>1942-11-27T00:00:00+01:00</dateBirth>
+            <place>Seattle</place>
+          </birth>
+          <bPhoto>false</bPhoto>
+          <bLeaveAlone>false</bLeaveAlone>
+          <paiInfoBean/>
+        </childList>
+        <childList>
+          <num>614051</num>
+          <lastname>DOE</lastname>
+          <firstname>ROBERT</firstname>
+          <sexe>M</sexe>
+          <birth>
+            <dateBirth>1941-05-24T00:00:00+02:00</dateBirth>
+            <place>Duluth</place>
+          </birth>
+          <bPhoto>true</bPhoto>
+          <bLeaveAlone>false</bLeaveAlone>
+          <paiInfoBean/>
+        </childList>
+      </familyResult>
+    </ns2:readFamilyResponse>
+  </soap:Body>
+</soap:Envelope>
diff --git a/tests/test_toulouse_maelis.py b/tests/test_toulouse_maelis.py
index b37ecc2c..1137efe0 100644
--- a/tests/test_toulouse_maelis.py
+++ b/tests/test_toulouse_maelis.py
@@ -39,16 +39,19 @@ FAMILY_SERVICE_WSDL = FakedResponse(content=get_xml_file('FamilyService.wsdl'),
 ACTIVITY_SERVICE_WSDL = FakedResponse(content=get_xml_file('ActivityService.wsdl'), status_code=200)
 INVOICE_SERVICE_WSDL = FakedResponse(content=get_xml_file('InvoiceService.wsdl'), status_code=200)
 FAILED_AUTH = FakedResponse(content=get_xml_file('R_failed_authentication.xml'), status_code=500)
 ISWSRUNNING_TRUE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'true', status_code=200)
 ISWSRUNNING_FALSE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'false', status_code=200)
 READ_FAMILY = FakedResponse(content=get_xml_file('R_read_family.xml'), status_code=200)
 READ_FAMILY_LAX = FakedResponse(content=get_xml_file('R_read_family_relax.xml'), status_code=200)
 READ_FAMILY_ORD = FakedResponse(content=get_xml_file('R_read_family_reordered.xml'), status_code=200)
+READ_FAMILY_QUOTIENT = FakedResponse(
+    content=get_xml_file('R_read_family_with_income_year.xml'), status_code=200
+)
 READ_RL1_FAMILY = FakedResponse(content=get_xml_file('R_read_family_with_only_rl1.xml'), status_code=200)
 IS_RL_EXISTS_TRUE = FakedResponse(content=get_xml_file('R_is_rl_exists.xml') % b'true', status_code=200)
 IS_RL_EXISTS_FALSE = FakedResponse(content=get_xml_file('R_is_rl_exists.xml') % b'false', status_code=200)
 IS_CHILD_EXISTS_TRUE = FakedResponse(content=get_xml_file('R_is_child_exists.xml') % b'true', status_code=200)
 IS_CHILD_EXISTS_FALSE = FakedResponse(
     content=get_xml_file('R_is_child_exists.xml') % b'false', status_code=200
 )
 CREATE_FAMILY = FakedResponse(content=get_xml_file('R_create_family.xml'), status_code=200)
@@ -880,16 +883,39 @@ def test_read_rl1(mocked_post, mocked_get, con, app):
     url = get_endpoint('read-rl')
     Link.objects.create(resource=con, family_id='1312', name_id='local')
 
     resp = app.get(url + '?NameID=local&rl_id=613878')
     assert resp.json['err'] == 0
     assert resp.json['data']['firstname'] == 'JHON'
 
 
+@mock.patch('passerelle.utils.Request.get')
+@mock.patch('passerelle.utils.Request.post')
+def test_read_rl1_with_income_year(mocked_post, mocked_get, con, app):
+    mocked_get.return_value = FAMILY_SERVICE_WSDL
+    mocked_post.return_value = READ_FAMILY_QUOTIENT
+    url = get_endpoint('read-rl')
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+
+    resp = app.get(url + '?NameID=local&rl_id=613878&income_year=2020')
+    assert resp.json['err'] == 0
+    assert resp.json['data']['quotientList'] == [
+        {
+            'yearRev': 2020,
+            'dateStart': '2021-01-01T00:00:00+01:00',
+            'dateEnd': '2021-12-31T00:00:00+01:00',
+            'mtt': 1500.33,
+            'cdquo': 'QS',
+            'cdquo_text': 'QUOTIENT SCOLAIRE',
+            'codeUti': None,
+        }
+    ]
+
+
 @mock.patch('passerelle.utils.Request.get')
 @mock.patch('passerelle.utils.Request.post')
 def test_read_rl2(mocked_post, mocked_get, con, app):
     mocked_get.return_value = FAMILY_SERVICE_WSDL
     mocked_post.return_value = READ_FAMILY
     url = get_endpoint('read-rl')
     Link.objects.create(resource=con, family_id='1312', name_id='local')
 
-- 
2.30.2

