From 7a3d1a92f322019f6d9dc4689f908ae41b32059a Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 14 Jan 2021 18:00:00 +0100
Subject: [PATCH 4/4] maelis: add bus-stops endpoint (#50081)

---
 passerelle/apps/maelis/models.py | 42 ++++++++++++++++++++++++++
 tests/data/maelis/bus_stops.json | 30 ++++++++++++++++++
 tests/test_maelis.py             | 52 +++++++++++++++++++++++++++-----
 3 files changed, 116 insertions(+), 8 deletions(-)
 create mode 100644 tests/data/maelis/bus_stops.json

diff --git a/passerelle/apps/maelis/models.py b/passerelle/apps/maelis/models.py
index 49cd6a7b..828abdc5 100644
--- a/passerelle/apps/maelis/models.py
+++ b/passerelle/apps/maelis/models.py
@@ -495,16 +495,58 @@ class Maelis(BaseResource):
                 'activity_id': bus_activity_id,
                 'unit_calendar_letter': unit_calendar_letter,
                 'unit_weekly_planning': unit_weekly_planning,
                 'subscribe_start_date': legacy_unit_info['unit_start_date'],
                 'subscribe_end_date': legacy_unit_info['unit_end_date'],
             })
         return {'data': bus_lines}
 
+    @endpoint(
+        display_category=_('Activities'),
+        perm='can_access',
+        display_order=4,
+        description=_('Get bus stops (places)'),
+        name='bus-stops',
+        parameters={
+            'NameID': {'description': _('Publik ID')},
+            'childID': {'description': _('Child ID')},
+            'busActivityID': {'description': _('Activity ID')},
+            'busUnitID': {'description': _('Bus Unit ID')},
+            'queryDate': {'description': _('Optional querying date (YYYY-MM-DD)')}
+    })
+    def bus_stops(self, request, NameID, childID, busActivityID, busUnitID, queryDate=None):
+        school_year, start_date, end_date = self.get_activities_dates(queryDate)
+        self.get_child_info(NameID, childID)
+        activities = self.get_child_activities(childID, school_year, start_date, end_date)
+
+        for activity in activities:
+            if activity['activityPortail']['idAct'] != busActivityID:
+                continue
+            break
+        else:
+            raise APIError('Bus activity not found: %s' % busActivityID, err_code='not-found')
+
+        for unit in activity['unitPortailList']:
+            if unit['idUnit'] != busUnitID:
+                continue
+            break
+        else:
+            raise APIError('Bus unit not found: %s' % busUnitID, err_code='not-found')
+
+        bus_stops = []
+        for place in unit['placeList']:
+            bus_stops.append({
+                'id': place['id'],
+                'text': ' '.join([w.capitalize() for w in place['lib'].split(' ')]),
+            })
+        if bus_stops:
+            bus_stops[0]['disabled'] = True  # hide terminus
+        return {'data': bus_stops}
+
     @endpoint(
         display_category=_('Activities'),
         perm='can_access',
         display_order=3,
         description=_('Read child planning'),
         name='child-planning',
         parameters={
             'NameID': {'description': _('Publik ID')},
diff --git a/tests/data/maelis/bus_stops.json b/tests/data/maelis/bus_stops.json
new file mode 100644
index 00000000..0c6189b3
--- /dev/null
+++ b/tests/data/maelis/bus_stops.json
@@ -0,0 +1,30 @@
+{
+    "data": [
+        {
+            "disabled": true,
+            "id": "A10002132200",
+            "text": "Alsh Mistral"
+        },
+        {
+            "id": "A10003144173",
+            "text": "Arret 1"
+        },
+        {
+            "id": "A10003144174",
+            "text": "Arret 2"
+        },
+        {
+            "id": "A10003144175",
+            "text": "Arret 3"
+        },
+        {
+            "id": "A10003144176",
+            "text": "Arret 4"
+        },
+        {
+            "id": "A10003144177",
+            "text": "Arret 5"
+        }
+    ],
+    "err": 0
+}
\ No newline at end of file
diff --git a/tests/test_maelis.py b/tests/test_maelis.py
index 0923e063..e66d289a 100644
--- a/tests/test_maelis.py
+++ b/tests/test_maelis.py
@@ -357,28 +357,28 @@ def test_child_activities(mocked_post, mocked_get, parameters, nb_subscribed, nb
         assert resp.json == get_json_file('child_activities')
     status = [x['user_subscribing_status'] for x in resp.json['data']]
     assert len([x for x in status if x == 'subscribed']) == nb_subscribed
     assert len([x for x in status if x == 'not-subscribed']) == nb_not_subscribed
 
 
 @pytest.mark.parametrize('parameters, err_desc', [
     ('&childID=99999', 'Child not found'),
-    ('&childID=21293&subscribingStatus=not-a-status', 'wrong value for subscribingStatus'),
-    ("&childID=21293&queryDate=2020-02-31", 'not a valid date'),
-    ("&childID=21293&queryDate=not-a-date", 'YYYY-MM-DD expected'),
+    ('&subscribingStatus=not-a-status', 'wrong value for subscribingStatus'),
+    ("&queryDate=2020-02-31", 'not a valid date'),
+    ("&queryDate=not-a-date", 'YYYY-MM-DD expected'),
 ])
 @mock.patch('passerelle.utils.Request.get')
 @mock.patch('passerelle.utils.Request.post')
 def test_child_activities_errors(mocked_post, mocked_get, parameters, err_desc,
                                 catalog_mocked_get, catalog_mocked_post, connector, app):
     mocked_get.side_effect = catalog_mocked_get
     mocked_post.side_effect = catalog_mocked_post
     Link.objects.create(resource=connector, family_id='3264', name_id='local')
-    url = '/maelis/test/child-activities?NameID=local'
+    url = '/maelis/test/child-activities?NameID=local&childID=21293'
     url += parameters
     resp = app.get(url)
     assert resp.json['err']
     assert err_desc in resp.json['err_desc']
 
 
 @mock.patch('passerelle.utils.Request.get')
 @mock.patch('passerelle.utils.Request.post')
@@ -447,24 +447,60 @@ def test_bus_lines(mocked_post, mocked_get, parameters, nb_bus_lines,
     resp = app.get(url)
     if parameters == '&direction=':
         assert resp.json == get_json_file('bus_lines')
     assert len(resp.json['data']) == nb_bus_lines
 
 
 @pytest.mark.parametrize('parameters, err_desc', [
     ('&childID=99999', 'Child not found'),
-    ('&childID=21293&queryDate=2020-02-31', 'not a valid date'),
-    ('&childID=21293&queryDate=not-a-date', 'YYYY-MM-DD expected'),
-    ('&childID=21293&direction=heaven', 'wrong value for direction'),
+    ('&queryDate=2020-02-31', 'not a valid date'),
+    ('&queryDate=not-a-date', 'YYYY-MM-DD expected'),
+    ('&direction=heaven', 'wrong value for direction'),
 ])
 @mock.patch('passerelle.utils.Request.get')
 @mock.patch('passerelle.utils.Request.post')
 def test_child_activities_errors(mocked_post, mocked_get, parameters, err_desc,
                                  catalog_mocked_get, catalog_mocked_post, connector, app):
     mocked_get.side_effect = catalog_mocked_get
     mocked_post.side_effect = catalog_mocked_post
     Link.objects.create(resource=connector, family_id='3264', name_id='local')
-    url = '/maelis/test/bus-lines?NameID=local&activityID=1&unitID=2'
+    url = '/maelis/test/bus-lines?NameID=local&childID=21293&activityID=1&unitID=2'
+    url += parameters
+    resp = app.get(url)
+    assert resp.json['err']
+    assert err_desc in resp.json['err_desc']
+
+
+@mock.patch('passerelle.utils.Request.get')
+@mock.patch('passerelle.utils.Request.post')
+def test_bus_stops(mocked_post, mocked_get,
+                   catalog_mocked_get, catalog_mocked_post, connector, app):
+    mocked_get.side_effect = catalog_mocked_get
+    mocked_post.side_effect = catalog_mocked_post
+    Link.objects.create(resource=connector, family_id='3264', name_id='local')
+    url = '/maelis/test/bus-stops?NameID=local&childID=21293'
+    url += '&busActivityID=A10003151396&busUnitID=A10003151402&queryDate=2020-12-15'
+    resp = app.get(url)
+    assert resp.json == get_json_file('bus_stops')
+    assert len(resp.json['data']) == 6
+
+
+@pytest.mark.parametrize('parameters, err_desc', [
+    ('&childID=99999', 'Child not found'),
+    ('&queryDate=2020-02-31', 'not a valid date'),
+    ('&queryDate=not-a-date', 'YYYY-MM-DD expected'),
+    ('&busActivityID=1', 'Bus activity not found: 1'),
+    ('&busUnitID=2', 'Bus unit not found: 2'),
+])
+@mock.patch('passerelle.utils.Request.get')
+@mock.patch('passerelle.utils.Request.post')
+def test_bus_stops_errors(mocked_post, mocked_get, parameters, err_desc,
+                                 catalog_mocked_get, catalog_mocked_post, connector, app):
+    mocked_get.side_effect = catalog_mocked_get
+    mocked_post.side_effect = catalog_mocked_post
+    Link.objects.create(resource=connector, family_id='3264', name_id='local')
+    url = '/maelis/test/bus-stops?NameID=local&childID=21293'
+    url += '&busActivityID=A10003151396&busUnitID=A10003151402'
     url += parameters
     resp = app.get(url)
     assert resp.json['err']
     assert err_desc in resp.json['err_desc']
-- 
2.29.2

