From b66e4a13cc7e089e2ac7fd1b10cf3dfa91f7a07a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 25 Feb 2020 18:47:08 +0100
Subject: [PATCH] toulouse_axel: add clae_booking_activities_info endpoint
 (#40177)

---
 passerelle/contrib/toulouse_axel/models.py |  69 ++++---
 tests/test_toulouse_axel.py                | 202 ++++++++++++++++++++-
 2 files changed, 248 insertions(+), 23 deletions(-)

diff --git a/passerelle/contrib/toulouse_axel/models.py b/passerelle/contrib/toulouse_axel/models.py
index 78c20417..d108d6c1 100644
--- a/passerelle/contrib/toulouse_axel/models.py
+++ b/passerelle/contrib/toulouse_axel/models.py
@@ -740,7 +740,7 @@ class ToulouseAxel(BaseResource):
 
         # prepare data
         post_data['IDDUI'] = link.dui
-        post_data['DATEDEMANDE'] = datetime.date.today().strftime('%Y-%m-%d')
+        post_data['DATEDEMANDE'] = datetime.date.today().strftime(utils.json_date_format)
 
         self.sanitize_update_family_data(dui=link.dui, post_data=post_data)
 
@@ -1013,28 +1013,14 @@ class ToulouseAxel(BaseResource):
             return {}
         return {child_id: bool(child.get('ACTIVITE', [])) for child_id, child in children_activities.items()}
 
-    @endpoint(
-        description=_("Get information about CLAE booking"),
-        perm='can_access',
-        parameters={
-            'NameID': {'description': _('Publik ID')},
-            'idpersonne': {'description': _('Child ID')},
-            'booking_date': {'description': _('Booking date')},
-        })
-    def clae_booking_info(self, request, NameID, idpersonne, booking_date):
-        link = self.get_link(NameID)
-        try:
-            booking_date = datetime.datetime.strptime(booking_date, utils.json_date_format)
-        except ValueError:
-            raise APIError('bad date format', err_code='bad-request', http_status=400)
-
+    def get_booking_data(self, dui, child_id, booking_date):
         reference_year = utils.get_reference_year_from_date(booking_date)
 
         # first get activities information for the child
         child_activities = self.get_child_activities(
-            dui=link.dui,
+            dui=dui,
             reference_year=reference_year,
-            child_id=idpersonne)
+            child_id=child_id)
 
         # then get booking of the requested week for the child
         activity_ids = [act['IDACTIVITE'] for act in child_activities.get('ACTIVITE', [])]
@@ -1050,9 +1036,9 @@ class ToulouseAxel(BaseResource):
         try:
             data = reservation_periode(self, {'PORTAIL': {
                 'DUI': {
-                    'IDDUI': link.dui,
+                    'IDDUI': dui,
                     'ENFANT': {
-                        'IDPERSONNE': idpersonne,
+                        'IDPERSONNE': child_id,
                         'ACTIVITE': activity_data,
                     }
                 }
@@ -1066,7 +1052,7 @@ class ToulouseAxel(BaseResource):
 
         child_booking = None
         for child in data.json_response['DATA']['PORTAIL']['DUI'].get('ENFANT', []):
-            if child['IDPERSONNE'] == idpersonne:
+            if child['IDPERSONNE'] == child_id:
                 child_booking = child
                 break
         if child_booking is None:
@@ -1088,9 +1074,48 @@ class ToulouseAxel(BaseResource):
             }
 
         for activity in child_activities.get('ACTIVITE', []):
+            activity['id'] = activity['IDACTIVITE']
+            start_date = datetime.datetime.strptime(activity['DATEENTREE'], utils.json_date_format)
+            end_date = datetime.datetime.strptime(activity['DATESORTIE'], utils.json_date_format)
+            activity['text'] = u'{} (inscription du {} au {})'.format(
+                activity['LIBELLEACTIVITE'],
+                start_date.strftime(utils.xml_date_format),
+                end_date.strftime(utils.xml_date_format))
+            activity['annee_reference'] = reference_year
+            activity['annee_reference_label'] = '{}/{}'.format(reference_year, reference_year + 1)
             activity['booking'] = booking_days.get(activity['IDACTIVITE'], {})
 
-        return {'data': child_activities}
+        return child_activities
+
+    @endpoint(
+        description=_("Get information about CLAE booking"),
+        perm='can_access',
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'idpersonne': {'description': _('Child ID')},
+            'booking_date': {'description': _('Booking date')},
+        })
+    def clae_booking_info(self, request, NameID, idpersonne, booking_date):
+        link = self.get_link(NameID)
+        try:
+            booking_date = datetime.datetime.strptime(booking_date, utils.json_date_format)
+        except ValueError:
+            raise APIError('bad date format, should be YYYY-MM-DD', err_code='bad-request', http_status=400)
+
+        booking_data = self.get_booking_data(dui=link.dui, child_id=idpersonne, booking_date=booking_date)
+
+        return {'data': booking_data}
+
+    @endpoint(
+        description=_("Get list of CLAE booking activities"),
+        perm='can_access',
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'idpersonne': {'description': _('Child ID')},
+            'booking_date': {'description': _('Booking date')},
+        })
+    def clae_booking_activities_info(self, request, NameID, idpersonne, booking_date):
+        return {'data': self.clae_booking_info(request, NameID, idpersonne, booking_date)['data'].get('ACTIVITE', [])}
 
 
 class Link(models.Model):
diff --git a/tests/test_toulouse_axel.py b/tests/test_toulouse_axel.py
index 2bc2dbb2..5fd138dc 100644
--- a/tests/test_toulouse_axel.py
+++ b/tests/test_toulouse_axel.py
@@ -1954,7 +1954,7 @@ def test_clae_booking_info_endpoint_axel_error(app, resource):
 def test_clae_booking_info_endpoint_bad_date_format(app, resource, value):
     Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
     resp = app.get('/toulouse-axel/test/clae_booking_info?NameID=yyy&idpersonne=3535&booking_date=%s' % value, status=400)
-    assert resp.json['err_desc'] == "bad date format"
+    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
     assert resp.json['err'] == 'bad-request'
 
 
@@ -2008,6 +2008,10 @@ def test_clae_booking_info_endpoint(app, resource, child_activities_data):
     assert resp.json['data'] == {
         'ACTIVITE': [
             {
+                'id': 'A19P1M1',
+                'text': 'Temps du matin (inscription du 01/08/2019 au 31/07/2020)',
+                'annee_reference': 2019,
+                'annee_reference_label': '2019/2020',
                 'COUTREVIENT': '99999',
                 'DATEDEBUT': '2019-08-01',
                 'DATEENTREE': '2019-08-01',
@@ -2030,6 +2034,10 @@ def test_clae_booking_info_endpoint(app, resource, child_activities_data):
                 }
             },
             {
+                'id': 'A19P1M2',
+                'text': 'Temps du midi (inscription du 01/08/2019 au 31/07/2020)',
+                'annee_reference': 2019,
+                'annee_reference_label': '2019/2020',
                 'COUTREVIENT': '99999',
                 'DATEDEBUT': '2019-08-01',
                 'DATEENTREE': '2019-08-01',
@@ -2052,6 +2060,10 @@ def test_clae_booking_info_endpoint(app, resource, child_activities_data):
                 }
             },
             {
+                'id': 'A19P1M3',
+                'text': 'Temps du soir (inscription du 01/08/2019 au 31/07/2020)',
+                'annee_reference': 2019,
+                'annee_reference_label': '2019/2020',
                 'COUTREVIENT': '99999',
                 'DATEDEBUT': '2019-08-01',
                 'DATEENTREE': '2019-08-01',
@@ -2074,6 +2086,10 @@ def test_clae_booking_info_endpoint(app, resource, child_activities_data):
                 }
             },
             {
+                'id': 'A19P1M4',
+                'text': u'Temps mercredi après midi (inscription du 01/08/2019 au 31/07/2020)',
+                'annee_reference': 2019,
+                'annee_reference_label': '2019/2020',
                 'COUTREVIENT': '99999',
                 'DATEDEBUT': '2019-08-01',
                 'DATEENTREE': '2019-08-01',
@@ -2133,6 +2149,190 @@ def test_clae_booking_info_endpoint(app, resource, child_activities_data):
     assert resp.json['data']['ACTIVITE'][3]['booking'] == {}
 
 
+def test_clae_booking_activities_info_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.enfants_activites') as operation:
+        operation.side_effect = AxelError('FooBar')
+        resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_date=2020-01-20')
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    with mock_getdata(content, 'EnfantsActivites'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_periode') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_date=2020-01-20')
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+
+@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
+def test_clae_booking_activities_info_endpoint_bad_date_format(app, resource, value):
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_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_clae_booking_activities_info_endpoint_no_result(app, resource, child_activities_data):
+    resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_date=2020-01-20')
+    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/child_activities.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    with mock_getdata(content, 'EnfantsActivites'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_periode') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=4242&booking_date=2020-01-20')
+    assert resp.json['err_desc'] == "Child not found"
+    assert resp.json['err'] == 'not-found'
+
+    content = """<PORTAIL>
+  <DUI>
+    <IDDUI>XXX</IDDUI>
+    <ENFANT>
+      <IDPERSONNE>4242</IDPERSONNE>
+      <ACTIVITE>
+        <ANNEEREFERENCE>2019</ANNEEREFERENCE>
+        <IDACTIVITE>A19P1M1</IDACTIVITE>
+        <JOUR>00000</JOUR>
+      </ACTIVITE>
+    </ENFANT>
+  </DUI>
+</PORTAIL>"""
+    activities = child_activities_data['ENFANT'][0]
+    with mock_getdata(content, 'ReservationPeriode'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities):
+            resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_date=2020-01-20')
+    assert resp.json['err_desc'] == "Child not found"
+    assert resp.json['err'] == 'not-found'
+
+
+def test_clae_booking_activities_info_endpoint(app, resource, child_activities_data):
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/booking_info.xml')
+    with open(filepath) as xml:
+        content = xml.read()
+    activities = child_activities_data['ENFANT'][0]
+    with mock_getdata(content, 'ReservationPeriode'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities):
+            resp = app.get('/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&booking_date=2020-01-20')
+    from pprint import pprint
+    pprint(resp.json)
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {
+            'id': 'A19P1M1',
+            'text': 'Temps du matin (inscription du 01/08/2019 au 31/07/2020)',
+            'annee_reference': 2019,
+            'annee_reference_label': '2019/2020',
+            'COUTREVIENT': '99999',
+            'DATEDEBUT': '2019-08-01',
+            'DATEENTREE': '2019-08-01',
+            'DATEFIN': '2020-07-31',
+            'DATESORTIE': '2020-07-31',
+            'IDACTIVITE': 'A19P1M1',
+            'ISPAI': False,
+            'LIBELLEACTIVITE': 'Temps du matin',
+            'TARIF': '0.42',
+            'TYPEACTIVITE': 'MAT',
+            'booking': {
+                'days': {
+                    'friday': False,
+                    'monday': False,
+                    'thursday': False,
+                    'tuesday': False,
+                    'wednesday': False
+                },
+                'raw_value': '00000'
+            }
+        },
+        {
+            'id': 'A19P1M2',
+            'text': 'Temps du midi (inscription du 01/08/2019 au 31/07/2020)',
+            'annee_reference': 2019,
+            'annee_reference_label': '2019/2020',
+            'COUTREVIENT': '99999',
+            'DATEDEBUT': '2019-08-01',
+            'DATEENTREE': '2019-08-01',
+            'DATEFIN': '2020-07-31',
+            'DATESORTIE': '2020-07-31',
+            'IDACTIVITE': 'A19P1M2',
+            'ISPAI': False,
+            'LIBELLEACTIVITE': 'Temps du midi',
+            'TARIF': '0.43',
+            'TYPEACTIVITE': 'MIDI',
+            'booking': {
+                'days': {
+                    'friday': True,
+                    'monday': True,
+                    'thursday': True,
+                    'tuesday': True,
+                    'wednesday': True
+                },
+                'raw_value': '11111'
+            }
+        },
+        {
+            'id': 'A19P1M3',
+            'text': 'Temps du soir (inscription du 01/08/2019 au 31/07/2020)',
+            'annee_reference': 2019,
+            'annee_reference_label': '2019/2020',
+            'COUTREVIENT': '99999',
+            'DATEDEBUT': '2019-08-01',
+            'DATEENTREE': '2019-08-01',
+            'DATEFIN': '2020-07-31',
+            'DATESORTIE': '2020-07-31',
+            'IDACTIVITE': 'A19P1M3',
+            'ISPAI': False,
+            'LIBELLEACTIVITE': 'Temps du soir',
+            'TARIF': '0.44',
+            'TYPEACTIVITE': 'SOIR',
+            'booking': {
+                'days': {
+                    'friday': True,
+                    'monday': True,
+                    'thursday': True,
+                    'tuesday': True,
+                    'wednesday': None
+                },
+                'raw_value': '11211'
+            }
+        },
+        {
+            'id': 'A19P1M4',
+            'text': u'Temps mercredi après midi (inscription du 01/08/2019 au 31/07/2020)',
+            'annee_reference': 2019,
+            'annee_reference_label': '2019/2020',
+            'COUTREVIENT': '99999',
+            'DATEDEBUT': '2019-08-01',
+            'DATEENTREE': '2019-08-01',
+            'DATEFIN': '2020-07-31',
+            'DATESORTIE': '2020-07-31',
+            'IDACTIVITE': 'A19P1M4',
+            'ISPAI': False,
+            'LIBELLEACTIVITE': u'Temps mercredi après midi',
+            'TARIF': '0.45',
+            'TYPEACTIVITE': 'GARD',
+            'booking': {
+                'days': {
+                    'friday': None,
+                    'monday': None,
+                    'thursday': None,
+                    'tuesday': None,
+                    'wednesday': True
+                },
+                'raw_value': '22122'
+            }
+        }
+    ]
+
+
 def test_are_children_registered_axel_error(resource):
     with mock.patch('passerelle.contrib.toulouse_axel.models.enfants_activites') as operation:
         operation.side_effect = AxelError('FooBar')
-- 
2.20.1

