From c9dd0f86f907f4b66f4167f47e401d2672bb82a2 Mon Sep 17 00:00:00 2001 From: Nicolas ROCHE Date: Sun, 19 Feb 2023 16:02:15 +0100 Subject: [PATCH] toulouse-maelis: add endpoints to update week-calendar (#75425) --- .../toulouse_maelis/activity_schemas.py | 36 ++ passerelle/contrib/toulouse_maelis/models.py | 118 +++++ ...rson_schedule_list_with_recurrent_week.xml | 466 ++++++++++++++++++ .../R_update_week_calendar.xml | 5 + .../R_update_week_calendar_error.xml | 13 + tests/test_toulouse_maelis.py | 199 ++++++++ 6 files changed, 837 insertions(+) create mode 100644 tests/data/toulouse_maelis/R_get_person_schedule_list_with_recurrent_week.xml create mode 100644 tests/data/toulouse_maelis/R_update_week_calendar.xml create mode 100644 tests/data/toulouse_maelis/R_update_week_calendar_error.xml diff --git a/passerelle/contrib/toulouse_maelis/activity_schemas.py b/passerelle/contrib/toulouse_maelis/activity_schemas.py index 58584a11..f203c42e 100644 --- a/passerelle/contrib/toulouse_maelis/activity_schemas.py +++ b/passerelle/contrib/toulouse_maelis/activity_schemas.py @@ -83,6 +83,42 @@ BOOKING_ACTIVITY_SCHEMA = { ], } +UPDATE_RECURRENT_WEEK_SCHEMA = { + 'type': 'object', + 'properties': { + 'person_id': { + 'type': 'string', + 'pattern': '^[0-9]+$', + }, + 'activity_id': { + 'type': 'string', + 'pattern': '^[A-Za-z0-9]+$', + }, + 'start_date': { + 'type': 'string', + 'pattern': '^[0-9]{4}-[0-9]{2}-[0-9]{2}$', + }, + 'end_date': { + 'type': 'string', + 'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2}){0,1}$', + }, + 'recurrent_week': { + 'type': 'array', + 'items': { + 'type': 'string', + 'pattern': '^[1-7]-[A-Z]$', + }, + }, + }, + 'required': [ + 'person_id', + 'activity_id', + 'start_date', + 'end_date', + 'recurrent_week', + ], +} + SUBSCRIPTION_SCHEMA = { 'type': 'object', 'properties': { diff --git a/passerelle/contrib/toulouse_maelis/models.py b/passerelle/contrib/toulouse_maelis/models.py index c5b71a4f..bbb1bc31 100644 --- a/passerelle/contrib/toulouse_maelis/models.py +++ b/passerelle/contrib/toulouse_maelis/models.py @@ -2198,6 +2198,124 @@ class ToulouseMaelis(BaseResource, HTTPResource): 'changes': updated, } + @endpoint( + display_category='Réservation', + description="Obtenir la semaine type d'une activité", + name='get-recurrent-week', + perm='can_access', + parameters={ + 'NameID': {'description': 'Publik NameID'}, + 'family_id': {'description': 'Numéro de DUI'}, + 'person_id': {'description': "Numéro du responsable légal ou de l'enfant"}, + 'activity_id': {'description': "Numéro de l'activité"}, + 'ref_date': { + 'description': "Date de référence, utilisée pour interroger l'agenda sur l'année et le mois", + 'type': 'date', + }, + }, + ) + def get_recurrent_week(self, request, person_id, activity_id, ref_date, NameID=None, family_id=None): + family_id = family_id or self.get_link(NameID).family_id + self.get_rl_or_child_raw(family_id, person_id) + + payload = { + 'requestBean': { + 'numDossier': family_id, + 'numPerson': person_id, + 'idAct': activity_id, + 'year': ref_date.year, + 'month': ref_date.month, + } + } + response = self.call('Activity', 'getPersonScheduleList', **payload) + + date_min_prev = None + recurrent_week = [] + day_names = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'] + for result_data in response or []: + for schedule in result_data['activityScheduleList']: + if schedule['activity']['idAct'] != activity_id or not schedule.get('weeklyCalendar'): + continue + units = [] + for item in schedule['unitScheduleList']: + key = item['unit']['calendarLetter'] + value = item['unit']['libelle'] + units.append((key, value)) + if item.get('datePrevMin'): + if not date_min_prev or item['datePrevMin'] > date_min_prev: + date_min_prev = item['datePrevMin'] + for item in schedule['weeklyCalendar'].get('dayWeekInfoList') or []: + if item['isOpen']: + day_num = item['dayNum'] + day_str = day_names[day_num - 1] + for key, value in units: + recurrent_week.append( + { + 'id': '%s-%s' % (day_num, key), + 'day': day_str, + 'label': value, + 'overlaps': ['%s-%s' % (day_num, k) for k, v in units if k != key], + 'text': '%s %s' % (day_str, value), + } + ) + if not recurrent_week: + raise APIError( + 'No week calendar for activity %s on %s' + % (activity_id, ref_date.strftime(utils.json_date_format)) + ) + return { + 'data': recurrent_week, + 'meta': {'date_min_prev': date_min_prev.strftime(utils.json_date_format)}, + } + + @endpoint( + display_category='Réservation', + description="Modifier la semaine type d'une inscription", + name='update-recurrent-week', + perm='can_access', + parameters={ + 'NameID': {'description': 'Publik NameID'}, + 'family_id': {'description': 'Numéro de DUI'}, + }, + post={ + 'request_body': { + 'schema': { + 'application/json': activity_schemas.UPDATE_RECURRENT_WEEK_SCHEMA, + } + } + }, + ) + def update_recurrent_week(self, request, post_data, NameID=None, family_id=None): + family_id = family_id or self.get_link(NameID).family_id + self.get_rl_or_child_raw(family_id, post_data['person_id']) + + recurrent_week = {} + for i in range(1, 8): + day_num = str(i) + recurrent_week[day_num] = { + 'dayNum': day_num, + 'calendarLetter': None, + 'isPresent': False, + } + for item in post_data.get('recurrent_week'): + day_num, key = item.split('-') + recurrent_week[day_num] = { + 'dayNum': day_num, + 'calendarLetter': key, + 'isPresent': True, + } + recurrent_week = sorted(recurrent_week.values(), key=lambda x: (x['dayNum'])) + + payload = { + 'numPerson': post_data['person_id'], + 'idActivity': post_data['activity_id'], + 'dateStart': post_data['start_date'], + 'dateEnd': post_data.get('end_date'), + 'dayWeekInfoList': recurrent_week, + } + self.call('Activity', 'updateWeekCalendar', **payload) + return {'data': 'ok'} + @endpoint( display_category='Facture', description="Ajouter une autorisation de prélèvement", diff --git a/tests/data/toulouse_maelis/R_get_person_schedule_list_with_recurrent_week.xml b/tests/data/toulouse_maelis/R_get_person_schedule_list_with_recurrent_week.xml new file mode 100644 index 00000000..def692b8 --- /dev/null +++ b/tests/data/toulouse_maelis/R_get_person_schedule_list_with_recurrent_week.xml @@ -0,0 +1,466 @@ + + + + + + + 261768 + NICO + BART + + + + A10049327682 + RESTAURATION SCOLAIRE 22/23 + + RESTSCOL + Restauration scolaire + + R + Restauration Scolaire + + + + + 2023 + + 1 + true + + + 2 + true + + + 3 + false + + + 4 + true + + + 5 + true + + + 6 + false + + + 7 + false + + + + + A10049355140 + PAI PANIER 22/23 + B + + 2023-03-27T00:00:00+02:00 + + 2023-04-01T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-02T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-03T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-04T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-05T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-06T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-07T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-08T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-09T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-10T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-11T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-12T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-13T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-14T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-15T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-16T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-17T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-18T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-19T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-20T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-21T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-22T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-23T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-24T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-25T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-26T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-27T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-28T00:00:00+02:00 + 0 + 0 + WRITABLE + ADD_PRES_PREVI + + + 2023-04-29T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-30T00:00:00+02:00 + 0 + 0 + NO_READ + + + + + A10049327683 + RESTAURATION SCOLAIRE 22/23 + X + + 2023-03-27T00:00:00+02:00 + + 2023-04-01T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-02T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-03T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-04T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-05T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-06T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-07T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-08T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-09T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-10T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-11T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-12T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-13T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-14T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-15T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-16T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-17T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-18T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-19T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-20T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-21T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-22T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-23T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-24T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-25T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-26T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-27T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-28T00:00:00+02:00 + 1 + 0 + WRITABLE + DEL_PRES_PREVI + + + 2023-04-29T00:00:00+02:00 + 0 + 0 + NO_READ + + + 2023-04-30T00:00:00+02:00 + 0 + 0 + NO_READ + + + + + + + + diff --git a/tests/data/toulouse_maelis/R_update_week_calendar.xml b/tests/data/toulouse_maelis/R_update_week_calendar.xml new file mode 100644 index 00000000..9ab307d1 --- /dev/null +++ b/tests/data/toulouse_maelis/R_update_week_calendar.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/data/toulouse_maelis/R_update_week_calendar_error.xml b/tests/data/toulouse_maelis/R_update_week_calendar_error.xml new file mode 100644 index 00000000..f245a654 --- /dev/null +++ b/tests/data/toulouse_maelis/R_update_week_calendar_error.xml @@ -0,0 +1,13 @@ + + + + soap:Server + E911 : Le calendrier hebdomadaire est incohérent avec la lettre de l'unité + + + E911 : Le calendrier hebdomadaire est incohérent avec la lettre de l'unité + + + + + diff --git a/tests/test_toulouse_maelis.py b/tests/test_toulouse_maelis.py index ca62bd21..19cf794d 100644 --- a/tests/test_toulouse_maelis.py +++ b/tests/test_toulouse_maelis.py @@ -5189,6 +5189,205 @@ def test_update_child_agenda_date_error(con, app): assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' +def test_get_recurrent_week(family_service, activity_service, con, app): + def request_check(request): + assert request.year == 2023 + assert request.month == 4 + + family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) + activity_service.add_soap_response( + 'getPersonScheduleList', + get_xml_file('R_get_person_schedule_list_with_recurrent_week.xml'), + request_check=request_check, + ) + url = get_endpoint('get-recurrent-week') + params = { + 'person_id': '613880', + 'activity_id': 'A10049327682', + 'ref_date': '2023-04-01', + } + + resp = app.get(url + '?family_id=1312', params=params) + assert resp.json['err'] == 0 + Link.objects.create(resource=con, family_id='1312', name_id='local') + + resp = app.get(url + '?NameID=local', params=params) + assert resp.json['err'] == 0 + assert resp.json['data'] == [ + { + 'id': '1-B', + 'day': 'Lundi', + 'label': 'PAI PANIER 22/23', + 'overlaps': ['1-X'], + 'text': 'Lundi PAI PANIER 22/23', + }, + { + 'id': '1-X', + 'day': 'Lundi', + 'label': 'RESTAURATION SCOLAIRE 22/23', + 'overlaps': ['1-B'], + 'text': 'Lundi RESTAURATION SCOLAIRE 22/23', + }, + { + 'id': '2-B', + 'day': 'Mardi', + 'label': 'PAI PANIER 22/23', + 'overlaps': ['2-X'], + 'text': 'Mardi PAI PANIER 22/23', + }, + { + 'id': '2-X', + 'day': 'Mardi', + 'label': 'RESTAURATION SCOLAIRE 22/23', + 'overlaps': ['2-B'], + 'text': 'Mardi RESTAURATION SCOLAIRE 22/23', + }, + { + 'id': '4-B', + 'day': 'Jeudi', + 'label': 'PAI PANIER 22/23', + 'overlaps': ['4-X'], + 'text': 'Jeudi PAI PANIER 22/23', + }, + { + 'id': '4-X', + 'day': 'Jeudi', + 'label': 'RESTAURATION SCOLAIRE 22/23', + 'overlaps': ['4-B'], + 'text': 'Jeudi RESTAURATION SCOLAIRE 22/23', + }, + { + 'id': '5-B', + 'day': 'Vendredi', + 'label': 'PAI PANIER 22/23', + 'overlaps': ['5-X'], + 'text': 'Vendredi PAI PANIER 22/23', + }, + { + 'id': '5-X', + 'day': 'Vendredi', + 'label': 'RESTAURATION SCOLAIRE 22/23', + 'overlaps': ['5-B'], + 'text': 'Vendredi RESTAURATION SCOLAIRE 22/23', + }, + ] + assert resp.json['meta'] == {'date_min_prev': '2023-03-27'} + + params['activity_id'] = 'plop' + resp = app.get(url + '?NameID=local', params=params) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'No week calendar for activity plop on 2023-04-01' + + +def test_get_recurrent_week_not_linked_error(con, app): + url = get_endpoint('get-recurrent-week') + params = { + 'person_id': '613880', + 'activity_id': 'A10049327682', + 'ref_date': '2023-04-01', + } + resp = app.get(url + '?NameID=local', params=params) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'User not linked to family' + + +def test_get_recurrent_week_person_not_found(family_service, con, app): + family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) + url = get_endpoint('get-recurrent-week') + params = { + 'person_id': '000000', + 'activity_id': 'A10049327682', + 'ref_date': '2023-04-01', + } + resp = app.get(url + '?family_id=1312', params=params) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == "no '000000' RL or child on '1312' family" + + +def test_update_recurrent_week(family_service, activity_service, con, app): + def request_check(request): + assert serialize_object(request.dayWeekInfoList) == [ + {'dayNum': 1, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'X'}, + {'dayNum': 2, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'B'}, + {'dayNum': 3, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, + {'dayNum': 4, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, + {'dayNum': 5, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, + {'dayNum': 6, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, + {'dayNum': 7, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, + ] + + family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) + activity_service.add_soap_response( + 'updateWeekCalendar', + get_xml_file('R_update_week_calendar.xml'), + request_check=request_check, + ) + url = get_endpoint('update-recurrent-week') + params = { + 'person_id': '613880', + 'activity_id': 'A10049327682', + 'start_date': '2023-04-01', + 'end_date': '2023-04-30', + 'recurrent_week': ['1-X', '2-B'], + } + + resp = app.post_json(url + '?family_id=311323', params=params) + assert resp.json['err'] == 0 + assert resp.json['data'] == 'ok' + + Link.objects.create(resource=con, family_id='311323', name_id='local') + resp = app.post_json(url + '?NameID=local', params=params) + assert resp.json['err'] == 0 + assert resp.json['data'] == 'ok' + + +def test_update_recurrent_week_not_linked_error(con, app): + url = get_endpoint('update-recurrent-week') + params = { + 'person_id': '613880', + 'activity_id': 'A10049327682', + 'start_date': '2023-04-01', + 'end_date': '', + 'recurrent_week': ['1-X', '2-B'], + } + resp = app.post_json(url + '?NameID=local', params=params) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'User not linked to family' + + +def test_update_recurrent_week_person_not_found(family_service, con, app): + family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) + url = get_endpoint('update-recurrent-week') + params = { + 'person_id': '000000', + 'activity_id': 'A10049327682', + 'start_date': '2023-04-01', + 'end_date': '', + 'recurrent_week': ['1-X', '2-B'], + } + resp = app.post_json(url + '?family_id=1312', params=params) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == "no '000000' RL or child on '1312' family" + + +def test_update_recurrent_week_soap_error(family_service, activity_service, con, app): + family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) + activity_service.add_soap_response('updateWeekCalendar', get_xml_file('R_update_week_calendar_error.xml')) + url = get_endpoint('update-recurrent-week') + params = { + 'person_id': '613880', + 'activity_id': 'A10049327682', + 'start_date': '2023-04-01', + 'end_date': '2023-04-30', + 'recurrent_week': ['1-Z'], + } + resp = app.post_json(url + '?family_id=311323', params=params) + assert resp.json['err'] == 1 + assert ( + "E911 : Le calendrier hebdomadaire est incohérent avec la lettre de l'unité" in resp.json['err_desc'] + ) + + def test_read_school_list_address_and_level(site_service, con, app): site_service.add_soap_response( 'readSchoolForAdressAndLevel', get_xml_file('R_read_school_for_adress_and_level.xml')