From ee12e951ea40a5201cdc2d686db61c9c26ccda9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 18 May 2021 10:50:04 +0200
Subject: [PATCH] caluire-axel: child_activities_info enpoint (#53934)

---
 functests/caluire_axel/test_caluire_axel.py   |  13 ++
 passerelle/contrib/caluire_axel/models.py     |  48 +++++++-
 passerelle/contrib/caluire_axel/schemas.py    |   1 +
 .../caluire_axel/xsd/Q_GetListActivites.xsd   |  26 ++++
 .../caluire_axel/xsd/R_GetListActivites.xsd   |  49 ++++++++
 tests/data/caluire_axel/activities_info.xml   |  11 ++
 tests/test_caluire_axel.py                    | 112 ++++++++++++++++--
 7 files changed, 248 insertions(+), 12 deletions(-)
 create mode 100644 passerelle/contrib/caluire_axel/xsd/Q_GetListActivites.xsd
 create mode 100644 passerelle/contrib/caluire_axel/xsd/R_GetListActivites.xsd
 create mode 100644 tests/data/caluire_axel/activities_info.xml

diff --git a/functests/caluire_axel/test_caluire_axel.py b/functests/caluire_axel/test_caluire_axel.py
index 6c92ae8e..80937f15 100644
--- a/functests/caluire_axel/test_caluire_axel.py
+++ b/functests/caluire_axel/test_caluire_axel.py
@@ -62,6 +62,19 @@ def test_link(conn, user):
         assert res['err'] == 0
         print('\n')
 
+        print("and GET activities info")
+        url = conn + '/child_activities_info?NameID=%s&idpersonne=%s&schooling_date=%s' % (
+            name_id,
+            child['IDENT'],
+            datetime.date.today().strftime('%Y-%m-%d'),
+        )
+        resp = requests.get(url)
+        resp.raise_for_status()
+        res = resp.json()
+        pprint.pprint(res)
+        assert res['err'] == 0
+        print('\n')
+
     print("GET school list")
     url = conn + '/school_list'
     payload = {
diff --git a/passerelle/contrib/caluire_axel/models.py b/passerelle/contrib/caluire_axel/models.py
index 00e48cef..7519e2d8 100644
--- a/passerelle/contrib/caluire_axel/models.py
+++ b/passerelle/contrib/caluire_axel/models.py
@@ -220,7 +220,7 @@ class CaluireAxel(BaseResource):
             'street': {'description': _('Address: street')},
             'zipcode': {'description': _('Address: zipcode')},
             'city': {'description': _('Address: city')},
-            'schooling_date': {'description': _('Booking date (to get reference year)')},
+            'schooling_date': {'description': _('Schooling date (to get reference year)')},
             'school_level': {'description': _('Requested school level')},
         },
     )
@@ -269,7 +269,7 @@ class CaluireAxel(BaseResource):
         parameters={
             'NameID': {'description': _('Publik ID')},
             'idpersonne': {'description': _('Child ID')},
-            'schooling_date': {'description': _('Booking date (to get reference year)')},
+            'schooling_date': {'description': _('Schooling date (to get reference year)')},
         },
     )
     def child_schooling_info(self, request, NameID, idpersonne, schooling_date):
@@ -300,6 +300,50 @@ class CaluireAxel(BaseResource):
 
         return {'data': schooling_data}
 
+    @endpoint(
+        display_category=_('Schooling'),
+        display_order=3,
+        description=_("Get information about activities of a child for the year"),
+        perm='can_access',
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'idpersonne': {'description': _('Child ID')},
+            'schooling_date': {'description': _('Schooling date (to get reference year)')},
+        },
+    )
+    def child_activities_info(self, request, NameID, idpersonne, schooling_date):
+        link = self.get_link(NameID)
+        try:
+            schooling_date = datetime.datetime.strptime(schooling_date, axel.json_date_format)
+        except ValueError:
+            raise APIError('bad date format, should be YYYY-MM-DD', err_code='bad-request', http_status=400)
+
+        child_data = self.get_child_data(link.family_id, idpersonne)
+        if child_data is None:
+            raise APIError('Child not found', err_code='not-found')
+
+        reference_year = utils.get_reference_year_from_date(schooling_date)
+        try:
+            result = schemas.get_list_activites(
+                self,
+                {
+                    'PORTAIL': {
+                        'GETLISTACTIVITES': {'IDENTINDIVIDU': idpersonne, 'ANNEE': str(reference_year)}
+                    }
+                },
+            )
+        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},
+            )
+
+        activities_data = result.json_response['DATA']['PORTAIL']['GETLISTACTIVITES']
+        print(result.xml_response)
+
+        return {'data': activities_data}
+
 
 class Link(models.Model):
     resource = models.ForeignKey(CaluireAxel, on_delete=models.CASCADE)
diff --git a/passerelle/contrib/caluire_axel/schemas.py b/passerelle/contrib/caluire_axel/schemas.py
index 7c6f4231..ac40d93d 100644
--- a/passerelle/contrib/caluire_axel/schemas.py
+++ b/passerelle/contrib/caluire_axel/schemas.py
@@ -76,6 +76,7 @@ find_individus = Operation('FindIndividus')
 get_famille_individus = Operation('GetFamilleIndividus')
 get_individu = Operation('GetIndividu')
 get_list_ecole = Operation('GetListEcole')
+get_list_activites = Operation('GetListActivites')
 
 
 LINK_SCHEMA = copy.deepcopy(
diff --git a/passerelle/contrib/caluire_axel/xsd/Q_GetListActivites.xsd b/passerelle/contrib/caluire_axel/xsd/Q_GetListActivites.xsd
new file mode 100644
index 00000000..3d57425a
--- /dev/null
+++ b/passerelle/contrib/caluire_axel/xsd/Q_GetListActivites.xsd
@@ -0,0 +1,26 @@
+<?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="PORTAILType">
+		<xsd:sequence>
+			<xsd:element ref="GETLISTACTIVITES" minOccurs="0" maxOccurs="1"/>
+		</xsd:sequence>  
+	</xsd:complexType>
+	
+	<xsd:complexType name="GETLISTACTIVITESType">
+		<xsd:sequence>
+			<xsd:element ref="ANNEE" />
+			<xsd:element ref="IDENTINDIVIDU" />
+		</xsd:sequence> 
+	</xsd:complexType>
+	
+	<xsd:element name="IDENTINDIVIDU" type="all:IDENTREQUIREDType"/>
+	<xsd:element name="ANNEE" type="all:ANNEEType"/>
+	
+	<xsd:element name="GETLISTACTIVITES" type="GETLISTACTIVITESType"/>
+	
+	<xsd:element name="PORTAIL" type="PORTAILType"/>	
+		
+</xsd:schema>
\ No newline at end of file
diff --git a/passerelle/contrib/caluire_axel/xsd/R_GetListActivites.xsd b/passerelle/contrib/caluire_axel/xsd/R_GetListActivites.xsd
new file mode 100644
index 00000000..b50fb419
--- /dev/null
+++ b/passerelle/contrib/caluire_axel/xsd/R_GetListActivites.xsd
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xsd:schema	xmlns:all="urn:AllAxelTypes" xmlns:ind="urn:Individu"  xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
+	
+	<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="GetListActivites" />
+			</xsd:restriction>
+	    </xsd:simpleType>
+		
+		<xsd:complexType name="PORTAILType">
+			<xsd:complexContent>
+				<xsd:extension base="PORTAILType">
+					<xsd:sequence>
+							<xsd:element ref="GETLISTACTIVITES" minOccurs="0" maxOccurs="1"/>
+					</xsd:sequence>
+				</xsd:extension>
+			 </xsd:complexContent>
+		</xsd:complexType>
+	</xsd:redefine>	
+		
+	<xsd:complexType name="ACTIVITEType">
+		<xsd:sequence>
+			<xsd:element ref="IDENTACTIVITE" />
+			<xsd:element ref="LIBELLEACTIVITE"/>
+			<xsd:element ref="ENTREE"/>
+			<xsd:element ref="SORTIE"/>
+		</xsd:sequence> 
+	</xsd:complexType>
+	
+	<xsd:complexType name="GETLISTACTIVITESType">
+		<xsd:sequence>
+			<xsd:element ref="CODE" />
+			<xsd:element ref="ACTIVITE" minOccurs="0" maxOccurs="unbounded" />
+		</xsd:sequence> 
+	</xsd:complexType>
+	
+	<xsd:element name="CODE" type="xsd:integer"/>	
+	<xsd:element name="IDENTACTIVITE" type="all:IDREQUIREDType"/>
+	<xsd:element name="LIBELLEACTIVITE" type="all:LIBELLE100Type"/>
+	<xsd:element name="ENTREE" type="all:DATEType"/>
+	<xsd:element name="SORTIE" type="all:DATEType"/>
+	<xsd:element name="ACTIVITE" type="ACTIVITEType"/>
+	
+	<xsd:element name="GETLISTACTIVITES" type="GETLISTACTIVITESType"/>
+		
+</xsd:schema>
diff --git a/tests/data/caluire_axel/activities_info.xml b/tests/data/caluire_axel/activities_info.xml
new file mode 100644
index 00000000..dc217657
--- /dev/null
+++ b/tests/data/caluire_axel/activities_info.xml
@@ -0,0 +1,11 @@
+<PORTAIL>
+  <GETLISTACTIVITES>
+    <CODE>1</CODE>
+    <ACTIVITE>
+      <IDENTACTIVITE>ELEM</IDENTACTIVITE>
+      <LIBELLEACTIVITE>Restaurant El&#233;mentaire </LIBELLEACTIVITE>
+      <ENTREE>01/09/2020</ENTREE>
+      <SORTIE>31/07/2021</SORTIE>
+    </ACTIVITE>
+  </GETLISTACTIVITES>
+</PORTAIL>
diff --git a/tests/test_caluire_axel.py b/tests/test_caluire_axel.py
index b595c89a..bd9b4c68 100644
--- a/tests/test_caluire_axel.py
+++ b/tests/test_caluire_axel.py
@@ -180,6 +180,32 @@ def test_operation_get_famille_individus(resource, content):
             )
 
 
+@pytest.mark.parametrize(
+    'content',
+    [
+        '<PORTAIL><GETLISTECOLE/></PORTAIL>',
+    ],
+)
+def test_operation_get_list_ecole(resource, content):
+    with mock_getdata(content, 'GetListEcole'):
+        with pytest.raises(AxelError):
+            schemas.get_list_ecole(
+                resource,
+                {
+                    'PORTAIL': {
+                        'GETLISTECOLE': {
+                            'NORUE': '42',
+                            'ADRESSE1': 'rue Pasteur',
+                            'CODEPOSTAL': '69300',
+                            'VILLE': 'Caluire et Cuire',
+                            'IDENTNIVEAU': '',
+                            'ANNEE': '2021',
+                        }
+                    }
+                },
+            )
+
+
 @pytest.mark.parametrize(
     'content',
     [
@@ -205,22 +231,18 @@ def test_operation_get_individu(resource, content):
 @pytest.mark.parametrize(
     'content',
     [
-        '<PORTAIL><GETLISTECOLE/></PORTAIL>',
+        '<PORTAIL><GETLISTACTIVITES/></PORTAIL>',
     ],
 )
-def test_operation_get_list_ecole(resource, content):
-    with mock_getdata(content, 'GetListEcole'):
+def test_operation_get_list_activites(resource, content):
+    with mock_getdata(content, 'GetListActivites'):
         with pytest.raises(AxelError):
-            schemas.get_list_ecole(
+            schemas.get_list_activites(
                 resource,
                 {
                     'PORTAIL': {
-                        'GETLISTECOLE': {
-                            'NORUE': '42',
-                            'ADRESSE1': 'rue Pasteur',
-                            'CODEPOSTAL': '69300',
-                            'VILLE': 'Caluire et Cuire',
-                            'IDENTNIVEAU': '',
+                        'GETLISTACTIVITES': {
+                            'IDENTINDIVIDU': 'XXX',
                             'ANNEE': '2021',
                         }
                     }
@@ -696,3 +718,73 @@ def test_child_schooling_info(app, resource, family_data):
             )
     assert resp.json['err'] == 0
     assert set(resp.json['data'].keys()) == set(['CODE', 'INDIVIDU', 'SCOLAIRE'])
+
+
+def test_child_activities_info_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_famille_individus') as operation:
+        operation.side_effect = AxelError('FooBar')
+        resp = app.get(
+            '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
+        )
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    with mock_getdata(content, 'GetFamilleIndividus'):
+        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.get(
+                '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
+            )
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+
+@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
+def test_child_activities_info_endpoint_bad_date_format(app, resource, value):
+    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
+    resp = app.get(
+        '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=%s' % value,
+        status=400,
+    )
+    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
+    assert resp.json['err'] == 'bad-request'
+
+
+def test_child_activities_info_endpoint_no_result(app, resource):
+    resp = app.get(
+        '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
+    )
+    assert resp.json['err_desc'] == "Person not found"
+    assert resp.json['err'] == 'not-found'
+
+    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/family_info.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    with mock_getdata(content, 'GetFamilleIndividus'):
+        resp = app.get(
+            '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=zzz&schooling_date=2021-05-10'
+        )
+    assert resp.json['err_desc'] == "Child not found"
+    assert resp.json['err'] == 'not-found'
+
+
+def test_child_activities_info(app, resource, family_data):
+    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/activities_info.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    with mock_getdata(content, 'GetListActivites'):
+        with mock.patch(
+            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
+            return_value=family_data,
+        ):
+            resp = app.get(
+                '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
+            )
+    assert resp.json['err'] == 0
+    assert set(resp.json['data'].keys()) == set(['CODE', 'ACTIVITE'])
-- 
2.30.2

