From fe029e991effa024d6510b14810134f3b4711662 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 16 Apr 2020 15:20:54 +0200
Subject: [PATCH 1/2] toulouse-axel: get possible days for annual values
 (#41405)

---
 passerelle/contrib/toulouse_axel/models.py |  37 +++++
 tests/test_toulouse_axel.py                | 152 ++++++++++++++++++++-
 2 files changed, 183 insertions(+), 6 deletions(-)

diff --git a/passerelle/contrib/toulouse_axel/models.py b/passerelle/contrib/toulouse_axel/models.py
index 0494f3d7..854c862e 100644
--- a/passerelle/contrib/toulouse_axel/models.py
+++ b/passerelle/contrib/toulouse_axel/models.py
@@ -985,6 +985,43 @@ class ToulouseAxel(BaseResource):
 
         return {'data': activity_days}
 
+    @endpoint(
+        description=_("Get annual possible days to book an activity of a child"),
+        perm='can_access',
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'idpersonne': {'description': _('Child ID')},
+            'activity_type': {'description': _('Activity type (MAT, MIDI, SOIR, GARD)')},
+        })
+    def clae_booking_activity_annual_possible_days(self, request, NameID, idpersonne, activity_type):
+        link = self.get_link(NameID)
+        if activity_type not in ['MAT', 'MIDI', 'SOIR', 'GARD']:
+            raise APIError('bad activity_type, should be MAT, MIDI, SOIR or GARD', err_code='bad-request', http_status=400)
+
+        today = datetime.date.today()
+        reference_year = utils.get_reference_year_from_date(today)
+        # find the week of the 15 septembre of the reference year
+        start_date, end_date = utils.get_week_dates_from_date(datetime.date(reference_year, 9, 15))
+
+        activity_days = []
+        activities = self.get_booking_data(
+            dui=link.dui, child_id=idpersonne, booking_date=start_date, activity_types=[activity_type]).get('ACTIVITE', [])
+        if activities:
+            activity = activities[0]
+            day_date = start_date
+            while day_date <= end_date:
+                day = WEEKDAYS[day_date.weekday()]
+                activity_days.append({
+                    'id': '{}:{}:{}:{}'.format(idpersonne, activity_type, activity['id'], day),
+                    'text': dateformat.format(day_date, 'l'),
+                    'disabled': activity['booking']['days'][day] is None,
+                    'prefill': activity['booking']['days'][day],
+                    'details': activity,
+                })
+                day_date = day_date + datetime.timedelta(days=1)
+
+        return {'data': activity_days}
+
     @endpoint(
         description=_("Get booked days for an activity of a child, for a period"),
         perm='can_access',
diff --git a/tests/test_toulouse_axel.py b/tests/test_toulouse_axel.py
index 2656cc32..21962eeb 100644
--- a/tests/test_toulouse_axel.py
+++ b/tests/test_toulouse_axel.py
@@ -2615,12 +2615,6 @@ def test_clae_booking_activity_possible_days_endpoint(app, resource, child_activ
     assert resp.json['data'][3]['prefill'] is False
     assert resp.json['data'][4]['prefill'] is True
 
-    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_activity_possible_days?NameID=yyy&idpersonne=3535'
-                '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT')
-
     # again - data are in cache
     resp = app.get(
         '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535'
@@ -2674,6 +2668,152 @@ def test_clae_booking_activity_possible_days_period(app, resource, today, start_
         assert resp.json['data'][-1]['id'] == '3535:MAT:TOTO:%s' % last_date
 
 
+@freezegun.freeze_time('2019-09-01')
+def test_clae_booking_activity_annual_possible_days_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.schemas.enfants_activites') as operation:
+        operation.side_effect = AxelError('FooBar')
+        resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    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.schemas.reservation_periode') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    assert resp.json['err_desc'] == "Axel error: FooBar"
+    assert resp.json['err'] == 'error'
+
+
+@freezegun.freeze_time('2019-09-01')
+def test_clae_booking_activity_annual_possible_days_endpoint_activity_type(app, resource):
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=FOO', status=400)
+    assert resp.json['err_desc'] == "bad activity_type, should be MAT, MIDI, SOIR or GARD"
+    assert resp.json['err'] == 'bad-request'
+
+
+@freezegun.freeze_time('2019-09-01')
+def test_clae_booking_activity_annual_possible_days_endpoint_no_result(app, resource, child_activities_data):
+    resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    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.schemas.reservation_periode') as operation:
+            operation.side_effect = AxelError('FooBar')
+            resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=4242&activity_type=MAT')
+    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_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    assert resp.json['err_desc'] == "Child not found"
+    assert resp.json['err'] == 'not-found'
+
+    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data') as activities_info:
+        activities_info.return_value = {'ACTIVITE': []}
+        resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == []
+
+
+@freezegun.freeze_time('2019-09-01')
+def test_clae_booking_activity_annual_possible_days_endpoint(app, resource, child_activities_data):
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    content = """<PORTAIL>
+  <DUI>
+    <IDDUI>XXX</IDDUI>
+    <ENFANT>
+      <IDPERSONNE>3535</IDPERSONNE>
+      <ACTIVITE>
+        <ANNEEREFERENCE>2019</ANNEEREFERENCE>
+        <IDACTIVITE>A19P1M1</IDACTIVITE>
+        <JOUR>10201</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_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    assert resp.json['err'] == 0
+    assert len(resp.json['data']) == 5
+    assert set(resp.json['data'][0].keys()) == set(['id', 'text', 'disabled', 'prefill', 'details'])
+    assert resp.json['data'][0]['id'] == '3535:MAT:A19P1M1:monday'
+    assert resp.json['data'][1]['id'] == '3535:MAT:A19P1M1:tuesday'
+    assert resp.json['data'][2]['id'] == '3535:MAT:A19P1M1:wednesday'
+    assert resp.json['data'][3]['id'] == '3535:MAT:A19P1M1:thursday'
+    assert resp.json['data'][4]['id'] == '3535:MAT:A19P1M1:friday'
+    assert resp.json['data'][0]['text'] == 'Monday'
+    assert resp.json['data'][1]['text'] == 'Tuesday'
+    assert resp.json['data'][2]['text'] == 'Wednesday'
+    assert resp.json['data'][3]['text'] == 'Thursday'
+    assert resp.json['data'][4]['text'] == 'Friday'
+    assert resp.json['data'][0]['disabled'] is False
+    assert resp.json['data'][1]['disabled'] is False
+    assert resp.json['data'][2]['disabled'] is True
+    assert resp.json['data'][3]['disabled'] is False
+    assert resp.json['data'][4]['disabled'] is False
+    assert resp.json['data'][0]['prefill'] is True
+    assert resp.json['data'][1]['prefill'] is False
+    assert resp.json['data'][2]['prefill'] is None
+    assert resp.json['data'][3]['prefill'] is False
+    assert resp.json['data'][4]['prefill'] is True
+
+    # again - data are in cache
+    resp = app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    assert resp.json['err'] == 0
+    assert len(resp.json['data']) == 5
+
+
+def test_clae_booking_activity_annual_possible_days_reference_year(app, resource, child_activities_data):
+    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
+    activities = child_activities_data['ENFANT'][0]
+    with freezegun.freeze_time('2019-09-01'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities):
+            with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation:
+                operation.return_value = OperationResult(json_response={'DATA': {'PORTAIL': {'DUI': {}}}}, xml_request='', xml_response='')
+                app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
+    assert payload['ENFANT']['ACTIVITE'][0]['ANNEEREFERENCE'] == '2019'
+    assert payload['ENFANT']['ACTIVITE'][0]['DATEDEBUT'] == '2019-09-09'
+    assert payload['ENFANT']['ACTIVITE'][0]['DATEDFIN'] == '2019-09-13'
+
+    with freezegun.freeze_time('2020-08-01'):
+        with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities):
+            with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation:
+                operation.return_value = OperationResult(json_response={'DATA': {'PORTAIL': {'DUI': {}}}}, xml_request='', xml_response='')
+                app.get('/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535&activity_type=MAT')
+    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
+    assert payload['ENFANT']['ACTIVITE'][0]['ANNEEREFERENCE'] == '2020'
+    assert payload['ENFANT']['ACTIVITE'][0]['DATEDEBUT'] == '2020-09-14'
+    assert payload['ENFANT']['ACTIVITE'][0]['DATEDFIN'] == '2020-09-18'
+
+
 @freezegun.freeze_time('2019-09-01')
 def test_clae_booking_activity_prefill_endpoint_axel_error(app, resource):
     Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
-- 
2.20.1

