# Copyright (C) 2022 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import base64 import datetime import json import logging import os import textwrap from unittest import mock import pytest import responses from django.db import transaction from django.utils.dateparse import parse_date from django.utils.timezone import now from requests.exceptions import ConnectionError, ReadTimeout from zeep import Settings from zeep.helpers import serialize_object from passerelle.apps.base_adresse.models import BaseAdresse, CityModel from passerelle.base.models import Job, ResourceLog from passerelle.contrib.toulouse_maelis.models import Link, Referential, ToulouseMaelis from passerelle.contrib.toulouse_maelis.utils import get_public_criterias from passerelle.utils.jsonresponse import APIError from passerelle.utils.soap import SOAPError, SOAPServiceUnreachable from passerelle.utils.templates import render_to_string from tests.test_manager import login from tests.utils import FakedResponse, ResponsesSoap, generic_endpoint_url, setup_access_rights TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'toulouse_maelis') WSDL_BASE_DIR = os.path.join( os.path.dirname(__file__), '..', 'passerelle', 'contrib', 'toulouse_maelis', 'tools', 'wsdl' ) def get_xml_file(filename): with open(os.path.join(TEST_BASE_DIR, filename), 'rb') as desc: return desc.read() def get_media_file(filename): with open(os.path.join(TEST_BASE_DIR, '%s' % filename), 'rb') as desc: return desc.read() def get_wsdl_file(filename): with open(os.path.join(WSDL_BASE_DIR, filename), 'rb') as desc: return desc.read() CONNECTION_ERROR = ConnectionError('No address associated with hostname') FAMILY_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('FamilyService.wsdl'), status_code=200) ACTIVITY_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('ActivityService.wsdl'), status_code=200) INVOICE_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('InvoiceService.wsdl'), status_code=200) SITE_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('SiteService.wsdl'), status_code=200) APE_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('ApeService.wsdl'), status_code=200) FAILED_AUTH = FakedResponse(content=get_xml_file('R_failed_authentication.xml'), status_code=500) ISWSRUNNING_TRUE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'true', status_code=200) ISWSRUNNING_FALSE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'false', status_code=200) TOMCAT_ERROR = FakedResponse(content=get_xml_file('R_tomcat_error.html'), status_code=404) def get_endpoint(name): url = generic_endpoint_url('toulouse-maelis', name) assert url == '/toulouse-maelis/test/%s' % name return url @pytest.fixture def requests_mock(): return responses.RequestsMock(assert_all_requests_are_fired=False) @pytest.fixture() def family_service(requests_mock): responses_soap = ResponsesSoap( wsdl_url='https://example.org/FamilyService?wsdl', wsdl_content=get_wsdl_file('FamilyService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), requests_mock=requests_mock, ) with responses_soap() as soap_mock: yield soap_mock @pytest.fixture() def activity_service(requests_mock): responses_soap = ResponsesSoap( wsdl_url='https://example.org/ActivityService?wsdl', wsdl_content=get_wsdl_file('ActivityService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), requests_mock=requests_mock, ) with responses_soap() as soap_mock: yield soap_mock @pytest.fixture() def invoice_service(requests_mock): responses_soap = ResponsesSoap( wsdl_url='https://example.org/InvoiceService?wsdl', wsdl_content=get_wsdl_file('InvoiceService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), requests_mock=requests_mock, ) with responses_soap() as soap_mock: yield soap_mock @pytest.fixture() def site_service(requests_mock): responses_soap = ResponsesSoap( wsdl_url='https://example.org/SiteService?wsdl', wsdl_content=get_wsdl_file('SiteService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), requests_mock=requests_mock, ) with responses_soap() as soap_mock: yield soap_mock @pytest.fixture() def ape_service(requests_mock): with ResponsesSoap( wsdl_url='https://example.org/ApeService?wsdl', wsdl_content=get_wsdl_file('ApeService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), requests_mock=requests_mock, )() as mock: yield mock @pytest.fixture def wcs_service(settings, requests_mock): wcs_service = { 'default': { 'title': 'test', 'url': 'https://wcs.example.com', 'secret': 'xxx', 'orig': 'passerelle', }, } settings.KNOWN_SERVICES = {'wcs': wcs_service} with requests_mock as mock: yield mock @pytest.fixture def authentic_service(settings, requests_mock): service = { 'idp': { 'url': 'http://idp.example.org/', 'verif_orig': 'abc', 'secret': 'def', }, } settings.KNOWN_SERVICES = {'authentic': service} with requests_mock as mock: yield mock @pytest.fixture(scope='module') def django_db_setup(django_db_setup, django_db_blocker): with django_db_blocker.unblock(): with transaction.atomic(): try: con = setup_access_rights( ToulouseMaelis.objects.get_or_create( slug='test', base_wsdl_url='https://example.org/', zeep_wsse_username='maelis-webservice', zeep_wsse_password='maelis-password', )[0] ) site_service = ResponsesSoap( wsdl_url='https://example.org/SiteService?wsdl', wsdl_content=get_wsdl_file('SiteService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), ) family_service = ResponsesSoap( wsdl_url='https://example.org/FamilyService?wsdl', wsdl_content=get_wsdl_file('FamilyService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), ) activity_service = ResponsesSoap( wsdl_url='https://example.org/ActivityService?wsdl', wsdl_content=get_wsdl_file('ActivityService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), ) ape_service = ResponsesSoap( wsdl_url='https://example.org/ApeService?wsdl', wsdl_content=get_wsdl_file('ApeService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), ) invoice_service = ResponsesSoap( wsdl_url='https://example.org/InvoiceService?wsdl', wsdl_content=get_wsdl_file('InvoiceService.wsdl'), settings=Settings(strict=False, xsd_ignore_sequence_order=True), ) with family_service() as soap_mock: soap_mock.add_soap_response('readCategoryList', get_xml_file('R_read_category_list.xml')) soap_mock.add_soap_response( 'readChildIndicatorList', get_xml_file('R_read_child_indicator_list.xml') ) soap_mock.add_soap_response('readCivilityList', get_xml_file('R_read_civility_list.xml')) soap_mock.add_soap_response('readCountryList', get_xml_file('R_read_country_list.xml')) soap_mock.add_soap_response('readCountyList', get_xml_file('R_read_county_list.xml')) soap_mock.add_soap_response('readCSPList', get_xml_file('R_read_csp_list.xml')) soap_mock.add_soap_response('readDietCodeList', get_xml_file('R_read_dietcode_list.xml')) soap_mock.add_soap_response('readDocumentList', get_xml_file('R_read_document_list.xml')) soap_mock.add_soap_response('readOrganList', get_xml_file('R_read_organ_list.xml')) soap_mock.add_soap_response('readPAIList', get_xml_file('R_read_pai_list.xml')) soap_mock.add_soap_response( 'readProfessionalSituationList', get_xml_file('R_read_professional_situation_list.xml'), ) soap_mock.add_soap_response('readQualityList', get_xml_file('R_read_quality_list.xml')) soap_mock.add_soap_response('readQuotientList', get_xml_file('R_read_quotient_list.xml')) soap_mock.add_soap_response( 'readRLIndicatorList', get_xml_file('R_read_rl_indicator_list.xml') ) soap_mock.add_soap_response( 'readSituationList', get_xml_file('R_read_situation_list.xml') ) soap_mock.add_soap_response('readStreetList', get_xml_file('R_read_street_list.xml')) soap_mock.add_soap_response('readTownList', get_xml_file('R_read_town_list.xml')) soap_mock.add_soap_response('readVaccinList', get_xml_file('R_read_vaccin_list.xml')) con.update_family_referentials() with site_service() as site_mock: site_mock.add_soap_response( 'readYearSchoolList', get_xml_file('R_read_year_school_list.xml') ) site_mock.add_soap_response('readLevelList', get_xml_file('R_read_level_list.xml')) site_mock.add_soap_response( 'readDerogReasonList', get_xml_file('R_read_derog_reason_list.xml') ) con.update_site_referentials() with activity_service() as activity_mock: activity_mock.add_soap_response( 'readActivityNatureTypeList', get_xml_file('R_read_activity_nature_type_list.xml') ) activity_mock.add_soap_response('readDirectList', get_xml_file('R_read_direct_list.xml')) activity_mock.add_soap_response( 'readServiceList', get_xml_file('R_read_service_list.xml') ) activity_mock.add_soap_response( 'readActivityList', get_xml_file('R_read_activity_list.xml') ) con.update_activity_referentials() with ape_service() as ape_mock: ape_mock.add_soap_response( 'readApeIndicatorList', get_xml_file('R_read_ape_indicator_list.xml') ) ape_mock.add_soap_response('readNurseryList', get_xml_file('R_read_nursery_list.xml')) con.update_ape_referentials() with invoice_service() as invoice_mock: invoice_mock.add_soap_response('readRegieList', get_xml_file('R_read_regie_list.xml')) con.update_invoice_referentials() with django_db_blocker.block(): yield finally: # prevent changes to persist after the tests transaction.set_rollback(True) @pytest.fixture() def con(db): return ToulouseMaelis.objects.get() def test_nature_codes(con): assert con.get_perisco_nature_codes() == ['A', 'R'] assert con.get_extrasco_nature_codes() == ['X'] assert con.get_loisir_nature_codes() == ['P', 'L', 'S', '1', '2', '3', '4', '5', '6', '7', '8', '9'] def test_manager(admin_user, app, con): app = login(app) path = '/%s/%s/' % (con.get_connector_slug(), con.slug) resp = app.get(path) assert [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') if x.text.startswith('Codes des natures des activités péri-scolaires') ][0].split(':')[1].strip() == 'A,R' assert [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') if x.text.startswith('Codes des natures des activités extra-scolaires') ][0].split(':')[1].strip() == 'X' assert ( 'P,L,S,1,2,3' in [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') if x.text.startswith('Codes des natures des activités loisirs') ][0] ) path = '/manage/%s/%s/edit' % (con.get_connector_slug(), con.slug) resp = app.get(path) resp.form['title'] = 'Malis connector' resp.form['description'] = 'Malis connector' resp.form['perisco_nature_codes'] = 'P,L, O ,P' resp.form['extrasco_nature_codes'] = 'Z' resp.form['loisir_nature_codes'] = '' resp = resp.form.submit() resp = resp.follow() assert [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') if x.text.startswith('Codes des natures des activités péri-scolaires') ][0].split(':')[1].strip() == 'P,L, O ,P' assert [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') if x.text.startswith('Codes des natures des activités extra-scolaires') ][0].split(':')[1].strip() == 'Z' assert 'Codes des natures des activités loisirs' not in [ x.text for x in resp.html.find('div', {'id': 'description'}).find_all('p') ] con = ToulouseMaelis.objects.get() assert con.get_perisco_nature_codes() == ['P', 'L', 'O', 'P'] assert con.get_extrasco_nature_codes() == ['Z'] assert con.get_loisir_nature_codes() == [] def test_manager_update_referentials(admin_user, app, con): app = login(app) path = '/%s/%s/' % (con.get_connector_slug(), con.slug) resp = app.get(path) resp = resp.click('Update referentials') resp = resp.follow() assert con.jobs_set().count() == 1 job = con.jobs_set().first() assert job.method_name == 'update_referentials' @mock.patch('passerelle.contrib.toulouse_maelis.models.ToulouseMaelis.soap_client_cache_timeout', 0) @mock.patch('passerelle.utils.Request.get') def test_call_with_wrong_wsdl_url(mocked_get, con): mocked_get.side_effect = CONNECTION_ERROR with pytest.raises(SOAPServiceUnreachable, match='SOAP service at.*is unreachable') as e: con.call('Family', 'isWSRunning') assert e.value.err == 1 assert e.value.http_status == 200 @mock.patch('passerelle.contrib.toulouse_maelis.models.ToulouseMaelis.soap_client_cache_timeout', 0) @mock.patch('passerelle.utils.Request.get') def test_call_with_wrong_wsdl_content(mocked_get, con): mocked_get.return_value = TOMCAT_ERROR with pytest.raises(APIError, match="'NoneType' object has no attribute 'getroottree'"): con.call('Family', 'isWSRunning') @mock.patch('passerelle.contrib.toulouse_maelis.models.ToulouseMaelis.soap_client_cache_timeout', 0) @mock.patch('passerelle.utils.Request.get') def test_call_with_wrong_wsdl_content_bis(mocked_get, con, app): mocked_get.return_value = TOMCAT_ERROR url = get_endpoint('get-baskets') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPInvalidContent' assert "'NoneType' object has no attribute 'getroottree'" in resp.json['err_desc'] @mock.patch('passerelle.contrib.toulouse_maelis.models.ToulouseMaelis.soap_client_cache_timeout', 0) @mock.patch('passerelle.utils.Request.get') @mock.patch('passerelle.utils.Request.post') def test_call_with_wrong_soap_content(mocked_post, mocked_get, con): mocked_get.return_value = FAMILY_SERVICE_WSDL mocked_post.return_value = TOMCAT_ERROR with pytest.raises(APIError, match="'NoneType' object has no attribute 'getroottree'"): con.call('Family', 'isWSRunning') @mock.patch('passerelle.utils.Request.get') @mock.patch('passerelle.utils.Request.post') def test_call_with_wrong_soap_content_bis(mocked_post, mocked_get, con, app): mocked_get.return_value = ACTIVITY_SERVICE_WSDL mocked_post.return_value = TOMCAT_ERROR url = get_endpoint('get-baskets') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPInvalidContent' assert "'NoneType' object has no attribute 'getroottree'" in resp.json['err_desc'] def test_call_with_wrong_credentials(family_service, con): family_service.add_soap_response('isWSRunning', get_xml_file('R_failed_authentication.xml'), status=500) with pytest.raises( APIError, match='The security token could not be authenticated or authorized', ) as e: con.call('Family', 'isWSRunning') assert e.value.__dict__ == { 'err': 1, 'log_error': False, 'http_status': 200, 'data': { 'soap_fault': { 'message': 'The security token could not be authenticated or authorized', 'code': 'ns1:FailedAuthentication', 'actor': None, 'detail': None, 'subcodes': None, } }, } def test_call(family_service, con): family_service.add_soap_response('isWSRunning', get_xml_file('R_is_ws_running.xml') % b'true') resp = con.call('Family', 'isWSRunning') assert resp is True @pytest.mark.parametrize( 'get_responses, post_responses, exception', [ ( [ FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL, SITE_SERVICE_WSDL, APE_SERVICE_WSDL, ], [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE], None, ), ( [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, CONNECTION_ERROR], [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE], SOAPError, ), ( [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL], [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, FAILED_AUTH], APIError, ), ( [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL], [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_FALSE], AssertionError, ), ], ) @mock.patch('passerelle.utils.Request.get') @mock.patch('passerelle.utils.Request.post') def test_check_status(mocked_post, mocked_get, get_responses, post_responses, exception, con): mocked_get.side_effect = get_responses mocked_post.side_effect = post_responses if exception: with pytest.raises(Exception): con.check_status() else: con.check_status() def test_replace_null_values(con): payload = { 'adresse': { 'num': '169', 'numComp': None, 'street1': 'Chateau', 'street2': None, 'town': 'Paris', 'zipcode': '75014', } } con.replace_null_values(payload) assert payload == { 'adresse': { 'num': '169', 'numComp': '', 'street1': 'Chateau', 'street2': '', 'town': 'Paris', 'zipcode': '75014', } } @mock.patch('passerelle.utils.Request.get') def test_update_referential(mocked_get, con): mocked_get.return_value = FAMILY_SERVICE_WSDL with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.return_value = FakedResponse( content=get_xml_file('R_read_category_list.xml'), status_code=200 ) data = con.get_referential_data('Family', 'Category') con.update_referential('Category', data, 'code', 'libelle') assert [ (x.item_id, x.item_text) for x in Referential.objects.filter(referential_name='Category') ] == [('BI', 'BIPARENTALE'), ('ACCEUI', "FAMILLE D'ACCUEIL"), ('MONO', 'MONOPARENTALE')] with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.return_value = FakedResponse( content=get_xml_file('R_read_category_list_2_items.xml'), status_code=200 ) data = con.get_referential_data('Family', 'Category') con.update_referential('Category', data, 'code', 'libelle') assert [ (x.item_id, x.item_text) for x in Referential.objects.filter(referential_name='Category') ] == [('BI', 'BIPARENTALE'), ('ACCEUI', 'Famille acceuillante')] # referential are not shared by connectors new_con = setup_access_rights( ToulouseMaelis.objects.get_or_create( slug='test2', zeep_wsse_username='maelis-webservice', zeep_wsse_password='maelis-password', )[0] ) assert new_con.referential.filter(referential_name='Category').count() == 0 with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.return_value = FakedResponse( content=get_xml_file('R_read_category_list.xml'), status_code=200 ) data = new_con.get_referential_data('Family', 'Category') new_con.update_referential('Category', data, 'code', 'libelle') assert new_con.referential.filter(referential_name='Category').count() == 3 assert con.referential.filter(referential_name='Category').count() == 2 @mock.patch('passerelle.utils.Request.get') def test_update_referential_empty(mocked_get, con): mocked_get.return_value = APE_SERVICE_WSDL assert len(Referential.objects.filter(referential_name='ApeIndicator')) == 3 with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.return_value = FakedResponse( content=get_xml_file('R_read_ape_indicator_list_empty.xml'), status_code=200 ) data = con.get_referential_data('Ape', 'ApeIndicator') con.update_referential('ApeIndicator', data, 'level', 'level') assert len(Referential.objects.filter(referential_name='ApeIndicator')) == 0 def test_cron(db): assert Referential.objects.filter(referential_name='Category').count() == 3 assert sorted(list({x.referential_name for x in Referential.objects.all()})) == [ 'Activity', 'ActivityNatureType', 'ApeIndicator', 'CSP', 'Category', 'ChildIndicator', 'Civility', 'Complement', 'Country', 'County', 'DerogReason', 'DietCode', 'Direct', 'Document', 'Level', 'Nursery', 'Organ', 'PAI', 'ProfessionalSituation', 'Quality', 'Quotient', 'RLIndicator', 'Regie', 'Service', 'Sex', 'Situation', 'Street', 'Town', 'Vaccin', 'YearSchool', ] def test_clean_logs_daily(con, app, settings, freezer): ResourceLog.objects.all().delete() freezer.move_to('2023-09-01 01:25:00') url = get_endpoint('read-category-list') resp = app.get(url) assert resp.json['err'] == 0 assert ResourceLog.objects.filter(timestamp__lte=datetime.datetime(2023, 9, 5, 1, 25)).count() == 1 assert settings.LOG_RETENTION_DAYS == 7 freezer.move_to('2023-09-09 01:25:00') con.daily() assert ResourceLog.objects.filter(timestamp__lte=datetime.datetime(2023, 9, 5, 1, 25)).count() == 0 def test_link(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 family_service.add_soap_response( 'readFamily', get_xml_file('R_read_family.xml'), request_check=request_check ) url = get_endpoint('link') assert Link.objects.count() == 0 # skip caching invoice con.referential.filter(referential_name='Regie').delete() params = { 'family_id': '1312', 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26', } resp = app.post_json(url + '?NameID=local', params=params) assert Link.objects.count() == 1 assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' # ignore accents provided by user params['firstname'] = 'Jhôñ' resp = app.post_json(url + '?NameID=local', params=params) assert Link.objects.count() == 1 assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' params['lastname'] = 'John' resp = app.post_json(url + '?NameID=local', params=params) assert Link.objects.count() == 1 assert resp.json['err'] == 1 assert resp.json['err_desc'] == "Data provided does not match any RL on '1312' family" def test_link_rl2(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 family_service.add_soap_response( 'readFamily', get_xml_file('R_read_family.xml'), request_check=request_check ) url = get_endpoint('link') assert Link.objects.count() == 0 # skip caching invoice con.referential.filter(referential_name='Regie').delete() params = { 'family_id': '1312', 'firstname': 'Jane', 'lastname': 'Doe', 'dateBirth': '1940-06-22', } resp = app.post_json(url + '?NameID=local', params=params) assert Link.objects.count() == 1 assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' @mock.patch('passerelle.utils.Request.get') @mock.patch('passerelle.utils.Request.post') def test_link_caching_invoices(mocked_post, mocked_get, con, app): mocked_get.side_effect = [FAMILY_SERVICE_WSDL, INVOICE_SERVICE_WSDL] mocked_post.side_effect = [ FakedResponse(content=get_xml_file('R_read_family.xml'), status_code=200), FakedResponse(content=get_xml_file('R_read_invoices.xml'), status_code=200), ] + [ FakedResponse(content=get_xml_file('R_read_invoices_empty.xml'), status_code=200), ] * 8 url = get_endpoint('link') assert con.invoice_set.count() == 0 assert Link.objects.count() == 0 params = { 'family_id': '1312', 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26', } resp = app.post_json(url + '?NameID=local', params=params) assert len(mocked_post.mock_calls) == 10 assert Link.objects.count() == 1 assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' assert con.invoice_set.count() == 2 def test_link_additional_properties_error(con, app): url = get_endpoint('link') params = { 'family_id': '1312', 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26', 'plop': 42, } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "Additional properties are not allowed ('plop' was unexpected)" def test_link_family_with_no_birth_error(family_service, con, app, caplog): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_no_rl1_birth.xml')) url = get_endpoint('link') params = { 'family_id': '1312', 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26', } resp = app.post_json(url + '?NameID=local', params=params) assert len(caplog.records) == 4 assert caplog.records[2].levelno == logging.WARNING assert caplog.records[2].message == "Maelis provides an invalid dateBirth for RL1 on '1312' family" assert resp.json['err'] == 1 assert resp.json['err_desc'] == "Data provided does not match any RL on '1312' family" def test_link_rl2_error(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 family_service.add_soap_response( 'readFamily', get_xml_file('R_read_family_with_only_rl1.xml'), request_check=request_check ) url = get_endpoint('link') params = { 'family_id': '1312', 'firstname': 'Jane', 'lastname': 'Doe', 'dateBirth': '1940-06-22', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "Data provided does not match any RL on '1312' family" def test_unlink(con, app): url = get_endpoint('unlink') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local') assert Link.objects.count() == 0 assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' resp = app.post_json(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_link_list(con, app, authentic_service, freezer): authentic_service.add( responses.GET, 'http://idp.example.org/api/users/83f6e19feb2043d2aafb041aea445b2c/', json={ 'uuid': '83f6e19feb2043d2aafb041aea445b2c', 'username': 'jdoe', 'first_name': 'Jhon', 'last_name': 'Doe', 'email': 'jdoe@example.org', 'date_joined': '2020-04-06T19:00:00.000000+02:00', 'last_login': '2023-07-10T11:00:00.000000+02:00', 'password': 'XXX', }, status=200, ) authentic_service.add( responses.GET, 'http://idp.example.org/api/users/local/', json={'result': 0, 'errors': {'detail': 'Pas trouvé.'}}, status=404, ) authentic_service.add( responses.GET, 'http://idp.example.org/api/users/456/', body=CONNECTION_ERROR, ) url = get_endpoint('get-link-list') # link 3 time to the 1312 family freezer.move_to('2023-07-10 15:00:00') Link.objects.create(resource=con, family_id='1312', name_id='83f6e19feb2043d2aafb041aea445b2c') freezer.move_to('2023-07-10 16:00:00') Link.objects.create(resource=con, family_id='1312', name_id='local') Link.objects.create(resource=con, family_id='1312', name_id='456') assert Link.objects.count() == 3 resp = app.get(url + '?family_id=1312') assert len(authentic_service.calls) == 3 assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': '83f6e19feb2043d2aafb041aea445b2c', 'context': { 'link': { 'name_id': '83f6e19feb2043d2aafb041aea445b2c', 'family_id': '1312', 'created': '2023-07-10T15:00:00Z', 'updated': '2023-07-10T15:00:00Z', }, 'user': { 'uuid': '83f6e19feb2043d2aafb041aea445b2c', 'username': 'jdoe', 'first_name': 'Jhon', 'last_name': 'Doe', 'email': 'jdoe@example.org', 'date_joined': '2020-04-06T19:00:00+02:00', 'last_login': '2023-07-10T11:00:00+02:00', }, }, 'text': 'Jhon Doe (lié le 10/07/2023 ; compte créé le 06/04/2020, dernière connexion le 10/07/2023)', }, { 'id': 'local', 'context': { 'link': { 'name_id': 'local', 'family_id': '1312', 'created': '2023-07-10T16:00:00Z', 'updated': '2023-07-10T16:00:00Z', } }, 'text': 'local (lié le 10/07/2023)', }, { 'id': '456', 'context': { 'link': { 'name_id': '456', 'family_id': '1312', 'created': '2023-07-10T16:00:00Z', 'updated': '2023-07-10T16:00:00Z', } }, 'text': '456 (lié le 10/07/2023)', }, ] resp = app.get(url + '?family_id=plop') assert resp.json['err'] == 0 assert resp.json['data'] == [] resp = app.get(url) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [x['text'][:50] for x in resp.json['data']] == [ 'Jhon Doe (lié le 10/07/2023 ; c', 'local (lié le 10/07/2023)', '456 (lié le 10/07/2023)', ] def test_get_link_list_service_error(con, app, freezer): url = get_endpoint('get-link-list') freezer.move_to('2023-07-10 15:00:00') Link.objects.create(resource=con, family_id='1312', name_id='83f6e19feb2043d2aafb041aea445b2c') freezer.move_to('2023-07-10 16:00:00') Link.objects.create(resource=con, family_id='1312', name_id='local') Link.objects.create(resource=con, family_id='1312', name_id='456') assert Link.objects.count() == 3 resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert [x['text'][:50] for x in resp.json['data']] == [ '83f6e19feb2043d2aafb041aea445b2c (lié le 10/07/202', 'local (lié le 10/07/2023)', '456 (lié le 10/07/2023)', ] def test_get_family_id(con, app): url = get_endpoint('get-family-id') Link.objects.create(resource=con, family_id='1312', name_id='local') # NameID is provided on front-office acces resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert resp.json['data'] == '1312' # family_id is provided on back-office acces resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert resp.json['data'] == '1312' # error from front-office resp = app.get(url + '?NameID=plop') assert resp.json['err'] == 0 assert resp.json['data'] is None # error by providing the 2 parameters : # we cannot stat from which portal the call come from resp = app.get(url + '?NameID=local&family_id=42') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'NameID and family_id both provided' def test_get_referential(con): assert con.get_referential('Category') == [ {'code': 'BI', 'id': 'BI', 'libelle': 'BIPARENTALE', 'text': 'BIPARENTALE'}, {'code': 'ACCEUI', 'id': 'ACCEUI', 'libelle': "FAMILLE D'ACCUEIL", 'text': "FAMILLE D'ACCUEIL"}, {'code': 'MONO', 'id': 'MONO', 'libelle': 'MONOPARENTALE', 'text': 'MONOPARENTALE'}, ] def test_get_referential_value(con): assert con.get_referential_value('CSP', '1') == 'AGRICULTEUR' assert con.get_referential_value('CSP', 'AGR') == 'AGRICULTEUR' def test_get_referential_value_not_found(con, caplog): assert con.get_referential_value('Civility', 'MR') == 'MR' assert len(caplog.records) == 1 assert caplog.records[0].levelno == logging.WARNING assert caplog.records[0].message == "No 'MR' key into Maelis 'Civility' referential" def test_read_category_list(con, app): url = get_endpoint('read-category-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'BI', 'text': 'BIPARENTALE', 'code': 'BI', 'libelle': 'BIPARENTALE'}, {'id': 'ACCEUI', 'text': "FAMILLE D'ACCUEIL", 'code': 'ACCEUI', 'libelle': "FAMILLE D'ACCUEIL"}, {'id': 'MONO', 'text': 'MONOPARENTALE', 'code': 'MONO', 'libelle': 'MONOPARENTALE'}, ] def test_read_country_list(con, app): url = get_endpoint('read-country-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 6 assert resp.json['data'][:3] == [ {'id': '212', 'code': '212', 'text': 'AFGHANISTAN', 'libelle': 'AFGHANISTAN'}, {'id': '303', 'code': '303', 'text': 'AFRIQUE DU SUD', 'libelle': 'AFRIQUE DU SUD'}, {'id': '125', 'code': '125', 'text': 'ALBANIE', 'libelle': 'ALBANIE'}, ] def test_read_county_list(con, app): url = get_endpoint('read-county-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 4 assert resp.json['data'][:3] == [ {'id': '01', 'code': '01', 'text': 'AIN', 'libelle': 'AIN'}, {'id': '02', 'code': '02', 'text': 'AISNE', 'libelle': 'AISNE'}, {'id': '03', 'code': '03', 'text': 'ALLIER', 'libelle': 'ALLIER'}, ] def test_read_town_list(con, app): url = get_endpoint('read-town-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 4 assert resp.json['data'] == [ {'code': '64001', 'id': '64001', 'libelle': 'AAST', 'text': 'AAST'}, {'code': '91122', 'id': '91122', 'libelle': 'BURES-SUR-YVETTE', 'text': 'BURES-SUR-YVETTE'}, {'code': '07120', 'id': '07120', 'libelle': 'LACHAMP-RAPHAEL', 'text': 'LACHAMP-RAPHAEL'}, { 'code': '69391', 'id': '69391', 'libelle': 'LYON 1ER ARRONDISSEMENT', 'text': 'LYON 1ER ARRONDISSEMENT', }, ] # check merging zipcode ban = BaseAdresse.objects.create(slug='ban') CityModel.objects.create( name='Lachamp-Raphaël', code='07120', zipcode='07530', population=68, resource=ban ) con.merge_zipcodes() resp = app.get(url) assert resp.json['data'] == [ {'code': '64001', 'id': '64001', 'libelle': 'AAST', 'text': 'AAST'}, {'code': '91122', 'id': '91122', 'libelle': 'BURES-SUR-YVETTE', 'text': 'BURES-SUR-YVETTE'}, { 'code': '07120', 'id': '07120', 'libelle': 'LACHAMP-RAPHAEL', 'text': 'LACHAMP-RAPHAEL', 'zip_and_text': '07530 LACHAMP-RAPHAEL', 'zipcode': '07530', }, { 'code': '69391', 'id': '69391', 'libelle': 'LYON 1ER ARRONDISSEMENT', 'text': 'LYON 1ER ARRONDISSEMENT', 'zip_and_text': '69001 LYON 1ER ARRONDISSEMENT', 'zipcode': '69001', }, ] def test_read_child_indicator_list(con, app): url = get_endpoint('read-child-indicator-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 8 assert resp.json['data'][0:2] == [ { 'id': 'AUTRE', 'text': 'Autre', 'choiceList': [], 'code': 'AUTRE', 'libelle': 'Autre', 'typeDesc': 'NOTE', }, { 'id': 'AVL', 'text': 'Auxiliaire de Vie loisirs', 'choiceList': [], 'code': 'AVL', 'libelle': 'Auxiliaire de Vie loisirs', 'typeDesc': 'NONE', }, ] def test_read_civility_list(con, app): url = get_endpoint('read-civility-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'MME', 'code': 'MME', 'text': 'Madame', 'libelle': 'Madame'}, {'id': 'M.', 'code': 'M.', 'text': 'Monsieur', 'libelle': 'Monsieur'}, ] def test_read_complement_list(con, app): url = get_endpoint('read-complement-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'A', 'text': 'bâtiment A'}, {'id': 'B', 'text': 'bâtiment B, ou bis'}, {'id': 'C', 'text': 'bâtiment C'}, {'id': 'Q', 'text': 'quater'}, {'id': 'T', 'text': 'ter'}, ] def test_read_csp_list(con, app): url = get_endpoint('read-csp-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 27 assert resp.json['data'][:5] == [ {'code': '14', 'id': '14', 'libelle': 'AGENT DE MAITRISE', 'text': 'AGENT DE MAITRISE'}, {'code': '1', 'id': '1', 'libelle': 'AGRICULTEUR', 'text': 'AGRICULTEUR'}, {'code': 'ART', 'id': 'ART', 'libelle': 'ARTISAN', 'text': 'ARTISAN'}, {'code': '2', 'id': '2', 'libelle': 'ARTISAN-COMMERCANT', 'text': 'ARTISAN-COMMERCANT'}, {'code': '15', 'id': '15', 'libelle': 'AUTRES', 'text': 'AUTRES'}, ] resp = app.get(url + '?distinct=False') assert resp.json['err'] == 0 assert len(resp.json['data']) == 43 assert resp.json['data'][:5] == [ {'id': '14', 'code': '14', 'text': 'AGENT DE MAITRISE', 'libelle': 'AGENT DE MAITRISE'}, {'id': '1', 'code': '1', 'text': 'AGRICULTEUR', 'libelle': 'AGRICULTEUR'}, {'id': 'AGR', 'code': 'AGR', 'text': 'AGRICULTEUR', 'libelle': 'AGRICULTEUR'}, {'id': 'ART', 'code': 'ART', 'text': 'ARTISAN', 'libelle': 'ARTISAN'}, {'id': 'ARTI', 'code': 'ARTI', 'text': 'ARTISAN', 'libelle': 'ARTISAN'}, ] def test_read_dietcode_list(con, app): url = get_endpoint('read-dietcode-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'STD', 'code': 'STD', 'text': '1- REPAS STANDARD', 'libelle': '1- REPAS STANDARD'}, {'id': 'RSP', 'code': 'RSP', 'text': '2- RÉGIME SANS PORC', 'libelle': '2- RÉGIME SANS PORC'}, {'id': 'RSV', 'code': 'RSV', 'text': '3- RÉGIME SANS VIANDE', 'libelle': '3- RÉGIME SANS VIANDE'}, { 'id': 'PAI', 'code': 'PAI', 'text': "4- PROTOCOLE D'ACCUEIL INDIVIDUALISÉ", 'libelle': "4- PROTOCOLE D'ACCUEIL INDIVIDUALISÉ", }, {'id': 'BB', 'code': 'BB', 'text': 'REPAS BEBE', 'libelle': 'REPAS BEBE'}, {'id': 'MSP', 'code': 'MSP', 'text': 'REPAS MOYEN SANS PORC', 'libelle': 'REPAS MOYEN SANS PORC'}, {'id': 'MSV', 'code': 'MSV', 'text': 'REPAS MOYEN SANS VIANDE', 'libelle': 'REPAS MOYEN SANS VIANDE'}, {'id': 'MST', 'code': 'MST', 'text': 'REPAS MOYEN STANDARD', 'libelle': 'REPAS MOYEN STANDARD'}, ] def test_read_direction_list(con, app): url = get_endpoint('read-direction-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 10 assert resp.json['data'][:5] == [ {'id': 'A10049327620', 'lib1': 'CCAS', 'lib2': "Centre communal d'action social", 'text': 'CCAS'}, { 'id': 'A10049327621', 'lib1': 'DASC', 'lib2': "Direction de l'action socioculturelle", 'text': 'DASC', }, {'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL'}, { 'id': 'A10049327622', 'lib1': 'DEPP', 'lib2': "Direction de l'éducation prestations périscolaires", 'text': 'DEPP', }, { 'id': 'A10049327623', 'lib1': 'DE SICS', 'lib2': 'Direction éducation inscription et carte scolaire', 'text': 'DE SICS', }, ] def test_read_document_list(con, app): url = get_endpoint('read-document-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'][:5] == [ { 'id': '43', 'code': '43', 'rang': 'FAMILY', 'text': 'Acte notarié de divorce', 'libelle': 'Acte notarié de divorce', }, { 'id': '44', 'code': '44', 'rang': 'PERSON', 'text': "Attestation aide médicale de l'état CPAM", 'libelle': "Attestation aide médicale de l'état CPAM", }, {'id': '45', 'code': '45', 'rang': 'FAMILY', 'text': 'Attestation CAF', 'libelle': 'Attestation CAF'}, { 'id': '46', 'code': '46', 'rang': 'FAMILY', 'text': 'Attestation CD31', 'libelle': 'Attestation CD31', }, { 'id': '47', 'code': '47', 'rang': 'FAMILY', 'text': "Attestation d'attribution ou non de bourse", 'libelle': "Attestation d'attribution ou non de bourse", }, ] def test_read_organ_list(con, app): url = get_endpoint('read-organ-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 92 assert resp.json['data'][:5] == [ {'id': 'A10000979374', 'code': 'ALC L OLIVIER', 'text': 'ALC L OLIVIER', 'libelle': None}, {'id': 'A10000979372', 'code': 'ALVA 06', 'text': 'ALVA 06', 'libelle': None}, {'id': 'A10000980566', 'code': 'ANTIBES', 'text': 'ANTIBES', 'libelle': None}, {'id': 'A10000980388', 'code': 'APAJH', 'text': 'APAJH', 'libelle': None}, {'id': 'A10016401771', 'code': 'ASCROS', 'text': 'ASCROS', 'libelle': None}, ] def test_read_pai_list(con, app): url = get_endpoint('read-pai-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'PAIALI', 'code': 'PAIALI', 'text': 'ALIMENTAIRE', 'libelle': 'ALIMENTAIRE'}, {'id': 'PAIO', 'code': 'PAIO', 'text': 'AUTRE', 'libelle': 'AUTRE'}, {'id': 'PAIMED', 'code': 'PAIMED', 'text': 'MEDICAL', 'libelle': 'MEDICAL'}, {'id': 'PAI2', 'code': 'PAI2', 'text': 'MEDICAL ET ALIMENTAIRE', 'libelle': 'MEDICAL ET ALIMENTAIRE'}, ] def test_read_professiona_situation_list(con, app): url = get_endpoint('read-professional-situation-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': '01', 'code': '01', 'text': 'Activité professionnelle', 'libelle': 'Activité professionnelle'}, {'id': '06', 'code': '06', 'text': 'Autre', 'libelle': 'Autre'}, {'id': '05', 'code': '05', 'text': 'Congé parental', 'libelle': 'Congé parental'}, {'id': '04', 'code': '04', 'text': 'Etudiant', 'libelle': 'Etudiant'}, {'id': '03', 'code': '03', 'text': 'Formation', 'libelle': 'Formation'}, {'id': '07', 'code': '07', 'text': 'Intérim', 'libelle': 'Intérim'}, {'id': '02', 'code': '02', 'text': "Recherche d'emploi", 'libelle': "Recherche d'emploi"}, ] def test_read_quality_list(con, app): url = get_endpoint('read-quality-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'][:5] == [ {'id': 'AU', 'code': 'AU', 'text': 'AUTRE', 'libelle': 'AUTRE'}, {'id': 'BP', 'code': 'BP', 'text': 'BEAU PERE', 'libelle': 'BEAU PERE'}, {'id': 'BM', 'code': 'BM', 'text': 'BELLE MERE', 'libelle': 'BELLE MERE'}, {'id': 'CONSO', 'code': 'CONSO', 'text': 'CONSOMMATEUR', 'libelle': 'CONSOMMATEUR'}, {'id': 'EN', 'code': 'EN', 'text': 'ENFANT', 'libelle': 'ENFANT'}, ] def test_read_quotient_list(con, app): url = get_endpoint('read-quotient-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'QF', 'code': 'QF', 'text': 'GRILLE DE QUOTIENT', 'libelle': 'GRILLE DE QUOTIENT'}, {'id': 'QCLSH', 'code': 'QCLSH', 'text': 'QUOTIENT CENTRE AERE', 'libelle': 'QUOTIENT CENTRE AERE'}, {'id': 'QJEU', 'code': 'QJEU', 'text': 'QUOTIENT JEUNESSE', 'libelle': 'QUOTIENT JEUNESSE'}, {'id': 'QS', 'code': 'QS', 'text': 'QUOTIENT SCOLAIRE', 'libelle': 'QUOTIENT SCOLAIRE'}, {'id': 'QSPORT', 'code': 'QSPORT', 'text': 'QUOTIENT SPORT', 'libelle': 'QUOTIENT SPORT'}, { 'id': 'MOY ECO', 'code': 'MOY ECO', 'text': 'REVENU MOYEN ( MENSUEL OU ANNUEL)', 'libelle': 'REVENU MOYEN ( MENSUEL OU ANNUEL)', }, ] def test_read_regie_list(con, app): url = get_endpoint('read-regie-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 9 assert resp.json['data'] == [ {'id': 103, 'code': 103, 'text': 'CCAS', 'libelle': 'CCAS'}, {'id': 101, 'code': 101, 'text': 'DASC', 'libelle': 'DASC'}, {'id': 102, 'code': 102, 'text': 'DE - CANTINE / CLAE', 'libelle': 'DE - CANTINE / CLAE'}, {'id': 106, 'code': 106, 'text': 'DE - PARCOURS EDUCATIFS', 'libelle': 'DE - PARCOURS EDUCATIFS'}, {'id': 109, 'code': 109, 'text': 'DSBL', 'libelle': 'DSBL'}, {'id': 104, 'code': 104, 'text': 'DSCS', 'libelle': 'DSCS'}, {'id': 105, 'code': 105, 'text': 'ENFANCE LOISIRS ET PE', 'libelle': 'ENFANCE LOISIRS ET PE'}, {'id': 107, 'code': 107, 'text': 'REMBOURSEMENT', 'libelle': 'REMBOURSEMENT'}, {'id': 108, 'code': 108, 'text': 'SENIORS', 'libelle': 'SENIORS'}, ] def test_read_rl_indicator_list(con, app): url = get_endpoint('read-rl-indicator-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 4 assert resp.json['data'][1:3] == [ { 'id': 'AVS', 'text': 'Auxiliaire de Vie scolaire', 'choiceList': [], 'code': 'AVS', 'libelle': 'Auxiliaire de Vie scolaire ', 'typeDesc': 'NONE', }, { 'id': 'ETABSPEC', 'text': 'Etablissement spécialisé', 'choiceList': [], 'code': 'ETABSPEC', 'libelle': 'Etablissement spécialisé', 'typeDesc': 'NOTE', }, ] def test_read_service_list(con, app): url = get_endpoint('read-service-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 25 assert resp.json['data'][:5] == [ { 'id': 'A10049329043', 'lib1': 'Accueil de loisirs', 'lib2': None, 'text': 'Accueil de loisirs', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, { 'id': 'A10049329048', 'lib1': 'Accueils jeunes et centres sociaux', 'lib2': None, 'text': 'Accueils jeunes et centres sociaux', 'idDir': 'A10049327627', 'direction': { 'id': 'A10049327627', 'lib1': 'DSCS ACC JEUNES', 'lib2': 'Direction des solidarités et de la cohésion sociale accueil', 'text': 'DSCS ACC JEUNES', }, }, { 'id': 'A10049329054', 'lib1': 'Activités numériques', 'lib2': None, 'text': 'Activités numériques', 'idDir': 'A10049327627', 'direction': { 'id': 'A10049327627', 'lib1': 'DSCS ACC JEUNES', 'lib2': 'Direction des solidarités et de la cohésion sociale accueil', 'text': 'DSCS ACC JEUNES', }, }, { 'id': 'A10049329049', 'lib1': 'Ateliers', 'lib2': None, 'text': 'Ateliers', 'idDir': 'A10049327621', 'direction': { 'id': 'A10049327621', 'lib1': 'DASC', 'lib2': "Direction de l'action socioculturelle", 'text': 'DASC', }, }, { 'id': 'A10049329042', 'lib1': 'CCAS', 'lib2': None, 'text': 'CCAS', 'idDir': 'plop', 'direction': None, }, ] resp = app.get(url + '?id=A10049329043') assert resp.json['data'] == [ { 'id': 'A10049329043', 'lib1': 'Accueil de loisirs', 'lib2': None, 'text': 'Accueil de loisirs', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, } ] resp = app.get(url + '?direction_id=A10049327624') assert resp.json['data'] == [ { 'id': 'A10049329043', 'lib1': 'Accueil de loisirs', 'lib2': None, 'text': 'Accueil de loisirs', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, { 'id': 'A10049329044', 'lib1': 'Convoyages', 'lib2': None, 'text': 'Convoyages', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, { 'id': 'A10049329045', 'lib1': 'Séjours vacances', 'lib2': None, 'text': 'Séjours vacances', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, ] def test_read_sex_list(con, app): url = get_endpoint('read-sex-list') resp = app.get(url) assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'F', 'text': 'Féminin'}, {'id': 'M', 'text': 'Masculin'}, ] def test_read_situation_list(con, app): url = get_endpoint('read-situation-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 9 assert resp.json['data'][:5] == [ {'id': 'C', 'code': 'C', 'text': 'Célibataire', 'libelle': 'Célibataire'}, {'id': 'D', 'code': 'D', 'text': 'Divorcé (e)', 'libelle': 'Divorcé (e)'}, {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'}, {'id': 'M', 'code': 'M', 'text': 'Marié (e)', 'libelle': 'Marié (e)'}, {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'}, ] resp = app.get(url + '?q= ') assert resp.json['err'] == 0 assert len(resp.json['data']) == 9 resp = app.get(url + '?id=V') assert resp.json['err'] == 0 assert resp.json['data'] == [{'id': 'V', 'code': 'V', 'text': 'Veuf (ve)', 'libelle': 'Veuf (ve)'}] resp = app.get(url + '?q= sÉ ') assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'}, {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'}, {'id': 'S', 'code': 'S', 'text': 'Séparé (e)', 'libelle': 'Séparé (e)'}, ] resp = app.get(url + '?q= sÉ &limit=2') assert resp.json['err'] == 0 assert resp.json['data'] == [ {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'}, {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'}, ] def test_read_street_list(con, app): url = get_endpoint('read-street-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 3 assert resp.json['data'] == [ { 'id': '2317', 'text': 'RUE ACHILLE VIADIEU', 'town': 'TOULOUSE', 'idTown': 'A00000000005', 'zipCode': '31400', 'idStreet': '2317', 'libelleStreet': 'RUE ACHILLE VIADIEU', }, { 'id': '2315', 'text': 'RUE DE LA VERRERIE', 'town': 'TOULOUSE', 'idTown': 'A00000000006', 'zipCode': '31500', 'idStreet': '2315', 'libelleStreet': 'RUE DE LA VERRERIE', }, { 'id': '2316', 'text': 'RUE VESTREPAIN', 'town': 'TOULOUSE', 'idTown': 'A00000000002', 'zipCode': '31100', 'idStreet': '2316', 'libelleStreet': 'RUE VESTREPAIN', }, ] def test_read_vaccin_list(con, app): url = get_endpoint('read-vaccin-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 20 assert resp.json['data'][:5] == [ {'id': 'BCG', 'code': 'BCG', 'text': 'BCG', 'libelle': 'BCG'}, { 'id': 'CIB', 'code': 'CIB', 'text': 'CONTRE-INDICATION TEMPORAIRE AU BCG', 'libelle': 'CONTRE-INDICATION TEMPORAIRE AU BCG', }, {'id': 'MONO', 'code': 'MONO', 'text': 'CONTROLE DU BCG (+)', 'libelle': 'CONTROLE DU BCG (+)'}, {'id': 'MONON', 'code': 'MONON', 'text': 'CONTROLE DU BCG (-)', 'libelle': 'CONTROLE DU BCG (-)'}, { 'id': 'DTC', 'code': 'DTC', 'text': 'DIPHTERIE TETANOS COQUELUCHE', 'libelle': 'DIPHTERIE TETANOS COQUELUCHE', }, ] def test_read_rl_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-rl-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613878', 'DOE JHON'), ('613879', 'DOE JANE'), ] resp = app.get(url + '?NameID=local&text_template={{ birth.dateBirth|date:"d/m/Y" }}') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613878', '25/07/1938'), ('613879', '21/06/1940'), ] def test_read_rl_list_no_rl2(family_service, con, app, caplog): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) url = get_endpoint('read-rl-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [('613878', 'DOE JHON')] # no warning about NUMPERS_AXEL indicator assert all([x.levelno == logging.INFO for x in caplog.records]) def test_read_rl_list_not_linked_error(con, app): url = get_endpoint('read-rl-list') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_rl_and_child_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-rl-and-child-list') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613878', 'DOE JHON'), ('613879', 'DOE JANE'), ('613880', 'DOE JANNIS'), ('613987', 'DOE JOHNNY ALLEN'), ('614051', 'DOE ROBERT'), ] params = { 'NameID': 'local', 'rl_text_template': 'RL {{ firstname }}, {{ birth.dateBirth|date:"d/m/Y" }}', 'child_text_template': 'Child {{ firstname }}, {{ birth.dateBirth|date:"d/m/Y" }}', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613878', 'RL JHON, 25/07/1938'), ('613879', 'RL JANE, 21/06/1940'), ('613880', 'Child JANNIS, 18/01/1943'), ('613987', 'Child JOHNNY ALLEN, 26/11/1942'), ('614051', 'Child ROBERT, 23/05/1941'), ] def test_read_rl_and_child_list_not_linked_error(con, app): url = get_endpoint('read-rl-list') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_person_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-person-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [(614059, 'ARKANA KENY')] resp = app.get(url + '?NameID=local&text_template={{ dateBirth|date:"d/m/Y" }}') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [(614059, '19/12/1982')] def test_read_person_list_not_linked_error(con, app): url = get_endpoint('read-person-list') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_child_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613880', 'DOE JANNIS'), ('613987', 'DOE JOHNNY ALLEN'), ('614051', 'DOE ROBERT'), ] resp = app.get(url + '?NameID=local&text_template={{ birth.dateBirth|date:"d/m/Y" }}') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('613880', '18/01/1943'), ('613987', '26/11/1942'), ('614051', '23/05/1941'), ] def test_read_child_list_not_linked_error(con, app): url = get_endpoint('read-child-list') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_child_person_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-person-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=613880') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [(614719, 'BENT AMEL')] resp = app.get( url + '?NameID=local&child_id=613880&text_template={{ personInfo.dateBirth|date:"d/m/Y" }}' ) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [(614719, '20/06/1985')] def test_read_child_person_list_not_linked_error(con, app): url = get_endpoint('read-child-person-list') resp = app.get(url + '?NameID=local&child_id=613880') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_child_person_list_not_exists_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-person-list') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=42') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '42' child on '1312' family" def test_search_family(family_service, con, app): family_service.add_soap_response( 'readFamilyListFromFullName', get_xml_file('R_read_family_list_from_full_name.xml') ) url = get_endpoint('search-family') resp = app.get(url + '?q=marge%20simpson') assert resp.json['err'] == 0 assert len(resp.json['data']) == 2 resp = app.get(url + '?q=marge%20simpson&limit=1') assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 resp = app.get(url + '?q=') assert resp.json['err'] == 0 assert resp.json['data'] == [] resp = app.get(url + '?q=marge%20simpson&limit=xxx') assert resp.json['err'] == 1 def test_search_family_dui(family_service, con, app): soap_mock = family_service.add_soap_response('readFamilyList', get_xml_file('R_read_family_list.xml')) url = get_endpoint('search-family-dui') resp = app.get(url + '?q=1312') assert soap_mock.call_count == 1 assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 resp = app.get(url + '?q=') assert soap_mock.call_count == 1 assert resp.json['err'] == 0 assert resp.json['data'] == [] resp = app.get(url + '?q=abcd') assert soap_mock.call_count == 1 assert resp.json['err'] == 0 assert resp.json['data'] == [] @pytest.mark.parametrize( 'xml', ['R_read_family.xml', 'R_read_family_relax.xml', 'R_read_family_reordered.xml'] ) def test_read_family(family_service, xml, con, app): family_service.add_soap_response('readFamily', get_xml_file(xml)) url = get_endpoint('read-family') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 data = resp.json['data'] del data['RL1'] del data['RL2'] del data['childList'] del data['emergencyPersonList'] assert data == { 'family_id': '1312', 'number': 1312, 'category': 'BI', 'situation': 'M', 'flagCom': True, 'nbChild': 2, 'nbTotalChild': None, 'nbAES': None, 'quotientList': [], 'indicatorList': [], 'childErrorList': [], 'category_text': 'BIPARENTALE', 'situation_text': 'Marié (e)', } data = resp.json['data']['RL1'] del data['profession'] del data['indicatorList'] del data['indicators'] del data['quotientList'] del data['quotients'] assert data == { 'num': '613878', 'lastname': 'DOE', 'firstname': 'JHON', 'maidenName': None, 'quality': 'PERE', 'civility': 'M.', 'birth': { 'cdDepartment': '91', 'communeCode': '91122', 'countryCode': '99350', 'dateBirth': '1938-07-26T00:00:00+01:00', 'place': 'Rabbat', 'cdDepartment_text': 'ESSONNE', 'communeCode_text': 'BURES-SUR-YVETTE', 'countryCode_text': 'MAROC', }, 'adresse': { 'idStreet': '2317', 'idStreet_text': 'RUE ACHILLE VIADIEU', 'num': 170, 'numComp': None, 'street1': 'RUE ACHILLE VIADIEU', 'street2': None, 'town': 'Paris', 'zipcode': '75014', }, 'contact': { 'phone': 'non', 'mobile': '0777777777', 'mail': 'djhon@example.org', 'isContactMail': True, 'isContactSms': True, 'isInvoicePdf': True, }, 'CAFInfo': None, 'fiscalInfo': None, 'civility_text': 'Monsieur', 'quality_text': 'PERE', 'subscribeActivityList': [], 'subscribe_natures': {}, } assert sorted(resp.json['data']['RL1']['indicatorList'], key=lambda x: x['code']) == [ { 'choice': None, 'code': 'AVL', 'code_text': 'Auxiliaire de Vie loisirs', 'libelle': 'Auxiliaire de Vie loisirs', 'note': None, }, { 'choice': None, 'code': 'ETABSPEC', 'code_text': 'Etablissement spécialisé', 'libelle': 'Etablissement spécialisé', 'note': 'SNPP', }, ] assert resp.json['data']['RL1']['indicators'] == { 'AVL': { 'code': 'AVL', 'id': 'AVL', 'isActive': True, 'libelle': 'Auxiliaire de Vie loisirs', 'text': 'Auxiliaire de Vie loisirs', 'typeDesc': 'NONE', }, 'AVS': { 'code': 'AVS', 'id': 'AVS', 'isActive': False, 'libelle': 'Auxiliaire de Vie scolaire ', 'text': 'Auxiliaire de Vie scolaire', 'typeDesc': 'NONE', }, 'ETABSPEC': { 'code': 'ETABSPEC', 'id': 'ETABSPEC', 'isActive': True, 'libelle': 'Etablissement spécialisé', 'note': 'SNPP', 'text': 'Etablissement spécialisé', 'typeDesc': 'NOTE', }, 'MDPH': { 'code': 'MDPH', 'id': 'MDPH', 'isActive': False, 'libelle': 'Notification MDPH', 'text': 'Notification MDPH', 'typeDesc': 'NONE', }, } assert resp.json['data']['RL1']['quotientList'] == [ { 'yearRev': 2020, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-12-31T00:00:00+01:00', 'mtt': 1500.33, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-01-01T00:00:00+01:00', 'mtt': 300.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-01-02T00:00:00+01:00', 'mtt': 200.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2021-01-02T00:00:00+01:00', 'dateEnd': '2021-01-02T00:00:00+01:00', 'mtt': 100.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2022-01-01T00:00:00+01:00', 'dateEnd': '2022-12-31T00:00:00+01:00', 'mtt': 1500.44, 'cdquo': 'MOY ECO', 'codeUti': None, 'cdquo_text': 'REVENU MOYEN ( MENSUEL OU ANNUEL)', }, ] assert resp.json['data']['RL1']['quotients'] == { 'QS': [ { 'yearRev': 2021, 'dateStart': '2021-01-02T00:00:00+01:00', 'dateEnd': '2021-01-02T00:00:00+01:00', 'mtt': 100.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-01-02T00:00:00+01:00', 'mtt': 200.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2021, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-01-01T00:00:00+01:00', 'mtt': 300.0, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, { 'yearRev': 2020, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-12-31T00:00:00+01:00', 'mtt': 1500.33, 'cdquo': 'QS', 'codeUti': None, 'cdquo_text': 'QUOTIENT SCOLAIRE', }, ], 'MOY ECO': [ { 'yearRev': 2021, 'dateStart': '2022-01-01T00:00:00+01:00', 'dateEnd': '2022-12-31T00:00:00+01:00', 'mtt': 1500.44, 'cdquo': 'MOY ECO', 'codeUti': None, 'cdquo_text': 'REVENU MOYEN ( MENSUEL OU ANNUEL)', } ], } data = resp.json['data']['childList'][0] del data['medicalRecord'] del data['authorizedPersonList'] del data['paiInfoBean'] del data['indicatorList'] del data['indicators'] del data['subscribeActivityList'] del data['subscribe_natures'] assert data == { 'num': '613880', 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'sexe_text': 'Féminin', 'birth': { 'cdDepartment': '91', 'dateBirth': '1943-01-19T00:00:00+01:00', 'place': 'Saint-louis', 'communeCode': '91122', 'countryCode': '99100', 'cdDepartment_text': 'ESSONNE', 'communeCode_text': 'BURES-SUR-YVETTE', 'countryCode_text': 'FRANCE', }, 'dietcode': 'RSV', 'dietcode_text': '3- RÉGIME SANS VIANDE', 'bPhoto': True, 'bLeaveAlone': False, 'insurance': { 'company': 'Total Disaster Insurance', 'contractEnd': '2022-12-31T00:00:00+01:00', 'contractNumber': '123', 'contractStart': '2022-01-01T00:00:00+01:00', 'memberNumber': '456', }, 'subscribeSchoolList': [], 'mother': {'num': 613963, 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE'}, 'father': {'num': 613878, 'civility': 'M.', 'firstname': 'JHON', 'lastname': 'DOE'}, 'rl': None, } if xml != 'R_read_family_relax.xml': assert resp.json['data']['childList'][0]['paiInfoBean'] == { 'code': 'PAIALI', 'code_text': 'ALIMENTAIRE', 'dateDeb': '2022-01-01T00:00:00+01:00', 'dateFin': '2022-12-31T00:00:00+01:00', 'description': 'bla bla PAI', } else: assert resp.json['data']['childList'][0]['paiInfoBean'] == { 'code': None, 'dateDeb': '2022-01-01T00:00:00+01:00', 'dateFin': '2022-12-31T00:00:00+01:00', 'description': 'bla bla PAI', } assert resp.json['data']['childList'][0]['medicalRecord'] == { 'familyDoctor': { 'name': 'DRE', 'phone': '0612341234', 'address': {'street1': 'Alameda', 'zipcode': '90220', 'town': 'Compton'}, }, 'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up', 'allergy2': 'shrimp and cauliflower', 'comment1': "the shrimp allergy isn't fully identified", 'comment2': None, 'observ1': 'Ay Caramba!', 'observ2': 'Eat my shorts!', 'isAuthHospital': True, 'hospital': 'Springfield General Hospital', 'vaccinList': [ { 'code': 'ROR', 'libelle': 'ROUGEOLE-OREILLONS-RUBEOLE', 'vaccinationDate': '2012-02-22T00:00:00+01:00', }, { 'code': 'DTC', 'libelle': 'DIPHTERIE TETANOS COQUELUCHE', 'vaccinationDate': '2011-01-11T00:00:00+01:00', }, { 'code': 'ROR', 'libelle': 'ROUGEOLE-OREILLONS-RUBEOLE', 'vaccinationDate': '1970-01-11T00:00:00+01:00', }, ], } assert resp.json['data']['emergencyPersonList'][0] == { 'firstname': 'KENY', 'lastname': 'ARKANA', 'dateBirth': '1982-12-20T00:00:00+01:00', 'quality': 'T', 'civility': 'MME', 'sexe': None, 'contact': {'phone': '0123456789', 'mobile': None, 'mail': 'pueblo@example.org'}, 'numPerson': 614059, 'civility_text': 'Madame', 'quality_text': 'TANTE', } assert resp.json['data']['childList'][0]['authorizedPersonList'][0] == { 'personInfo': { 'num': 614719, 'lastname': 'BENT', 'firstname': 'AMEL', 'dateBirth': '1985-06-21T00:00:00+02:00', 'civility': 'MME', 'civility_text': 'Madame', 'sexe': 'F', 'sexe_text': 'Féminin', 'contact': {'phone': '0123456789', 'mobile': '0623456789', 'mail': 'abent@example.org'}, }, 'personQuality': { 'code': 'T', 'code_text': 'TANTE', 'libelle': 'TANTE', }, } assert sorted(resp.json['data']['childList'][0]['indicatorList'], key=lambda x: x['code']) == [ {'choice': None, 'code': 'AUTRE', 'code_text': 'Autre', 'libelle': 'Autre', 'note': 'rebellious'}, { 'choice': None, 'code': 'LUNETTE', 'code_text': 'Port de lunettes', 'libelle': 'Port de lunettes', 'note': None, }, ] indicators = resp.json['data']['childList'][0]['indicators'] assert len(indicators) == 8 assert len([x for x in indicators.values() if x['isActive']]) == 2 assert [x for x in indicators.values() if x['typeDesc'] == 'NOTE'] == [ { 'id': 'AUTRE', 'code': 'AUTRE', 'text': 'Autre', 'libelle': 'Autre', 'typeDesc': 'NOTE', 'isActive': True, 'note': 'rebellious', }, { 'id': 'ETABSPEC', 'code': 'ETABSPEC', 'text': 'Etablissement spécialisé', 'libelle': 'Etablissement spécialisé', 'typeDesc': 'NOTE', 'isActive': False, 'note': None, }, ] assert [ (x['typeActivity']['natureSpec']['code'], x['libelle']) for x in resp.json['data']['childList'][0]['subscribeActivityList'] ] == [ ('R', 'RESTAURATION SCOLAIRE 22/23'), ('A', 'CLAE MIDI 22/23'), ('A', 'CLAE MATIN 22/23'), ('X', 'SEMST2 ADL MERC. ELEM Maourine 22/23'), ('8', 'ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES'), ('E', 'M.A ARNAUD BERNARD'), ] assert resp.json['data']['childList'][0]['subscribe_natures'] == { '2022-2023': ['8', 'A', 'R', 'X'], '2023-2024': ['R'], } def test_read_family_zipcode(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-family') ban = BaseAdresse.objects.create(slug='ban') CityModel.objects.create( name='Bures-sur-Yvette', code='91122', zipcode='91440', population=96866, resource=ban ) resp = app.get(url + '?family_id=1312') assert resp.json['data']['RL1']['birth']['zipCode'] == '91440' def test_read_family_not_linked_error(con, app): url = get_endpoint('read-family') resp = app.get(url + '?NameID=') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_family_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_not_found.xml')) url = get_endpoint('read-family') resp = app.get(url + '?family_id=000') assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPFault' assert ( '=E01 : Le numéro de dossier (numéro famille) ou le nom de famille sont requis' in resp.json['err_desc'] ) def test_read_family_soap_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_soap_error.xml')) url = get_endpoint('read-family') resp = app.get(url + '?family_id=abc') assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPFault' assert ( resp.json['err_desc'] == 'SOAP service at https://example.org/FamilyService?wsdl returned an error "Unmarshalling Error: Not a number: abc "' ) def test_read_family_without_birth(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_no_birth.xml')) url = get_endpoint('read-family') resp = app.get(url + '?family_id=1312') assert resp.json['data']['RL1']['birth'] is None def test_read_rl1(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-rl') resp = app.get(url + '?family_id=1312&rl_id=613878') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&rl_id=613878') assert resp.json['err'] == 0 assert resp.json['data']['firstname'] == 'JHON' template = '{{ data.quotients.QS.0.mtt }} {{ data.quotients.QS.1.mtt }}' assert render_to_string(template, resp.json) == '100.0 200.0' def test_read_rl1_with_income_year(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_income_year.xml')) url = get_endpoint('read-rl') resp = app.get(url + '?family_id=1312&rl_id=613878&income_year=2020') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&rl_id=613878&income_year=2020') assert resp.json['err'] == 0 assert resp.json['data']['quotientList'] == [ { 'yearRev': 2020, 'dateStart': '2021-01-01T00:00:00+01:00', 'dateEnd': '2021-12-31T00:00:00+01:00', 'mtt': 1500.33, 'cdquo': 'QS', 'cdquo_text': 'QUOTIENT SCOLAIRE', 'codeUti': None, } ] def test_read_rl2(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-rl') resp = app.get(url + '?family_id=1312&rl_id=613879') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&rl_id=613879') assert resp.json['err'] == 0 assert resp.json['data'] == { 'family_id': '1312', 'num': '613879', 'lastname': 'DOE', 'firstname': 'JANE', 'maidenName': 'SMITH', 'quality': 'MERE', 'civility': 'MME', 'birth': { 'cdDepartment': '91', 'communeCode': '91122', 'countryCode': '99351', 'dateBirth': '1940-06-22T00:00:00+02:00', 'place': 'Bardot', 'cdDepartment_text': 'ESSONNE', 'communeCode_text': 'BURES-SUR-YVETTE', 'countryCode_text': 'TUNISIE', }, 'adresse': { 'idStreet': None, 'num': 170, 'numComp': None, 'street1': "Chateau d'eau", 'street2': None, 'town': 'Paris', 'zipcode': '75014', }, 'contact': { 'phone': None, 'mobile': None, 'mail': None, 'isContactMail': False, 'isContactSms': False, 'isInvoicePdf': False, }, 'profession': { 'codeCSP': 'ART', 'profession': 'informaticien', 'employerName': 'EO', 'phone': '0123456789', 'addressPro': {'num': None, 'street': None, 'zipcode': None, 'town': 'Orléans'}, 'codeCSP_text': 'ARTISAN', 'situation': '01', 'situation_text': 'Activité professionnelle', 'weeklyHours': '9h-18h', }, 'CAFInfo': { 'number': '789', 'organ': 'A10007752822', 'organ_text': 'LA COLLE SUR LOUP', }, 'fiscalInfo': {'spi': '00 01 123 456 789 C'}, 'civility_text': 'Madame', 'quality_text': 'MERE', 'quotientList': [], 'quotients': {}, 'indicatorList': [], 'indicators': { 'AVL': { 'code': 'AVL', 'id': 'AVL', 'isActive': False, 'libelle': 'Auxiliaire de Vie loisirs', 'text': 'Auxiliaire de Vie loisirs', 'typeDesc': 'NONE', }, 'AVS': { 'code': 'AVS', 'id': 'AVS', 'isActive': False, 'libelle': 'Auxiliaire de Vie scolaire ', 'text': 'Auxiliaire de Vie scolaire', 'typeDesc': 'NONE', }, 'ETABSPEC': { 'code': 'ETABSPEC', 'id': 'ETABSPEC', 'isActive': False, 'libelle': 'Etablissement spécialisé', 'note': None, 'text': 'Etablissement spécialisé', 'typeDesc': 'NOTE', }, 'MDPH': { 'code': 'MDPH', 'id': 'MDPH', 'isActive': False, 'libelle': 'Notification MDPH', 'text': 'Notification MDPH', 'typeDesc': 'NONE', }, }, 'subscribeActivityList': [ { 'libelle': 'CSocial Adult 2021/2022 - Bijoux en cuirs 21/03/22', 'libelle2': None, 'typeIns': '1', 'libelleTypeIns': 'DEFINITIVE', 'subscribesUnit': [ { 'idUnit': 'A10053179465', 'libelle': 'CSocial Adult 2021/2022 - Bijoux en cuirs 21/03/22', 'bUniStd': True, 'dateStart': '2023-03-22T00:00:00+01:00', 'dateEnd': '2023-03-22T00:00:00+01:00', } ], 'place': 'RANGUEIL', 'planningHebdomadaire': None, 'typeConsum': 'INS', 'libelleTypeConsum': 'INSCRIT', 'comment': None, 'idActivity': 'A10053179463', 'typeActivity': None, } ], 'subscribe_natures': {}, } def test_read_rl_not_linked_error(con, app): url = get_endpoint('read-rl') resp = app.get(url + '?NameID=local&rl_id=613879') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_rl_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-rl') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&rl_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' RL on '1312' family" def test_read_subscribe_activity_list(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-subscribe-activity-list') resp = app.get(url + '?family_id=1312&person_id=613880') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') # RL2 resp = app.get(url + '?NameID=local&person_id=613879') assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10053179463', 'CSocial Adult 2021/2022 - Bijoux en cuirs 21/03/22') ] # child resp = app.get(url + '?NameID=local&person_id=613880') assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10049327682', 'RESTAURATION SCOLAIRE 22/23', 'R', 'RESTSCOL'), ('A10049327686', 'CLAE MIDI 22/23', 'A', 'ACCPERI'), ('A10049327689', 'CLAE MATIN 22/23', 'A', 'ACCMAT'), ('A10049354913', 'SEMST2 ADL MERC. ELEM Maourine 22/23', 'X', 'EXTMERC'), ('A10053179798', 'ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', '8', '25'), ('M10000000109', 'M.A ARNAUD BERNARD', 'E', 'CRECHCO'), ] resp = app.get(url + '?NameID=local&person_id=613880&nature=PERISCO') assert resp.json['err'] == 0 assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10049327682', 'RESTAURATION SCOLAIRE 22/23', 'R', 'RESTSCOL'), ('A10049327686', 'CLAE MIDI 22/23', 'A', 'ACCPERI'), ('A10049327689', 'CLAE MATIN 22/23', 'A', 'ACCMAT'), ] resp = app.get(url + '?NameID=local&person_id=613880&nature=EXTRASCO') assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10049354913', 'SEMST2 ADL MERC. ELEM Maourine 22/23', 'X', 'EXTMERC'), ] resp = app.get(url + '?NameID=local&person_id=613880&nature=LOISIR') assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10053179798', 'ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', '8', '25'), ] resp = app.get(url + '?NameID=local&person_id=613880&type_ids=ACCMAT') assert resp.json['err'] == 0 assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [('A10049327689', 'CLAE MATIN 22/23', 'A', 'ACCMAT')] resp = app.get(url + '?NameID=local&person_id=613880&school_year=2022-2023') assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10049327682', 'RESTAURATION SCOLAIRE 22/23', 'R', 'RESTSCOL'), ('A10049327686', 'CLAE MIDI 22/23', 'A', 'ACCPERI'), ('A10049327689', 'CLAE MATIN 22/23', 'A', 'ACCMAT'), ('A10049354913', 'SEMST2 ADL MERC. ELEM Maourine 22/23', 'X', 'EXTMERC'), ('A10053179798', 'ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', '8', '25'), ] resp = app.get(url + '?NameID=local&person_id=613880&school_year=2023-2024') assert [ (x['id'], x['text'], x['typeActivity']['natureSpec']['code'], x['typeActivity']['code']) for x in resp.json['data'] ] == [ ('A10049327682', 'RESTAURATION SCOLAIRE 22/23', 'R', 'RESTSCOL'), ] def test_read_subscribe_activity_list_not_linked_error(con, app): url = get_endpoint('read-subscribe-activity-list') resp = app.get(url + '?NameID=local&person_id=613880') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_subscribe_activity_list_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-subscribe-activity-list') resp = app.get(url + '?family_id=1312&person_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' RL or child on '1312' family" def test_read_person(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-person') resp = app.get(url + '?family_id=1312&person_id=614059') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=614059') assert resp.json['err'] == 0 assert resp.json['data']['firstname'] == 'KENY' def test_read_person_not_linked_error(con, app): url = get_endpoint('read-person') resp = app.get(url + '?NameID=local&person_id=614059') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_person_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' emergency person on '1312' family" def test_read_child(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child') resp = app.get(url + '?family_id=1312&child_id=613880') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=613880') assert resp.json['err'] == 0 assert resp.json['data']['firstname'] == 'JANNIS' def test_read_child_zipcode(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child') ban = BaseAdresse.objects.create(slug='ban') CityModel.objects.create( name='Bures-sur-Yvette', code='91122', zipcode='91440', population=96866, resource=ban ) resp = app.get(url + '?family_id=1312&child_id=613880') assert resp.json['err'] == 0 assert resp.json['data']['firstname'] == 'JANNIS' assert resp.json['data']['birth'].get('zipCode') == '91440' def test_read_child_not_linked_error(con, app): url = get_endpoint('read-child') resp = app.get(url + '?NameID=local&child_id=613880') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_child_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' child on '1312' family" def test_read_child_person(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-person') resp = app.get(url + '?family_id=1312&child_id=613880&person_id=614719') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=613880&person_id=614719') assert resp.json['err'] == 0 assert resp.json['data']['personInfo']['firstname'] == 'AMEL' def test_read_child_person_not_linked_error(con, app): url = get_endpoint('read-child-person') resp = app.get(url + '?NameID=local&child_id=613880&person_id=614719') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_child_person_no_child_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=42&person_id=614719') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '42' child on '1312' family" def test_read_child_person_no_person_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('read-child-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&child_id=613880&person_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' authorized person on '613880' child" @pytest.mark.parametrize('string, result', [(b'true', True), (b'false', False)]) def test_is_rl_exists(string, result, family_service, con, app): family_service.add_soap_response('isRLExists', get_xml_file('R_is_rl_exists.xml') % string) url = get_endpoint('is-rl-exists') params = { 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26', } resp = app.post_json(url, params=params) assert resp.json['err'] == 0 assert resp.json['data'] == result def test_is_rl_exists_schema_error(con, app): url = get_endpoint('is-rl-exists') params = { 'firstname': 'Jhon', 'lastname': 'Doe', 'dateBirth': '1938-07-26 more text', } resp = app.post_json(url, params=params, status=400) assert resp.json['err'] == 1 assert "does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" in resp.json['err_desc'] @pytest.mark.parametrize('string, result', [(b'true', True), (b'false', False)]) def test_is_child_exists(family_service, string, result, con, app): family_service.add_soap_response('isChildExists', get_xml_file('R_is_rl_exists.xml') % string) url = get_endpoint('is-child-exists') params = { 'firstname': 'Doe', 'lastname': 'Jhonny allen', 'dateBirth': '1942-11-27', } resp = app.post_json(url, params=params) assert resp.json['err'] == 0 assert resp.json['data'] == result def test_create_family(family_service, con, app): def request_check(request): assert request.emergencyPersonList[0]['firstname'] == 'Keny' family_service.add_soap_response( 'createFamily', get_xml_file('R_create_family.xml'), request_check=request_check ) url = get_endpoint('create-family') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/communeCode': None, 'rl1/birth/cdDepartment': '91', 'rl1/birth/countryCode': '99350', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/birth/place': 'Rabbat', 'rl1/adresse/idStreet': '2317', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', 'rl1/adresse/numComp': 'B', 'rl1/contact/isContactMail': True, 'rl1/profession/codeCSP': 'ART', 'rl1/profession/situation': '01', 'rl1/CAFInfo/organ': 'A10007752822', 'rl1/fiscalInfo/spi': '00 01 123 456 789 C', 'emergencyPersonList/0/civility': 'MME', 'emergencyPersonList/0/firstname': 'Keny', 'emergencyPersonList/0/lastname': 'Arkana', 'emergencyPersonList/0/sexe': 'F', 'emergencyPersonList/0/quality': 'T', 'childList/0/lastname': 'Zimmerman', 'childList/0/firstname': 'Robert', 'childList/0/sexe': 'M', 'childList/0/birth/dateBirth': '1941-05-24', 'childList/0/birth/place': 'Saint-louis', 'childList/0/birth/communeCode': '91122', 'childList/0/birth/cdDepartment': '91', 'childList/0/birth/countryCode': '99100', 'childList/0/dietcode': 'RSV', 'childList/0/medicalRecord/vaccinList/0/code': 'DTC', 'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26', 'childList/0/insurance/company': 'Total Disaster Insurance', 'childList/0/insurance/contractNumber': '123', 'childList/0/insurance/memberNumber': '456', 'childList/0/insurance/contractStart': '2022-01-01', 'childList/0/insurance/contractEnd': '2022-12-31', } resp = app.post_json(url, params=params) assert resp.json['err'] == 0 assert not Link.objects.exists() resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == { 'number': 196545, 'password': '394634V2', 'rl1ErrorList': [], 'childErrorList': [], } assert Link.objects.get(resource=con, family_id='196545', name_id='local') def test_create_family_empty_referential_key_error(con, app): url = get_endpoint('create-family') params = { 'category': '', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "category: '' does not match '.+'" def test_create_family_already_linked_error(con, app, freezer): url = get_endpoint('create-family') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } freezer.move_to('2024-02-07 10:21:00') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User already linked to family' link = resp.json['link'] link['id'] = 'xx' link['resource_id'] = 'yy' assert link == { 'id': 'xx', 'resource_id': 'yy', 'name_id': 'local', 'family_id': '1312', 'created': '2024-02-07T10:21:00Z', 'updated': '2024-02-07T10:21:00Z', } def test_create_family_maelis_error(family_service, con, app): family_service.add_soap_response('createFamily', get_xml_file('R_create_family_error.xml')) url = get_endpoint('create-family') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert 'Il existe déjà' in resp.json['err_desc'] def test_create_family_wrong_referential_key_error(con, app): url = get_endpoint('create-family') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/communeCode': None, 'rl1/birth/cdDepartment': '91', 'rl1/birth/countryCode': '99350', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/birth/place': 'Rabbat', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', 'rl1/adresse/numComp': 'B', 'rl1/profession/codeCSP': 'ART', 'rl1/profession/situation': '01', 'rl1/CAFInfo/organ': 'A10007752822', 'childList/0/lastname': 'Zimmerman', 'childList/0/firstname': 'Robert', 'childList/0/sexe': 'M', 'childList/0/birth/dateBirth': '1941-05-24', 'childList/0/birth/place': 'Saint-louis', 'childList/0/birth/communeCode': '91122', 'childList/0/birth/cdDepartment': '91', 'childList/0/birth/countryCode': '99100', 'childList/0/dietcode': 'RSV', 'childList/0/medicalRecord/vaccinList/0/code': 'plop', 'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "childList/0/medicalRecord/vaccinList/0/code key value 'plop' do not belong to 'Vaccin' referential" ) params['childList/0/medicalRecord/vaccinList/0/code'] = 'DTC' params['rl1/profession/situation'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "rl1/profession/situation key value 'plop' do not belong to 'ProfessionalSituation' referential" ) params['rl1/profession/situation'] = '01' params['childList/0/birth/cdDepartment'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "childList/0/birth/cdDepartment key value 'plop' do not belong to 'County' referential" ) def test_update_family(family_service, con, app): def request_check(request): assert request.emergencyPersonList['personList'][0]['firstname'] == 'Keny' family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('update-family') params = { 'category': 'BI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/communeCode': None, 'rl1/birth/cdDepartment': '91', 'rl1/birth/countryCode': '99350', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/birth/place': 'Rabbat', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', 'rl1/adresse/numComp': 'B', 'rl1/profession/codeCSP': 'ART', 'rl1/profession/situation': '01', 'rl1/CAFInfo/organ': 'A10007752822', 'emergencyPersonList/0/civility': 'MME', 'emergencyPersonList/0/firstname': 'Keny', 'emergencyPersonList/0/lastname': 'Arkana', 'emergencyPersonList/0/sexe': 'F', 'emergencyPersonList/0/dateBirth': '1982-12-20', 'emergencyPersonList/0/quality': 'T', 'childList/0/lastname': 'Zimmerman', # add child 'childList/0/firstname': 'Robert', 'childList/0/sexe': 'M', 'childList/0/birth/dateBirth': '1941-05-24', 'childList/0/birth/place': 'Duluth', 'childList/0/birth/communeCode': '91122', 'childList/0/birth/cdDepartment': '91', 'childList/0/birth/countryCode': '99100', 'childList/0/dietcode': 'RSV', 'childList/0/paiInfoBean/code': 'PAIALI', 'childList/0/medicalRecord/vaccinList/0/code': 'DTC', 'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26', 'childList/0/insurance/company': 'Armagedon Colapse', 'childList/0/insurance/contractNumber': '444', 'childList/0/insurance/memberNumber': '555', 'childList/0/insurance/contractStart': '2022-01-02', 'childList/0/insurance/contractEnd': '2022-12-31', 'childList/1/num': '613880', # update child 'childList/1/firstname': 'Brunelle', 'childList/1/lastname': 'Doe', 'childList/1/birth/dateBirth': '1943-01-19', 'childList/1/sexe': 'F', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data']['number'] == 196544 assert not resp.json['data']['childErrorList'] def test_update_family_not_linked_error(con, app): url = get_endpoint('update-family') params = { 'category': 'BI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } 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_family_maelis_error(family_service, con, app): family_service.add_soap_response('updateFamily', get_xml_file('R_update_family_error.xml')) url = get_endpoint('update-family') params = { 'category': 'ACCEUI', 'situation': 'C', 'childList/0/lastname': 'Zimmerman', 'childList/0/firstname': 'Robert', 'childList/0/sexe': 'M', 'childList/0/birth/dateBirth': '1941-05-24', 'childList/0/birth/place': 'Duluth', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert 'E65a : Il existe déjà un enfant' in resp.json['err_desc'] def test_update_family_soap_error(family_service, con, app): family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family_soap_error.xml'), status=500 ) url = get_endpoint('update-family') params = { 'nbChild': '100', 'category': 'BI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert 'Une erreur est survenue' in resp.json['err_desc'] def test_update_family_wrong_referential_key_error(con, app): url = get_endpoint('update-family') params = { 'category': 'BI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/communeCode': None, 'rl1/birth/cdDepartment': '91', 'rl1/birth/countryCode': '99350', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/birth/place': 'Rabbat', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', 'rl1/adresse/numComp': 'B', 'rl1/profession/codeCSP': 'ART', 'rl1/profession/situation': '01', 'rl1/CAFInfo/organ': 'A10007752822', 'emergencyPersonList/0/civility': 'MME', 'emergencyPersonList/0/firstname': 'Keny', 'emergencyPersonList/0/lastname': 'Arkana', 'emergencyPersonList/0/sexe': 'F', 'emergencyPersonList/0/dateBirth': '1982-12-20', 'emergencyPersonList/0/quality': 'T', 'childList/0/lastname': 'Zimmerman', 'childList/0/firstname': 'Robert', 'childList/0/sexe': 'M', 'childList/0/birth/dateBirth': '1941-05-24', 'childList/0/birth/place': 'Duluth', 'childList/0/birth/communeCode': '91122', 'childList/0/birth/cdDepartment': '91', 'childList/0/birth/countryCode': '99100', 'childList/0/dietcode': 'RSV', 'childList/0/paiInfoBean/code': 'PAIALI', 'childList/0/medicalRecord/vaccinList/0/code': 'plop', 'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "childList/0/medicalRecord/vaccinList/0/code key value 'plop' do not belong to 'Vaccin' referential" ) params['childList/0/medicalRecord/vaccinList/0/code'] = 'DTC' params['rl1/profession/situation'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "rl1/profession/situation key value 'plop' do not belong to 'ProfessionalSituation' referential" ) params['rl1/profession/situation'] = '01' params['childList/0/birth/communeCode'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "childList/0/birth/communeCode key value 'plop' do not belong to 'Town' referential" ) def test_create_rl1(family_service, con, app): family_service.add_soap_response('createFamily', get_xml_file('R_create_family.xml')) url = get_endpoint('create-rl1') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url, params=params) assert resp.json['err'] == 0 assert not Link.objects.exists() resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == {'family_id': 196545} assert Link.objects.get(resource=con, family_id='196545', name_id='local') def test_create_rl1_empty_referential_key_error(con, app): url = get_endpoint('create-rl1') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': '', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': '', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "rl1/civility: '' does not match '.+'" def test_create_rl1_already_linked_error(con, app, freezer): url = get_endpoint('create-rl1') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } freezer.move_to('2024-02-07 10:21:00') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User already linked to family' link = resp.json['link'] link['id'] = 'xx' link['resource_id'] = 'yy' assert link == { 'id': 'xx', 'resource_id': 'yy', 'name_id': 'local', 'family_id': '1312', 'created': '2024-02-07T10:21:00Z', 'updated': '2024-02-07T10:21:00Z', } def test_create_rl1_wrong_referential_key_error(con, app): url = get_endpoint('create-rl1') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/numComp': 'plop', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "rl1/adresse/numComp key value 'plop' do not belong to 'Complement' referential" ) params['rl1/adresse/numComp'] = 'B' params['rl1/birth/countryCode'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "rl1/birth/countryCode key value 'plop' do not belong to 'Country' referential" ) def test_create_rl1_maelis_error(family_service, con, app): family_service.add_soap_response('createFamily', get_xml_file('R_create_family_error.xml')) url = get_endpoint('create-rl1') params = { 'category': 'ACCEUI', 'situation': 'C', 'rl1/civility': 'M.', 'rl1/firstname': 'Jhon', 'rl1/lastname': 'Doe', 'rl1/quality': 'AU', 'rl1/birth/dateBirth': '1938-07-26', 'rl1/adresse/street1': 'Chateau', 'rl1/adresse/town': 'Paris', 'rl1/adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert 'Il existe déjà' in resp.json['err_desc'] def test_update_rl1(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 assert request.rl1['adresse']['street1'] == "Chateau d'eau" family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('update-rl1') params = { 'civility': 'M.', 'firstname': 'Jhonny', 'lastname': 'Doe', 'quality': 'PERE', 'birth/dateBirth': '1943-06-15', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 def test_update_rl1_not_linked_error(con, app): url = get_endpoint('update-rl1') params = { 'civility': 'M.', 'firstname': 'Jhonny', 'lastname': 'Doe', 'quality': 'PERE', 'birth/dateBirth': '1943-06-15', } 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_rl1_connection_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname')) url = get_endpoint('update-rl1') params = { 'civility': 'M.', 'firstname': 'Jhonny', 'lastname': 'Doe', 'quality': 'PERE', 'birth/dateBirth': '1943-06-15', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=200) assert resp.json['err'] == 1 assert 'No address associated with hostname' in resp.json['err_desc'] def test_update_rl1_wrong_referential_key_error(con, app): url = get_endpoint('update-rl1') params = { 'civility': 'M.', 'firstname': 'Jhonny', 'lastname': 'Doe', 'quality': 'plop', 'birth/dateBirth': '1943-06-15', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential" def test_create_rl2(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('create-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', 'adresse/num': '170', 'adresse/street1': "Chateau d'eau", 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == {'id': '614062'} def test_create_rl2_not_linked_error(con, app): url = get_endpoint('create-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', 'adresse/num': '170', 'adresse/street1': "Chateau d'eau", 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } 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_create_rl2_connection_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname')) url = get_endpoint('create-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', 'adresse/num': '170', 'adresse/street1': "Chateau d'eau", 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=200) assert resp.json['err'] == 1 assert 'No address associated with hostname' in resp.json['err_desc'] def test_create_rl2_already_exists_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('create-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', 'adresse/num': '170', 'adresse/street1': "Chateau d'eau", 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'RL2 already defined on family' def test_create_rl2_wrong_referential_key_error(con, app): url = get_endpoint('create-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'plop', 'birth/dateBirth': '1940-06-22', 'adresse/num': '170', 'adresse/street1': "Chateau d'eau", 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential" def test_update_rl2(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 assert request.rl2['adresse']['street1'] == "Chateau d'eau" family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('update-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 def test_update_rl2_not_linked_error(con, app): url = get_endpoint('update-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'quality': 'MERE', 'maidenName': 'Smith', 'birth/dateBirth': '1940-06-22', } 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_rl2_connection_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname')) url = get_endpoint('update-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=200) assert resp.json['err'] == 1 assert 'No address associated with hostname' in resp.json['err_desc'] def test_update_rl2_not_exists_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) url = get_endpoint('update-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'MERE', 'birth/dateBirth': '1940-06-22', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'No RL2 to update on family' def test_update_rl2_wrong_referential_key_error(con, app): url = get_endpoint('update-rl2') params = { 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE', 'maidenName': 'Smith', 'quality': 'plop', 'birth/dateBirth': '1940-06-22', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential" def test_create_child(family_service, con, app): family_service.add_soap_response('createChild', get_xml_file('R_create_child.xml')) url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', 'insurance/company': 'Total Disaster Insurance', 'insurance/contractNumber': '123', 'insurance/memberNumber': '456', 'insurance/contractStart': '2022-01-01', 'insurance/contractEnd': '2022-12-31', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == {'child_id': 613880} def test_create_child_empty_referential_key_error(con, app): url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': '', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "sexe: '' does not match '.+'" def test_create_child_not_linked_error(con, app): url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } 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_create_child_wrong_referential_key_error(con, app): url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'plop', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' required referential" params['sexe'] = 'F' params['birth/cdDepartment'] = 'plop' resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "birth/cdDepartment key value 'plop' do not belong to 'County' referential" ) def test_create_child_connection_error(family_service, con, app): family_service.add_soap_response('createChild', ConnectionError('No address associated with hostname')) url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=200) assert resp.json['err'] == 1 assert 'No address associated with hostname' in resp.json['err_desc'] def test_create_child_maelis_error(family_service, con, app): family_service.add_soap_response('createChild', get_xml_file('R_create_child_error.xml')) url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert 'Il existe déjà' in resp.json['err_desc'] def test_update_child(family_service, con, app): def request_check(request): assert request.childList[0]['num'] == '613880' assert request.childList[0]['authorizedPersonList'][0]['personInfo']['firstname'] == 'AMEL' family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('update-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', 'bPhoto': True, 'bLeaveAlone': False, 'insurance/company': 'Armagedon Colapse', 'insurance/contractNumber': '444', 'insurance/memberNumber': '555', 'insurance/contractStart': '2022-01-02', 'insurance/contractEnd': '2022-12-31', } resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 0 def test_update_child_not_linked_error(con, app): url = get_endpoint('update-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_wrong_referential_key_error(con, app): url = get_endpoint('create-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'plop', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' required referential" def test_update_child_connection_error(family_service, con, app): family_service.add_soap_response('readFamily', ConnectionError('No address associated with hostname')) url = get_endpoint('update-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=200) assert resp.json['err'] == 1 assert 'No address associated with hostname' in resp.json['err_desc'] def test_update_child_not_exists_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml')) url = get_endpoint('update-child') params = { 'lastname': 'DOE', 'firstname': 'JANNIS', 'sexe': 'F', 'birth/dateBirth': '1943-01-19', 'birth/place': 'Port Arthur', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=42', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'No child 42 to update on family' def test_update_coordinate(family_service, con, app): family_service.add_soap_response('updateCoordinate', get_xml_file('R_update_family.xml')) url = get_endpoint('update-coordinate') params = { 'adresse/num': '169', 'adresse/numComp': 'B', 'adresse/idStreet': '2317', 'adresse/street1': 'Château', 'adresse/street2': None, 'adresse/town': 'Paris', 'adresse/zipcode': '75014', 'contact/isContactMail': True, 'profession/codeCSP': 'ART', 'profession/situation': '01', 'profession/weeklyHours': '9h-18h', 'profession/profession': 'informaticien', 'profession/employerName': 'EO', 'profession/phone': '0123456789', 'profession/addressPro': {'num': None, 'street': None, 'zipcode': None, 'town': 'Orléans'}, 'CAFInfo/number': '789', 'CAFInfo/organ': 'A10007752822', 'FiscalInfo/spi': '00 01 123 456 789 C', } resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_coordinate_schema_error(con, app): url = get_endpoint('update-coordinate') params = { 'contact/isContactMail': 'true more text', } resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "'adresse' is a required property" params = { 'contact/isContactMail': 'true more text', 'adresse/street1': 'Château', 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert 'JSONValidationError' in resp.json['err_class'] def test_update_coordinate_wrong_referential_key_error(con, app): url = get_endpoint('update-coordinate') params = { 'adresse/num': '169', 'adresse/numComp': 'plop', 'adresse/street1': 'Château', 'adresse/street2': None, 'adresse/town': 'Paris', 'adresse/zipcode': '75014', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "adresse/numComp key value 'plop' do not belong to 'Complement' referential" ) params['adresse/numComp'] = 'B' params['profession/situation'] = 'plop' resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "profession/situation key value 'plop' do not belong to 'ProfessionalSituation' referential" ) def test_update_quotient(family_service, con, app): family_service.add_soap_response('createUpdateQuotient', get_xml_file('R_create_update_quotient.xml')) url = get_endpoint('update-quotient') params = { 'yearRev': '2021', 'dateStart': '2022-10-01', 'dateEnd': '2023-01-31', 'mtt': '1500.33', 'cdquo': 'QS', } resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_quotient_schema_error(con, app): url = get_endpoint('update-quotient') params = { 'yearRev': '2021', 'dateStart': '2022-10-01', 'dateEnd': '2023-01-31', 'mtt': '1500,33', 'cdquo': 'QS', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "mtt: '1500,33' does not match '^[0-9]+\\\\.?[0-9]*$'" def test_update_quotient_soap_error(family_service, con, app): family_service.add_soap_response( 'createUpdateQuotient', get_xml_file('R_create_update_quotient_soap_error.xml'), status=500 ) url = get_endpoint('update-quotient') params = { 'yearRev': '2021', 'dateStart': '2022-10-01', 'dateEnd': '2023-01-31', 'mtt': '1500.33', 'cdquo': 'QS', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert 'E07 : Il existe déjà un quotient postérieur' in resp.json['err_desc'] def test_update_quotient_wrong_referential_key_error(con, app): url = get_endpoint('update-quotient') params = { 'yearRev': '2021', 'dateStart': '2023-10-01', 'dateEnd': '2023-01-31', 'mtt': '1500.33', 'cdquo': 'plop', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "cdquo key value 'plop' do not belong to 'Quotient' required referential" def test_create_person(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 assert len(request.emergencyPersonList['personList']) == 2 assert request.emergencyPersonList['personList'][0]['numPerson'] == 614059 assert request.emergencyPersonList['personList'][0]['firstname'] == 'KENY' assert request.emergencyPersonList['personList'][1]['numPerson'] is None assert request.emergencyPersonList['personList'][1]['firstname'] == 'Mathias' family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('create-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 def test_create_person_required_field_error(con, app): url = get_endpoint('create-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "'quality' is a required property" def test_create_person_empty_referential_key_error(con, app): url = get_endpoint('create-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': '', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "quality: '' does not match '.+'" def test_create_person_not_linked_error(con, app): url = get_endpoint('create-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } 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_create_person_wrong_referential_key_error(con, app): url = get_endpoint('create-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'plop', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' referential" def test_update_person(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 assert len(request.emergencyPersonList['personList']) == 1 assert request.emergencyPersonList['personList'][0]['numPerson'] == 614059 assert request.emergencyPersonList['personList'][0]['firstname'] == 'Mathias' family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('update-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } resp = app.post_json(url + '?family_id=1312&person_id=614059', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&person_id=614059', params=params) assert resp.json['err'] == 0 def test_update_person_not_linked_error(con, app): url = get_endpoint('update-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } resp = app.post_json(url + '?NameID=local&person_id=614059', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_person_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('update-person') params = { 'civility': None, 'firstname': 'Mathias', 'lastname': 'Cassel', 'quality': 'O', 'sexe': 'M', 'dateBirth': '1972-01-01', 'contact/phone': None, 'contact/mobile': '0623456789', 'contact/mail': None, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&person_id=000000', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' authorized person on '1312' family" def test_delete_person(family_service, con, app): def request_check(request): assert request.dossierNumber == 1312 assert request.emergencyPersonList is None family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check ) url = get_endpoint('delete-person') resp = app.post_json(url + '?family_id=1312&person_id=614059') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&person_id=614059') assert resp.json['err'] == 0 def test_delete_person_not_linked_error(con, app): url = get_endpoint('delete-person') resp = app.post_json(url + '?NameID=local&person_id=614059') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_delete_person_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('delete-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&person_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '000000' authorized person on '1312' family" def test_create_child_person(family_service, con, app): def request_check(request): assert request.numFamily == '1312' assert request.numPerson == 613880 assert len(request.personList) == 2 assert request.personList[0]['personInfo']['num'] == 614719 assert request.personList[0]['personInfo']['firstname'] == 'AMEL' assert request.personList[1]['personInfo']['num'] is None assert request.personList[1]['personInfo']['firstname'] == 'Diana' family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateChildAutorization', get_xml_file('R_update_child_authorization.xml'), request_check=request_check, ) url = get_endpoint('create-child-person') params = { 'personInfo/civility': 'MME', 'personInfo/firstname': 'Diana', 'personInfo/lastname': 'Ross', 'personInfo/sexe': 'F', 'personInfo/dateBirth': '1944-03-26', 'personInfo/contact/phone': '0199999999', 'personInfo/contact/mobile': '0723456789', 'personInfo/contact/mail': 'dross@example.org', 'personQuality/code': 'TUTEUR', } resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 0 def test_create_child_person_empty_referential_key_error(con, app): url = get_endpoint('create-child-person') params = { 'personInfo/civility': 'MME', 'personInfo/firstname': 'Diana', 'personInfo/lastname': 'Ross', 'personInfo/sexe': 'F', 'personInfo/dateBirth': '1944-03-26', 'personInfo/contact/phone': '01999999999', 'personInfo/contact/mobile': '0723456789', 'personInfo/contact/mail': 'dross@example.org', 'personQuality/code': '', } resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "personQuality/code: '' does not match '.+'" def test_create_child_person_not_linked_error(con, app): url = get_endpoint('create-child-person') params = { 'personInfo/civility': 'MME', 'personInfo/firstname': 'Diana', 'personInfo/lastname': 'Ross', 'personInfo/sexe': 'F', 'personInfo/dateBirth': '1944-03-26', 'personInfo/contact/phone': '01999999999', 'personInfo/contact/mobile': '0723456789', 'personInfo/contact/mail': 'dross@example.org', 'personQuality/code': 'TUTEUR', } resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_create_child_person_wrong_referential_key_error(con, app): url = get_endpoint('create-child-person') params = { 'personInfo/civility': 'MME', 'personInfo/firstname': 'Diana', 'personInfo/lastname': 'Ross', 'personInfo/sexe': 'plop', 'personInfo/dateBirth': '1944-03-26', 'personInfo/contact/phone': '0199999999', 'personInfo/contact/mobile': '0723456789', 'personInfo/contact/mail': 'dross@example.org', 'personQuality/code': 'TUTEUR', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "personInfo/sexe key value 'plop' do not belong to 'Sex' referential" def test_create_child_person_no_child_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('create-child-person') params = { 'personInfo/civility': 'MME', 'personInfo/firstname': 'Diana', 'personInfo/lastname': 'Ross', 'personInfo/sexe': 'F', 'personInfo/dateBirth': '1944-03-26', 'personInfo/contact/phone': '01999999999', 'personInfo/contact/mobile': '0723456789', 'personInfo/contact/mail': 'dross@example.org', 'personQuality/code': 'TUTEUR', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=42', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '42' child on '1312' family" def test_update_child_person(family_service, con, app): def request_check(request): assert request.numFamily == '1312' assert request.numPerson == 613880 assert len(request.personList) == 1 assert request.personList[0]['personInfo']['num'] == 614719 assert request.personList[0]['personInfo']['firstname'] == 'Angelo' family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateChildAutorization', get_xml_file('R_update_child_authorization.xml'), request_check=request_check, ) url = get_endpoint('update-child-person') params = { 'personInfo/civility': 'M.', 'personInfo/firstname': 'Angelo', 'personInfo/lastname': 'Bent', 'personInfo/sexe': 'M', 'personInfo/contact/phone': '0102030405', 'personInfo/contact/mobile': None, 'personInfo/contact/mail': None, 'personQuality/code': 'O', } resp = app.post_json(url + '?family_id=1312&child_id=613880&person_id=614719', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params) assert resp.json['err'] == 0 def test_update_child_person_not_linked_error(con, app): url = get_endpoint('update-child-person') params = { 'personInfo/civility': 'M.', 'personInfo/firstname': 'Angelo', 'personInfo/lastname': 'Bent', 'personInfo/dateBirth': '1985-06-22', 'personInfo/contact/phone': '0102030405', 'personInfo/contact/mobile': None, 'personInfo/contact/mail': None, 'personQuality/code': 'O', } resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_person_wrong_referential_key_error(con, app): url = get_endpoint('update-child-person') params = { 'personInfo/civility': 'M.', 'personInfo/firstname': 'Angelo', 'personInfo/lastname': 'Bent', 'personInfo/sexe': 'plop', 'personInfo/dateBirth': '1985-06-22', 'personInfo/contact/phone': '0102030405', 'personInfo/contact/mobile': None, 'personInfo/contact/mail': None, 'personQuality/code': 'O', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "personInfo/sexe key value 'plop' do not belong to 'Sex' referential" def test_update_child_person_no_child_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('update-child-person') params = { 'personInfo/civility': 'M.', 'personInfo/firstname': 'Angelo', 'personInfo/lastname': 'Bent', 'personInfo/dateBirth': '1985-06-22', 'personInfo/contact/phone': '0102030405', 'personInfo/contact/mobile': None, 'personInfo/contact/mail': None, 'personQuality/code': 'O', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=42&person_id=614719', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '42' child on '1312' family" def test_update_child_person_not_found(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('update-child-person') params = { 'personInfo/civility': 'M.', 'personInfo/firstname': 'Angelo', 'personInfo/lastname': 'Bent', 'personInfo/dateBirth': '1985-06-22', 'personInfo/contact/phone': '0102030405', 'personInfo/contact/mobile': None, 'personInfo/contact/mail': None, 'personQuality/code': 'O', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=000000', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "No '000000' authorized person on '613880' child" def test_delete_child_person(family_service, con, app): def request_check(request): assert request.numFamily == '1312' assert request.numPerson == 613880 assert len(request.personList) == 0 family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) family_service.add_soap_response( 'updateChildAutorization', get_xml_file('R_update_child_authorization.xml'), request_check=request_check, ) url = get_endpoint('delete-child-person') resp = app.post_json(url + '?family_id=1312&child_id=613880&person_id=614719') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719') assert resp.json['err'] == 0 def test_delete_child_person_not_linked_error(con, app): url = get_endpoint('delete-child-person') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_delete_child_person_no_child_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('delete-child-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=42&person_id=614719') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no '42' child on '1312' family" def test_delete_child_person_no_person_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('delete-child-person') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=000000') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "No '000000' authorized person on '613880' child" def test_update_child_dietcode(family_service, con, app): family_service.add_soap_response('createOrUpdateChildDiet', get_xml_file('R_update_child_dietcode.xml')) url = get_endpoint('update-child-dietcode') resp = app.post_json(url + '?family_id=1312&child_id=613878&dietcode=RSV') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=RSV') assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_child_dietcode_not_linked_error(con, app): url = get_endpoint('update-child-dietcode') resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=RVS') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_dietcode_wrong_referential_key_error(con, app): url = get_endpoint('update-child-dietcode') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=plop') assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "dietcode parameter key value 'plop' do not belong to 'DietCode' referential" ) def test_update_child_pai(family_service, con, app): family_service.add_soap_response('updateChildPAI', get_xml_file('R_update_child_pai.xml')) url = get_endpoint('update-child-pai') params = { 'code': 'PAIALI', 'dateDeb': '2022-01-01', 'dateFin': '', 'description': 'some text', } resp = app.post_json(url + '?family_id=1312&child_id=613878', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_child_pai_empty_payload_error(con, app): url = get_endpoint('update-child-pai') resp = app.post_json(url + '?NameID=local&child_id=613878', params=None, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "None is not of type 'object'" def test_update_child_pai_wrong_payload_type_error(con, app): url = get_endpoint('update-child-pai') params = { 'code': 'PAIALI', 'dateDeb': '2022-01-01', 'dateFin': '', 'description': 42, } resp = app.post_json(url + '?NameID=local&child_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert 'JSONValidationError' in resp.json['err_class'] def test_update_child_pai_empty_referential_key_error(con, app): url = get_endpoint('update-child-pai') params = { 'code': '', 'dateDeb': '2022-01-01', 'dateFin': '', 'description': 'some text', } resp = app.post_json(url + '?NameID=local&child_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "code: '' does not match '.+'" def test_update_child_pai_not_linked_error(con, app): url = get_endpoint('update-child-pai') params = { 'code': 'PAIALI', 'dateDeb': '2022-01-01', 'dateFin': '', 'description': 'some text', } resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_pai_soap_error(family_service, con, app): family_service.add_soap_response( 'updateChildPAI', get_xml_file('R_update_child_pai_soap_error.xml'), status=500 ) url = get_endpoint('update-child-pai') params = { 'code': 'PAIALI', 'dateDeb': '2022-01-01', 'dateFin': '', 'description': 'a' * 501, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 1 assert 'Une erreur est survenue' in resp.json['err_desc'] assert 'valeur trop grande' in resp.json['err_desc'] assert 'maximum : 500' in resp.json['err_desc'] def test_update_child_medical_record(family_service, con, app): family_service.add_soap_response( 'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record.xml') ) url = get_endpoint('update-child-medical-record') params = { 'familyDoctor/name': 'Dre', 'familyDoctor/phone': '0612341234', 'familyDoctor/address/street1': 'Alameda', 'familyDoctor/address/zipcode': '90220', 'familyDoctor/address/town': 'Compton', 'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up, and shrimp', 'allergy2': 'cauliflower', 'comment1': "the shrimp allergy isn't fully identified", 'comment2': None, 'observ1': 'Ay Caramba!', 'observ2': None, 'isAuthHospital': True, 'hospital': 'Springfield General Hospital', 'vaccinList/0/code': 'DTC', 'vaccinList/0/vaccinationDate': '2011-01-11', 'vaccinList/1/code': 'ROR', 'vaccinList/1/vaccinationDate': '2022-02-22', } resp = app.post_json(url + '?family_id=1312&child_id=613878', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_child_medical_record_with_empty_vaccin_list(family_service, con, app): family_service.add_soap_response( 'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record.xml') ) url = get_endpoint('update-child-medical-record') params = { 'familyDoctor/name': 'Dre', 'familyDoctor/phone': '0612341234', 'familyDoctor/address/street1': 'Alameda', 'familyDoctor/address/zipcode': '90220', 'familyDoctor/address/town': 'Compton', 'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up, and shrimp', 'allergy2': 'cauliflower', 'comment1': "the shrimp allergy isn't fully identified", 'comment2': None, 'observ1': 'Ay Caramba!', 'observ2': None, 'isAuthHospital': True, 'hospital': 'Springfield General Hospital', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_child_medical_record_not_linked_error(con, app): url = get_endpoint('update-child-medical-record') resp = app.post_json(url + '?NameID=local&child_id=613878', params={}) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_medical_record_soap_error(family_service, con, app): family_service.add_soap_response( 'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record_soap_error.xml'), status=500 ) url = get_endpoint('update-child-medical-record') params = { 'vaccinList/0/code': 'DTC', 'vaccinList/0/vaccinationDate': '2022-02-31', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 1 assert 'Unmarshalling Error' in resp.json['err_desc'] assert 'pas une valeur de calendrier grégorien' in resp.json['err_desc'] def test_update_child_medical_record_wrong_referential_key_error(con, app): url = get_endpoint('update-child-medical-record') params = { 'familyDoctor/name': 'Dre', 'familyDoctor/phone': '0612341234', 'familyDoctor/address/street1': 'Alameda', 'familyDoctor/address/zipcode': '90220', 'familyDoctor/address/town': 'Compton', 'vaccinList/0/code': 'DTC', 'vaccinList/0/vaccinationDate': '2011-01-11', 'vaccinList/1/code': 'plop', 'vaccinList/1/vaccinationDate': '2022-02-22', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613878', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "vaccinList/1/code key value 'plop' do not belong to 'Vaccin' referential" def test_update_rl_indicator(family_service, con, app): def request_check(request): assert [(x['code'], x['isActive']) for x in request.indicatorList] == [ ('AVL', True), ('AVS', False), ('ETABSPEC', True), ('MDPH', False), ] family_service.add_soap_response( 'updatePersonIndicatorList', get_xml_file('R_update_indicator.xml'), request_check=request_check, ) url = get_endpoint('update-rl-indicator') params = { 'indicatorList/0/code': 'AVL', 'indicatorList/0/isActive': True, 'indicatorList/1/code': 'AVS', 'indicatorList/1/isActive': False, 'indicatorList/2/code': 'ETABSPEC', 'indicatorList/2/note': 'SNPP', 'indicatorList/2/isActive': 'True', 'indicatorList/3/code': 'MDPH', 'indicatorList/3/isActive': 'False', } resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_rl_indicator_not_linked_error(con, app): url = get_endpoint('update-rl-indicator') params = { 'indicatorList': [ { 'code': 'AVL', 'isActive': True, }, ], } resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' @pytest.mark.parametrize('value', ['plop', '', 2, 0.5, 'N']) def test_update_rl_indicator_schema_error(value, con, app): url = get_endpoint('update-rl-indicator') params = { 'indicatorList/0/code': 'AVL', 'indicatorList/0/isActive': value, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert 'JSONValidationError' in resp.json['err_class'] def test_update_rl_indicator_no_indicator_error(con, app): url = get_endpoint('update-rl-indicator') params = {'indicatorList': []} Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'indicatorList: [] is too short' def test_update_rl_indicator_empty_referential_key_error(con, app): url = get_endpoint('update-rl-indicator') params = { 'indicatorList': [ { 'code': '', 'isActive': True, }, ], } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'" def test_update_rl_indicator_wrong_referential_key_error(con, app): url = get_endpoint('update-rl-indicator') params = { 'indicatorList': [ { 'code': 'plop', 'isActive': True, }, ], } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "indicatorList/0/code key value 'plop' do not belong to 'RLIndicator' required referential" ) def test_update_child_add_vaccination(family_service, con, app): def request_check(request): assert request['numPerson'] == 613880 assert request['vaccinList'][0]['code'] == '105' assert request['vaccinList'][0]['vaccinationDate'] == datetime.datetime(2023, 4, 9) family_service.add_soap_response( 'addChildVaccinList', get_xml_file('R_add_child_vaccin_list.xml'), request_check=request_check, ) url = get_endpoint('update-child-add-vaccination') params = { 'code': '105', 'vaccinationDate': '2023-04-09', } resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params) assert resp.json['err'] == 0 resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 0 def test_update_child_add_vaccination_soap_error(family_service, con, app): family_service.add_soap_response( 'addChildVaccinList', get_xml_file('R_add_child_vaccin_list_soap_error.xml'), ) url = get_endpoint('update-child-add-vaccination') params = { 'code': '105', 'vaccinationDate': '2023-04-09', } resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['data']['soap_fault']['message'] == 'Exemple' def test_update_child_indicator(family_service, con, app): def request_check(request): assert [(x['code'], x['isActive']) for x in request.indicatorList] == [ ('APPDENTAIRE', True), ('AUTRE', False), ('AVL', True), ('AVS', False), ('ETABSPEC', True), ('LENTILLE', False), ('LUNETTE', True), ('MDPH', False), ] family_service.add_soap_response( 'updatePersonIndicatorList', get_xml_file('R_update_indicator.xml'), request_check=request_check, ) url = get_endpoint('update-child-indicator') params = { 'indicatorList/0/code': 'APPDENTAIRE', 'indicatorList/0/isActive': 1, 'indicatorList/1/code': 'AUTRE', 'indicatorList/1/note': 'rebellious', 'indicatorList/1/isActive': 0, 'indicatorList/2/code': 'AVL', 'indicatorList/2/isActive': '1', 'indicatorList/3/code': 'AVS', 'indicatorList/3/isActive': '0', 'indicatorList/4/code': 'ETABSPEC', 'indicatorList/4/note': None, 'indicatorList/4/isActive': 'Oui', 'indicatorList/5/code': 'LENTILLE', 'indicatorList/5/isActive': 'Non', 'indicatorList/6/code': 'LUNETTE', 'indicatorList/6/isActive': 'TRUE', 'indicatorList/7/code': 'MDPH', 'indicatorList/7/isActive': 'FALSE', } resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_child_indicator_not_linked_error(con, app): url = get_endpoint('update-child-indicator') params = { 'indicatorList': [ { 'code': 'LUNETTE', 'isActive': True, }, ], } resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_update_child_indicator_no_indicator_error(con, app): url = get_endpoint('update-child-indicator') params = {'indicatorList': []} Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'indicatorList: [] is too short' def test_update_child_indicator_empty_referential_key_error(con, app): url = get_endpoint('update-child-indicator') params = { 'indicatorList': [ { 'code': '', 'isActive': True, }, ], } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'" def test_update_child_indicator_wrong_referential_key_error(con, app): url = get_endpoint('update-child-indicator') params = { 'indicatorList': [ { 'code': 'plop', 'isActive': True, }, ], } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "indicatorList/0/code key value 'plop' do not belong to 'ChildIndicator' required referential" ) def test_add_supplied_document(family_service, con, app, freezer): def request_check(request): assert request.documentList[0]['depositDate'] == datetime.datetime(2022, 12, 20, 0, 0) assert request.documentList[0]['visaDate'] is None assert request.documentList[0]['validityDate'] is None assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg') assert request.documentList[0]['fileSupplied']['name'] == '201x201.jpg' assert request.documentList[0]['fileSupplied']['fileType'] == 'image/jpeg' family_service.add_soap_response( 'addSuppliedDocument', get_xml_file('R_add_supplied_document.xml') % b'OK', request_check=request_check, ) url = get_endpoint('add-supplied-document') params = { 'numPerson': '613880', 'documentList/0/code': '46', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, } freezer.move_to('2022-12-20 18:30:00') resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_add_supplied_document_providing_dates(family_service, con, app): def request_check(request): assert request.documentList[0]['depositDate'] == datetime.datetime(2022, 12, 20, 0, 0) assert request.documentList[0]['visaDate'] == datetime.datetime(2022, 12, 21, 0, 0) assert request.documentList[0]['validityDate'] == datetime.datetime(2022, 12, 22, 0, 0) family_service.add_soap_response( 'addSuppliedDocument', get_xml_file('R_add_supplied_document.xml') % b'OK', request_check=request_check, ) url = get_endpoint('add-supplied-document') params = { 'numPerson': '613880', 'documentList/0/code': '46', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/visaDate': '2022-12-21', 'documentList/0/validityDate': '2022-12-22', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_add_supplied_document_not_linked_error(con, app): url = get_endpoint('add-supplied-document') params = { 'documentList': [], } 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_add_supplied_document_empty_referential_key_error(con, app): url = get_endpoint('add-supplied-document') params = { 'documentList/0/code': '', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "documentList/0/code: '' does not match '.+'" def test_add_supplied_document_wrong_referential_key_error(con, app): url = get_endpoint('add-supplied-document') params = { 'documentList/0/code': 'plop', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "documentList/0/code key value 'plop' do not belong to 'Document' required referential" ) def test_add_supplied_document_extra_parameter_error(con, app): url = get_endpoint('add-supplied-document') params = { 'documentList/0/code': '46', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, 'documentList/0/plop': 'additional parameter', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "documentList/0: Additional properties are not allowed ('plop' was unexpected)" ) def test_add_supplied_document_maelis_error(family_service, con, app): def request_check(request): assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg') family_service.add_soap_response( 'addSuppliedDocument', get_xml_file('R_add_supplied_document.xml') % b'KO', request_check=request_check, ) url = get_endpoint('add-supplied-document') params = { 'documentList/0/code': '46', 'documentList/0/depositDate': '2022-12-20', 'documentList/0/file': { # w.c.s. file field 'filename': '201x201.jpg', 'content_type': 'image/jpeg', 'content': base64.b64encode(get_media_file('201x201.jpg')).decode(), }, } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'maelis fails to add the supplied document' def test_read_supplied_document_validity(family_service, con, app): def request_check(request): assert request.validityDate is None assert request.numPerson is None # document is valid family_service.add_soap_response( 'readSuppliedDocumentValidity', get_xml_file('R_read_supplied_document_validity.xml') % b'true', request_check=request_check, ) url = get_endpoint('read-supplied-document-validity') params = { 'code': '46', } 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'] == 'ok' # document is not valid family_service.add_soap_response( 'readSuppliedDocumentValidity', get_xml_file('R_read_supplied_document_validity.xml') % b'false', request_check=request_check, ) resp = app.get(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ko' def test_read_supplied_document_validity_with_optional_parameters(family_service, con, app): def request_check(request): assert request.validityDate == datetime.datetime(2022, 12, 21, 0, 0) assert request.numPerson == 613878 family_service.add_soap_response( 'readSuppliedDocumentValidity', get_xml_file('R_read_supplied_document_validity.xml') % b'true', request_check=request_check, ) url = get_endpoint('read-supplied-document-validity') params = { 'code': '85', 'ref_date': '2022-12-21', 'person_id': '613878', } resp = app.get(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 def test_read_supplied_document_validity_not_linked_error(con, app): url = get_endpoint('read-supplied-document-validity') params = { 'code': '46', } 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_read_supplied_document_validity_wrong_referential_key_error(con, app): url = get_endpoint('read-supplied-document-validity') params = { 'code': 'plop', } resp = app.get(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "code parameter key value 'plop' do not belong to 'Document' required referential" ) def test_read_supplied_document_validity_maelis_error(family_service, con, app): family_service.add_soap_response( 'readSuppliedDocumentValidity', get_xml_file('R_read_supplied_document_validity_error.xml'), ) url = get_endpoint('read-supplied-document-validity') params = { 'code': '46', 'person_id': '123', } resp = app.get(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPFault' assert "E36A : La personne d'identifiant [123] n'existe pas" in resp.json['err_desc'] def test_add_rl1_direct_debit_order(family_service, invoice_service, con, app): def request_check(request): assert request.numDossier == 1312 assert request.bank['dateStart'] == datetime.datetime(2023, 1, 1, 0, 0) family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) invoice_service.add_soap_response( 'addDirectDebitOrder', get_xml_file('R_add_direct_debit_order.xml'), request_check=request_check, ) url = get_endpoint('add-rl1-direct-debit-order') params = { 'codeRegie': '22', 'bank/bankBIC': 'BDFEFR2T', 'bank/bankIBAN': 'FR7630001007941234567890185', 'bank/bankRUM': 'xxx', 'bank/dateStart': '2023-01-01', 'bank/bankAddress': '75049 PARIS cedex 01', 'bank/civility': 'x', 'bank/lastName': 'Ewing', 'bank/firstName': 'John Ross', } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_add_rl1_direct_debit_order_not_linked_error(con, app): url = get_endpoint('add-rl1-direct-debit-order') params = { 'codeRegie': '22', 'bank/bankBIC': 'BDFEFR2T', 'bank/bankIBAN': 'FR7630001007941234567890185', 'bank/bankRUM': 'xxx', 'bank/dateStart': '2023-01-01', 'bank/bankAddress': '75049 PARIS cedex 01', 'bank/civility': 'x', 'bank/lastName': 'Ewing', 'bank/firstName': 'John Ross', } 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_add_rl1_direct_debit_order_soap_error(family_service, invoice_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) invoice_service.add_soap_response( 'addDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500 ) url = get_endpoint('add-rl1-direct-debit-order') params = { 'codeRegie': '12345', 'bank/bankBIC': 'BDFEFR2T', 'bank/bankIBAN': 'FR7630001007941234567890185', 'bank/bankRUM': 'xxx', 'bank/dateStart': '2023-01-01', 'bank/bankAddress': '75049 PARIS cedex 01', 'bank/civility': 'x', 'bank/lastName': 'Ewing', 'bank/firstName': 'John Ross', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == 'SOAP service at https://example.org/InvoiceService?wsdl returned an error "E520 : La REGIE CS [{0}] n\'\'existe pas dans la base Maelis"' ) def test_get_rl1_direct_debit_order(family_service, invoice_service, con, app): def request_check(request): assert request.numDossier == 1312 family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) invoice_service.add_soap_response( 'getDirectDebitOrder', get_xml_file('R_get_direct_debit_order.xml'), request_check=request_check, ) url = get_endpoint('get-rl1-direct-debit-order') params = { 'codeRegie': '22', 'dateRef': '2023-01-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'] == { 'bankBIC': 'BDFEFR2T', 'bankIBAN': 'FR7630001007941234567890185', 'bankRUM': 'xxx', 'dateStart': '2023-01-01T00:00:00+01:00', 'bankAddress': '75049 PARIS cedex 01', 'civility': 'x', 'lastName': 'Ewing', 'firstName': 'John Ross', } def test_get_rl1_direct_debit_order_parameter_error(con, app): url = get_endpoint('get-rl1-direct-debit-order') params = { 'codeRegie': '22', 'dateRef': 'plop', } resp = app.get(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.views.InvalidParameterValue' assert resp.json['err_desc'] == 'invalid value for parameter "dateRef (YYYY-MM-DD expected)"' def test_get_rl1_direct_debit_order_not_linked_error(con, app): url = get_endpoint('get-rl1-direct-debit-order') params = { 'codeRegie': '22', 'dateRef': '2023-01-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_rl1_direct_debit_order_soap_error(family_service, invoice_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) invoice_service.add_soap_response( 'getDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500 ) url = get_endpoint('get-rl1-direct-debit-order') params = { 'codeRegie': '12345', 'dateRef': '2023-01-01', } Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == 'SOAP service at https://example.org/InvoiceService?wsdl returned an error "E520 : La REGIE CS [{0}] n\'\'existe pas dans la base Maelis"' ) def test_read_school_year_list(con, app, freezer): url = get_endpoint('read-school-years-list') freezer.move_to('2023-11-09') resp = app.get(url + '?subscribable=0') assert resp.json['err'] == 0 assert len(resp.json['data']) == 3 assert resp.json['data'] == [ { 'id': 2022, 'text': '2022', 'schoolYear': 2022, 'dateEndYearSchool': '2023-07-07T00:00:00+02:00', 'dateStartYearSchool': '2022-09-01T00:00:00+02:00', 'dateEndSubscribeSchool': '2023-09-01T00:00:00+02:00', 'dateStartSubscribeSchool': '2022-09-01T00:00:00+02:00', }, { 'id': 2023, 'text': '2023', 'schoolYear': 2023, 'dateEndYearSchool': '2024-07-07T00:00:00+02:00', 'dateStartYearSchool': '2023-09-04T00:00:00+02:00', 'dateEndSubscribeSchool': '2024-07-01T00:00:00+02:00', 'dateStartSubscribeSchool': '2022-09-01T00:00:00+02:00', }, { 'id': 2024, 'text': '2024', 'schoolYear': 2024, 'dateEndYearSchool': '2025-07-07T00:00:00+02:00', 'dateStartYearSchool': '2024-09-01T00:00:00+02:00', 'dateEndSubscribeSchool': None, 'dateStartSubscribeSchool': None, }, ] # get only subscribable school years by default resp = app.get(url) assert resp.json['err'] == 0 assert [x['text'] for x in resp.json['data']] == ['2023'] resp = app.get(url + '?subscribable=plop') assert resp.json['err'] == 1 assert resp.json['err_desc'] == "invalid truth value 'plop'" def test_read_school_levels_list(con, app): url = get_endpoint('read-school-levels-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 22 for item in resp.json['data']: assert 'id' in item assert 'text' in item resp = app.get(url, params={'age': '8'}) assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 level = resp.json['data'][0] assert level['id'] == 'CE2' assert level['code'] == 'CE2' assert level['text'] == 'Cours élémentaire 2' assert level['libelle'] == 'Cours élémentaire 2' def test_read_exemption_reasons_list(con, app): url = get_endpoint('read-exemption-reasons-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 4 for item in resp.json['data']: assert 'id' in item assert 'text' in item def test_read_person_agenda(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml') ) url = get_endpoint('read-person-agenda') resp = app.get(url + '?family_id=1312&person_id=613880&start_date=2023-01-01&end_date=2023-01-15') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=613880&start_date=2023-01-01&end_date=2023-01-15') assert resp.json['err'] == 0 assert resp.json['extra_data'] == { 'start_date': '2023-01-01', 'end_date': '2023-01-15', 'school_year': '2022/2023', } assert len(resp.json['data']) == 16 assert resp.json['data'] == [ { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327690', }, 'disabled': True, 'id': '613880:A10049327689:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327683', }, 'disabled': True, 'id': '613880:A10049327682:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-03T00:00:00+01:00', 'day_str': '2023-01-03', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327690', }, 'disabled': True, 'id': '613880:A10049327689:2023-01-03', 'prefill': False, 'text': 'Tuesday 3 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-03T00:00:00+01:00', 'day_str': '2023-01-03', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'READ_ONLY', 'status_color': 'green', 'unit_id': 'A10049327683', }, 'disabled': True, 'id': '613880:A10049327682:2023-01-03', 'prefill': True, 'text': 'Tuesday 3 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_ABSENCE', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-05T00:00:00+01:00', 'day_str': '2023-01-05', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-05', 'prefill': True, 'text': 'Thursday 5 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_ABSENCE', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-05T00:00:00+01:00', 'day_str': '2023-01-05', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-05', 'prefill': True, 'text': 'Thursday 5 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_ABSENCE', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-06T00:00:00+01:00', 'day_str': '2023-01-06', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-06', 'prefill': True, 'text': 'Friday 6 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_PRES_REAL', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-06T00:00:00+01:00', 'day_str': '2023-01-06', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'WRITABLE', 'status_color': 'white', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-06', 'prefill': False, 'text': 'Friday 6 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_PRES_PREVI', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-09T00:00:00+01:00', 'day_str': '2023-01-09', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'WRITABLE', 'status_color': 'white', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-09', 'prefill': False, 'text': 'Monday 9 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_PRES_PREVI', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-09T00:00:00+01:00', 'day_str': '2023-01-09', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'WRITABLE', 'status_color': 'white', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-09', 'prefill': False, 'text': 'Monday 9 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_PRES_PREVI', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-10T00:00:00+01:00', 'day_str': '2023-01-10', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'WRITABLE', 'status_color': 'white', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-10', 'prefill': False, 'text': 'Tuesday 10 January 2023', }, { 'details': { 'absence': None, 'action': 'DEL_PRES_PREVI', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-10T00:00:00+01:00', 'day_str': '2023-01-10', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-10', 'prefill': True, 'text': 'Tuesday 10 January 2023', }, { 'details': { 'absence': None, 'action': 'DEL_PRES_PREVI', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-12T00:00:00+01:00', 'day_str': '2023-01-12', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-12', 'prefill': True, 'text': 'Thursday 12 January 2023', }, { 'details': { 'absence': None, 'action': 'DEL_PRES_PREVI', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-12T00:00:00+01:00', 'day_str': '2023-01-12', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-12', 'prefill': True, 'text': 'Thursday 12 January 2023', }, { 'details': { 'absence': None, 'action': 'DEL_PRES_PREVI', 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-13T00:00:00+01:00', 'day_str': '2023-01-13', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 1, 'status': 'WRITABLE', 'status_color': 'green', 'unit_id': 'A10049327690', }, 'disabled': False, 'id': '613880:A10049327689:2023-01-13', 'prefill': True, 'text': 'Friday 13 January 2023', }, { 'details': { 'absence': None, 'action': 'ADD_PRES_PREVI', 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-13T00:00:00+01:00', 'day_str': '2023-01-13', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'WRITABLE', 'status_color': 'white', 'unit_id': 'A10049327683', }, 'disabled': False, 'id': '613880:A10049327682:2023-01-13', 'prefill': False, 'text': 'Friday 13 January 2023', }, ] def test_read_person_agenda_multi_units(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_with_multi_units.xml') ) url = get_endpoint('read-person-agenda') resp = app.get(url + '?family_id=1312&person_id=613880&start_date=2023-01-01&end_date=2023-01-15') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=613880&start_date=2023-01-01&end_date=2023-01-15') assert resp.json['err'] == 0 assert resp.json['extra_data'] == { 'start_date': '2023-01-01', 'end_date': '2023-01-15', 'school_year': '2022/2023', } assert len(resp.json['data']) == 5 assert resp.json['data'] == [ { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'activity_type': 'ACCMAT', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327690', }, 'disabled': True, 'id': '613880:A10049327689:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire (PAI PANIER 22/23)', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327684', }, 'disabled': True, 'id': '613880:A10049327682:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire (RESTAURATION SCOLAIRE 22/23)', 'activity_type': 'RESTSCOL', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327683', }, 'disabled': True, 'id': '613880:A10049327682:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327693', 'activity_label': 'Accueil p\\xc3\\xa9riscolaire', 'activity_type': 'ACCPERI', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327694', }, 'disabled': True, 'id': '613880:A10049327693:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, { 'details': { 'absence': None, 'action': None, 'activity_id': 'A10049327691', 'activity_label': 'Accueil du soir', 'activity_type': 'ACCSOIR', 'child_id': '613880', 'day': '2023-01-02T00:00:00+01:00', 'day_str': '2023-01-02', 'hasPlace': None, 'realPresence': 0, 'scheduledPresence': 0, 'status': 'READ_ONLY', 'status_color': 'white', 'unit_id': 'A10049327692', }, 'disabled': True, 'id': '613880:A10049327691:2023-01-02', 'prefill': False, 'text': 'Monday 2 January 2023', }, ] def test_read_person_agenda_with_activity(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_with_activity.xml') ) url = get_endpoint('read-person-agenda') resp = app.get(url + '?family_id=1312&person_id=322423&start_date=2023-05-01&end_date=2023-05-31') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=322423&start_date=2023-05-01&end_date=2023-05-31') assert resp.json['err'] == 0 assert resp.json['extra_data'] == { 'start_date': '2023-05-01', 'end_date': '2023-05-31', 'school_year': '2022/2023', } assert len(resp.json['data']) == 18 # extra-sco bookings ('X' nature) are displayed but disabled extra_sco_bookings = [x for x in resp.json['data'] if x['details']['activity_type'] == 'EXTMERC'] assert len([x for x in extra_sco_bookings if x['details']['status'] == 'WRITABLE']) == 3 assert all([x['disabled'] for x in extra_sco_bookings]) assert resp.json['data'][4:6] == [ { 'id': '322423:A10049354913:2023-05-10', 'text': 'Wednesday 10 May 2023', 'prefill': True, 'disabled': True, # disabled 'details': { 'day': '2023-05-10T00:00:00+02:00', 'scheduledPresence': 1, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'DEL_PRES_PREVI', 'hasPlace': None, 'absence': None, 'status_color': 'green', 'activity_id': 'A10049354913', 'activity_type': 'EXTMERC', 'activity_label': 'ADL Élémentaire Maourine', 'child_id': '322423', 'day_str': '2023-05-10', 'unit_id': 'A10049354915', }, }, { 'id': '322423:A10049327689:2023-05-11', 'text': 'Thursday 11 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-11T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'status_color': 'white', 'activity_id': 'A10049327689', 'activity_type': 'ACCMAT', 'activity_label': 'Accueil du matin', 'child_id': '322423', 'day_str': '2023-05-11', 'unit_id': 'A10049327690', }, }, ] def test_read_person_agenda_not_linked_error(con, app): url = get_endpoint('read-person-agenda') resp = app.get(url + '?NameID=local&person_id=613880&start_date=2022-09-01&end_date=2023-08-31') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_person_agenda_date_error(con, app): url = get_endpoint('read-person-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local&person_id=613880&start_date=bad&end_date=2023-08-31', status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' resp = app.get(url + '?NameID=local&person_id=613880&start_date=2022-09-01&end_date=bad', status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' resp = app.get( url + '?NameID=local&person_id=613880&start_date=2023-09-01&end_date=2023-08-31', status=400 ) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' resp = app.get( url + '?NameID=local&person_id=613880&start_date=2022-09-01&end_date=2024-08-31', status=400 ) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_update_person_agenda(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml') ) url = get_endpoint('update-person-agenda') def request_check(request): assert request.numDossier == 1312 assert len(request.unitPersonDayInfoList) == 4 assert request.unitPersonDayInfoList[0].numPerson == 613880 assert request.unitPersonDayInfoList[0].idAct == 'A10049327689' assert request.unitPersonDayInfoList[0].idUni == 'A10049327690' assert request.unitPersonDayInfoList[0].date == datetime.datetime(2023, 1, 5, 0, 0) assert request.unitPersonDayInfoList[0].action == 'ADD_ABSENCE' assert request.unitPersonDayInfoList[1].numPerson == 613880 assert request.unitPersonDayInfoList[1].idAct == 'A10049327682' assert request.unitPersonDayInfoList[1].idUni == 'A10049327683' assert request.unitPersonDayInfoList[1].date == datetime.datetime(2023, 1, 6, 0, 0) assert request.unitPersonDayInfoList[1].action == 'ADD_PRES_REAL' assert request.unitPersonDayInfoList[2].numPerson == 613880 assert request.unitPersonDayInfoList[2].idAct == 'A10049327682' assert request.unitPersonDayInfoList[2].idUni == 'A10049327683' assert request.unitPersonDayInfoList[2].date == datetime.datetime(2023, 1, 10, 0, 0) assert request.unitPersonDayInfoList[2].action == 'DEL_PRES_PREVI' assert request.unitPersonDayInfoList[3].numPerson == 613880 assert request.unitPersonDayInfoList[3].idAct == 'A10049327682' assert request.unitPersonDayInfoList[3].idUni == 'A10049327683' assert request.unitPersonDayInfoList[3].date == datetime.datetime(2023, 1, 13, 0, 0) assert request.unitPersonDayInfoList[3].action == 'ADD_PRES_PREVI' activity_service.add_soap_response( 'updatePersonSchedule', get_xml_file('R_update_person_schedule.xml'), request_check=request_check ) params = { 'person_id': '613880', 'start_date': '2023-01-01', 'end_date': '2023-01-15', 'booking_list': [ # '613880:A10049327689:2023-01-05', # remove this one '613880:A10049327682:2023-01-05', '613880:A10049327689:2023-01-06', # '613880:A10049327682:2023-01-10', # and this one '613880:A10049327689:2023-01-12', '613880:A10049327682:2023-01-12', '613880:A10049327689:2023-01-13', # but add: '613880:A10049327682:2023-01-06', '613880:A10049327682:2023-01-13', ], } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json == { 'changes': [ { 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'booked': True, 'day': '2023-01-06', }, { 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'booked': True, 'day': '2023-01-13', }, { 'activity_id': 'A10049327689', 'activity_label': 'Accueil du matin', 'booked': False, 'day': '2023-01-05', }, { 'activity_id': 'A10049327682', 'activity_label': 'Restauration scolaire', 'booked': False, 'day': '2023-01-10', }, ], 'count': 4, 'err': 0, 'updated': True, } def test_update_person_agenda_no_changes(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml') ) url = get_endpoint('update-person-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') params = { 'person_id': '613880', 'start_date': '2023-01-01', 'end_date': '2023-01-15', 'booking_list': [ '613880:A10049327689:2023-01-05', '613880:A10049327682:2023-01-05', '613880:A10049327689:2023-01-06', '613880:A10049327682:2023-01-10', '613880:A10049327689:2023-01-12', '613880:A10049327682:2023-01-12', '613880:A10049327689:2023-01-13', ], } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json == [] def test_update_person_agenda_maelis_error(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml') ) url = get_endpoint('update-person-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') activity_service.add_soap_response( 'updatePersonSchedule', get_xml_file('R_update_person_schedule_error.xml') ) params = { 'person_id': '613880', 'start_date': '2023-01-01', 'end_date': '2023-01-15', 'booking_list': [ '613880:A10049327682:2023-01-13', ], } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Foo ; Bar' def test_update_person_agenda_not_linked_error(con, app): url = get_endpoint('update-person-agenda') params = { 'person_id': '613880', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'booking_list': [], } 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_person_agenda_date_error(con, app): url = get_endpoint('update-person-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') params = { 'person_id': '613880', 'start_date': 'bad', 'end_date': '2023-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "start_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" params = { 'person_id': '613880', 'start_date': '2022-09-01', 'end_date': 'bad', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "end_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" params = { 'person_id': '613880', 'start_date': '2023-09-01', 'end_date': '2023-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params = { 'person_id': '613880', 'start_date': '2022-09-01', 'end_date': '2024-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 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', 'warning_msg': None} 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 family '1312', person '613880', activity 'plop' on 2023-04-01" ) del params['activity_id'] resp = app.get(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "missing parameters: 'activity_id'." # do not raise on calls generated by the form providing 'None' activity params['activity_id'] = 'None' resp = app.get(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == [] assert resp.json['meta'] == { 'date_min_prev': None, 'warning_msg': "No week calendar for family '1312', person '613880', activity 'None' on 2023-04-01", } def test_get_recurrent_week_no_open_day(family_service, activity_service, con, app, caplog, settings): 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_no_open_day.xml'), ) url = get_endpoint('get-recurrent-week') params = { 'person_id': '613880', 'activity_id': 'A10049327682', 'ref_date': '2023-04-01', } con.set_log_level('DEBUG') ResourceLog.objects.all().delete() resp = app.get(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "No open day for family '1312', person '613880', activity 'A10049327682' on 2023-04-01" ) # SOAP request and response are logged assert '1312' in ResourceLog.objects.all()[2].extra['request_payload'] assert 'false' in ResourceLog.objects.all()[2].extra['response_content'] assert 'true' not in ResourceLog.objects.all()[2].extra['response_content'] # error is logged assert ResourceLog.objects.all()[3].message == 'Error occurred while processing request' assert ResourceLog.objects.all()[3].extra['error_summary'] == [ "passerelle.utils.jsonresponse.APIError: No open day for family '1312', person '613880', activity 'A10049327682' on 2023-04-01\n" ] assert len(caplog.records) == 4 assert caplog.records[3].levelno == logging.ERROR assert caplog.records[3].message == 'Error occurred while processing request' 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 request.numFamily == 311323 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_empty(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 1, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, {'dayNum': 2, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, {'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': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_update_recurrent_week_null(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 1, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, {'dayNum': 2, 'isPresent': False, 'isOpen': None, 'calendarLetter': None}, {'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': None, } resp = app.post_json(url + '?family_id=311323', 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') ) url = get_endpoint('read-schools-for-address-and-level') params = { 'year': '2022', 'level': 'CP', 'id_street': '2317', 'num': '4', 'comp': 'B', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert len(resp.json['data']) == 8 for item in resp.json['data']: assert 'id' in item assert 'text' in item params = { 'year': '2022', 'level': '', 'id_street': '2317', 'num': '', 'comp': '', } resp = app.get(url, params=params) assert resp.json['err'] == 0 def test_read_schools_for_address_and_level_empty_referential_key_error(con, app): url = get_endpoint('read-schools-for-address-and-level') params = { 'year': '2022', 'level': 'CP', 'id_street': '', 'num': '4', 'comp': 'B', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'id_street parameter is required and could not be None' def test_read_schools_for_address_and_level_wrong_referential_key_error(con, app): url = get_endpoint('read-schools-for-address-and-level') params = { 'year': '2022', 'level': 'plop', 'id_street': '2317', 'num': '4', 'comp': 'B', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "level parameter key value 'plop' do not belong to 'Level' referential" params = { 'year': '2022', 'level': 'CP', 'id_street': 'plop', 'num': '4', 'comp': 'B', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "id_street parameter key value 'plop' do not belong to 'Street' required referential" ) params = { 'year': '2022', 'level': 'CP', 'id_street': '2317', 'num': 'plop', 'comp': 'B', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'num parameter should be a number' params = { 'year': '2022', 'level': 'CP', 'id_street': '2317', 'num': '4', 'comp': 'plop', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "comp parameter key value 'plop' do not belong to 'Complement' referential" ) def test_read_school_list_child_and_level(family_service, con, app): family_service.add_soap_response( 'readSchoolForChildAndLevel', get_xml_file('R_read_school_for_child_and_level.xml') ) url = get_endpoint('read-schools-for-child-and-level') resp = app.get(url, params={'child_id': '190115', 'year': '2023'}) assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 for item in resp.json['data']: assert 'id' in item assert 'text' in item def test_read_child_school_informations(family_service, con, app): family_service.add_soap_response( 'getChildSubscribeSchoolInformation', get_xml_file('R_get_child_subscribe_school_information.xml') ) url = get_endpoint('read-child-school-informations') resp = app.get(url, params={'family_id': '47916', 'child_id': '190115', 'year': '2023', 'level': 'CP'}) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='47916', name_id='local') resp = app.get(url, params={'NameID': 'local', 'child_id': '190115', 'year': '2023', 'level': 'CP'}) assert resp.json['err'] == 0 assert 'rl1Info' in resp.json['data'] assert 'childSubscribeSchoolInformation' in resp.json['data'] assert 'personSubscribeSchoolList' in resp.json['data'] school_list = resp.json['data']['childSubscribeSchoolInformation']['subscribeSchoolInformation'][ 'derogSchoolList' ] assert [(x['id'], x['text']) for x in school_list] == [ ('2578', 'AMIDONNIERS ELEMENTAIRE'), ('2578', 'AMIDONNIERS ELEMENTAIRE'), ('2654', 'AUBRAC LUCIE ELEMENTAIRE'), ] def test_create_child_school_pre_registration(family_service, con, app): family_service.add_soap_response( 'preSubscribeSchoolPerim', get_xml_file('R_create_child_school_pre_registration.xml') ) url = get_endpoint('create-child-school-pre-registration') resp = app.post_json( url, params={ 'numPerson': '248460', 'schoolYear': '2023', 'levelCode': 'CM1', 'dateSubscribe': '2023-09-01T00:00:00+02:00', }, ) assert resp.json['err'] == 0 assert resp.json['data']['subscribeSchoolBean']['idSchool'] == '2435' assert resp.json['data']['subscribeSchoolBean']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE' assert resp.json['data']['subscribeSchoolBean']['isWaitList'] def test_create_child_school_pre_registration_soap_error(family_service, con, app): family_service.add_soap_response( 'preSubscribeSchoolPerim', get_xml_file('R_create_child_school_pre_registration_soap_error.xml') ) url = get_endpoint('create-child-school-pre-registration') resp = app.post_json( url, params={ 'numPerson': '248460', 'schoolYear': '2023', 'levelCode': 'CM1', 'dateSubscribe': '2023-09-01T00:00:00+02:00', }, ) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPFault' assert ( resp.json['err_desc'] == 'SOAP service at https://example.org/FamilyService?wsdl returned an error "E25 : Cette personne nappartient pas à cette famille"' ) def test_create_child_school_pre_registration_maelis_error(family_service, con, app): family_service.add_soap_response( 'preSubscribeSchoolPerim', get_xml_file('R_create_child_school_pre_registration_maelis_error.xml') ) url = get_endpoint('create-child-school-pre-registration') resp = app.post_json( url, params={ 'numPerson': '248460', 'schoolYear': '2023', 'levelCode': 'CM1', 'dateSubscribe': '2023-09-01T00:00:00+02:00', }, ) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' assert resp.json['err_desc'] == 'E113 : Il existe déjà une inscription scolaire pour cet enfant' def test_create_child_school_pre_registration_with_exemption(family_service, con, app): family_service.add_soap_response( 'presubscribeSchoolDerog', get_xml_file('R_create_child_school_pre_registration_with_exemption.xml') ) url = get_endpoint('create-child-school-pre-registration-with-exemption') resp = app.post_json( url, params={ 'numPerson': '248460', 'schoolYear': '2023', 'levelCode': 'CM1', 'datePresubscribe': '2023-09-01T00:00:00+02:00', 'idRequestSchool1': '2435', 'derogReasonCode': '11DERO-1', 'derogComment': 'exemption comment', }, ) assert resp.json['err'] == 0 assert resp.json['data']['idSchool'] == '2435' assert resp.json['data']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE' assert resp.json['data']['isWaitList'] assert resp.json['data']['isDerog'] assert resp.json['data']['derogReason'] == '11DERO-1' assert resp.json['data']['derogComment'] == 'exemption comment' def test_create_child_school_pre_registration_with_sibling(family_service, con, app): family_service.add_soap_response( 'presubscribeSchoolSibling', get_xml_file('R_create_child_school_pre_registration_with_sibling.xml') ) url = get_endpoint('create-child-school-pre-registration-with-sibling') resp = app.post_json( url, params={ 'numPerson': '248565', 'schoolYear': '2023', 'levelCode': 'CM1', 'datePresubscribe': '2023-09-01T00:00:00+02:00', 'idSchoolRequested': '2435', 'numPersonSibling': '248562', }, ) assert resp.json['err'] == 0 assert resp.json['data']['idSchool'] == '2435' assert resp.json['data']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE' assert resp.json['data']['isWaitList'] assert resp.json['data']['isDerog'] assert resp.json['data']['codeWait'] == 'MO_FRATERIE' assert resp.json['data']['derogReason'] == '01PRIO-5' assert resp.json['data']['derogComment'] == 'SERGHEI3 LISA' @pytest.mark.parametrize( 'start_dob, end_dob, expected', [ ( None, None, [ 'Petit enfant (- de 3 ans)', 'Enfant (3-11 ans)', 'Ado (12-17 ans)', 'Jeune (18-25 ans)', 'Adulte (26-59 ans)', 'Sénior (60 ans et plus)', ], ), ('2011-01-01', '2020-12-31', ['Enfant (3-11 ans)', 'Ado (12-17 ans)']), ('2011-01-01', '2015-12-31', ['Enfant (3-11 ans)', 'Ado (12-17 ans)']), ('1900-01-01', '1963-01-01', ['Sénior (60 ans et plus)']), ('1963-01-02', '1997-01-01', ['Adulte (26-59 ans)']), ('1997-01-02', '2005-01-01', ['Jeune (18-25 ans)']), ('2005-01-02', '2011-01-01', ['Ado (12-17 ans)']), ('2011-01-02', '2020-01-01', ['Enfant (3-11 ans)']), ('2020-01-02', '2023-01-01', ['Petit enfant (- de 3 ans)']), ], ) def test_get_public_criterias(start_dob, end_dob, expected): today = parse_date('2023-01-01') if start_dob: start_dob = parse_date(start_dob) start_dob = datetime.datetime.combine(start_dob, datetime.datetime.min.time()) if end_dob: end_dob = parse_date(end_dob) end_dob = datetime.datetime.combine(end_dob, datetime.datetime.min.time()) result = get_public_criterias(today, start_dob, end_dob) assert expected == [x[1] for x in result] def test_read_activity_list(con, app, freezer): url = get_endpoint('read-activity-list') con.loisir_nature_codes = '1,4,L,, S ' con.save() freezer.move_to('2024-02-29') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 9 # activities are sorted by start date, text and next by end date activities = [(x['unit']['dateStart'], x['text'], x['unit']['dateEnd']) for x in resp.json['data']] assert activities == sorted(activities) # services label is added to activities if a service id is provided assert [ ( x['id'], x['activity']['activityPortail']['idService'], x['activity']['activityPortail']['idService_text'], ) for x in resp.json['data'] ] == [ ('A10051141965-A10051141990-A10053179227', 'A10049329051', 'Sorties'), ('A10051141965-A10051141968-A10053179226', 'A10049329051', 'Sorties'), ('A10051141965-A10051141966-A10053179226', 'A10049329051', 'Sorties'), ('A10056514645-A10056514650-A10053179757', None, None), ('A10056514645-A10056514648-A10053179876', None, None), ('A10056514645-A10056514649-A10053179757', None, None), ('A10051141965-A10051141970-A10053179226', 'A10049329051', 'Sorties'), ('A10056517594-A10056517595-A10056517597', 'plop', None), ('A10056517599-A10056517596-A10056517597', 'plop', None), ] # item text differs on so called maelis "standard" and "non-standard" activities # * standard : activity having only one (standard) unit # * non-standard : activity having many units -> unit is precised within parenthesis assert [x['text'] for x in resp.json['data']] == [ 'Vitrail Fusing 1/2 Je Adultes 2022/2023 - Mardi 14h-17h (Inscription 1er semestre), Un autre centre culturel', 'Vitrail Fusing 1/2 Je Adultes 2022/2023 - Mardi 14h-17h (Inscription annuelle), Centre Culturel ALBAN MINVILLE', 'Vitrail Fusing 1/2 Je Adultes 2022/2023 - Mardi 14h-17h (Vitrail Fusing 1/2 Je Adultes 2022/2023 - Mardi 14h-17h), Centre Culturel ALBAN MINVILLE', 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES (MERCREDI - 13h45/17h - 8/15Ans), ARGOULETS', 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES (MERCREDI - 14h/16h30 - 10/15Ans), LA RAMEE', 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES (MERCREDI - 15h30/17h - 8/15Ans), ARGOULETS', 'Vitrail Fusing 1/2 Je Adultes 2022/2023 - Mardi 14h-17h (Inscription 2ème semestre), Centre Culturel ALBAN MINVILLE', 'Promenade forêt enchantée, TERRITOIRE OUEST', 'Promenade forêt enchantée, TERRITOIRE OUEST', ] item = resp.json['data'][2] assert item['activity']['service'] == { 'id': 'A10049329051', 'lib1': 'Sorties', 'lib2': None, 'text': 'Sorties', 'idDir': 'A10049327621', 'direction': { 'id': 'A10049327621', 'lib1': 'DASC', 'lib2': "Direction de l'action socioculturelle", 'text': 'DASC', }, } item['activity'] = 'N/A' item['unit'] = 'N/A' item['place'] = 'N/A' assert item == { 'id': 'A10051141965-A10051141966-A10053179226', 'text': 'Vitrail Fusing 1/2 Je Adultes 2022/2023' + ' - Mardi 14h-17h (Vitrail Fusing 1/2 Je Adultes 2022/2023' + ' - Mardi 14h-17h), Centre Culturel ALBAN MINVILLE', 'activity': 'N/A', 'unit': 'N/A', 'place': 'N/A', 'criterias': { 'service': { 'text': 'Service', 'data': {'sorties': 'Sorties'}, 'order': ['sorties'], }, 'nature': {'text': "Nature de l'activité", 'data': {'4': 'ART PLASTIQUE'}, 'order': ['4']}, 'type': { 'text': 'Discipline', 'data': {'activite-reguliere': 'ACTIVITE REGULIERE'}, 'order': ['activite-reguliere'], }, 'place': { 'text': 'Lieu', 'data': {'A10053179226': 'Centre Culturel ALBAN MINVILLE'}, 'order': ['A10053179226'], }, 'public': { 'text': 'Public', 'data': {'1': 'Enfant (3-11 ans)', '2': 'Ado (12-17 ans)'}, 'order': ['1', '2'], }, 'day': {'text': 'Jours', 'data': {'2': 'Mardi'}, 'order': ['2']}, }, } assert resp.json['meta'] == { 'all_criterias': { 'service': {'text': 'Service', 'data': {'sorties': 'Sorties'}, 'order': ['sorties']}, 'nature': { 'text': "Nature de l'activité", 'data': {'4': 'ART PLASTIQUE', '1': 'Activités Régulières'}, 'order': ['1', '4'], }, 'type': { 'text': 'Discipline', 'data': { 'activite-reguliere': 'ACTIVITE REGULIERE', 'activites-aquatiques-activite-reguliere': 'Activités Aquatiques Activité Réguliére', 'activite-pedestre-activite-reguliere': 'Activité Pédestre Activité régulière', }, 'order': [ 'activite-reguliere', 'activite-pedestre-activite-reguliere', 'activites-aquatiques-activite-reguliere', ], }, 'public': { 'text': 'Public', 'data': { '0': 'Petit enfant (- de 3 ans)', '1': 'Enfant (3-11 ans)', '2': 'Ado (12-17 ans)', '3': 'Jeune (18-25 ans)', '4': 'Adulte (26-59 ans)', '5': 'Sénior (60 ans et plus)', }, 'order': ['0', '1', '2', '3', '4', '5'], }, 'day': { 'text': 'Jours', 'data': {'2': 'Mardi', '3': 'Mercredi', '1': 'Lundi', '4': 'Jeudi', '5': 'Vendredi'}, 'order': ['1', '2', '3', '4', '5'], }, 'place': { 'text': 'Lieu', 'data': { 'A10053179226': 'Centre Culturel ALBAN MINVILLE', 'A10053179227': 'Un autre centre culturel', 'A10053179757': 'ARGOULETS', 'A10053179876': 'LA RAMEE', 'A10056517597': 'TERRITOIRE OUEST', }, 'order': ['A10053179757', 'A10053179226', 'A10053179876', 'A10056517597', 'A10053179227'], }, }, 'all_criterias_order': ['service', 'nature', 'type', 'public', 'day', 'place'], } # make sure activities have a single place defined for item in resp.json['data']: assert len(item['criterias']['place']['order']) == 1 con.loisir_nature_codes = 'X,L,S' con.save() resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 0 assert resp.json == { 'data': [], 'meta': { 'all_criterias': { 'service': {'text': 'Service', 'data': {}, 'order': []}, 'nature': {'text': "Nature de l'activité", 'data': {}, 'order': []}, 'type': {'text': 'Discipline', 'data': {}, 'order': []}, 'public': {'text': 'Public', 'data': {}, 'order': []}, 'day': {'text': 'Jours', 'data': {}, 'order': []}, 'place': {'text': 'Lieu', 'data': {}, 'order': []}, }, 'all_criterias_order': ['service', 'nature', 'type', 'public', 'day', 'place'], }, 'err': 0, } def test_read_activity_list_no_nature(activity_service, con, app, freezer): def request_check(request): assert request.schoolyear == 1970 assert request.dateStartCalend == datetime.datetime(2023, 3, 1, 0, 0) assert request.dateEndCalend == datetime.datetime(2025, 2, 28, 0, 0) activity_service.add_soap_response( 'readActivityList', get_xml_file('R_read_activity_list_no_nature.xml'), request_check=request_check ) url = get_endpoint('read-activity-list') freezer.move_to('2024-02-29') con.referential.filter(referential_name='Activity').delete() con.update_catalog_referential() resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 0 def test_get_person_activity_list(activity_service, con, app): def request_check(request): assert request.yearSchool == 2022 activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), request_check=request_check, ) url = get_endpoint('get-person-activity-list') con.extrasco_nature_codes = 'V' con.save() params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'nature': '', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10051141965', 'Activité modèle'), ('A10053187087', 'Vacances Ete 2023'), ('A10053187065', 'Vacances Hivers 2023'), ] data = resp.json['data'][1] del data['unitInfoList'][1] assert data == { 'activity': { 'activityType': { 'code': 'LOI_VAC', 'libelle': 'Loisirs - Vacances', 'natureSpec': {'code': 'V', 'libelle': 'Vacances Enfants'}, }, 'blocNoteList': [], 'coderegie': None, 'idActivity': 'A10053187087', 'idService': 'A10049329051', 'libelle1': 'Vacances Ete 2023', 'libelle2': None, 'paiementPortal': 'I', 'typInsPortal': 'I', 'service': { 'id': 'A10049329051', 'lib1': 'Sorties', 'lib2': None, 'text': 'Sorties', 'idDir': 'A10049327621', 'direction': { 'id': 'A10049327621', 'lib1': 'DASC', 'lib2': "Direction de l'action socioculturelle", 'text': 'DASC', }, }, }, 'id': 'A10053187087', 'incompleteFamilyFile': False, 'indicatorBlockSubscribeList': [], 'text': 'Vacances Ete 2023', 'unitInfoList': [ { 'com': None, 'dateEnd': '2023-07-31T00:00:00+02:00', 'dateStart': '2023-07-10T00:00:00+02:00', 'idIns': None, 'idUnit': 'A10053187241', 'libelle': 'Juillet', 'placeInfoList': [ { 'capacityInfo': {'controlOK': True, 'message': None}, 'idIns': None, 'place': { 'ageEnd': None, 'ageStart': None, 'blocNoteList': [], 'etatIns': None, 'idIns': None, 'idPlace': 'A10053179604', 'latitude': 1, 'lib1': 'ALEX JANY', 'lib2': None, 'longitude': 2, 'adresse': None, 'startHour': None, 'startHour2': None, 'endHour': None, 'endHour2': None, }, } ], }, ], } assert resp.json['meta']['person']['numPerson'] == 246423 params['text_template'] = '{{ unitInfoList.0.libelle }}' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10051141965', 'Inscription 2ème semestre'), ('A10053187087', 'Juillet'), ('A10053187065', 'Semaine 2'), ] del params['text_template'] params['type_ids'] = 'LOI_VAC,,' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10053187087', 'Vacances Ete 2023'), ('A10053187065', 'Vacances Hivers 2023'), ] params['type_ids'] = '' params['nature'] = 'LOISIR' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10051141965', 'Activité modèle'), ] params['nature'] = 'EXTRASCO' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10053187087', 'Vacances Ete 2023'), ('A10053187065', 'Vacances Hivers 2023'), ] def test_get_person_activity_list_not_linked_error(con, app): url = get_endpoint('get-person-activity-list') params = { 'NameID': 'local', 'family_id': '', 'person_id': '246423', 'nature': '', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_person_activity_list_date_error(con, app): url = get_endpoint('get-person-activity-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'nature': '', 'start_date': 'bad', 'end_date': '2023-08-31', } resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2022-09-01' params['end_date'] = 'bad' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2023-09-01' params['end_date'] = '2023-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params['start_date'] = '2022-09-01' params['end_date'] = '2024-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_get_person_unit_list(activity_service, con, app): def request_check(request): assert request.yearSchool == 2022 activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), request_check=request_check, ) url = get_endpoint('get-person-unit-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10053187241', 'Juillet'), ('A10053187242', 'Aout'), ] assert resp.json['data'][0] == { 'com': None, 'dateEnd': '2023-07-31T00:00:00+02:00', 'dateStart': '2023-07-10T00:00:00+02:00', 'id': 'A10053187241', 'idIns': None, 'idUnit': 'A10053187241', 'libelle': 'Juillet', 'placeInfoList': [ { 'capacityInfo': {'controlOK': True, 'message': None}, 'idIns': None, 'place': { 'adresse': None, 'ageEnd': None, 'ageStart': None, 'blocNoteList': [], 'endHour': None, 'endHour2': None, 'etatIns': None, 'idIns': None, 'idPlace': 'A10053179604', 'latitude': 1, 'lib1': 'ALEX JANY', 'lib2': None, 'longitude': 2, 'startHour': None, 'startHour2': None, }, } ], 'text': 'Juillet', } assert resp.json['meta']['person']['numPerson'] == 246423 assert resp.json['meta']['activity']['activity']['idActivity'] == 'A10053187087' params['text_template'] = '{{ meta.activity.activity.activityType.natureSpec.libelle }} - {{ libelle }}' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A10053187241', 'Vacances Enfants - Juillet'), ('A10053187242', 'Vacances Enfants - Aout'), ] def test_get_person_unit_list_not_linked_error(con, app): url = get_endpoint('get-person-unit-list') params = { 'NameID': 'local', 'family_id': '', 'person_id': '246423', 'activity_id': 'A10053187087', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_person_unit_list_date_error(con, app): url = get_endpoint('get-person-unit-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'start_date': 'bad', 'end_date': '2023-08-31', } resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2022-09-01' params['end_date'] = 'bad' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2023-09-01' params['end_date'] = '2023-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params['start_date'] = '2022-09-01' params['end_date'] = '2024-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_get_person_unit_list_no_activity_error(activity_service, con, app): activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), ) url = get_endpoint('get-person-unit-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'plop', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'No activity plop for person' def test_get_person_place_list(activity_service, con, app): def request_check(request): assert request.yearSchool == 2022 activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), request_check=request_check, ) url = get_endpoint('get-person-place-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [('A10053179604', 'ALEX JANY')] assert resp.json['data'] == [ { 'capacityInfo': {'controlOK': True, 'message': None}, 'id': 'A10053179604', 'idIns': None, 'place': { 'adresse': None, 'ageEnd': None, 'ageStart': None, 'blocNoteList': [], 'endHour': None, 'endHour2': None, 'etatIns': None, 'idIns': None, 'idPlace': 'A10053179604', 'latitude': 1.0, 'lib1': 'ALEX JANY', 'lib2': None, 'longitude': 2.0, 'startHour': None, 'startHour2': None, }, 'text': 'ALEX JANY', } ] assert resp.json['meta']['person']['numPerson'] == 246423 assert resp.json['meta']['activity']['activity']['idActivity'] == 'A10053187087' assert resp.json['meta']['unit']['idUnit'] == 'A10053187241' assert resp.json['meta']['place_ids'] == ['A10053179604'] params['text_template'] = '{{ meta.unit.libelle }} - {{ place.lib1 }}' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [('A10053179604', 'Juillet - ALEX JANY')] def test_get_person_place_list_not_linked_error(con, app): url = get_endpoint('get-person-place-list') params = { 'NameID': 'local', 'family_id': '', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_person_place_list_date_error(con, app): url = get_endpoint('get-person-place-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'start_date': 'bad', 'end_date': '2023-08-31', } resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2022-09-01' params['end_date'] = 'bad' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2023-09-01' params['end_date'] = '2023-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params['start_date'] = '2022-09-01' params['end_date'] = '2024-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_get_person_place_list_no_unit_error(activity_service, con, app): activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), ) url = get_endpoint('get-person-place-list') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'plop', 'unit_id': 'plop', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'No activity plop for person' params['activity_id'] = 'A10053187087' resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'No unit plop for person' def test_get_person_catalog_geojson(activity_service, con, app): def request_check(request): assert request.yearSchool == 2022 activity_service.add_soap_response( 'getPersonCatalogueActivity', get_xml_file('R_read_person_catalog_activity.xml'), request_check=request_check, ) url = get_endpoint('get-person-catalog-geojson') con.extrasco_nature_codes = 'V' con.save() params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'nature': '', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert len(resp.json['features']) == 1 assert resp.json == { 'err': 0, 'features': [ { 'geometry': {'coordinates': [2.0, 1.0], 'type': 'Point'}, 'properties': { 'id': 'A10053187087:A10053187241:A10053179604', 'text': 'Vacances Ete 2023 / Juillet / ALEX JANY', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'person': { 'dateBirth': '2014-04-01T00:00:00+02:00', 'firstname': 'BART', 'lastname': 'SIMPSON', 'numPerson': 246423, 'sexe': 'M', }, 'activity': { 'activity': { 'activityType': { 'code': 'LOI_VAC', 'libelle': 'Loisirs - Vacances', 'natureSpec': {'code': 'V', 'libelle': 'Vacances ' 'Enfants'}, }, 'blocNoteList': [], 'coderegie': None, 'idActivity': 'A10053187087', 'idService': 'A10049329051', 'libelle1': 'Vacances ' 'Ete 2023', 'libelle2': None, 'paiementPortal': 'I', 'service': { 'id': 'A10049329051', 'lib1': 'Sorties', 'lib2': None, 'text': 'Sorties', 'idDir': 'A10049327621', 'direction': { 'id': 'A10049327621', 'lib1': 'DASC', 'lib2': "Direction de l'action socioculturelle", 'text': 'DASC', }, }, 'typInsPortal': 'I', }, 'incompleteFamilyFile': False, 'indicatorBlockSubscribeList': [], }, 'unit': { 'com': None, 'dateEnd': '2023-07-31T00:00:00+02:00', 'dateStart': '2023-07-10T00:00:00+02:00', 'idIns': None, 'idUnit': 'A10053187241', 'libelle': 'Juillet', }, 'place': { 'capacityInfo': {'controlOK': True, 'message': None}, 'idIns': None, 'place': { 'adresse': None, 'ageEnd': None, 'ageStart': None, 'blocNoteList': [], 'endHour': None, 'endHour2': None, 'etatIns': None, 'idIns': None, 'idPlace': 'A10053179604', 'latitude': 1.0, 'lib1': 'ALEX JANY', 'lib2': None, 'longitude': 2.0, 'startHour': None, 'startHour2': None, }, }, }, 'type': 'Feature', }, ], 'type': 'FeatureCollection', } params['place_id'] = 'plop' resp = app.get(url, params=params) assert len(resp.json['features']) == 0 del params['place_id'] resp = app.get(url, params=params) assert len(resp.json['features']) == 1 params['unit_id'] = 'plop' resp = app.get(url, params=params) assert len(resp.json['features']) == 0 del params['unit_id'] resp = app.get(url, params=params) assert len(resp.json['features']) == 2 params['activity_id'] = 'plop' resp = app.get(url, params=params) assert len(resp.json['features']) == 0 del params['activity_id'] resp = app.get(url, params=params) assert len(resp.json['features']) == 4 params['type_ids'] = 'LOI_VAC,LOI_ADU' resp = app.get(url, params=params) assert len(resp.json['features']) == 4 params['type_ids'] = 'plop' resp = app.get(url, params=params) assert len(resp.json['features']) == 0 params['type_ids'] = '' params['nature'] = 'EXTRASCO' resp = app.get(url, params=params) assert len(resp.json['features']) == 4 assert [ x['properties']['activity']['activity']['activityType']['natureSpec']['code'] for x in resp.json['features'] ] == ['V', 'V', 'V', 'V'] params['nature'] = 'LOISIR' resp = app.get(url, params=params) assert len(resp.json['features']) == 0 # no lon/lat def test_get_person_catalog_geojson_not_linked_error(con, app): url = get_endpoint('get-person-catalog-geojson') params = { 'NameID': '', 'family_id': '', 'person_id': '246423', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_person_catalog_geojson_date_error(con, app): url = get_endpoint('get-person-catalog-geojson') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'start_date': 'bad', 'end_date': '2023-08-31', } resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2022-09-01' params['end_date'] = 'bad' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['start_date'] = '2023-09-01' params['end_date'] = '2023-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params['start_date'] = '2022-09-01' params['end_date'] = '2024-08-31' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_read_activity_nature_list(con, app): url = get_endpoint('read-activity-nature-list') resp = app.get(url) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('A', 'Accueil Périscolaire'), ('P', 'Loisirs'), ('L', 'Loisirs Enfants'), ('S', 'Loisirs Senior'), ('E', 'Petite Enfance'), ('R', 'Restauration Scolaire'), ('V', 'Vacances Enfants'), ] assert resp.json['data'][0] == { 'id': 'A', 'code': 'A', 'text': 'Accueil Périscolaire', 'libelle': 'Accueil Périscolaire', 'activityTypeList': [ {'code': 'ACCMAT', 'libelle': 'Accueil du matin'}, {'code': 'ACCMIDI', 'libelle': 'Accueil du mercredi'}, {'code': 'ACCPERI', 'libelle': 'Accueil périscolaire'}, {'code': 'ACCSOIR', 'libelle': 'Accueil du soir'}, ], } assert [(x['id'], x['text']) for x in resp.json['meta']['A']] == [ ('ACCMAT', 'Accueil du matin'), ('ACCMIDI', 'Accueil du mercredi'), ('ACCPERI', 'Accueil périscolaire'), ('ACCSOIR', 'Accueil du soir'), ] resp = app.get(url + '?nature_ids=P,L,S') assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']] == [ ('P', 'Loisirs'), ('L', 'Loisirs Enfants'), ('S', 'Loisirs Senior'), ] def test_read_ape_indicator_list(con, app): url = get_endpoint('read-ape-indicators-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 3 for item in resp.json['data']: assert 'id' in item assert 'text' in item assert len(resp.json['meta']) assert len(resp.json['meta']['INDI_APE_ENF']) == 5 for item in resp.json['meta']['INDI_APE_ENF']: assert 'id' in item assert 'text' in item def test_get_person_subscription_info(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data'] == { 'controlResult': {'controlOK': True, 'message': None}, 'personInfo': { 'idMaelis': 'S10055586371', 'num': 261768, 'lastname': 'NICO', 'firstname': 'BART', 'dateBirth': '2014-04-01T00:00:00+02:00', 'sexe': 'M', }, 'activity': { 'idActivity': 'A10049337567', 'libelle1': 'SEJOUR CORSE FEV 2023', 'libelle2': None, 'activityType': { 'code': 'EXTVAC', 'libelle': 'Vacances', 'natureSpec': {'code': 'X', 'libelle': 'Extrascolaire'}, }, 'typInsPortal': 'I', 'paiementPortal': 'I', 'blocNoteList': [], 'coderegie': None, 'idService': None, }, 'unit': { 'idUnit': 'A10049337568', 'libelle': 'SEJOUR CORSE FEV 2023', 'dateStart': '2023-02-13T00:00:00+01:00', 'dateEnd': '2023-02-24T00:00:00+01:00', 'placeInfoList': [], 'idIns': None, 'com': None, }, 'place': { 'idPlace': 'A10049337572', 'lib1': 'SEJOUR', 'lib2': None, 'idIns': None, 'etatIns': None, 'ageStart': None, 'ageEnd': None, 'blocNoteList': [], 'longitude': None, 'latitude': None, 'adresse': None, 'endHour': None, 'endHour2': None, 'startHour': None, 'startHour2': None, }, 'calendarGeneration': {'code': 'FORBIDDEN', 'value': 'I'}, 'weeklyCalendarActivity': { 'dayWeekInfoList': [ {'dayNum': 1, 'isOpen': True}, {'dayNum': 2, 'isOpen': True}, {'dayNum': 3, 'isOpen': True}, {'dayNum': 4, 'isOpen': True}, {'dayNum': 5, 'isOpen': True}, {'dayNum': 6, 'isOpen': True}, {'dayNum': 7, 'isOpen': True}, ] }, 'openDayList': [], 'unitScheduleList': [], 'billingInformation': None, 'action': 'ADD_SUBSCRIBE', 'indicatorList': [], 'indicators': {}, 'recurrent_week': [], 'conveyance': None, 'agenda': [], } # no date provided del params['ref_date'] resp = app.get(url, params=params) assert resp.json['err'] == 0 # passing an empty date params['ref_date'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 def test_get_person_subscription_info_with_recurrent_week(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='311323', name_id='local') params['NameID'] = 'local' params['family_id'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data'] == { 'controlResult': {'controlOK': True, 'message': None}, 'personInfo': { 'idMaelis': 'S10055586371', 'num': 261768, 'lastname': 'NICO', 'firstname': 'BART', 'dateBirth': '2014-04-01T00:00:00+02:00', 'sexe': 'M', }, 'activity': { 'blocNoteList': [], 'coderegie': None, 'idActivity': 'A10055585858', 'idService': None, 'libelle1': 'ADL ELEMENTAIRE Maourine FEVRIER 22/23', 'libelle2': None, 'activityType': { 'code': 'EXTVAC', 'libelle': 'Vacances', 'natureSpec': {'code': 'X', 'libelle': 'Extrascolaire'}, }, 'typInsPortal': 'I', 'paiementPortal': 'I', }, 'unit': { 'idUnit': 'A10055585860', 'libelle': 'ADL ELEMENTAIRE Maourine FEVRIER 22/23', 'dateStart': '2023-02-13T00:00:00+01:00', 'dateEnd': '2023-02-24T00:00:00+01:00', 'placeInfoList': [], 'com': None, 'idIns': None, }, 'place': { 'idPlace': 'M10053212196', 'lib1': 'MAOURINE (la) ELEMENTAIRE', 'lib2': None, 'idIns': None, 'etatIns': None, 'ageStart': None, 'ageEnd': None, 'blocNoteList': [], 'longitude': None, 'latitude': None, 'adresse': None, 'startHour': None, 'startHour2': None, 'endHour': None, 'endHour2': None, }, 'calendarGeneration': {'code': 'NOT_REQUIRED', 'value': 'F'}, 'weeklyCalendarActivity': { 'dayWeekInfoList': [ {'dayNum': 1, 'isOpen': True}, {'dayNum': 2, 'isOpen': True}, {'dayNum': 3, 'isOpen': True}, {'dayNum': 4, 'isOpen': True}, {'dayNum': 5, 'isOpen': True}, {'dayNum': 6, 'isOpen': False}, {'dayNum': 7, 'isOpen': False}, ] }, 'openDayList': [], 'unitScheduleList': [ { 'unit': { 'idActivity': None, 'idUnit': 'A10055586816', 'libelle': 'Journée', 'calendarLetter': 'C', 'dateDeb': '2023-02-13T00:00:00+01:00', 'dateFin': '2023-02-24T00:00:00+01:00', }, 'datePrevMin': None, 'dayInfoList': [], }, { 'unit': { 'idActivity': None, 'idUnit': 'A10055586815', 'libelle': 'Demi-journée', 'calendarLetter': 'B', 'dateDeb': '2023-02-13T00:00:00+01:00', 'dateFin': '2023-02-24T00:00:00+01:00', }, 'datePrevMin': None, 'dayInfoList': [], }, ], 'billingInformation': None, 'action': 'ADD_SUBSCRIBE', 'conveyance': None, 'indicatorList': [], 'indicators': {}, 'agenda': [], 'recurrent_week': [ {'id': '1-C', 'day': 'Lundi', 'label': 'Journée', 'overlaps': ['1-B'], 'text': 'Lundi Journée'}, { 'id': '1-B', 'day': 'Lundi', 'label': 'Demi-journée', 'overlaps': ['1-C'], 'text': 'Lundi Demi-journée', }, {'id': '2-C', 'day': 'Mardi', 'label': 'Journée', 'overlaps': ['2-B'], 'text': 'Mardi Journée'}, { 'id': '2-B', 'day': 'Mardi', 'label': 'Demi-journée', 'overlaps': ['2-C'], 'text': 'Mardi Demi-journée', }, { 'id': '3-C', 'day': 'Mercredi', 'label': 'Journée', 'overlaps': ['3-B'], 'text': 'Mercredi Journée', }, { 'id': '3-B', 'day': 'Mercredi', 'label': 'Demi-journée', 'overlaps': ['3-C'], 'text': 'Mercredi Demi-journée', }, {'id': '4-C', 'day': 'Jeudi', 'label': 'Journée', 'overlaps': ['4-B'], 'text': 'Jeudi Journée'}, { 'id': '4-B', 'day': 'Jeudi', 'label': 'Demi-journée', 'overlaps': ['4-C'], 'text': 'Jeudi Demi-journée', }, { 'id': '5-C', 'day': 'Vendredi', 'label': 'Journée', 'overlaps': ['5-B'], 'text': 'Vendredi Journée', }, { 'id': '5-B', 'day': 'Vendredi', 'label': 'Demi-journée', 'overlaps': ['5-C'], 'text': 'Vendredi Demi-journée', }, ], } # no date provided del params['ref_date'] resp = app.get(url, params=params) assert resp.json['err'] == 0 # passing an empty date params['ref_date'] = '' resp = app.get(url, params=params) assert resp.json['err'] == 0 def test_get_person_subscription_info_with_recurrent_week_required(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week_required.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data']['calendarGeneration'] == {'code': 'REQUIRED', 'value': 'O'} assert any([x['isOpen'] for x in resp.json['data']['weeklyCalendarActivity']['dayWeekInfoList']]) # recurrent_week is not display to user assert resp.json['data']['recurrent_week'] == [] def test_get_person_subscription_info_with_recurrent_week_required_error(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week_required_error.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == 'connector do not manage activity having both calendarGeneration required and several units' ) def test_get_person_subscription_info_with_recurrent_week_forbidden(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data']['calendarGeneration'] == {'code': 'FORBIDDEN', 'value': 'I'} assert any([x['isOpen'] for x in resp.json['data']['weeklyCalendarActivity']['dayWeekInfoList']]) # recurrent_week is not display to user assert resp.json['data']['recurrent_week'] == [] def test_get_person_subscription_info_with_conveyance(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '322423', 'person_id': '261768', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'ref_date': '', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [ (x['id'], x['text']) for x in resp.json['data']['conveyance']['morningJourney']['depositPlaceList'] ] == [('A10053179757', 'ARGOULETS'), ('A10053179757', 'ARGOULETS')] assert [ (x['id'], x['text']) for x in resp.json['data']['conveyance']['afternoonJourney']['depositPlaceList'] ] == [('A10053179757', 'ARGOULETS'), ('A10053179757', 'ARGOULETS')] def test_get_person_subscription_info_with_conveyance_no_morning(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance_no_morning.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '322423', 'person_id': '261768', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'ref_date': '', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert not resp.json['data']['conveyance']['morningJourney'] assert [ (x['id'], x['text']) for x in resp.json['data']['conveyance']['afternoonJourney']['depositPlaceList'] ] == [('A10053179757', 'ARGOULETS'), ('A10053179757', 'ARGOULETS')] def test_get_person_subscription_info_with_indicators(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_indicator_list.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '322423', 'person_id': '261768', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'ref_date': '', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert [(x['id'], x['text']) for x in resp.json['data']['indicatorList']] == [ ('AUT_SEUL', 'Autorisation à partir seul'), ] assert 'AUT_SEUL' in resp.json['data']['indicators'] def test_get_person_subscription_info_with_agenda(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_open_day_list.xml') ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '322423', 'person_id': '261768', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'ref_date': '2023-03-11', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert len(resp.json['data']['agenda']) == 15 assert resp.json['data']['agenda'][6:10] == [ { 'id': '261768:A10049354913:A10049354915:2023-05-10', 'text': 'Wednesday 10 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-10T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-05-10', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine', 'activity_id': 'A10049354915', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-17', 'text': 'Wednesday 17 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-17T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-05-17', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine', 'activity_id': 'A10049354915', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-24', 'text': 'Wednesday 24 May 2023', 'prefill': False, 'disabled': True, 'details': { 'day': '2023-05-24T00:00:00+02:00', 'hasPlace': False, 'day_str': '2023-05-24', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine', 'activity_id': 'A10049354915', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-31', 'text': 'Wednesday 31 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-31T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-05-31', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine', 'activity_id': 'A10049354915', }, }, ] def test_get_person_subscription_info_with_agenda_multi_units(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_open_day_list_with_multi_units.xml') ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '322423', 'person_id': '261768', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'ref_date': '2023-03-11', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert len(resp.json['data']['agenda']) == 10 assert resp.json['data']['agenda'] == [ { 'id': '261768:A10049354913:A10055597162:2023-04-11', 'text': 'Tuesday 11 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-11T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-11', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Demi-journée)', 'activity_id': 'A10055597162', }, }, { 'id': '261768:A10049354913:A10055597164:2023-04-11', 'text': 'Tuesday 11 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-11T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-11', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Journée)', 'activity_id': 'A10055597164', }, }, { 'id': '261768:A10049354913:A10055597162:2023-04-12', 'text': 'Wednesday 12 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-12T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-12', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Demi-journée)', 'activity_id': 'A10055597162', }, }, { 'id': '261768:A10049354913:A10055597164:2023-04-12', 'text': 'Wednesday 12 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-12T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-12', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Journée)', 'activity_id': 'A10055597164', }, }, { 'id': '261768:A10049354913:A10055597162:2023-04-13', 'text': 'Thursday 13 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-13T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-13', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Demi-journée)', 'activity_id': 'A10055597162', }, }, { 'id': '261768:A10049354913:A10055597164:2023-04-13', 'text': 'Thursday 13 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-13T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-13', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Journée)', 'activity_id': 'A10055597164', }, }, { 'id': '261768:A10049354913:A10055597162:2023-04-14', 'text': 'Friday 14 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-14T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-14', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Demi-journée)', 'activity_id': 'A10055597162', }, }, { 'id': '261768:A10049354913:A10055597164:2023-04-14', 'text': 'Friday 14 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-14T00:00:00+02:00', 'hasPlace': True, 'day_str': '2023-04-14', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Journée)', 'activity_id': 'A10055597164', }, }, { 'id': '261768:A10049354913:A10055597162:2023-04-19', 'text': 'Wednesday 19 April 2023', 'prefill': False, 'disabled': True, 'details': { 'day': '2023-04-19T00:00:00+02:00', 'hasPlace': False, 'day_str': '2023-04-19', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Demi-journée)', 'activity_id': 'A10055597162', }, }, { 'id': '261768:A10049354913:A10055597164:2023-04-19', 'text': 'Wednesday 19 April 2023', 'prefill': False, 'disabled': True, 'details': { 'day': '2023-04-19T00:00:00+02:00', 'hasPlace': False, 'day_str': '2023-04-19', 'status_color': 'white', 'activity_label': 'ADL Élémentaire Maourine (Journée)', 'activity_id': 'A10055597164', }, }, ] def test_get_person_subscription_info_error(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_error.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data']['controlResult'] == { 'controlOK': False, 'message': 'E1019 : Il existe déjà une inscription à cette unité', } def test_get_person_subscription_info_error2(activity_service, con, app): activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_error2.xml'), ) url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['data']['controlResult']['controlOK'] is False assert ( 'E1018 : Il existe déjà une inscription à une unité incompatible' in resp.json['data']['controlResult']['message'] ) def test_get_person_subscription_info_not_linked_error(con, app): url = get_endpoint('get-person-subscription-info') params = { 'NameID': 'local', 'family_id': '', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '2023-01-22', } resp = app.get(url, params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_person_subscription_info_date_error(con, app): url = get_endpoint('get-person-subscription-info') params = { 'NameID': '', 'family_id': '311323', 'person_id': '246423', 'activity_id': 'A10053187087', 'unit_id': 'A10053187241', 'place_id': 'A10053179604', 'ref_date': '22/01/2023', } resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' params['ref_date'] = '2023-02-29' resp = app.get(url, params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == '2023-02-29 is not a valid date' def test_add_person_basket_subscription(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 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'] == { 'controlResult': {'controlOK': True, 'message': None}, 'basket': { 'codeRegie': 109, 'dateAdd': '2023-04-20T20:41:58+02:00', 'dateMaj': '2023-04-20T20:40:50+02:00', 'delai': 30, 'id': 'S10055641698', 'idFam': 'S10055638201', 'lignes': [ { 'personneInfo': { 'dateBirth': '2014-04-01T00:00:00+02:00', 'firstname': 'BART', 'lastname': 'EO_NICOLAS', 'numPerson': 266145, 'sexe': 'M', }, 'idPanier': 'S10055641698', 'id': 'S10055641705', 'idIns': 'S10055641658', 'idInsLieu': 'S10055641703', 'inscription': { 'dateDeb': '2023-02-01T00:00:00+01:00', 'dateFin': '2023-06-30T00:00:00+02:00', 'idAct': 'A10053179798', 'idInsAct': 'S10055641702', 'idInsLieu': 'S10055641703', 'idLieu': 'A10053179757', 'idRegie': 'A10049327667', 'idUnit': 'A10053179809', 'libAct': 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', 'libAct2': None, 'libLieu': 'ARGOULETS', 'libUnit': 'MERCREDI - 15h30/17h - 8/15Ans', }, 'qte': 1.0, 'prixUnit': 150.0, 'montant': 150.0, 'datEchn': '2023-12-31T00:00:00+01:00', 'dateMaj': '2023-04-20T20:41:58+02:00', }, { 'personneInfo': { 'dateBirth': '2016-05-09T00:00:00+02:00', 'firstname': 'LISA', 'lastname': 'EO_NICOLAS', 'numPerson': 266148, 'sexe': 'F', }, 'idPanier': 'S10055641698', 'id': 'S10055641699', 'idIns': 'S10055641665', 'idInsLieu': 'S10055641696', 'inscription': { 'dateDeb': '2023-02-01T00:00:00+01:00', 'dateFin': '2023-06-30T00:00:00+02:00', 'idAct': 'A10053179798', 'idInsAct': 'S10055641695', 'idInsLieu': 'S10055641696', 'idLieu': 'A10053179757', 'idRegie': 'A10049327667', 'idUnit': 'A10053179809', 'libAct': 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', 'libAct2': None, 'libLieu': 'ARGOULETS', 'libUnit': 'MERCREDI - 15h30/17h - 8/15Ans', }, 'qte': 1.0, 'prixUnit': 150.0, 'montant': 150.0, 'datEchn': '2023-12-31T00:00:00+01:00', 'dateMaj': '2023-04-20T20:40:50+02:00', }, ], }, } assert con.subscription_set.count() == 0 params['recurrent_week'] = None resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_with_recurrent_week(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 1, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'B'}, {'dayNum': 2, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'C'}, ] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': ['1-B', '2-C'], } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 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 def test_add_person_basket_subscription_with_recurrent_week_empty(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 @pytest.mark.parametrize( 'is_active_value, is_active_result', [ (True, True), (False, False), (1, True), (0, False), ('oui', True), ('NON', False), ], ) def test_add_person_basket_subscription_with_indicators( is_active_value, is_active_result, family_service, activity_service, con, app ): def request_check(request): assert [(x['code'], x['isActive']) for x in request.indicatorList] == [('AUT_SEUL', is_active_result)] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_indicator_list.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'indicatorList/0/code': 'AUT_SEUL', 'indicatorList/0/isActive': is_active_value, } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_with_indicators_skipping_undef_isActive_value( family_service, activity_service, con, app ): def request_check(request): assert request.indicatorList == [] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_indicator_list.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'indicatorList/0/code': 'AUT_SEUL', 'indicatorList/0/isActive': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_with_recurrent_week_required( family_service, activity_service, con, app ): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 3, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'B'}, ] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week_required.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_with_recurrent_week_forbidden_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': ['1-B', '2-C'], } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "recurrent item '1-B' is not available no on this activity" def test_add_basket_subscription_providing_wcs_demand(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) Link.objects.create(resource=con, family_id='1312', name_id='local') url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data']['controlResult']['controlOK'] is True assert resp.json['data']['basket']['codeRegie'] == 109 # unrelated basket lines was removed from response assert all([x['personneInfo']['numPerson'] == 266145 for x in resp.json['data']['basket']['lignes']]) subscription = con.subscription_set.get(wcs_form_number='13-12') assert ( subscription.wcs_form_api_url == 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/' ) assert subscription.created is not None assert subscription.regie_id == '109' assert subscription.family_id == '1312' assert subscription.invoice is None assert subscription.status() == 'pending_basket' assert subscription.maelis_data == resp.json['data'] assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # refuse more subcription related to this demand resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "'13-12' wcs demand is already linked to a subscription" def test_add_person_basket_subscription_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket_error.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'E1019 : Il existe déjà une inscription à cette unité' def test_add_person_basket_subscription_not_linked_error(con, app): url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } 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_add_person_basket_subscription_wrong_person_id_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': 'plop', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' RL or child on '311323' family" Link.objects.create(resource=con, family_id='311323', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' RL or child on '311323' family" def test_add_person_basket_subscription_with_conveyance(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.conveyanceSubscribe) == { 'idPlaceMorning': 'A10053179757', 'idPlaceAfternoon': 'A10053179757', } family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'conveyanceSubscribe/idPlaceMorning': 'A10053179757', 'conveyanceSubscribe/idPlaceAfternoon': 'A10053179757', } resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_providing_conveyance_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'conveyanceSubscribe/idPlaceMorning': 'A10053179757', } resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'no conveyance defined on this activity' def test_add_person_basket_subscription_with_conveyance_not_found(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'conveyanceSubscribe/idPlaceMorning': 'plop', 'conveyanceSubscribe/idPlaceAfternoon': 'A10053179757', } resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'no "plop" place defined on "morningJourney" conveyance' params['conveyanceSubscribe/idPlaceMorning'] = '' params['conveyanceSubscribe/idPlaceAfternoon'] = 'plop' resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'no "plop" place defined on "afternoonJourney" conveyance' def test_add_person_basket_subscription_with_none_conveyance(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.conveyanceSubscribe) == { 'idPlaceMorning': None, 'idPlaceAfternoon': None, } family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance.xml'), ) activity_service.add_soap_response( 'addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml'), request_check=request_check, ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'conveyanceSubscribe/idPlaceMorning': '', 'conveyanceSubscribe/idPlaceAfternoon': None, } resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 0 def test_add_person_basket_subscription_with_indicators_schema_error(con, app): url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'indicatorList/0/code': 'AUTH_SEUL', 'indicatorList/0/isActive': 'plop', } resp = app.post_json(url + '?family_id=311323', params=params, status=400) assert resp.json['err'] == 1 assert 'JSONValidationError' in resp.json['err_class'] def test_add_person_basket_subscription_with_indicators_wrong_referential_key_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_indicator_list.xml'), ) url = get_endpoint('add-person-basket-subscription') params = { 'person_id': '613880', 'activity_id': 'A10049354913', 'unit_id': 'A10049354915', 'place_id': 'M10053212196', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'indicatorList/0/code': 'plop', 'indicatorList/0/isActive': 'False', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "indicatorList/0/code key value 'plop' do not belong to activity indicators" ) def test_add_person_subscription(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe.xml'), ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 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'] == {'controlOK': True, 'message': None} def test_add_person_subscription_with_recurrent_week(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 1, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'B'}, {'dayNum': 2, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'C'}, ] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe.xml'), request_check=request_check, ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': ['1-B', '2-C'], } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 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 def test_add_person_subscription_with_recurrent_week_empty(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe.xml'), request_check=request_check, ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 def test_add_person_subscription_with_recurrent_week_required(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.dayWeekInfoList) == [ {'dayNum': 3, 'isPresent': True, 'isOpen': None, 'calendarLetter': 'B'}, ] family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_recurrent_week_required.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe.xml'), request_check=request_check, ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': '', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 0 def test_add_person_subscription_with_recurrent_week_forbidden_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'recurrent_week': ['1-B', '2-C'], } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "recurrent item '1-B' is not available no on this activity" def test_add_person_subscription_with_conveyance(family_service, activity_service, con, app): def request_check(request): assert serialize_object(request.conveyanceSubscribe) == { 'idPlaceMorning': 'A10053179757', 'idPlaceAfternoon': 'A10053179757', } family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) activity_service.add_soap_response( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info_with_conveyance.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe.xml'), request_check=request_check, ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10053179798', 'unit_id': 'A10053179803', 'place_id': 'A10053179757', 'start_date': '2022-09-01', 'end_date': '2023-08-31', 'conveyanceSubscribe/idPlaceMorning': 'A10053179757', 'conveyanceSubscribe/idPlaceAfternoon': 'A10053179757', } resp = app.post_json(url + '?family_id=322423', params=params) assert resp.json['err'] == 0 def test_add_person_subscription_not_linked_error(con, app): url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } 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_add_person_subscription_wrong_person_id_error(family_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml')) url = get_endpoint('add-person-subscription') params = { 'person_id': 'plop', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' RL or child on '311323' family" Link.objects.create(resource=con, family_id='311323', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' RL or child on '311323' family" def test_add_person_subscription_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( 'getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml'), ) activity_service.add_soap_response( 'addPersonUnitSubscribe', get_xml_file('R_add_person_unit_subscribe_error.xml'), ) url = get_endpoint('add-person-subscription') params = { 'person_id': '613880', 'activity_id': 'A10051141965', 'unit_id': 'A10051141990', 'place_id': 'A10053179226', 'start_date': '2022-09-01', 'end_date': '2023-08-31', } resp = app.post_json(url + '?family_id=311323', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'E1019 : Il existe déjà une inscription à cette unité' def test_read_activity_agenda(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity.xml') ) url = get_endpoint('read-activity-agenda') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-05-01', 'end_date': '2023-05-31', } 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['extra_data'] == { 'start_date': '2023-05-01', 'end_date': '2023-05-31', } assert len(resp.json['data']) == 4 assert resp.json['data'] == [ { 'id': '261768:A10049354913:A10049354915:2023-05-10', 'text': 'Wednesday 10 May 2023', 'prefill': True, 'disabled': False, 'details': { 'day': '2023-05-10T00:00:00+02:00', 'scheduledPresence': 1, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'DEL_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-05-10', 'status_color': 'green', 'activity_label': '', 'activity_id': 'A10049354915', 'maelis_activity_id': 'A10049354913', 'maelis_unit_id': 'A10049354915', 'maelis_day_str': '10/05/2023', 'maelis_unit_label': 'SEMST2 ADL MERC. ELEM Maourine 22/23', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-17', 'text': 'Wednesday 17 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-17T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-05-17', 'status_color': 'white', 'activity_label': '', 'activity_id': 'A10049354915', 'maelis_activity_id': 'A10049354913', 'maelis_unit_id': 'A10049354915', 'maelis_day_str': '17/05/2023', 'maelis_unit_label': 'SEMST2 ADL MERC. ELEM Maourine 22/23', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-24', 'text': 'Wednesday 24 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-24T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-05-24', 'status_color': 'white', 'activity_label': '', 'activity_id': 'A10049354915', 'maelis_activity_id': 'A10049354913', 'maelis_unit_id': 'A10049354915', 'maelis_day_str': '24/05/2023', 'maelis_unit_label': 'SEMST2 ADL MERC. ELEM Maourine 22/23', }, }, { 'id': '261768:A10049354913:A10049354915:2023-05-31', 'text': 'Wednesday 31 May 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-05-31T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-05-31', 'status_color': 'white', 'activity_label': '', 'activity_id': 'A10049354915', 'maelis_activity_id': 'A10049354913', 'maelis_unit_id': 'A10049354915', 'maelis_day_str': '31/05/2023', 'maelis_unit_label': 'SEMST2 ADL MERC. ELEM Maourine 22/23', }, }, ] def test_read_activity_agenda_multi_units(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity_with_multi_units.xml') ) url = get_endpoint('read-activity-agenda') params = { 'person_id': '261771', 'activity_id': 'A10055597158', 'start_date': '2023-04-01', 'end_date': '2023-04-30', } 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['extra_data'] == { 'start_date': '2023-04-01', 'end_date': '2023-04-30', } assert len(resp.json['data']) == 10 assert resp.json['data'][:8] == [ { 'id': '261771:A10055597158:A10055597162:2023-04-11', 'text': 'Tuesday 11 April 2023', 'prefill': True, 'disabled': False, 'details': { 'day': '2023-04-11T00:00:00+02:00', 'scheduledPresence': 1, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'DEL_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-11', 'status_color': 'green', 'activity_label': 'Demi-journée', 'activity_id': 'A10055597162', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597162', 'maelis_day_str': '11/04/2023', 'maelis_unit_label': 'Demi-journée', }, }, { 'id': '261771:A10055597158:A10055597164:2023-04-11', 'text': 'Tuesday 11 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-11T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-11', 'status_color': 'white', 'activity_label': 'Journée', 'activity_id': 'A10055597164', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597164', 'maelis_day_str': '11/04/2023', 'maelis_unit_label': 'Journée', }, }, { 'id': '261771:A10055597158:A10055597162:2023-04-12', 'text': 'Wednesday 12 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-12T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-12', 'status_color': 'white', 'activity_label': 'Demi-journée', 'activity_id': 'A10055597162', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597162', 'maelis_day_str': '12/04/2023', 'maelis_unit_label': 'Demi-journée', }, }, { 'id': '261771:A10055597158:A10055597164:2023-04-12', 'text': 'Wednesday 12 April 2023', 'prefill': True, 'disabled': False, 'details': { 'day': '2023-04-12T00:00:00+02:00', 'scheduledPresence': 1, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'DEL_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-12', 'status_color': 'green', 'activity_label': 'Journée', 'activity_id': 'A10055597164', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597164', 'maelis_day_str': '12/04/2023', 'maelis_unit_label': 'Journée', }, }, { 'id': '261771:A10055597158:A10055597162:2023-04-13', 'text': 'Thursday 13 April 2023', 'prefill': True, 'disabled': False, 'details': { 'day': '2023-04-13T00:00:00+02:00', 'scheduledPresence': 1, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'DEL_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-13', 'status_color': 'green', 'activity_label': 'Demi-journée', 'activity_id': 'A10055597162', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597162', 'maelis_day_str': '13/04/2023', 'maelis_unit_label': 'Demi-journée', }, }, { 'id': '261771:A10055597158:A10055597164:2023-04-13', 'text': 'Thursday 13 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-13T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-13', 'status_color': 'white', 'activity_label': 'Journée', 'activity_id': 'A10055597164', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597164', 'maelis_day_str': '13/04/2023', 'maelis_unit_label': 'Journée', }, }, { 'id': '261771:A10055597158:A10055597162:2023-04-14', 'text': 'Friday 14 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-14T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-14', 'status_color': 'white', 'activity_label': 'Demi-journée', 'activity_id': 'A10055597162', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597162', 'maelis_day_str': '14/04/2023', 'maelis_unit_label': 'Demi-journée', }, }, { 'id': '261771:A10055597158:A10055597164:2023-04-14', 'text': 'Friday 14 April 2023', 'prefill': False, 'disabled': False, 'details': { 'day': '2023-04-14T00:00:00+02:00', 'scheduledPresence': 0, 'realPresence': 0, 'status': 'WRITABLE', 'action': 'ADD_PRES_PREVI', 'hasPlace': None, 'absence': None, 'day_str': '2023-04-14', 'status_color': 'white', 'activity_label': 'Journée', 'activity_id': 'A10055597164', 'maelis_activity_id': 'A10055597158', 'maelis_unit_id': 'A10055597164', 'maelis_day_str': '14/04/2023', 'maelis_unit_label': 'Journée', }, }, ] def test_read_activity_agenda_on_civil_year(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity.xml') ) url = get_endpoint('read-activity-agenda') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-01-01', 'end_date': '2023-12-31', } 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['extra_data'] == { 'start_date': '2023-01-01', 'end_date': '2023-12-31', } def test_read_activity_agenda_not_linked_error(con, app): url = get_endpoint('read-activity-agenda') resp = app.get( url + '?NameID=local&person_id=261768&activity_id=A10049354913&start_date=2023-05-01&end_date=2023-05-31' ) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_read_activity_agenda_date_error(con, app): url = get_endpoint('read-activity-agenda') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': 'bad', 'end_date': '2023-08-31', } resp = app.get(url + '?family_id=1312', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'invalid value for parameter "start_date (YYYY-MM-DD expected)"' params['start_date'] = '2022-09-01' params['end_date'] = 'bad' resp = app.get(url + '?family_id=1312', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'invalid value for parameter "end_date (YYYY-MM-DD expected)"' params['start_date'] = '2023-09-01' params['end_date'] = '2023-08-31' resp = app.get(url + '?family_id=1312', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' def test_read_activity_agenda_empty(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_empty.xml') ) url = get_endpoint('read-activity-agenda') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-05-01', 'end_date': '2023-05-31', } resp = app.get(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_update_activity_agenda(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity.xml') ) url = get_endpoint('update-activity-agenda') def request_check(request): assert request.numDossier == 1312 assert len(request.unitPersonDayInfoList) == 4 assert [dict(x) for x in serialize_object(request.unitPersonDayInfoList)] == [ { 'numPerson': 261768, 'idAct': 'A10049354913', 'idUni': 'A10049354915', 'date': datetime.datetime(2023, 5, 10, 0, 0), 'action': 'DEL_PRES_PREVI', }, { 'numPerson': 261768, 'idAct': 'A10049354913', 'idUni': 'A10049354915', 'date': datetime.datetime(2023, 5, 17, 0, 0), 'action': 'ADD_PRES_PREVI', }, { 'numPerson': 261768, 'idAct': 'A10049354913', 'idUni': 'A10049354915', 'date': datetime.datetime(2023, 5, 24, 0, 0), 'action': 'ADD_PRES_PREVI', }, { 'numPerson': 261768, 'idAct': 'A10049354913', 'idUni': 'A10049354915', 'date': datetime.datetime(2023, 5, 31, 0, 0), 'action': 'ADD_PRES_PREVI', }, ] activity_service.add_soap_response( 'updatePersonSchedule', get_xml_file('R_update_person_schedule_list_on_activity.xml'), request_check=request_check, ) params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-05-01', 'end_date': '2023-05-31', 'booking_list': [ #'261768:A10049354913:A10049354915:2023-05-10', # remove this one '261768:A10049354913:A10049354915:2023-05-17', # add this one # add 2 others but get errors from maelis '261768:A10049354913:A10049354915:2023-05-24', '261768:A10049354913:A10049354915:2023-05-31', ], } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json == { 'updated': True, 'count': 2, 'changes': [ {'activity_label': '', 'day': '2023-05-10', 'booked': False}, {'activity_label': '', 'day': '2023-05-17', 'booked': True}, ], 'err': 0, } with open(os.path.join(TEST_BASE_DIR, 'update_activity_agenda_template.html')) as fd: template = fd.read() message = render_to_string(template, {'form_workflow_data_ws_response': resp.json}) assert [l.strip() for l in message.split('\n') if l.strip()] == [ '

Réservations : 2023-05-17

', '

Annulations : 2023-05-10

', ] def test_update_activity_agenda_multi_units(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity_with_multi_units.xml') ) url = get_endpoint('update-activity-agenda') def request_check(request): assert request.numDossier == 1312 assert len(request.unitPersonDayInfoList) == 4 assert [dict(x) for x in serialize_object(request.unitPersonDayInfoList)] == [ { 'numPerson': 261771, 'idAct': 'A10055597158', 'idUni': 'A10055597162', 'date': datetime.datetime(2023, 4, 11, 0, 0), 'action': 'DEL_PRES_PREVI', }, { 'numPerson': 261771, 'idAct': 'A10055597158', 'idUni': 'A10055597162', 'date': datetime.datetime(2023, 4, 13, 0, 0), 'action': 'DEL_PRES_PREVI', }, { 'numPerson': 261771, 'idAct': 'A10055597158', 'idUni': 'A10055597164', 'date': datetime.datetime(2023, 4, 13, 0, 0), 'action': 'ADD_PRES_PREVI', }, { 'numPerson': 261771, 'idAct': 'A10055597158', 'idUni': 'A10055597164', 'date': datetime.datetime(2023, 4, 14, 0, 0), 'action': 'ADD_PRES_PREVI', }, ] activity_service.add_soap_response( 'updatePersonSchedule', get_xml_file('R_update_person_schedule.xml'), request_check=request_check, ) params = { 'person_id': '261771', 'activity_id': 'A10055597158', 'start_date': '2023-04-11', 'end_date': '2023-04-21', 'booking_list': [ # '261771:A10055597158:A10055597162:2023-04-11 # remove this one '261771:A10055597158:A10055597164:2023-04-12', # keep this one '261771:A10055597158:A10055597164:2023-04-13', # switch unit on this day '261771:A10055597158:A10055597164:2023-04-14', # add this one ], } resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json == { 'updated': True, 'count': 4, 'changes': [ {'activity_label': 'Demi-journée', 'day': '2023-04-11', 'booked': False}, {'activity_label': 'Demi-journée', 'day': '2023-04-13', 'booked': False}, {'activity_label': 'Journée', 'day': '2023-04-13', 'booked': True}, {'activity_label': 'Journée', 'day': '2023-04-14', 'booked': True}, ], 'err': 0, } with open(os.path.join(TEST_BASE_DIR, 'update_activity_agenda_template.html')) as fd: template = fd.read() message = render_to_string(template, {'form_workflow_data_ws_response': resp.json}) assert [x.strip() for x in message.split('\n') if x.strip()] == [ '

Demi-journée :

', '

Annulations : 2023-04-11, 2023-04-13

', '

Journée :

', '

Réservations : 2023-04-13, 2023-04-14

', ] def test_update_activity_agenda_no_changes(activity_service, con, app): activity_service.add_soap_response( 'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_on_activity.xml') ) url = get_endpoint('update-activity-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-05-01', 'end_date': '2023-05-31', 'booking_list': [ '261768:A10049354913:A10049354915:2023-05-10', ], } resp = app.post_json(url + '?NameID=local', params=params) assert resp.json == {'changes': [], 'count': 0, 'err': 0, 'errors': [], 'updated': False} def test_update_activity_agenda_not_linked_error(con, app): url = get_endpoint('update-activity-agenda') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-05-01', 'end_date': '2023-05-31', 'booking_list': [ '261768:A10049354913:A10049354915:2023-05-10', ], } 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_activity_agenda_date_error(con, app): url = get_endpoint('update-activity-agenda') Link.objects.create(resource=con, family_id='1312', name_id='local') params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': 'bad', 'end_date': '2023-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "start_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2022-09-01', 'end_date': 'bad', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "end_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2023-09-01', 'end_date': '2023-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date should be before end_date' params = { 'person_id': '261768', 'activity_id': 'A10049354913', 'start_date': '2022-09-01', 'end_date': '2024-08-31', 'booking_list': [], } resp = app.post_json(url + '?NameID=local', params=params, status=400) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)' def test_get_baskets(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('get-baskets') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 data = resp.json['data'] assert len(data[0]['lignes']) == 2 del data[0]['lignes'][1] assert data[0] == { 'id': 'S10055641698', 'text': 'DSBL', 'codeRegie': 109, 'dateAdd': '2023-04-20T12:05:51+02:00', 'dateMaj': '2023-04-20T12:05:42+02:00', 'delai': 30, 'idFam': 'S10055638201', 'lignes': [ { 'personneInfo': { 'dateBirth': '2016-05-09T00:00:00+02:00', 'firstname': 'LISA', 'lastname': 'EO_NICOLAS', 'numPerson': 266148, 'sexe': 'F', }, 'idPanier': 'S10055641698', 'id': 'S10055641668', 'idIns': 'S10055641665', 'idInsLieu': 'S10055641666', 'inscription': { 'dateDeb': '2023-02-01T00:00:00+01:00', 'dateFin': '2023-06-30T00:00:00+02:00', 'idAct': 'A10053179798', 'idInsAct': 'S10055641665', 'idInsLieu': 'S10055641666', 'idLieu': 'A10053179757', 'idRegie': 'A10049327667', 'idUnit': 'A10053179809', 'libAct': 'TEST ECOLE DES SPORTS 22/23 SEMESTRE 2 - MULTIACTIVITES', 'libAct2': None, 'libLieu': 'ARGOULETS', 'libUnit': 'MERCREDI - 15h30/17h - 8/15Ans', }, 'qte': 1.0, 'prixUnit': 150.0, 'montant': 150.0, 'datEchn': '2023-12-31T00:00:00+01:00', 'dateMaj': '2023-04-20T12:05:51+02:00', } ], } def test_get_baskets_having_wcs_demand(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) Link.objects.create(resource=con, family_id='1312', name_id='local') url = get_endpoint('get-baskets') # subscribe providing a wcs demand resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert subscription.trigger_status() == 'pending' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # get basket having subscription still here activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert subscription.trigger_status() == 'pending' # get basket having subscription removed activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggering' def test_get_baskets_no_family_error(activity_service, con, app): activity_service.add_soap_response( 'getFamilyBasket', get_xml_file('R_get_family_basket_family_error.xml') ) url = get_endpoint('get-baskets') resp = app.get(url + '?family_id=123') assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_get_baskets_having_wcs_demand_without_family(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) Link.objects.create(resource=con, family_id='1312', name_id='local') url = get_endpoint('get-baskets') # subscribe providing a wcs demand resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert subscription.trigger_status() == 'pending' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # get basket having family removed activity_service.add_soap_response( 'getFamilyBasket', get_xml_file('R_get_family_basket_family_error.xml') ) resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggering' def test_get_baskets_not_linked_error(con, app): url = get_endpoint('get-baskets') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_get_baskets_no_basket(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) url = get_endpoint('get-baskets') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_update_basket_time(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('updateBasketTime', get_xml_file('R_update_basket_time.xml')) url = get_endpoint('update-basket-time') params = {'basket_id': 'S10055641698'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', 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_basket_time_not_linked_error(con, app): url = get_endpoint('update-basket-time') params = {'basket_id': 'S10055641698'} 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_basket_time_no_basket(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) url = get_endpoint('update-basket-time') params = {'basket_id': 'S10055641698'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'S10055641698' basket on family" def test_update_basket_time_basket_not_found(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('update-basket-time') params = {'basket_id': 'plop'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' basket on family" def test_delete_basket_line(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response( 'deletePersonUnitBasket', get_xml_file('R_delete_person_unit_basket.xml') ) url = get_endpoint('delete-basket-line') params = {'basket_id': 'S10055641698', 'line_id': 'S10055641668'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert len(resp.json['data']['lignes']) == 2 # return the basket assert 'S10055641668' not in [x['id'] for x in resp.json['data']['lignes']] def test_delete_basket_line_not_linked_error(con, app): url = get_endpoint('delete-basket-line') params = {'basket_id': 'S10055641698', 'line_id': 'S10055641668'} 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_delete_basket_line_no_basket(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) url = get_endpoint('delete-basket-line') params = {'basket_id': 'S10055641698', 'line_id': 'S10055641668'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'S10055641698' basket on family" def test_delete_basket_line_basket_not_found(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('delete-basket-line') params = {'basket_id': 'plop', 'line_id': 'S10055641668'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' basket on family" def test_delete_basket_line_line_not_found(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('delete-basket-line') params = {'basket_id': 'S10055641698', 'line_id': 'plop'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' basket line on basket" def test_delete_basket(activity_service, con, app): def request_check(request): assert request.idUtilisat in ('local', 'Middle-office') activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response( 'deleteBasket', get_xml_file('R_delete_basket.xml'), request_check=request_check, ) url = get_endpoint('delete-basket') params = {'basket_id': 'S10055641698'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_delete_basket_not_linked_error(con, app): url = get_endpoint('delete-basket') params = {'basket_id': 'S10055641698'} 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_delete_basket_no_basket(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) url = get_endpoint('delete-basket') params = {'basket_id': 'S10055641698'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'S10055641698' basket on family" def test_delete_basket_not_found(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('delete-basket') params = {'basket_id': 'plop'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' basket on family" def test_validate_basket(family_service, activity_service, con, app): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # subscribe again resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266148', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/13/', 'form_number': '13-13', }, ) assert resp.json['err'] == 0 resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert resp.json['data'] == { 'idFam': 'S10055638201', 'factureLst': [ { 'numInvoice': '18', 'idInvoice': 'F10055641671', 'libelleTTF': 'DSBL TEST', 'regie': {'code': 109, 'libelle': 'DSBL'}, 'numFamily': 1312, 'name': 'EO_NICOLAS MARGE', 'refTIPI': None, 'amountInvoice': '300', 'amountPaid': '0', 'amountPaidTG': '0', 'dateInvoice': '2023-04-20T00:00:00+02:00', 'dateStartPayment': None, 'dateDeadline': '2023-12-31T00:00:00+01:00', 'dateDeadlinePayment': None, 'dateTIPI': None, 'authTIPI': None, 'pdfName': None, 'pdfFile': None, 'payer': { 'num': 266143, 'lastname': 'EO_NICOLAS', 'firstname': 'MARGE', 'sexe': None, 'civility': 'MME', 'mail': None, }, 'lineInvoiceList': [ { 'numLine': 1, 'numPers': '266148', 'idActivity': 'A10053179798', 'idUnit': 'A10053179809', 'idIns': 'S10055641665', 'libelleLine': 'PORTAIL MERCREDI - 15h30/17h - 8/15Ans', 'name': 'EO_NICOLAS LISA', 'dateStart': '2023-02-01T00:00:00+01:00', 'dateEnd': '2023-06-30T00:00:00+02:00', 'quantity': 1.0, 'unitPrice': 150.0, 'amountLine': '150', }, { 'numLine': 2, 'numPers': '266145', 'idActivity': 'A10053179798', 'idUnit': 'A10053179809', 'idIns': 'S10055641658', 'libelleLine': 'PORTAIL MERCREDI - 15h30/17h - 8/15Ans', 'name': 'EO_NICOLAS BART', 'dateStart': '2023-02-01T00:00:00+01:00', 'dateEnd': '2023-06-30T00:00:00+02:00', 'quantity': 1.0, 'unitPrice': 150.0, 'amountLine': '150', }, ], } ], 'idInsLst': ['S10055641665', 'S10055641658'], } invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert invoice.basket_generation_date is not None assert invoice.subscription_set.count() == 2 def test_validate_basket_having_a_previously_removed_line( family_service, activity_service, con, app, freezer ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_one_line.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 assert con.subscription_set.count() == 1 assert con.subscription_set.get(wcs_form_number='13-12').basket_removal_date is None # subscribe again freezer.move_to('2023-03-03 18:22:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266148', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/13/', 'form_number': '13-13', }, ) assert resp.json['err'] == 0 assert con.subscription_set.count() == 2 assert con.subscription_set.get(wcs_form_number='13-13').basket_removal_date is None # maelis send the basket with one deleted line freezer.move_to('2023-03-03 18:25:00') resp = app.get(get_endpoint('get-baskets') + '?family_id=1312') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.basket_removal_date.isoformat() == '2023-03-03T18:25:00+00:00' assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggering' # validate basket with maelis providing the previously deleted line freezer.move_to('2023-03-03 18:30:00') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 # created invoice is not linked to the removed subscription invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert invoice.basket_generation_date.isoformat() == '2023-03-03T18:30:00+00:00' assert invoice.subscription_set.count() == 1 assert invoice.subscription_set.get() == con.subscription_set.get(wcs_form_number='13-13') def test_validate_basket_error_having_all_previously_removed_line( family_service, activity_service, con, app, freezer ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 assert con.subscription_set.count() == 1 # maelis send an empty basket freezer.move_to('2023-03-03 18:25:00') resp = app.get(get_endpoint('get-baskets') + '?family_id=1312') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.basket_removal_date.isoformat() == '2023-03-03T18:25:00+00:00' assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggering' # refuse to validate the basket so as to prevent maelis building an invoice freezer.move_to('2023-03-03 18:30:00') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "Basket 'S10055641698' has no related pending subscription" def test_validate_basket_not_linked_error(con, app): url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} 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_validate_basket_no_basket(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'S10055641698' basket on family" def test_validate_basket_not_found(activity_service, con, app): activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'plop'} resp = app.post_json(url + '?family_id=1312', params=params) assert resp.json['err'] == 1 assert resp.json['err_desc'] == "no 'plop' basket on family" def test_validate_basket_no_invoice(family_service, activity_service, con, app, caplog): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket_no_invoice.xml')) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert caplog.records[-1].levelno == logging.ERROR assert ( caplog.records[-1].message == "Pas de facture à la validation du panier 'S10055641698' sur la famille '1312'" ) def test_cancel_basket_invoice_cron( family_service, activity_service, invoice_service, con, app, freezer, caplog ): def request_check(request): assert request == 'F10055641671' family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), request_check=request_check, ) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 data = resp.json['data']['factureLst'][0] assert data['regie']['code'] == 109 assert data['numInvoice'] == '18' assert data['idInvoice'] == 'F10055641671' assert caplog.records[-1].levelno == logging.INFO assert caplog.records[-1].message == 'Ajout de sur la famille \'1312\'' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert invoice.basket_generation_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:30:00' assert invoice.maelis_cancel_notification_date is None # invoice is not yet cancelled con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] # invoice is no more display but cancellation order is not sent to maelis yet freezer.move_to('2023-03-03 19:00:00') con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelling' assert invoice.maelis_cancel_notification_date is None resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' not in [x['id'] for x in resp.json['data']] # cancellation order is now sent to maelis freezer.move_to('2023-03-03 19:20:00') con.cancel_basket_invoices() assert caplog.records[-1].levelno == logging.INFO assert caplog.records[-1].message == 'Annulation de sur la famille \'1312\'' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' assert invoice.maelis_cancel_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 19:20:00' def test_cancel_basket_invoice_cron_having_for_payment_date( family_service, activity_service, invoice_service, con, app, freezer, caplog ): def request_check(request): assert request == 'F10055641671' family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), request_check=request_check, ) Link.objects.create(resource=con, family_id='1312', name_id='local') assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert invoice.basket_generation_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:30:00' assert invoice.maelis_cancel_notification_date is None # invoice is payable resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] assert resp.json['data'][0]['online_payment'] is True # notificate payment starts freezer.move_to('2023-03-03 18:35:00') resp = app.get(get_endpoint('regie/109/invoice/1312-18') + '?payment') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.start_payment_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:35:00' # invoice is still displayed before cancellation order is sent to maelis con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'for_payment' assert invoice.maelis_cancel_notification_date is None # invoice is no more payable resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] assert resp.json['data'][0]['online_payment'] is False # start payment date is not updated on furter invoice call providing '?payment' freezer.move_to('2023-03-03 18:40:00') resp = app.get(get_endpoint('regie/109/invoice/1312-18') + '?payment') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.start_payment_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:35:00' # cancellation order is now sent to maelis freezer.move_to('2023-03-03 18:55:00') con.cancel_basket_invoices() assert caplog.records[-1].levelno == logging.INFO assert caplog.records[-1].message == 'Annulation de sur la famille \'1312\'' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' assert invoice.maelis_cancel_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:55:00' def test_cancel_basket_invoice_cron_keep_paid_invoices( family_service, activity_service, invoice_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?family_id=1312', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # get a basket invoice freezer.move_to('2023-03-03 18:30:00') url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 assert caplog.records[-1].levelno == logging.INFO assert caplog.records[-1].message == 'Ajout de sur la famille \'1312\'' assert [(str(repr(x)), x.status()) for x in con.invoice_set.filter(regie_id=109)] == [ ('', 'created') ] # get family invoices freezer.move_to('2023-03-03 18:35:00') resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert '1312-18' in [x['id'] for x in resp.json['data']] assert 'Mise à jour de ' not in caplog.records[-1].message assert [(str(repr(x)), x.status()) for x in con.invoice_set.filter(regie_id=109)] == [ ('', 'created'), ] resp = app.get(get_endpoint('regie/109/invoices/history') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' not in [x['id'] for x in resp.json['data']] # pay invoice freezer.move_to('2023-03-03 18:38:00') url = get_endpoint('regie/109/invoice/1312-18/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 assert [(str(repr(x)), x.status()) for x in con.invoice_set.filter(regie_id=109)] == [ ('', 'paid'), ] resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' not in [x['id'] for x in resp.json['data']] resp = app.get(get_endpoint('regie/109/invoices/history') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] # invoice is not cancelled and no cancellation order is sent to maelis freezer.move_to('2023-03-03 19:20:00') con.cancel_basket_invoices() assert [(str(repr(x)), x.status()) for x in con.invoice_set.filter(regie_id=109)] == [ ('', 'paid'), ] invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.maelis_cancel_notification_date is None resp = app.get(get_endpoint('regie/109/invoices/history') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] def test_cancel_basket_invoice_cron_maelis_error( family_service, activity_service, invoice_service, con, app, freezer ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list_error.xml'), ) url = get_endpoint('validate-basket') params = {'basket_id': 'S10055641698'} Link.objects.create(resource=con, family_id='1312', name_id='local') assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json(url + '?NameID=local', params=params) assert resp.json['err'] == 0 data = resp.json['data']['factureLst'][0] assert data['regie']['code'] == 109 assert data['numInvoice'] == '18' assert data['idInvoice'] == 'F10055641671' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert invoice.basket_generation_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:30:00' assert invoice.maelis_cancel_notification_date is None resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] # error on cancellation order freezer.move_to('2023-03-03 19:20:00') try: con.cancel_basket_invoices() except SOAPError: pass else: assert False, 'cron should raise an exception' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelling' assert invoice.maelis_cancel_notification_date is None resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' not in [x['id'] for x in resp.json['data']] def test_cancel_basket_invoice_on_get_baskets(family_service, activity_service, con, app, freezer, caplog): def request_check(request): assert request == 'F10055641671' family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), request_check=request_check, ) Link.objects.create(resource=con, family_id='1312', name_id='local') url = get_endpoint('get-baskets') assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' # invoice is not yet cancelled resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' # invoice is no more display but cancellation order is not sent to maelis yet freezer.move_to('2023-03-03 19:00:00') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelling' assert invoice.maelis_cancel_notification_date is None # cancellation order is now sent to maelis freezer.move_to('2023-03-03 19:20:00') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.maelis_cancel_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 19:20:00' def test_read_nursery_list(con, app): url = get_endpoint('read-nursery-list') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 11 for item in resp.json['data']: assert 'id' in item assert 'text' in item resp = app.get(url, params={'activity_type': 'CRECHCO'}) assert len(resp.json['data']) == 8 resp = app.get(url, params={'code_psu': 'REGULAR'}) assert len(resp.json['data']) == 9 assert resp.json['data'][0] == { 'id': 'M10000000001', 'activity_id': 'M10000000001', 'unit_id': 'M10053212402', 'place_id': 'M10053212401', 'unit_ids': {'OCCASIONAL': 'M10053212403', 'REGULAR': 'M10053212402'}, 'obs1': 'Quartier 1.2', 'obs2': 'Secteur 1', 'text': 'CC AMIDONNIERS', 'place': { 'address': { 'num': 29, 'town': 'TOULOUSE', 'street1': 'ALL DE BRIENNE', 'street2': None, 'zipcode': '31000', 'idStreet': None, }, 'idPlace': 'M10053212401', 'libelle': 'CC AMIDONNIERS', 'latitude': 43.606099, 'libelle2': None, 'longitude': 1.430282, }, 'libelle': 'CC AMIDONNIERS', 'libelle2': None, 'manager1': {'phone': '0561615590', 'poste': 'CCAS', 'lastname': 'THOMAS', 'firstname': 'GUYLAINE'}, 'manager2': None, 'unitList': [ {'idUnit': 'M10053212402', 'libelle': 'CC AMIDONNIERS - Réguliers', 'typeAcc': 'REGULAR'}, {'idUnit': 'M10053212403', 'libelle': 'CC AMIDONNIERS - Occasionnels', 'typeAcc': 'OCCASIONAL'}, ], 'idActivity': 'M10000000001', 'idService': 'A10049329043', 'activityType': {'code': 'CRECHCO', 'libelle': 'Crèche collective'}, 'service': { 'id': 'A10049329043', 'lib1': 'Accueil de loisirs', 'lib2': None, 'text': 'Accueil de loisirs', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, } resp = app.get(url, params={'service_ids': 'A10049329048,A10049327627'}) assert len(resp.json['data']) == 3 assert all(x['idService'] in ['A10049329048', 'A10049327627'] for x in resp.json['data']) resp = app.get(url, params={'service_ids': 'A10049329048'}) assert len(resp.json['data']) == 2 assert all(x['idService'] == 'A10049329048' for x in resp.json['data']) def test_get_nursery_geojson(con, app): url = get_endpoint('get-nursery-geojson') params = { 'activity_type': 'CRECHCO', 'code_psu': 'REGULAR', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert resp.json['type'] == 'FeatureCollection' assert len(resp.json['features']) == 6 assert resp.json['features'][0] == { 'type': 'Feature', 'geometry': {'coordinates': [1.430282, 43.606099], 'type': 'Point'}, 'properties': { 'id': 'M10000000001:M10053212402:M10053212401', 'obs1': 'Quartier 1.2', 'obs2': 'Secteur 1', 'text': 'CC AMIDONNIERS - Réguliers', 'place': { 'address': { 'num': 29, 'town': 'TOULOUSE', 'street1': 'ALL DE BRIENNE', 'street2': None, 'zipcode': '31000', 'idStreet': None, }, 'idPlace': 'M10053212401', 'libelle': 'CC AMIDONNIERS', 'latitude': 43.606099, 'libelle2': None, 'longitude': 1.430282, }, 'libelle': 'CC AMIDONNIERS', 'libelle2': None, 'manager1': { 'phone': '0561615590', 'poste': 'CCAS', 'lastname': 'THOMAS', 'firstname': 'GUYLAINE', }, 'manager2': None, 'unitList': [ { 'idUnit': 'M10053212402', 'libelle': 'CC AMIDONNIERS - Réguliers', 'typeAcc': 'REGULAR', }, { 'idUnit': 'M10053212403', 'libelle': 'CC AMIDONNIERS - Occasionnels', 'typeAcc': 'OCCASIONAL', }, ], 'idActivity': 'M10000000001', 'idService': 'A10049329043', 'activityType': {'code': 'CRECHCO', 'libelle': 'Crèche collective'}, 'activity_id': 'M10000000001', 'place_id': 'M10053212401', 'unit_id': 'M10053212402', 'unit': { 'idUnit': 'M10053212402', 'libelle': 'CC AMIDONNIERS - Réguliers', 'typeAcc': 'REGULAR', }, 'service': { 'id': 'A10049329043', 'lib1': 'Accueil de loisirs', 'lib2': None, 'text': 'Accueil de loisirs', 'idDir': 'A10049327624', 'direction': { 'id': 'A10049327624', 'lib1': 'DEL', 'lib2': 'Direction enfance et loisirs', 'text': 'DEL', }, }, }, } params = { 'activity_type': 'CRECHFAM', 'code_psu': 'REGULAR', 'service_ids': 'A10049329048,A10049327627', } resp = app.get(url, params=params) assert resp.json['err'] == 0 assert len(resp.json['features']) == 2 assert all( x['properties']['idService'] in ['A10049329048', 'A10049327627'] for x in resp.json['features'] ) def test_create_nursery_demand(ape_service, con, app): def request_check(request): assert [(x['code'], x['isActive']) for x in request.child['indiPersList']] == [ ('APE_ALLO', True), ('APE-MINE', False), ] assert [(x['code'], x['isActive']) for x in request.apeBook['indiResapeList']] == [ ('APE_FIRSTC', True), ('APE_FRAT', False), ] assert [(x['code'], x['isActive']) for x in request['indiFamList']] == [('APE_COMPO1', False)] ape_service.add_soap_response( 'addApeBook', get_xml_file('R_create_nursery_demand.xml'), request_check=request_check ) data = { 'family_id': '322425', 'accept_other_nurseries': False, 'start_date': '2023-04-01', 'child_first_name': 'Enfant', 'child_last_name': 'nouveau né', 'child_birthdate': '2022-11-01', 'child_gender': 'G', 'comment': 'Une place en crèche, svp', 'number_of_days': '1', 'child_indicators/0/code': 'APE_ALLO', 'child_indicators/0/isActive': True, 'child_indicators/1/code': 'APE-MINE', 'child_indicators/1/isActive': False, 'demand_indicators/0/code': 'APE_FIRSTC', 'demand_indicators/0/isActive': 'Oui', 'demand_indicators/1/code': 'APE_FRAT', 'demand_indicators/1/isActive': 0, 'family_indicators/0/code': 'APE_COMPO1', 'family_indicators/0/isActive': 'False', 'start_hour_Mon': '09:00', 'end_hour_Mon': '18:00', 'nursery1/idActivity': 'M10000000004', 'nursery1/idUnit': 'M10053180335', 'nursery1/idPlace': 'M10053180334', } url = get_endpoint('create-nursery-demand') resp = app.post_json(url, params=data) assert resp.json['err'] == 0 data['start_hour_Tue'] = '' resp = app.post_json(url, params=data) assert resp.json['err'] == 0 def test_create_nursery_demand_wrong_referential_key_error(con, app): url = get_endpoint('create-nursery-demand') params = { 'family_id': '322425', 'start_date': '2023-04-01', 'family_indicators/0/code': 'APE_ALLO', 'family_indicators/0/isActive': 'False', } resp = app.post_json(url, params=params) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "family_indicators/0/code key value 'APE_ALLO' do not belong to APE 'FAM' indicators" ) def test_invoices(invoice_service, con, app, caplog, freezer): def request_check(request): assert request.numDossier == 1312 assert request.codeRegie == 102 assert request.dateStart == datetime.datetime(1970, 1, 1, 0, 0) invoice_service.add_soap_response( 'readInvoices', get_xml_file('R_read_invoices.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoices') freezer.move_to('2023-03-03 18:00:00') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert len([x for x in caplog.records if 'Ajout de sur la famille \'1312\'' Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert resp.json['has_invoice_for_payment'] is True assert len(resp.json['data']) for invoice in resp.json['data']: assert invoice['display_id'] assert invoice['label'] assert invoice['total_amount'] assert not invoice['paid'] data = resp.json['data'][0] del data['maelis_item'] assert data == { 'id': '1312-30', 'created': '2023-03-01', 'pay_limit_date': '2023-04-30', 'display_id': '30', 'total_amount': '162.3', 'amount': '162.3', 'amount_paid': '0', 'label': 'TEST EO', 'has_pdf': False, 'online_payment': True, 'paid': False, 'payment_date': None, 'no_online_payment_reason': None, 'reference_id': '30', } assert len([x for x in caplog.records if 'Ajout de sur la famille \'1312\': [\'- "pdfName": "invoice.pdf",\', \'+ "pdfName": null,\']' ) invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.created.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:00:00' assert invoice.updated.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:20:00' assert invoice.maelis_data_update_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:20:00' assert invoice.status() == 'created' # Cancelled basket invoices are not displayed freezer.move_to('2023-03-03 18:30:00') invoice.basket_generation_date = invoice.created invoice.save() assert invoice.status() == 'cancelling' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert resp.json['data'] == [] @mock.patch('passerelle.utils.Request.get') def test_invoices_cache(mocked_get, con, app): mocked_get.return_value = INVOICE_SERVICE_WSDL url = get_endpoint('regie/102/invoices') with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.side_effect = ReadTimeout('timeout') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert resp.json['data'] == [] with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.return_value = FakedResponse(content=get_xml_file('R_read_invoices.xml'), status_code=200) resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert len(resp.json['data']) for invoice in resp.json['data']: assert invoice['display_id'] assert invoice['label'] assert invoice['total_amount'] assert not invoice['paid'] with mock.patch('passerelle.utils.Request.post') as mocked_post: mocked_post.side_effect = ReadTimeout('timeout') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert len(resp.json['data']) def test_invoices_not_linked_error(con, app): url = get_endpoint('regie/102/invoices') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_invoices_wrong_referential_key_error(con, app): url = get_endpoint('regie/plop/invoices') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "regie_id parameter key value 'plop' do not belong to 'Regie' required referential" ) def test_invoices_unicity(invoice_service, con, app, caplog): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) url = get_endpoint('regie/102/invoices') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert con.invoice_set.filter(regie_id=102).count() == 2 assert con.invoice_set.filter(regie_id=109).count() == 0 url = get_endpoint('regie/109/invoices') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert con.invoice_set.filter(regie_id=109).count() == 2 url = get_endpoint('regie/102/invoices') resp = app.get(url + '?family_id=1234') assert resp.json['err'] == 0 assert con.invoice_set.filter(regie_id=102).count() == 2 assert caplog.records[-1].levelno == logging.ERROR assert [x.message for x in caplog.records][-2:] == [ ' sur la famille \'1234\' existe déjà sur la famille \'1312\'', ' sur la famille \'1234\' existe déjà sur la famille \'1312\'', ] def test_invoices_without_number(invoice_service, con, app): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_no_number.xml')) url = get_endpoint('regie/102/invoices') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 assert con.invoice_set.filter(regie_id=102).count() == 0 def test_invoices_history(invoice_service, con, app): def request_check(request): assert request.numDossier == 1312 assert request.codeRegie == 102 assert request.dateStart == datetime.datetime(1970, 1, 1, 0, 0) invoice_service.add_soap_response( 'readInvoices', get_xml_file('R_read_invoices.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoices/history') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 0 Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert resp.json['has_invoice_for_payment'] is True for invoice in resp.json['data']: assert invoice['display_id'] assert invoice['label'] assert invoice['total_amount'] assert invoice['paid'] data = resp.json['data'][0] del data['maelis_item'] assert data == { 'id': '1312-8', 'created': '2023-02-24', 'pay_limit_date': '', 'display_id': '8', 'total_amount': '952503.6', 'amount': '0.0', 'amount_paid': '952503.6', 'label': 'CLAE JANVIER 2023', 'has_pdf': False, 'online_payment': False, 'paid': True, 'payment_date': None, 'no_online_payment_reason': None, 'reference_id': '8', } invoice = con.invoice_set.get(regie_id=102, invoice_id=8) assert invoice.status() == 'notified' def test_invoices_history_not_linked_error(con, app): url = get_endpoint('regie/102/invoices/history') resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'User not linked to family' def test_invoices_history_wrong_referential_key_error(con, app): url = get_endpoint('regie/plop/invoices/history') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "regie_id parameter key value 'plop' do not belong to 'Regie' required referential" ) def test_invoice(invoice_service, con, app): def request_check(request): assert request.numDossier == 1312 assert request.codeRegie == 102 assert request.dateStart == datetime.datetime(1970, 1, 1, 0, 0) invoice_service.add_soap_response( 'readInvoices', get_xml_file('R_read_invoices.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoice/1312-8') resp = app.get(url + '?NameID=ignored') assert resp.json['err'] == 0 assert resp.json['data']['display_id'] == '8' assert resp.json['data']['label'] == 'CLAE JANVIER 2023' @mock.patch('passerelle.utils.Request.get') @mock.patch('passerelle.utils.Request.post') def test_invoice_online_payment_no_response(mocked_post, mocked_get, con, app, db): mocked_get.side_effect = (INVOICE_SERVICE_WSDL,) mocked_post.side_effect = [ FakedResponse(content=get_xml_file('R_read_invoices.xml'), status_code=200), ReadTimeout('timeout'), ReadTimeout('timeout'), ] url = get_endpoint('regie/102/invoice/1312-30') # Assert we get the invoice in cache resp = app.get(url + '?NameID=ignored') assert resp.json['err'] == 0 assert resp.json['data']['online_payment'] is True assert resp.json['data']['no_online_payment_reason'] is None # Maelis is no more available resp = app.get(url + '?NameID=ignored') assert resp.json['err'] == 0 assert resp.json['data']['online_payment'] is False assert resp.json['data']['no_online_payment_reason'] == 'Le service est temporairement indisponible.' # No change on invoice already paid url = get_endpoint('regie/102/invoice/1312-8') resp = app.get(url + '?NameID=ignored') assert resp.json['err'] == 0 assert resp.json['data']['online_payment'] is False assert resp.json['data']['no_online_payment_reason'] is None def test_invoices_online_payment_no_invoice(invoice_service, con, app, caplog, freezer): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_canceled.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) url = get_endpoint('regie/102/invoices') + '?NameID=local' Link.objects.create(resource=con, family_id='1312', name_id='local') # Assert we get the invoice in cache freezer.move_to('2023-03-03 18:00:00') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 assert resp.json['data'][0]['online_payment'] is True assert resp.json['data'][0]['no_online_payment_reason'] is None invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_no_more_returned_date is None assert invoice.status() == 'created' # Maelis do not send the "canceled by agents" invoice freezer.move_to('2023-03-03 18:10:00') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 0 # invoice is now more available invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_no_more_returned_date.isoformat() == '2023-03-03T18:10:00+00:00' assert invoice.status() == 'cancelled_by_agent' # Maelis re-send the invoice freezer.move_to('2023-03-03 18:20:00') resp = app.get(url) assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 assert resp.json['data'][0]['online_payment'] is True assert resp.json['data'][0]['no_online_payment_reason'] is None invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_no_more_returned_date is None assert invoice.status() == 'created' def test_invoice_if_cancelled(family_service, activity_service, invoice_service, con, app, freezer): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), ) url = get_endpoint('regie/109/invoice/1312-18') assert con.cancel_invoice_delay == 30 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?family_id=1312', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?family_id=1312', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 resp = app.get(url + '?NameID=ignored') assert resp.json['err'] == 0 assert resp.json['data']['display_id'] == '18' assert resp.json['data']['label'] == 'DSBL TEST' # cancelling basket invoice is no more returned freezer.move_to('2023-03-03 19:00:00') invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelling' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice cancelling' # cancelled basket invoice is no more returned freezer.move_to('2023-03-03 19:20:00') con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice cancelled' def test_invoice_for_payment(family_service, activity_service, invoice_service, con, app, freezer): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), ) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) url = get_endpoint('regie/109/invoice/1312-18') assert con.max_payment_delay == 20 # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?family_id=1312', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?family_id=1312', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 # invoice is payable resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] assert resp.json['data'][0]['online_payment'] is True # notificate payment starts freezer.move_to('2023-03-03 18:35:00') resp = app.get(url + '?NameID=ignored&payment') assert resp.json['err'] == 0 assert resp.json['data']['display_id'] == '18' assert resp.json['data']['label'] == 'DSBL TEST' # basket invoice is still returned but is no more payable invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.start_payment_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:35:00' assert invoice.status() == 'for_payment' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 0 assert resp.json['data']['display_id'] == '18' assert resp.json['data']['pay_limit_date'] == '' assert resp.json['data']['online_payment'] is False assert resp.json['data']['no_online_payment_reason'] == 'Transation de payement en cours' # invoice is no more payable resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert resp.json['err'] == 0 assert '1312-18' in [x['id'] for x in resp.json['data']] assert resp.json['data'][0]['online_payment'] is False # start payment date is not updated on furter invoice call providing '?payment' freezer.move_to('2023-03-03 18:40:00') resp = app.get(get_endpoint('regie/109/invoice/1312-18') + '?payment') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.start_payment_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:35:00' # basket invoice is no more returned since cancellation order sent to maelis freezer.move_to('2023-03-03 18:55:00') con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' resp = app.get(url + '?NameID=local') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice cancelled' def test_invoice_wrong_referential_key_error(con, app): url = get_endpoint('regie/plop/invoice/1312-8') resp = app.get(url) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "regie_id parameter key value 'plop' do not belong to 'Regie' required referential" ) def test_invoice_not_found_invoice(invoice_service, con, app): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) url = get_endpoint('regie/102/invoice/1-2') resp = app.get(url + '?family_id=1312') assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice not found' def test_pay_invoice(invoice_service, con, app, freezer): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) resp = app.get(get_endpoint('regie/102/invoice/1312-30') + '?family_id=1312') assert resp.json['err'] == 0 assert resp.json['data']['amount_paid'] == '0' assert resp.json['data']['paid'] is False assert resp.json['data']['amount'] == '162.3' assert resp.json['data']['online_payment'] is True assert resp.json['data']['pay_limit_date'] == '2023-04-30' url = get_endpoint('regie/102/invoice/1312-30/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } freezer.move_to('2023-03-03 18:39:00') resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.lingo_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:39:00' assert invoice.maelis_notification_date is None assert invoice.status() == 'paid' resp = app.get(get_endpoint('regie/102/invoice/1312-30') + '?family_id=1312') assert resp.json['err'] == 0 assert resp.json['data']['amount_paid'] == '162.3' assert resp.json['data']['paid'] is True assert resp.json['data']['amount'] == '0.0' assert resp.json['data']['online_payment'] is False assert resp.json['data']['pay_limit_date'] == '' def test_pay_invoice_job(invoice_service, con, app, freezer): def request_check(request): assert dict(serialize_object(request)) == { 'numDossier': 1312, 'numPerson': 261483, 'lastName': None, 'firstName': None, 'codeRegie': 102, 'amount': 162.3, 'datePaiement': datetime.datetime(2023, 3, 3, 18, 38), 'refTransaction': 'xxx', 'numInvoices': [30], } invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) invoice_service.add_soap_response( 'payInvoices', get_xml_file('R_pay_invoices.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoice/1312-30/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } freezer.move_to('2023-03-03 18:39:00') resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.lingo_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:39:00' assert invoice.maelis_notification_date is None assert invoice.maelis_notification_data is None assert invoice.status() == 'paid' job = Job.objects.get(method_name='notify_invoice_paid_job', natural_id='102/30') assert job.status == 'registered' freezer.move_to('2023-03-03 18:40:00') con.jobs() invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:40:00' assert invoice.maelis_notification_data == 4 assert invoice.status() == 'notified' job = Job.objects.get(method_name='notify_invoice_paid_job', natural_id='102/30') assert job.status == 'completed' assert job.update_timestamp > job.creation_timestamp def test_pay_invoice_job_error(invoice_service, con, app, freezer, caplog): caplog.set_level('WARNING') invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) invoice_service.add_soap_response('payInvoices', ConnectionError('boom!')) invoice_service.add_soap_response('payInvoices', get_xml_file('R_pay_invoices.xml')) url = get_endpoint('regie/102/invoice/1312-30/pay/') freezer.move_to('2023-03-03 18:39:00') app.post_json( url, params={ 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', }, ) job = Job.objects.get() assert job.status == 'registered' assert caplog.messages == [] freezer.move_to('2023-03-03 18:40:00') con.jobs() job.refresh_from_db() assert job.status == 'registered' assert len(caplog.messages) == 1 assert 'fails to notify' in caplog.text freezer.tick(6 * 60) con.jobs() job.refresh_from_db() assert job.status == 'completed' assert len(caplog.messages) == 1 invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.status() == 'notified' def test_pay_invoice_cron(invoice_service, con, app, freezer): def request_check(request): assert dict(serialize_object(request)) == { 'numDossier': 1312, 'numPerson': 261483, 'lastName': None, 'firstName': None, 'codeRegie': 102, 'amount': 162.3, 'datePaiement': datetime.datetime(2023, 3, 3, 18, 38), 'refTransaction': 'xxx', 'numInvoices': [30], } invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) invoice_service.add_soap_response( 'payInvoices', get_xml_file('R_pay_invoices.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoice/1312-30/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } freezer.move_to('2023-03-03 18:39:00') resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.lingo_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:39:00' assert invoice.maelis_notification_date is None assert invoice.maelis_notification_data is None assert invoice.status() == 'paid' freezer.move_to('2023-03-03 18:40:00') con.notify_invoices_paid() invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_notification_date is None assert invoice.maelis_notification_data is None assert invoice.status() == 'paid' freezer.move_to('2023-03-03 18:55:00') con.notify_invoices_paid() invoice = con.invoice_set.get(regie_id=102, invoice_id=30) assert invoice.maelis_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:55:00' assert invoice.maelis_notification_data == 4 assert invoice.status() == 'notified' def test_pay_invoice_cron_maelis_error(invoice_service, con, app, freezer, caplog): caplog.set_level('WARNING') invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_2_invoices_to_pay.xml')) invoice_service.add_soap_response('payInvoices', get_xml_file('R_pay_invoices_error.xml')) invoice_service.add_soap_response('payInvoices', get_xml_file('R_pay_invoices.xml')) # pay 2 invoices freezer.move_to('2023-03-03 18:39:00') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } url = get_endpoint('regie/102/invoice/1312-30/pay/') resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 url = get_endpoint('regie/102/invoice/1312-8/pay/') resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 assert con.invoice_set.get(regie_id=102, invoice_id=30).status() == 'paid' assert con.invoice_set.get(regie_id=102, invoice_id=8).status() == 'paid' caplog.clear() # run hourly cron that fails on first invoice, but continue notifying the second one freezer.move_to('2023-03-03 18:55:00') con.notify_invoices_paid() assert 'fails to notify' in caplog.text assert 'stopping' in caplog.text assert con.invoice_set.get(regie_id=102, invoice_id=30).status() == 'error' assert con.invoice_set.get(regie_id=102, invoice_id=8).status() == 'notified' def test_pay_invoice_wrong_referential_key_error(con, app): url = get_endpoint('regie/plop/invoice/1312-8/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } resp = app.post_json(url, params=data) assert resp.json['err'] == 1 assert ( resp.json['err_desc'] == "regie_id parameter key value 'plop' do not belong to 'Regie' required referential" ) def test_pay_invoice_not_found_invoice(invoice_service, con, app): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) url = get_endpoint('regie/102/invoice/1-2/pay') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } resp = app.post_json(url, params=data) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice not found' def test_pay_historical_invoice(invoice_service, con, app): invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices.xml')) url = get_endpoint('regie/102/invoice/1312-8/pay/') data = { 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': 'xxx', } resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice already paid' def test_pay_not_yet_cancelled_basket_invoice( family_service, activity_service, invoice_service, con, app, freezer ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 url = get_endpoint('regie/109/invoice/1312-18/pay/') data = { 'transaction_date': '2023-03-03T19:20:00', 'transaction_id': 'xxx', } # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?family_id=1312', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?family_id=1312', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 # cancellation order was not sent to maelis freezer.move_to('2023-03-03 19:20:00') invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelling' assert invoice.maelis_cancel_notification_date is None resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 0 assert resp.json['data'] == 'ok' def test_pay_cancelled_basket_invoice(family_service, activity_service, invoice_service, con, app, freezer): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), ) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) assert con.cancel_invoice_delay == 30 assert con.max_payment_delay == 20 url = get_endpoint('regie/109/invoice/1312-18/pay/') data = { 'transaction_date': '2023-03-03T19:20:00', 'transaction_id': 'xxx', } # subscribe freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?family_id=1312', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 # invoice created on validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?family_id=1312', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 # cancellation order sent to maelis freezer.move_to('2023-03-03 19:20:00') con.cancel_basket_invoices() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' assert invoice.maelis_cancel_notification_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 19:20:00' resp = app.post_json(url + '?NameID=ignored', params=data) assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'Invoice cancelled' def test_invoice_pdf(invoice_service, con, app): def request_check(request): assert request.codeRegie == 102 assert request.numInvoice == 8 invoice_service.add_soap_response( 'getInvoicePDF', get_xml_file('R_get_invoice_pdf.xml'), request_check=request_check ) url = get_endpoint('regie/102/invoice/1312-8/pdf') resp = app.get(url + '?family_id=1312') Link.objects.create(resource=con, family_id='1312', name_id='local') resp = app.get(url + '?NameID=local') assert 'Content-Type' in resp.headers assert 'Content-Disposition' in resp.headers assert resp.headers['Content-Type'] == 'application/pdf' assert resp.headers['Content-Disposition'] == 'attachment; filename=1312-8.pdf' assert resp.body[:5] == b'%PDF-' def test_invoice_pdf_not_linked_error(con, app): url = get_endpoint('regie/102/invoice/1312-8/pdf') resp = app.get(url, status=404) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'django.http.response.Http404' assert resp.json['err_desc'] == 'Fichier PDF non trouvé' def test_invoice_pdf_wrong_referential_key_error(con, app): url = get_endpoint('regie/plop/invoice/1312-8/pdf') resp = app.get(url + '?family_id=1312', status=404) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'django.http.response.Http404' assert resp.json['err_desc'] == 'Fichier PDF non trouvé' def test_invoice_pdf_wrong_family_id_error(con, app): url = get_endpoint('regie/102/invoice/000-8/pdf') resp = app.get(url + '?family_id=1312', status=404) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'django.http.response.Http404' assert resp.json['err_desc'] == 'Fichier PDF non trouvé' def test_invoice_pdf_error(invoice_service, con, app): invoice_service.add_soap_response('getInvoicePDF', get_xml_file('R_get_invoice_pdf_error.xml')) url = get_endpoint('regie/102/invoice/1312-8/pdf/') resp = app.get(url + '?family_id=1312', status=404) assert resp.json['err'] == 1 assert resp.json['err_class'] == 'django.http.response.Http404' assert resp.json['err_desc'] == 'Fichier PDF non trouvé' def test_trigger_wcs_on_paid_subscriptions_cron( family_service, activity_service, invoice_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 assert resp.json['data']['controlResult']['controlOK'] is True assert resp.json['data']['basket']['codeRegie'] == 109 assert len(resp.json['data']['basket']['lignes']) == 1 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.created.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:20:00' assert subscription.invoice is None assert subscription.status() == 'pending_basket' assert subscription.maelis_data == resp.json['data'] assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 assert len(resp.json['data']['factureLst']) == 1 # basket validation generate only one invoice assert resp.json['data']['factureLst'][0]['regie']['code'] == 109 assert resp.json['data']['factureLst'][0]['numInvoice'] == '18' invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.created.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:30:00' assert invoice.basket_generation_date.strftime('%Y-%m-%d %H:%M:%S') == '2023-03-03 18:30:00' assert invoice.status() == 'created' assert invoice.maelis_data == resp.json['data']['factureLst'][0] assert 'S10055641658' in [x['idIns'] for x in invoice.maelis_data['lineInvoiceList']] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_invoice' assert subscription.trigger_status() == 'pending' # get family invoices freezer.move_to('2023-03-03 18:35:00') resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert '1312-18' in [x['id'] for x in resp.json['data']] invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' # pay invoice freezer.move_to('2023-03-03 18:38:00') resp = app.post_json( get_endpoint('regie/109/invoice/1312-18/pay/') + '?NameID=ignored', params={ 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': '1c5451752a064fc2bd7ea750998683e1', }, ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'paid' job = Job.objects.get(method_name='notify_invoice_paid_job', natural_id='109/18') assert job.status == 'registered' subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.invoice == invoice assert subscription.status() == 'pending_invoice' assert subscription.trigger_status() == 'pending' invoice_service.add_soap_response('payInvoices', get_xml_file('R_pay_invoices.xml')) con.jobs(count=1) # only run the notify job subscription.refresh_from_db() assert subscription.invoice == invoice assert subscription.status() == 'paid' assert subscription.trigger_status() == 'triggering' assert subscription.wcs_trigger_payload['data']['subscription_status'] == 'paid' # send trigger to wcs con.hourly() # only run the trigger job assert ( 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in wcs_service.calls[-1].request.url ) trigger_body = json.loads(wcs_service.calls[-1].request.body) assert trigger_body['err'] == 0 assert trigger_body['data']['subscription_status'] == 'paid' assert trigger_body['data']['invoice_status'] == 'notified' assert trigger_body['data']['regie_text'] == 'DSBL' assert any(['trigger wcs' in x.message for x in caplog.records]) subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.wcs_trigger_date is not None assert subscription.trigger_status() == 'triggered' def test_trigger_wcs_on_paid_subscriptions_job( family_service, activity_service, invoice_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) invoice_service.add_soap_response('readInvoices', get_xml_file('R_read_invoices_regie_109.xml')) invoice_service.add_soap_response('payInvoices', get_xml_file('R_pay_invoices.xml')) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert 'S10055641658' in [x['idIns'] for x in invoice.maelis_data['lineInvoiceList']] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_invoice' # get family invoices freezer.move_to('2023-03-03 18:35:00') resp = app.get(get_endpoint('regie/109/invoices') + '?family_id=1312') assert '1312-18' in [x['id'] for x in resp.json['data']] # pay invoice freezer.move_to('2023-03-03 18:38:00') resp = app.post_json( get_endpoint('regie/109/invoice/1312-18/pay/') + '?NameID=ignored', params={ 'transaction_date': '2023-03-03T18:38:00', 'transaction_id': '1c5451752a064fc2bd7ea750998683e1', }, ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'paid' job = Job.objects.get(method_name='notify_invoice_paid_job', natural_id='109/18') assert job.status == 'registered' subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'pending' assert not Job.objects.filter( method_name='trigger_subscription_job', natural_id='13-12/%s' % subscription.pk ).exists() # notify paid invoice con.jobs(count=1) job = Job.objects.get(method_name='trigger_subscription_job', natural_id='13-12/%s' % subscription.pk) assert job.status == 'registered' con.jobs(count=1) assert any( [ 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in x.request.url for x in wcs_service.calls ] ) job.refresh_from_db() assert job.status == 'completed' subscription.refresh_from_db() assert subscription.trigger_status() == 'triggered' def test_trigger_wcs_on_cancelled_subscriptions_cron( family_service, activity_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), ) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert 'S10055641658' in [x['idIns'] for x in invoice.maelis_data['lineInvoiceList']] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_invoice' # send invoice cancellation order to maelis and trigger wcs freezer.move_to('2023-03-03 19:20:00') con.hourly() invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' assert ( 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in wcs_service.calls[-1].request.url ) trigger_body = json.loads(wcs_service.calls[-1].request.body) assert trigger_body['err'] == 1 assert trigger_body['err_desc'] == 'La facture a été annulée' assert trigger_body['data']['subscription_status'] == 'cancelled' assert trigger_body['data']['regie_text'] == 'DSBL' assert any(['trigger wcs' in x.message for x in caplog.records]) subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggered' def test_trigger_wcs_on_cancelled_subscriptions_job( family_service, activity_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket.xml')) activity_service.add_soap_response('validateBasket', get_xml_file('R_validate_basket.xml')) activity_service.add_soap_response( 'cancelInvoiceAndDeleteSubscribeList', get_xml_file('R_cancel_invoice_and_delete_subscribe_list.xml'), ) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # validate basket freezer.move_to('2023-03-03 18:30:00') resp = app.post_json( get_endpoint('validate-basket') + '?NameID=local', params={'basket_id': 'S10055641698'} ) assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'created' assert 'S10055641658' in [x['idIns'] for x in invoice.maelis_data['lineInvoiceList']] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_invoice' # send invoice cancellation order to maelis (side effect of get-basket) freezer.move_to('2023-03-03 19:20:00') resp = app.get(get_endpoint('get-baskets') + '?NameID=local') assert resp.json['err'] == 0 invoice = con.invoice_set.get(regie_id=109, invoice_id=18) assert invoice.status() == 'cancelled' subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggering' job = Job.objects.get(method_name='trigger_subscription_job', natural_id='13-12/%s' % subscription.pk) assert job.status == 'registered' # send invoice cancellation order to maelis and trigger wcs con.jobs() assert ( 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in wcs_service.calls[-1].request.url ) trigger_body = json.loads(wcs_service.calls[-1].request.body) assert trigger_body['err'] == 1 assert trigger_body['err_desc'] == 'La facture a été annulée' assert trigger_body['data']['subscription_status'] == 'cancelled' assert trigger_body['data']['regie_text'] == 'DSBL' assert any(['trigger wcs' in x.message for x in caplog.records]) job = Job.objects.get(method_name='trigger_subscription_job', natural_id='13-12/%s' % subscription.pk) assert job.status == 'completed' subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggered' def test_trigger_wcs_on_removed_subscriptions_cron( family_service, activity_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.basket_removal_date is None assert subscription.status() == 'pending_basket' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # basket was removed, send trigger to wcs con.hourly() assert ( 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in wcs_service.calls[-1].request.url ) trigger_body = json.loads(wcs_service.calls[-1].request.body) assert trigger_body['err'] == 1 assert trigger_body['err_desc'] == "Le panier n'a pas été validé" assert trigger_body['data']['subscription_status'] == 'removed' assert trigger_body['data']['regie_text'] == 'DSBL' assert any(['trigger wcs' in x.message for x in caplog.records]) subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.basket_removal_date.isoformat() == '2023-03-03T18:20:00+00:00' assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggered' # removal date is keept freezer.move_to('2023-03-03 19:20:00') con.hourly() subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.basket_removal_date.isoformat() == '2023-03-03T18:20:00+00:00' def test_trigger_wcs_on_removed_subscriptions_job( family_service, activity_service, wcs_service, con, app, freezer, caplog ): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 0}, status=200, ) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert [x['idIns'] for x in subscription.maelis_data['basket']['lignes']] == ['S10055641658'] # get basket having subscription removed resp = app.get(get_endpoint('get-baskets') + '?NameID=local') assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'removed' assert subscription.trigger_status() == 'triggering' # send trigger to wcs con.jobs() assert ( 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/' in wcs_service.calls[-1].request.url ) trigger_body = json.loads(wcs_service.calls[-1].request.body) assert trigger_body['err'] == 1 assert trigger_body['err_desc'] == "Le panier n'a pas été validé" assert trigger_body['data']['subscription_status'] == 'removed' assert trigger_body['data']['regie_text'] == 'DSBL' assert any(['trigger wcs' in x.message for x in caplog.records]) subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggered' def test_trigger_wcs_service_error(family_service, activity_service, con, app, freezer, caplog): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' # basket was removed, send trigger to wcs con.hourly() assert caplog.records[-1].levelno == logging.WARNING assert ( caplog.records[-1].message == 'Cannot find wcs service for https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/' ) subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggered' assert ( subscription.wcs_trigger_response == 'Cannot find wcs service for https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/' ) def test_trigger_wcs_api_error(family_service, activity_service, wcs_service, con, app, freezer, caplog): family_service.add_soap_response('readFamily', get_xml_file('R_read_family_for_subscription.xml')) activity_service.add_soap_response('getPersonUnitInfo', get_xml_file('R_get_person_unit_info.xml')) activity_service.add_soap_response('addPersonUnitBasket', get_xml_file('R_add_person_unit_basket.xml')) activity_service.add_soap_response('getFamilyBasket', get_xml_file('R_get_family_basket_empty.xml')) Link.objects.create(resource=con, family_id='1312', name_id='local') # subscribe providing a wcs demand freezer.move_to('2023-03-03 18:20:00') resp = app.post_json( get_endpoint('add-person-basket-subscription') + '?NameID=local', params={ 'person_id': '266145', 'activity_id': 'A10053179798', 'unit_id': 'A10053179809', 'place_id': 'A10053179757', 'start_date': '2023-02-01', 'end_date': '2023-06-30', 'form_api_url': 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/', 'form_number': '13-12', }, ) assert resp.json['err'] == 0 subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.status() == 'pending_basket' assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 0 # basket was removed, send trigger to wcs wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 1, 'err_class': 'Access denied', 'err_desc': None}, status=403, ) con.hourly() assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 1 assert caplog.records[-1].levelno == logging.WARNING assert textwrap.wrap(caplog.records[-1].message, 80) == [ 'POST request failed (url=https://wcs.example.com/api/forms/exemple-inscription-', 'loisirs-1/12/hooks/update_subscription/?orig=passerelle, status_code=403,', 'json_content={"err": 1, "err_class": "Access denied", "err_desc": null})', ] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggering' # retry wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', body=CONNECTION_ERROR, ) con.hourly() assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 2 assert caplog.records[-1].levelno == logging.WARNING assert textwrap.wrap(caplog.records[-1].message, 80) == [ 'POST request failed (url=https://wcs.example.com/api/forms/exemple-inscription-', 'loisirs-1/12/hooks/update_subscription/?orig=passerelle,', "request_exception=ConnectionError('No address associated with hostname'))", ] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggering' # retry again wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', body='plop', status=500, ) con.hourly() assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 3 assert caplog.records[-1].levelno == logging.WARNING assert textwrap.wrap(caplog.records[-1].message, 80) == [ 'POST request failed (url=https://wcs.example.com/api/forms/exemple-inscription-', 'loisirs-1/12/hooks/update_subscription/?orig=passerelle, status_code=500,', "content=b'plop')", ] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggering' assert subscription.wcs_trigger_response is None # bad wcs 404 response wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', body='not a json content', status=404, ) con.hourly() assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 4 assert caplog.records[-1].levelno == logging.WARNING assert textwrap.wrap(caplog.records[-1].message, 80) == [ 'POST request failed (url=https://wcs.example.com/api/forms/exemple-inscription-', 'loisirs-1/12/hooks/update_subscription/?orig=passerelle, status_code=404,', "content=b'not a json content')", ] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggering' assert subscription.wcs_trigger_response is None # stop triggering a removed wcs demand wcs_service.add( responses.POST, 'https://wcs.example.com/api/forms/exemple-inscription-loisirs-1/12/hooks/update_subscription/', json={'err': 1, 'err_class': 'Page non trouvée', 'err_desc': None}, status=404, ) con.hourly() assert len([x for x in wcs_service.calls if '/hooks/' in x.request.url]) == 5 assert caplog.records[-1].levelno == logging.INFO assert textwrap.wrap(caplog.records[-1].message, 80) == [ 'POST request failed (url=https://wcs.example.com/api/forms/exemple-inscription-', 'loisirs-1/12/hooks/update_subscription/?orig=passerelle, status_code=404,', 'json_content={"err": 1, "err_class": "Page non trouvée", "err_desc": null})', ] subscription = con.subscription_set.get(wcs_form_number='13-12') assert subscription.trigger_status() == 'triggered' assert subscription.wcs_trigger_response == {'err': 1, 'err_class': 'Page non trouvée', 'err_desc': None} def test_earliest_updated(con): con.referential.all().delete() assert con.earliest_updated(con.referential.all()) is None ref = con.referential.create(referential_name='foo', item_id='1', item_data={}) assert con.earliest_updated(con.referential.all()) == ref.updated assert con.earliest_updated(con.referential.filter(referential_name='bar')) is None @pytest.mark.parametrize('ref_name', ['Activity', 'ActivityNatureType', 'Direct', 'Service']) def test_get_activity_referentials_earliest_timestamp(con, ref_name): con.referential.all().delete() assert con.get_activity_referentials_earliest_timestamp() is None con.referential.create(referential_name='foo', item_id='1', item_data={}) assert con.get_activity_referentials_earliest_timestamp() is None activity = con.referential.create(referential_name=ref_name, item_id='1', item_data={}) assert con.get_activity_referentials_earliest_timestamp() == activity.updated @pytest.mark.parametrize('ref_name', ['Activity', 'ActivityNatureType', 'Direct', 'Service']) def test_is_activity_referentials_too_old(con, ref_name): con.referential.all().delete() assert con.is_activity_referentials_too_old() is True activity = con.referential.create(referential_name=ref_name, item_id='1', item_data={}) assert con.is_activity_referentials_too_old() is False con.referential.update(updated=activity.updated - datetime.timedelta(hours=6, minutes=1)) assert con.is_activity_referentials_too_old() is True @pytest.mark.parametrize('ref_name', ['Activity', 'ActivityNatureType', 'Direct', 'Service']) def test_get_referentials_earliest_timestamp(con, ref_name): con.referential.all().delete() assert con.get_referentials_earliest_timestamp() is None con.referential.create(referential_name=ref_name, item_id='1', item_data={}) assert con.get_referentials_earliest_timestamp() is None ref = con.referential.create(referential_name='foo', item_id='1', item_data={}) assert con.get_referentials_earliest_timestamp() == ref.updated def test_is_referentials_too_old(con): con.referential.all().delete() assert con.is_referentials_too_old() is True ref = con.referential.create(referential_name='foo', item_id='1', item_data={}) assert con.is_referentials_too_old() is False con.referential.update(updated=ref.updated - datetime.timedelta(hours=30, minutes=1)) assert con.is_referentials_too_old() is True def test_should_update_referentials(con, freezer): freezer.move_to('2023-12-10T12:01:01') con.referential.all().delete() assert con.should_update_referentials() is True con.referential.create(referential_name='foo', item_id='1', item_data={}) freezer.move_to('2023-12-11T12:00:01') assert con.should_update_referentials() is False # after 24 hours update should happen freezer.move_to('2023-12-11T12:01:01') assert con.should_update_referentials() is True con.referential.update(updated=now()) assert con.should_update_referentials() is False # less than 24 hours, update should not happen freezer.move_to('2023-12-11T23:59:01') assert con.should_update_referentials() is False # but between 00:00 and 06:00 if referential is more thant 7 hours old, update freezer.move_to('2023-12-12T00:00:01') assert con.should_update_referentials() is True