# passerelle - uniform access to multiple data sources and services # Copyright (C) 2020 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 copy import datetime import decimal import json import os import xml.etree.ElementTree as ET from contextlib import contextmanager from unittest import mock import freezegun import jsonschema import pytest import xmlschema from django.core.cache import cache import tests.utils from passerelle.contrib.toulouse_axel import schemas from passerelle.contrib.toulouse_axel.models import Link, Lock, ToulouseAxel from passerelle.contrib.toulouse_axel.utils import ( csp_mapping, lien_parente_mapping, regime_mapping, situation_familiale_mapping, type_regime_mapping, upperize, ) from passerelle.contrib.utils.axel import AxelError, OperationResult from passerelle.utils.jsonresponse import APIError from passerelle.utils.soap import SOAPError @pytest.fixture def resource(db): return tests.utils.make_resource( ToulouseAxel, slug='test', wsdl_url='http://example.net/AXEL_WS/AxelWS.php?wsdl' ) @pytest.fixture def link_params(): return { 'IDDUI': 'XXX', 'PRENOM': 'John', 'NOM': 'Doe', 'NAISSANCE': '2010-10-10', } @pytest.fixture def update_params(): filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/update_family_info.json') with open(filepath) as jsonfile: content = jsonfile.read() return json.loads(content) @pytest.fixture def family_data(): filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() resp = ( ''' RefFamilleDui OK 10/10/2010 10:10:01 %s '''.strip() % content ) return schemas.ref_famille_dui.response_converter.decode(ET.fromstring(resp))['DATA']['PORTAIL']['DUI'] @pytest.fixture def child_activities_data(): filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() resp = ( ''' EnfantsActivites OK 10/10/2010 10:10:01 %s '''.strip() % content ) return schemas.enfants_activites.response_converter.decode(ET.fromstring(resp))['DATA']['PORTAIL']['DUI'] @pytest.fixture def flat_update_params(): filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/flat_update_family_info.json') with open(filepath) as jsonfile: content = jsonfile.read() return json.loads(content) @pytest.fixture def booking_params(): return { 'booking_start_date': '2020-04-13', 'booking_end_date': '2020-04-17', 'booking_list_MAT': [ '3535:MAT:A19P1M1:2020-04-13', '3535:MAT:A19P1M1:2020-04-14', '3535:MAT:A19P1M1:2020-04-16', '3535:MAT:A19P1M1:2020-04-17', ], 'booking_list_MIDI': [ '3535:MIDI:A19P1M2:2020-04-13', '3535:MIDI:A19P1M2:2020-04-14', '3535:MIDI:A19P1M2:2020-04-16', '3535:MIDI:A19P1M2:2020-04-17', ], 'booking_list_SOIR': ['3535:SOIR:A19P1M3:2020-04-13'], 'booking_list_GARD': ['3535:GARD:A19P1M4:2020-04-15'], 'child_id': '3535', 'regime': 'AV', } @pytest.fixture def annual_booking_params(): return { 'booking_list_MAT': [ '3535:MAT:A19P1M1:monday', '3535:MAT:A19P1M1:tuesday', '3535:MAT:A19P1M1:thursday', '3535:MAT:A19P1M1:friday', ], 'booking_list_MIDI': [ '3535:MIDI:A19P1M2:monday', '3535:MIDI:A19P1M2:tuesday', '3535:MIDI:A19P1M2:thursday', '3535:MIDI:A19P1M2:friday', ], 'booking_list_SOIR': ['3535:SOIR:A19P1M3:monday'], 'booking_list_GARD': ['3535:GARD:A19P1M4:wednesday'], 'child_id': '3535', 'regime': 'AV', 'booking_date': '2019-08-01', } def test_lock(app, resource): resp = app.get('/toulouse-axel/test/lock?key=&locker=', status=400) assert resp.json['err_desc'] == 'key is empty' assert resp.json['err'] == 'bad-request' assert Lock.objects.count() == 0 resp = app.get('/toulouse-axel/test/lock?key=foobar&locker=') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is True assert resp.json['locker'] == '' assert resp.json['lock_date'] is not None lock_date = resp.json['lock_date'] lock = Lock.objects.latest('pk') assert lock.resource == resource assert lock.key == 'foobar' assert lock.locker == '' # again resp = app.get('/toulouse-axel/test/lock?key=foobar&locker=') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is True assert Lock.objects.count() == 1 assert resp.json['locker'] == '' assert resp.json['lock_date'] == lock_date def test_lock_with_locker(app, resource): assert Lock.objects.count() == 0 resp = app.get('/toulouse-axel/test/lock?key=foobar&locker=something') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is True assert resp.json['locker'] == 'something' assert resp.json['lock_date'] is not None lock_date = resp.json['lock_date'] lock = Lock.objects.latest('pk') assert lock.resource == resource assert lock.key == 'foobar' assert lock.locker == 'something' # again resp = app.get('/toulouse-axel/test/lock?key=foobar&locker=') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is True assert Lock.objects.count() == 1 assert resp.json['locker'] == 'something' assert resp.json['lock_date'] == lock_date def test_unlock(app, resource): Lock.objects.create(resource=resource, key='foobar', locker='something') resp = app.get('/toulouse-axel/test/unlock?key=foobar') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is False assert resp.json['locker'] == 'something' assert resp.json['lock_date'] is not None assert Lock.objects.count() == 0 # again resp = app.get('/toulouse-axel/test/unlock?key=foobar') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is False assert 'locker' not in resp.json assert 'lock_date' not in resp.json assert Lock.objects.count() == 0 def test_locked(app, resource): assert Lock.objects.count() == 0 resp = app.get('/toulouse-axel/test/locked?key=foobar') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is False assert 'locker' not in resp.json assert 'lock_date' not in resp.json Lock.objects.create(resource=resource, key='foobar', locker='something') resp = app.get('/toulouse-axel/test/locked?key=foobar') assert resp.json['err'] == 0 assert resp.json['key'] == 'foobar' assert resp.json['locked'] is True assert resp.json['locker'] == 'something' assert resp.json['lock_date'] is not None def test_operation_status_error(resource): resp = ''' RefVerifDui NOK '''.strip() with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.soap_client') as client: client.return_value.service.getData.return_value = resp with pytest.raises(AxelError, match='Foo reason'): schemas.ref_verif_dui( resource, { 'PORTAIL': { 'DUI': { 'IDDUI': 'XXX', 'IDPERSONNE': '42', 'PRENOM': 'John', 'NOM': 'Doe', 'NAISSANCE': '2010-10-10', } } }, ) @contextmanager def mock_getdata(content, operation): with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.soap_client') as client: resp = ''' %s OK 10/10/2010 10:10:01 %s '''.strip() % ( operation, content, ) client.return_value.service.getData.return_value = resp yield @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_ref_date_gestion_dui(resource, content): with mock_getdata(content, 'RefDateGestionDui'): with pytest.raises(AxelError): schemas.ref_date_gestion_dui(resource) @pytest.mark.parametrize( 'content', [ '', 'foo', '42', ], ) def test_operation_ref_verif_dui(resource, content): with mock_getdata(content, 'RefVerifDui'): with pytest.raises(AxelError): schemas.ref_verif_dui( resource, { 'PORTAIL': { 'DUI': { 'PRENOM': 'John', 'NOM': 'Doe', 'NAISSANCE': '2010-10-10', } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_ref_famille_dui(resource, content): with mock_getdata(content, 'RefFamilleDui'): with pytest.raises(AxelError): schemas.ref_famille_dui( resource, { 'PORTAIL': { 'DUI': { 'IDDUI': 'XXX', } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_form_maj_famille_dui(resource, content): with mock_getdata(content, 'FormMajFamilleDui'): with pytest.raises(AxelError): schemas.form_maj_famille_dui( resource, { 'PORTAIL': { 'DUI': { 'IDDUI': 'XXX', } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_ref_facture_a_payer(resource, content): with mock_getdata(content, 'RefFactureAPayer'): with pytest.raises(AxelError): schemas.ref_facture_a_payer( resource, { 'PORTAIL': { 'DUI': { 'IDDUI': 'XXX', } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_list_dui_factures(resource, content): with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'): with pytest.raises(AxelError): schemas.list_dui_factures(resource, {'LISTFACTURE': {'NUMDUI': 'XXX', 'DEBUT': '1970-01-01'}}) @pytest.mark.parametrize( 'content', [ "", ], ) def test_operation_ref_facture_pdf(resource, content): with mock_getdata(content, 'RefFacturePDF'): with pytest.raises(AxelError): schemas.ref_facture_pdf( resource, { 'PORTAIL': { 'FACTUREPDF': { 'IDFACTURE': 42, } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_form_paiement_dui(resource, content): with mock_getdata(content, 'FormPaiementDui'): with pytest.raises(AxelError): schemas.form_paiement_dui( resource, { 'PORTAIL': { 'DUI': { 'IDFACTURE': '42', 'IDREGIEENCAISSEMENT': '', 'MONTANTPAYE': '42.42', 'DATEPAIEMENT': '01/01/2020 12:12:12', 'REFERENCE': '42', } } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_enfants_activites(resource, content): with mock_getdata(content, 'EnfantsActivites'): with pytest.raises(AxelError): schemas.enfants_activites( resource, { 'DUI': { 'IDDUI': 'XXX', 'ANNEEREFERENCE': '2042', 'TYPESACTIVITES': 'MAT,MIDI,SOIR,GARD', } }, ) @pytest.mark.parametrize( 'content', [ '', ], ) def test_operation_reservation_periode(resource, content): with mock_getdata(content, 'ReservationPeriode'): with pytest.raises(AxelError): schemas.reservation_periode( resource, { 'PORTAIL': { 'DUI': { 'IDDUI': 'XXX', } } }, ) def test_management_dates_endpoint_axel_error(app, resource): with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_date_gestion_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/management_dates') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' assert resp.json['data'] == {'xml_request': None, 'xml_response': None} def test_management_dates_endpoint(app, resource): content = ''' 08/08/2019 18/10/2019 18/01/2020 ''' with mock_getdata(content, 'RefDateGestionDui'): resp = app.get('/toulouse-axel/test/management_dates') assert set(resp.json.keys()) == {'err', 'data'} assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'REPORT-REVENUS', 'report_revenus', 'EXTRACTION-FAMILLES', 'extraction_familles', 'EXTRACTION-CAFPRO', 'extraction_cafpro', } # again - data are in cache resp = app.get('/toulouse-axel/test/management_dates') assert set(resp.json.keys()) == {'err', 'data'} assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'REPORT-REVENUS', 'report_revenus', 'EXTRACTION-FAMILLES', 'extraction_familles', 'EXTRACTION-CAFPRO', 'extraction_cafpro', } with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.return_value = {'foo': 'bar'} resp = app.get('/toulouse-axel/test/management_dates') assert set(resp.json.keys()) == {'err', 'data'} assert resp.json['err'] == 0 assert resp.json['data'] == {'foo': 'bar'} def test_link_endpoint_nameid_empty(app, resource, link_params): resp = app.post_json('/toulouse-axel/test/link?NameID=', params=link_params, status=400) assert resp.json['err_desc'] == 'NameID is empty' assert resp.json['err'] == 'bad-request' def test_link_endpoint_axel_error(app, resource, link_params): with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_verif_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' assert resp.json['data'] == {'xml_request': None, 'xml_response': None} # test xml_request and xml_response only for this endpoint xml_request = """ XXX Doe John 10/10/2010 """ with mock_getdata('', 'RefVerifDui'): with mock.patch('xmlschema.XMLSchema.validate') as xml_validate: xml_validate.side_effect = xmlschema.XMLSchemaValidationError(None, None) resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'].startswith('Axel error: invalid request') assert resp.json['err'] == 'error' assert resp.json['data']['xml_request'] == xml_request assert resp.json['data']['xml_response'] is None xml_response = """ RefVerifDui NOK Foo reason """ response = """ RefVerifDui NOK """.strip() with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.soap_client') as client: client.return_value.service.getData.return_value = response resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'Axel error: Foo reason' assert resp.json['err'] == 'error' assert resp.json['data']['xml_request'] == xml_request assert resp.json['data']['xml_response'] == xml_response content = """ XXX 42 2 """ xml_response = ( """ RefVerifDui OK 10/10/2010 10:10:01 %s """ % content ) with mock_getdata(content, 'RefVerifDui'): with mock.patch('passerelle.contrib.utils.axel.AxelSchema.decode') as decode: decode.side_effect = xmlschema.XMLSchemaValidationError(None, None) resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'].startswith('Axel error: invalid response') assert resp.json['err'] == 'error' assert resp.json['data']['xml_request'] == xml_request assert resp.json['data']['xml_response'] == xml_response with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.soap_client') as client: client.side_effect = SOAPError('SOAP service is down') resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'SOAP service is down' @pytest.mark.parametrize( 'xml_response', [ 'XXX0', 'XXX421', 'XXX424', ], ) def test_link_endpoint_no_result(app, resource, link_params, xml_response): content = ( ''' %s ''' % xml_response ) with mock_getdata(content, 'RefVerifDui'): resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_link_endpoint_conflict(app, resource, link_params): content = ''' XXX 42 2 ''' # existing link but dui is wrong link = Link.objects.create(resource=resource, name_id='yyy', dui='YYY', person_id='42') with mock_getdata(content, 'RefVerifDui'): resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'Data conflict' assert resp.json['err'] == 'conflict' # existing link but person_id is wrong link.dui = 'XXX' link.person_id = '35' link.save() with mock_getdata(content, 'RefVerifDui'): resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert resp.json['err_desc'] == 'Data conflict' assert resp.json['err'] == 'conflict' @pytest.mark.parametrize('code', [2, 3]) def test_link_endpoint(app, resource, link_params, code): content = ( ''' XXX 42 %s ''' % code ) with mock_getdata(content, 'RefVerifDui'): resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert set(resp.json.keys()) == {'err', 'link', 'created', 'dui', 'data'} assert resp.json['err'] == 0 assert resp.json['dui'] == 'XXX' assert resp.json['created'] is True assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] # again with mock_getdata(content, 'RefVerifDui'): resp = app.post_json('/toulouse-axel/test/link?NameID=yyy', params=link_params) assert set(resp.json.keys()) == {'err', 'link', 'created', 'dui', 'data'} assert resp.json['err'] == 0 assert resp.json['dui'] == 'XXX' assert resp.json['created'] is False # link already exists assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] def test_unlink_endpoint_no_result(app, resource): resp = app.post('/toulouse-axel/test/unlink?NameID=yyy') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_unlink_endpoint(app, resource): link = Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.post('/toulouse-axel/test/unlink?NameID=yyy') assert Link.objects.exists() is False assert resp.json['err'] == 0 assert resp.json['link'] == link.pk assert resp.json['dui'] == 'XXX' assert resp.json['deleted'] is True def test_active_dui_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err_desc'] == 'No family info' assert resp.json['err'] == 'no-family-info' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_verif_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_active_dui_endpoint_no_result(app, resource, family_data): resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err_desc'] == 'Unknown NameID' assert resp.json['err'] == 'unknown' def test_active_dui_endpoint_wrong_rl(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='1234') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err_desc'] == 'No corresponding RL' assert resp.json['err'] == 'no-rl' @pytest.mark.parametrize( 'xml_response,code', [ ('XXX0', 0), ('XXX421', 1), ('XXX424', 4), ], ) def test_active_dui_endpoint_wrong_dui_code(app, resource, family_data, xml_response, code): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = ( ''' %s ''' % xml_response ) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): with mock_getdata(content, 'RefVerifDui'): resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err_desc'] == 'Wrong DUI status' assert resp.json['err'] == 'dui-code-error-%s' % code @pytest.mark.parametrize('code', [2, 3]) def test_active_dui_endpoint(app, resource, family_data, code): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = ( ''' XXX 42 %s ''' % code ) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): with mock_getdata(content, 'RefVerifDui'): resp = app.get('/toulouse-axel/test/active_dui?NameID=yyy') assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'ADRESSE', 'CODEMISEAJOUR', 'DEMATFACTURES', 'ENFANT', 'IDDUI', 'NBENFANTACTIF', 'NBRLACTIF', 'REACTUALISATIONENLIGNE', 'REVENUS', 'RL1', 'RL2', 'SITUATIONFAMILIALE', 'TELFIXE', } def test_referential_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/referential/foo/') assert resp.json['err_desc'] == 'Referential not found' assert resp.json['err'] == 'not-found' @pytest.mark.parametrize( 'code, mapping', [ ('situation_familiale', situation_familiale_mapping), ('csp', csp_mapping), ('lien_parente', lien_parente_mapping), ('type_regime', type_regime_mapping), ('regime', regime_mapping), ], ) def test_referential_endpoint(app, resource, code, mapping): resp = app.get('/toulouse-axel/test/referential/%s/' % code) expected = [{'id': k, 'text': v} for k, v in mapping.items()] assert resp.json['data'] == expected def test_family_info_endpoint_axel_error(app, resource, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.side_effect = APIError('Axel error: FooBar') with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' def test_family_info_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.return_value = OperationResult( json_response={'DATA': {'PORTAIL': None}}, xml_request='', xml_response='' ) resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err_desc'] == 'Family not found' assert resp.json['err'] == 'not-found' @freezegun.freeze_time('2020-06-30') def test_family_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.return_value = {'foo': 'bar'} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'ADRESSE', 'CODEMISEAJOUR', 'DEMATFACTURES', 'ENFANT', 'IDDUI', 'NBENFANTACTIF', 'NBRLACTIF', 'REACTUALISATIONENLIGNE', 'REVENUS', 'RL1', 'RL2', 'SITUATIONFAMILIALE', 'SITUATIONFAMILIALE_label', 'TELFIXE', 'management_dates', 'annee_reference', 'annee_reference_short', 'annee_reference_label', } assert resp.json['data']['ENFANT'][0]['id'] == '4242' assert resp.json['data']['ENFANT'][0]['text'] == 'foo foo' assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['id'] == 0 assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['text'] == 'foo foo' assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['id'] == 1 assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['text'] == 'foo2 foo2' assert resp.json['data']['ENFANT'][0]['CONTACT'][2]['id'] == 2 assert resp.json['data']['ENFANT'][0]['CONTACT'][2]['text'] == 'foo3 foo3' assert resp.json['data']['ENFANT'][1]['id'] == '3535' assert resp.json['data']['ENFANT'][1]['text'] == 'foo foo' assert resp.json['data']['management_dates'] == {'foo': 'bar'} assert resp.json['data']['annee_reference'] == 2019 assert resp.json['data']['annee_reference_short'] == '19' assert resp.json['data']['annee_reference_label'] == '2019/2020' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.are_children_registered' ) as registered: registered.return_value = {'4242': True} with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.return_value = {'foo': 'bar'} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data']['ENFANT'][0]['clae_cantine_current'] is True assert resp.json['data']['ENFANT'][1]['clae_cantine_current'] is None with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.are_children_registered' ) as registered: registered.return_value = {} with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.return_value = {'foo': 'bar'} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data']['ENFANT'][0]['clae_cantine_current'] is None assert resp.json['data']['ENFANT'][1]['clae_cantine_current'] is None assert resp.json['data']['SITUATIONFAMILIALE'] == 'S' assert resp.json['data']['SITUATIONFAMILIALE_label'] == 'Séparé (e)' assert resp.json['data']['RL1']['CSP'] == 'ETU' assert resp.json['data']['RL1']['CSP_label'] == 'Etudiants' assert resp.json['data']['RL2']['CSP'] == 'EMP' assert resp.json['data']['RL2']['CSP_label'] == 'Employés' assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['LIENPARENTE'] == 'GRP1' assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['LIENPARENTE_label'] == 'Grands-parents paternels' assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['LIENPARENTE'] is None assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['LIENPARENTE_label'] is None assert resp.json['data']['REVENUS']['TYPEREGIME'] == 'GENE' assert resp.json['data']['REVENUS']['TYPEREGIME_label'] == 'Régime général' # a DUI with less data filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info_light.xml') with open(filepath) as xml: content = xml.read() with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_management_dates' ) as management_dates: management_dates.return_value = {'foo': 'bar'} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/family_info?NameID=yyy') assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'ADRESSE', 'CODEMISEAJOUR', 'DEMATFACTURES', 'ENFANT', 'IDDUI', 'NBENFANTACTIF', 'NBRLACTIF', 'REACTUALISATIONENLIGNE', 'REVENUS', 'RL1', 'SITUATIONFAMILIALE', 'SITUATIONFAMILIALE_label', 'TELFIXE', 'management_dates', 'annee_reference', 'annee_reference_short', 'annee_reference_label', } assert resp.json['data']['ADRESSE'] is None def test_children_info_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/children_info?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_children_info_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/children_info?NameID=yyy') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_children_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/children_info?NameID=yyy') assert resp.json['err'] == 0 assert len(resp.json['data']) == 2 assert resp.json['data'][0]['id'] == '4242' assert resp.json['data'][0]['text'] == 'foo foo' assert resp.json['data'][0]['CONTACT'][0]['id'] == 0 assert resp.json['data'][0]['CONTACT'][0]['text'] == 'foo foo' assert resp.json['data'][0]['CONTACT'][1]['id'] == 1 assert resp.json['data'][0]['CONTACT'][1]['text'] == 'foo2 foo2' assert resp.json['data'][0]['CONTACT'][2]['id'] == 2 assert resp.json['data'][0]['CONTACT'][2]['text'] == 'foo3 foo3' assert resp.json['data'][1]['id'] == '3535' assert resp.json['data'][1]['text'] == 'foo foo' def test_child_info_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_child_info_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' def test_child_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=4242') assert resp.json['err'] == 0 assert set(resp.json['data'].keys()) == { 'id', 'text', 'ASSURANCE', 'CONTACT', 'DATENAISSANCE', 'IDPERSONNE', 'PRENOM', 'PRENOMMERE', 'PRENOMPERE', 'NOM', 'NOMMERE', 'NOMPERE', 'RATTACHEAUTREDUI', 'SANITAIRE', 'SEXE', 'clae_cantine_current', } assert resp.json['data']['id'] == '4242' assert resp.json['data']['text'] == 'foo foo' assert resp.json['data']['CONTACT'][0]['id'] == 0 assert resp.json['data']['CONTACT'][0]['text'] == 'foo foo' assert resp.json['data']['CONTACT'][1]['id'] == 1 assert resp.json['data']['CONTACT'][1]['text'] == 'foo2 foo2' assert resp.json['data']['CONTACT'][2]['id'] == 2 assert resp.json['data']['CONTACT'][2]['text'] == 'foo3 foo3' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.are_children_registered' ) as registered: registered.return_value = {'4242': True} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=4242') assert resp.json['err'] == 0 assert resp.json['data']['clae_cantine_current'] is True with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.are_children_registered' ) as registered: registered.return_value = {} with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_info?NameID=yyy&idpersonne=4242') assert resp.json['err'] == 0 assert resp.json['data']['clae_cantine_current'] is None assert resp.json['data']['CONTACT'][0]['LIENPARENTE'] == 'GRP1' assert resp.json['data']['CONTACT'][0]['LIENPARENTE_label'] == 'Grands-parents paternels' assert resp.json['data']['CONTACT'][1]['LIENPARENTE'] is None assert resp.json['data']['CONTACT'][1]['LIENPARENTE_label'] is None def test_child_contacts_info_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/child_contacts_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_child_contacts_info_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/child_contacts_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_contacts_info?NameID=yyy&idpersonne=zzz') assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' def test_child_contacts_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_contacts_info?NameID=yyy&idpersonne=4242') assert resp.json['err'] == 0 assert len(resp.json['data']) == 3 assert resp.json['data'][0]['id'] == 0 assert resp.json['data'][0]['text'] == 'foo foo' assert resp.json['data'][1]['id'] == 1 assert resp.json['data'][1]['text'] == 'foo2 foo2' assert resp.json['data'][2]['id'] == 2 assert resp.json['data'][2]['text'] == 'foo3 foo3' with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/child_contacts_info?NameID=yyy&idpersonne=3535') assert resp.json['err'] == 0 assert len(resp.json['data']) == 1 assert resp.json['data'][0]['id'] == 0 assert resp.json['data'][0]['text'] == 'foo foo' def test_children_contacts_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/family_info.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFamilleDui'): resp = app.get('/toulouse-axel/test/children_contacts_info?NameID=yyy') assert resp.json['err'] == 0 assert len(resp.json['data']) == 3 assert {x['text'] for x in resp.json['data']} == {'foo foo', 'foo2 foo2', 'foo3 foo3'} assert {x['id'] for x in resp.json['data']} == {0, 1, 2} def test_update_family_info_endpoint_axel_error(app, resource, update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.form_maj_famille_dui') as operation: operation.side_effect = AxelError('FooBar') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' assert 'error_post_data' in resp.json['data'] def test_update_family_info_endpoint_no_result(app, resource, update_params): resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_update_family_info_endpoint(app, resource, update_params, family_data): link = Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = '' with mock_getdata(content, 'FormMajFamilleDui'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert resp.json['err'] == 0 assert resp.json['dui'] == 'XXX' assert resp.json['updated'] is True assert 'data' in resp.json assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] with mock.patch('passerelle.contrib.toulouse_axel.schemas.form_maj_famille_dui') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert operation.call_args_list[0][0][1]['PORTAIL']['DUI']['IDDUI'] == 'XXX' assert operation.call_args_list[0][0][1]['PORTAIL']['DUI'][ 'DATEDEMANDE' ] == datetime.date.today().strftime('%Y-%m-%d') assert operation.call_args_list[0][0][1]['PORTAIL']['DUI']['QUIACTUALISEDUI'] == '1' link.person_id = '35' link.save() with mock.patch('passerelle.contrib.toulouse_axel.schemas.form_maj_famille_dui') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert operation.call_args_list[0][0][1]['PORTAIL']['DUI']['IDDUI'] == 'XXX' assert operation.call_args_list[0][0][1]['PORTAIL']['DUI'][ 'DATEDEMANDE' ] == datetime.date.today().strftime('%Y-%m-%d') assert operation.call_args_list[0][0][1]['PORTAIL']['DUI']['QUIACTUALISEDUI'] == '2' def test_update_family_info_flat_endpoint(app, resource, flat_update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = '' with mock_getdata(content, 'FormMajFamilleDui'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resp = app.post_json( '/toulouse-axel/test/update_family_info?NameID=yyy', params=flat_update_params ) assert resp.json['err'] == 0 assert resp.json['dui'] == 'XXX' assert resp.json['updated'] is True assert 'data' in resp.json assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] def test_sanitize_update_family_data_missing_rl_fields(app, resource, update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA full_update_params = copy.deepcopy(update_params) for key in ['IDPERSONNE', 'NOM', 'PRENOM', 'NOMJEUNEFILLE', 'DATENAISSANCE', 'CIVILITE']: assert key not in full_update_params['RL1'] assert key not in full_update_params['RL2'] resource.pre_sanitize_update_family_data(post_data=full_update_params) jsonschema.validate(full_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=full_update_params) for key in ['IDPERSONNE', 'NOM', 'PRENOM', 'NOMJEUNEFILLE', 'DATENAISSANCE', 'CIVILITE']: assert full_update_params['RL1'][key] == family_data['RL1'][key] assert full_update_params['RL2'][key] == family_data['RL2'][key] assert full_update_params['RL1']['INDICATEURRL'] == '1' assert full_update_params['RL2']['INDICATEURRL'] == '2' def test_sanitize_update_family_data_missing_revenus_fields(app, resource, update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA full_update_params = copy.deepcopy(update_params) assert 'NBENFANTSACHARGE' not in update_params['REVENUS'] resource.pre_sanitize_update_family_data(post_data=full_update_params) jsonschema.validate(full_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=full_update_params) assert full_update_params['REVENUS']['NBENFANTSACHARGE'] == family_data['REVENUS']['NBENFANTSACHARGE'] # if revenus are not set in Axel full_update_params = copy.deepcopy(update_params) family_data.pop('REVENUS') resource.pre_sanitize_update_family_data(post_data=full_update_params) jsonschema.validate(full_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=full_update_params) assert full_update_params['REVENUS']['NBENFANTSACHARGE'] is None def test_pre_sanitize_update_upperize(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA def check_upper(data): if isinstance(data, dict): for val in data.values(): check_upper(val) if isinstance(data, list): for val in data: check_upper(val) if isinstance(data, str): assert data == data.upper() resource.pre_sanitize_update_family_data(post_data=update_params) jsonschema.validate(update_params, json_schema) check_upper(update_params) assert upperize('something with an accent é') == 'SOMETHING WITH AN ACCENT E' def test_pre_sanitize_update_family_data_adresse(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:adresse partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:adresse'] = False for key in partial_update_params['ADRESSE'].keys(): partial_update_params['ADRESSE'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) for value in partial_update_params['ADRESSE'].values(): assert value is None def test_pre_sanitize_update_family_data_revenus(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:revenus partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:revenus'] = False for key in partial_update_params['REVENUS'].keys(): partial_update_params['REVENUS'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'REVENUS' not in partial_update_params partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:revenus'] = False partial_update_params.pop('REVENUS') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'REVENUS' not in partial_update_params def test_pre_sanitize_update_family_data_rln(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:rln partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl1'] = False for key in partial_update_params['RL1'].keys(): partial_update_params['RL1'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'RL1' not in partial_update_params partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl2'] = False for key in partial_update_params['RL2'].keys(): partial_update_params['RL2'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'RL2' not in partial_update_params partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl1'] = False partial_update_params['maj:rl2'] = False partial_update_params.pop('RL1') partial_update_params.pop('RL2') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'RL1' not in partial_update_params assert 'RL2' not in partial_update_params def test_pre_sanitize_update_family_data_rln_adresse_employeur(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:rln_adresse_employeur partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl1_adresse_employeur'] = False for key in partial_update_params['RL1']['ADREMPLOYEUR'].keys(): partial_update_params['RL1']['ADREMPLOYEUR'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ADREMPLOYEUR' not in partial_update_params['RL1'] partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl2_adresse_employeur'] = False for key in partial_update_params['RL2']['ADREMPLOYEUR'].keys(): partial_update_params['RL2']['ADREMPLOYEUR'][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ADREMPLOYEUR' not in partial_update_params['RL2'] # combine with maj:rln partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl1'] = False partial_update_params['maj:rl1_adresse_employeur'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'RL1' not in partial_update_params partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl2'] = False partial_update_params['maj:rl2_adresse_employeur'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'RL2' not in partial_update_params # test maj:rln_adresse_employeur not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl1_adresse_employeur'] = val partial_update_params['RL1'].pop('ADREMPLOYEUR') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ADREMPLOYEUR' not in partial_update_params['RL1'] partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:rl2_adresse_employeur'] = val partial_update_params['RL2'].pop('ADREMPLOYEUR') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ADREMPLOYEUR' not in partial_update_params['RL2'] def test_pre_sanitize_update_family_data_enfant_n(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0'] = False for key in partial_update_params['ENFANT'][0].keys(): if key == 'IDPERSONNE': continue partial_update_params['ENFANT'][0][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False for key in partial_update_params['ENFANT'][1].keys(): if key == 'IDPERSONNE': continue partial_update_params['ENFANT'][1][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '4242' # do not fill IDPERSONNE for the removed child partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False for key in partial_update_params['ENFANT'][1].keys(): partial_update_params['ENFANT'][1][key] = None # reset fields resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '4242' # remove all children partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0'] = False partial_update_params['maj:enfant_1'] = False partial_update_params.pop('ENFANT') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # unknown child partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_5'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 2 # missing IDPERSONNE partial_update_params = copy.deepcopy(update_params) partial_update_params['ENFANT'][0].pop('IDPERSONNE') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 def test_pre_sanitize_update_family_data_enfant_n_assurance(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_assurance partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_assurance'] = False for key in partial_update_params['ENFANT'][1]['ASSURANCE'].keys(): partial_update_params['ENFANT'][1]['ASSURANCE'][key] = None # reset fields partial_update_params['maj:enfant_0'] = False # check that ordering is not a problem resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'ASSURANCE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_assurance'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_assurance not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_assurance'] = val partial_update_params['maj:enfant_0'] = False partial_update_params['ENFANT'][0].pop('ASSURANCE') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ASSURANCE' not in partial_update_params['ENFANT'][0] def test_pre_sanitize_update_family_data_enfant_n_contact(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_contact partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_contact'] = False for i, contact in enumerate(partial_update_params['ENFANT'][0]['CONTACT']): for key in contact.keys(): partial_update_params['ENFANT'][0]['CONTACT'][i][key] = None # reset fields partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '4242' assert 'CONTACT' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_contact'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_contact not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_contact'] = val partial_update_params['ENFANT'][0].pop('CONTACT') partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'CONTACT' not in partial_update_params['ENFANT'][0] # third contact of first child is not complete partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'CONTACT' in partial_update_params['ENFANT'][0] assert len(partial_update_params['ENFANT'][0]['CONTACT']) == 2 def test_pre_sanitize_update_family_data_enfant_n_sanitaire(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_sanitaire partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire'] = False for key in partial_update_params['ENFANT'][1]['SANITAIRE'].keys(): partial_update_params['ENFANT'][1]['SANITAIRE'][key] = None # reset fields partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_sanitaire'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_sanitaire not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire'] = val partial_update_params['maj:enfant_1_sanitaire'] = val partial_update_params['ENFANT'][0].pop('SANITAIRE') partial_update_params['ENFANT'][1].pop('SANITAIRE') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] assert 'SANITAIRE' not in partial_update_params['ENFANT'][1] def test_sanitize_update_family_data_enfant_n_sanitaire_allergie(app, resource, update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_sanitaire_allergie partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_allergie'] = False for key in partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'].keys(): partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'][key] = None # reset fields partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert '_to_reset' in partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '4242' assert 'ALLERGIE' in partial_update_params['ENFANT'][0]['SANITAIRE'] # fields were set with origin values found in Axel new_values = partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'] old_values = family_data['ENFANT'][0]['SANITAIRE']['ALLERGIE'] assert new_values == old_values # combine with maj:enfant_n_sanitaire partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire'] = False partial_update_params['maj:enfant_1_sanitaire_allergie'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_sanitaire_allergie'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_sanitaire_allergie not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_allergie'] = val partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) new_values = partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'] old_values = family_data['ENFANT'][0]['SANITAIRE']['ALLERGIE'] assert new_values == old_values # allergie field is required partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_allergie'] = False partial_update_params['ENFANT'][0]['SANITAIRE'].pop('ALLERGIE') resource.pre_sanitize_update_family_data(post_data=partial_update_params) with pytest.raises(jsonschema.exceptions.ValidationError, match="'ALLERGIE' is a required property"): jsonschema.validate(partial_update_params, json_schema) def test_sanitize_update_family_data_enfant_n_sanitaire_allergie_values( app, resource, update_params, family_data ): json_schema = schemas.UPDATE_FAMILY_SCHEMA # check values partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ASTHME'] = 'NON' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['MEDICAMENTEUSES'] = '0' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ALIMENTAIRES'] = 'False' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['AUTRES'] = '' resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert 'ALLERGIE' not in partial_update_params['ENFANT'][0]['SANITAIRE'] partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ASTHME'] = False partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['MEDICAMENTEUSES'] = '' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ALIMENTAIRES'] = None partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['AUTRES'] = '' resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert 'ALLERGIE' not in partial_update_params['ENFANT'][0]['SANITAIRE'] partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ASTHME'] = 'OUI' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['MEDICAMENTEUSES'] = '1' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ALIMENTAIRES'] = 'True' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['AUTRES'] = 'accariens' resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'] == [ {'TYPE': 'ASTHME', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': None}, {'TYPE': 'MEDICAMENTEUSES', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': None}, {'TYPE': 'ALIMENTAIRES', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': None}, {'TYPE': 'AUTRES', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': 'ACCARIENS'}, ] partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ASTHME'] = '' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['MEDICAMENTEUSES'] = '1' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['ALIMENTAIRES'] = 'True' partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE']['AUTRES'] = '' resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert partial_update_params['ENFANT'][0]['SANITAIRE']['ALLERGIE'] == [ {'TYPE': 'MEDICAMENTEUSES', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': None}, {'TYPE': 'ALIMENTAIRES', 'ALLERGIQUE': 'OUI', 'NOMALLERGIE': None}, ] def test_pre_sanitize_update_family_data_enfant_n_sanitaire_medecin(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_sanitaire_medecin partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire_medecin'] = False for key in partial_update_params['ENFANT'][1]['SANITAIRE']['MEDECIN'].keys(): partial_update_params['ENFANT'][1]['SANITAIRE']['MEDECIN'][key] = None # reset fields partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'MEDECIN' not in partial_update_params['ENFANT'][0]['SANITAIRE'] # combine with maj:enfant_n_sanitaire partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire'] = False partial_update_params['maj:enfant_1_sanitaire_medecin'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_sanitaire_medecin'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_sanitaire_medecin not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_medecin'] = val partial_update_params['maj:enfant_1_sanitaire_medecin'] = val partial_update_params['ENFANT'][0]['SANITAIRE'].pop('MEDECIN') partial_update_params['ENFANT'][1]['SANITAIRE'].pop('MEDECIN') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'MEDECIN' not in partial_update_params['ENFANT'][0]['SANITAIRE'] assert 'MEDECIN' not in partial_update_params['ENFANT'][1]['SANITAIRE'] def test_pre_sanitize_update_family_data_enfant_n_sanitaire_vaccin(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_sanitaire_vaccin partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire_vaccin'] = False for key in partial_update_params['ENFANT'][1]['SANITAIRE']['VACCIN'].keys(): partial_update_params['ENFANT'][1]['SANITAIRE']['VACCIN'][key] = None # reset fields partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'VACCIN' not in partial_update_params['ENFANT'][0]['SANITAIRE'] # combine with maj:enfant_n_sanitaire partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire'] = False partial_update_params['maj:enfant_1_sanitaire_vaccin'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_sanitaire_vaccin'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_sanitaire_vaccin not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_vaccin'] = val partial_update_params['maj:enfant_1_sanitaire_vaccin'] = val partial_update_params['ENFANT'][0]['SANITAIRE'].pop('VACCIN') partial_update_params['ENFANT'][1]['SANITAIRE'].pop('VACCIN') resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert 'VACCIN' not in partial_update_params['ENFANT'][0]['SANITAIRE'] assert 'VACCIN' not in partial_update_params['ENFANT'][1]['SANITAIRE'] def test_sanitize_update_family_data_enfant_n_sanitaire_handicap(app, resource, update_params, family_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA # test maj:enfant_n_sanitaire_handicap partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_handicap'] = False # reset fields handicap_fields = [ 'AUTREDIFFICULTE', 'ECOLESPECIALISEE', 'INDICATEURAUXILIAIREVS', 'INDICATEURECOLE', 'INDICATEURHANDICAP', 'INDICATEURNOTIFMDPH', ] for key in handicap_fields: partial_update_params['ENFANT'][0]['SANITAIRE']['HANDICAP'][key] = None partial_update_params['maj:enfant_1'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) assert '_to_reset' in partial_update_params['ENFANT'][0]['SANITAIRE']['HANDICAP'] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '4242' # fields were set with origin values found in Axel new_values = partial_update_params['ENFANT'][0]['SANITAIRE'] for key in handicap_fields: assert new_values[key] == family_data['ENFANT'][0]['SANITAIRE'][key] assert '_to_reset' not in new_values assert 'HANDICAP' not in new_values # combine with maj:enfant_n_sanitaire partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1_sanitaire'] = False partial_update_params['maj:enfant_1_sanitaire_handicap'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert len(partial_update_params['ENFANT']) == 1 assert partial_update_params['ENFANT'][0]['IDPERSONNE'] == '3535' assert 'SANITAIRE' not in partial_update_params['ENFANT'][0] # combine with maj:enfant_n partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_1'] = False partial_update_params['maj:enfant_1_sanitaire_handicap'] = False partial_update_params['maj:enfant_0'] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) assert 'ENFANT' not in partial_update_params # test maj:enfant_n_sanitaire_handicap not set for val in [None, '']: partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_handicap'] = val partial_update_params['maj:enfant_1'] = False # reset fields for key in handicap_fields: partial_update_params['ENFANT'][0]['SANITAIRE']['HANDICAP'][key] = None resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_family_data', return_value=family_data ): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) new_values = partial_update_params['ENFANT'][0]['SANITAIRE'] for key in handicap_fields: assert new_values[key] == family_data['ENFANT'][0]['SANITAIRE'][key] assert 'HANDICAP' not in new_values # handicap field is required partial_update_params = copy.deepcopy(update_params) partial_update_params['maj:enfant_0_sanitaire_handicap'] = False partial_update_params['ENFANT'][0]['SANITAIRE'].pop('HANDICAP') resource.pre_sanitize_update_family_data(post_data=partial_update_params) with pytest.raises(jsonschema.exceptions.ValidationError, match="'HANDICAP' is a required property"): jsonschema.validate(partial_update_params, json_schema) @pytest.mark.parametrize( 'flags', [ # get family data to fill handicap fields ['maj:enfant_0_sanitaire_handicap', 'maj:revenus', 'maj:rl1', 'maj:rl2'], # get family data to fill revenus fields ['maj:rl1', 'maj:rl2'], # get family data to fill rl1 fields ['maj:revenus', 'maj:rl2'], # get family data to fill rl2 fields ['maj:revenus', 'maj:rl1'], ], ) def test_sanitize_update_family_data_axel_error(app, resource, update_params, flags): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') json_schema = schemas.UPDATE_FAMILY_SCHEMA partial_update_params = copy.deepcopy(update_params) for flag in flags: partial_update_params[flag] = False resource.pre_sanitize_update_family_data(post_data=partial_update_params) jsonschema.validate(partial_update_params, json_schema) with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_famille_dui') as operation: operation.side_effect = AxelError('FooBar') with pytest.raises(APIError, match='Axel error: FooBar'): resource.sanitize_update_family_data(dui='XXX', post_data=partial_update_params) def test_update_family_info_endpoint_sanitize_axel_error(app, resource, update_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.sanitize_update_family_data' ) as sanitize: sanitize.side_effect = APIError('Axel error: FooBar') resp = app.post_json('/toulouse-axel/test/update_family_info?NameID=yyy', params=update_params) assert resp.json['err_desc'] == 'Axel error: FooBar' def test_invoices_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=', status=400) assert 'InvalidParameterValue' in resp.json['err_class'] assert resp.json['err'] == 1 def test_invoices_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_invoices_endpoint_no_invoices(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = ''' XXX 0 0 ''' with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_invoices_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': 'XXX-42', 'display_id': '42', 'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'amount': '4.94', 'total_amount': '44.94', 'amount_paid': '40.00', 'online_payment': True, 'created': '2019-11-12', 'pay_limit_date': '2019-12-04', 'has_pdf': True, 'paid': False, 'vendor': { 'toulouse-axel': { 'IDFACTURATION': '4242-35AA', 'IDFACTURE': 42, 'IDREGIE': 'MAREGIE', 'DATEECHEANCE': '2019-12-04', 'DATEEMISSION': '2019-11-12', 'EXISTEPDF': '1', 'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'MONTANTTOTAL': '44.94', 'NUMFACTURE': 42, 'RESTEAPAYER': '4.94', } }, }, { 'id': 'XXX-43', 'display_id': '43', 'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019', 'amount': '44.94', 'total_amount': '44.94', 'amount_paid': '', 'online_payment': True, 'created': '2019-12-12', 'pay_limit_date': '2020-01-04', 'has_pdf': False, 'paid': False, 'vendor': { 'toulouse-axel': { 'IDFACTURATION': '4243-35AA', 'IDFACTURE': 43, 'DATEECHEANCE': '2020-01-04', 'DATEEMISSION': '2019-12-12', 'EXISTEPDF': '0', 'IDREGIE': 'MAREGIE', 'LIBELLE': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019', 'MONTANTTOTAL': '44.94', 'NUMFACTURE': 43, 'RESTEAPAYER': '44.94', } }, }, ] with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/AUTREREGIE/invoices?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': 'XXX-44', 'display_id': '44', 'label': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019', 'amount': '44.94', 'total_amount': '44.94', 'amount_paid': '', 'online_payment': True, 'created': '2020-01-12', 'pay_limit_date': '2020-01-15', 'has_pdf': True, 'paid': False, 'vendor': { 'toulouse-axel': { 'IDFACTURATION': '4244-35AA', 'IDFACTURE': 44, 'IDREGIE': 'AUTREREGIE', 'DATEECHEANCE': '2020-01-15', 'DATEEMISSION': '2020-01-12', 'EXISTEPDF': '1', 'LIBELLE': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019', 'MONTANTTOTAL': '44.94', 'NUMFACTURE': 44, 'RESTEAPAYER': '44.94', } }, } ] def test_invoices_history_endpoint_empty_nameid_error(app, resource): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices/history?NameID=', status=400) assert resp.json['err_desc'] == 'invalid value for parameter "NameID"' assert resp.json['err'] == 1 def test_invoices_history_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.list_dui_factures') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices/history?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_invoices_history_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices/history?NameID=yyy') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_invoices_history_endpoint_no_invoices(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = ''' 0 ''' with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices/history?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_invoices_history_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices_history.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices/history?NameID=yyy') assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'amount': 0, 'created': '2017-03-23', 'display_id': '42', 'has_pdf': True, 'id': 'historical-XXX-42', 'label': 'PRESTATIONS SEPTEMBRE 2015', 'online_payment': False, 'paid': False, 'pay_limit_date': '', 'total_amount': '28.98', 'vendor': { 'toulouse-axel': { 'EMISSION': '2017-03-23', 'IDAXEL': 'AXEL', 'IDDIRECTION': 'DIR-A', 'IDFACTURE': 42, 'IDFAMILLE': 'XXX', 'IPDF': 'O', 'LIBDIRECTION': 'DIRECTION A', 'LIBELLE': 'PRESTATIONS SEPTEMBRE 2015', 'MONTANT': '28.98', 'NOFACTURE': 42, 'NUMDIRECTION': 10, } }, }, { 'amount': 0, 'created': '2017-03-23', 'display_id': '43', 'has_pdf': False, 'id': 'historical-XXX-43', 'label': 'PRESTATIONS OCTOBRE 2015', 'online_payment': False, 'paid': False, 'pay_limit_date': '', 'total_amount': '28.98', 'vendor': { 'toulouse-axel': { 'EMISSION': '2017-03-23', 'IDAXEL': 'AXEL', 'IDDIRECTION': 'DIR-B', 'IDFACTURE': 43, 'IDFAMILLE': 'XXX', 'IPDF': 'N', 'LIBDIRECTION': 'DIRECTION B', 'LIBELLE': 'PRESTATIONS OCTOBRE 2015', 'MONTANT': '28.98', 'NOFACTURE': 43, 'NUMDIRECTION': 11, } }, }, ] def test_invoice_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_invoice_endpoint_no_result(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35?NameID=yyy') assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44?NameID=yyy') assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' @pytest.mark.parametrize('dui', ['XXX', 'S-XXX']) def test_invoice_endpoint(app, resource, dui): Link.objects.create(resource=resource, name_id='yyy', dui=dui, person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read().replace('XXX', dui) with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/%s-42?NameID=yyy' % dui) assert resp.json['err'] == 0 assert resp.json['data'] == { 'id': '%s-42' % dui, 'display_id': '42', 'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'amount': '4.94', 'total_amount': '44.94', 'amount_paid': '40.00', 'online_payment': True, 'created': '2019-11-12', 'pay_limit_date': '2019-12-04', 'has_pdf': True, 'paid': False, 'vendor': { 'toulouse-axel': { 'IDFACTURATION': '4242-35AA', 'IDFACTURE': 42, 'IDREGIE': 'MAREGIE', 'DATEECHEANCE': '2019-12-04', 'DATEEMISSION': '2019-11-12', 'EXISTEPDF': '1', 'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'MONTANTTOTAL': '44.94', 'NUMFACTURE': 42, 'RESTEAPAYER': '4.94', } }, } filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices_history.xml') with open(filepath) as xml: content = xml.read().replace('XXX', dui) with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/historical-%s-42?NameID=yyy' % dui) assert resp.json['err'] == 0 assert resp.json['data'] == { 'amount': 0, 'created': '2017-03-23', 'display_id': '42', 'has_pdf': True, 'id': 'historical-%s-42' % dui, 'label': 'PRESTATIONS SEPTEMBRE 2015', 'online_payment': False, 'paid': False, 'pay_limit_date': '', 'total_amount': '28.98', 'vendor': { 'toulouse-axel': { 'EMISSION': '2017-03-23', 'IDAXEL': 'AXEL', 'IDDIRECTION': 'DIR-A', 'IDFACTURE': 42, 'IDFAMILLE': dui, 'IPDF': 'O', 'LIBDIRECTION': 'DIRECTION A', 'LIBELLE': 'PRESTATIONS SEPTEMBRE 2015', 'MONTANT': '28.98', 'NOFACTURE': 42, 'NUMDIRECTION': 10, } }, } @pytest.mark.parametrize('dui', ['XXX', 'S-XXX']) def test_invoice_endpoint_anonymous(app, resource, dui): Link.objects.create(resource=resource, name_id='yyy', dui=dui, person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read().replace('XXX', dui) with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/%s-42' % dui) assert resp.json['err'] == 0 assert resp.json['data'] == { 'id': '%s-42' % dui, 'display_id': '42', 'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'amount': '4.94', 'total_amount': '44.94', 'amount_paid': '40.00', 'online_payment': True, 'created': '2019-11-12', 'pay_limit_date': '2019-12-04', 'has_pdf': True, 'paid': False, 'vendor': { 'toulouse-axel': { 'IDFACTURATION': '4242-35AA', 'IDFACTURE': 42, 'IDREGIE': 'MAREGIE', 'DATEECHEANCE': '2019-12-04', 'DATEEMISSION': '2019-11-12', 'EXISTEPDF': '1', 'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', 'MONTANTTOTAL': '44.94', 'NUMFACTURE': 42, 'RESTEAPAYER': '4.94', } }, } filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices_history.xml') with open(filepath) as xml: content = xml.read().replace('XXX', dui) with mock_getdata(content, 'ListeDuiFacturesPayeesRecettees'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/historical-%s-42' % dui) assert resp.json['err'] == 0 assert resp.json['data'] == { 'amount': 0, 'created': '2017-03-23', 'display_id': '42', 'has_pdf': True, 'id': 'historical-%s-42' % dui, 'label': 'PRESTATIONS SEPTEMBRE 2015', 'online_payment': False, 'paid': False, 'pay_limit_date': '', 'total_amount': '28.98', 'vendor': { 'toulouse-axel': { 'EMISSION': '2017-03-23', 'IDAXEL': 'AXEL', 'IDDIRECTION': 'DIR-A', 'IDFACTURE': 42, 'IDFAMILLE': dui, 'IPDF': 'O', 'LIBDIRECTION': 'DIRECTION A', 'LIBELLE': 'PRESTATIONS SEPTEMBRE 2015', 'MONTANT': '28.98', 'NOFACTURE': 42, 'NUMDIRECTION': 10, } }, } def test_invoice_pdf_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_pdf') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_invoice_pdf_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' with mock_getdata(content, 'RefFactureAPayer'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-43/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'PDF not available' assert resp.json['err'] == 'not-available' pdf_content = ''' ''' with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice: invoice.return_value = {'has_pdf': True, 'display_id': '42'} with mock_getdata(pdf_content, 'RefFacturePDF'): resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404) assert resp.json['err_desc'] == 'PDF error' assert resp.json['err'] == 'error' @pytest.mark.parametrize('dui', ['XXX', 'S-XXX']) def test_invoice_pdf_endpoint(app, resource, dui): Link.objects.create(resource=resource, name_id='yyy', dui=dui, person_id='42') pdf_content = ''' ''' with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice: invoice.return_value = {'has_pdf': True, 'display_id': '42'} with mock_getdata(pdf_content, 'RefFacturePDF'): app.get('/toulouse-axel/test/regie/MAREGIE/invoice/%s-42/pdf?NameID=yyy' % dui) assert invoice.call_args_list[0][1]['historical'] is False with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice: invoice.return_value = {'has_pdf': True, 'display_id': '42'} with mock_getdata(pdf_content, 'RefFacturePDF'): app.get('/toulouse-axel/test/regie/MAREGIE/invoice/historical-%s-42/pdf?NameID=yyy' % dui) assert invoice.call_args_list[0][1]['historical'] is True def test_pay_invoice_endpoint_axel_error(app, resource): payload = { 'transaction_date': '2020-01-01T12:00:00', 'transaction_id': 'foo', } Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.ref_facture_a_payer') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json( '/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.form_paiement_dui') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json( '/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_pay_invoice_endpoint_no_result(app, resource): payload = { 'transaction_date': '2020-01-01T12:00:00', 'transaction_id': 'foo', } filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'RefFactureAPayer'): resp = app.post_json( '/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35/pay?NameID=yyy', params=payload ) assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' with mock_getdata(content, 'RefFactureAPayer'): resp = app.post_json( '/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44/pay?NameID=yyy', params=payload ) assert resp.json['err_desc'] == 'Invoice not found' assert resp.json['err'] == 'not-found' @pytest.mark.parametrize('dui', ['XXX', 'S-XXX']) def test_pay_invoice_endpoint(app, resource, dui): payload = { 'transaction_date': '2020-01-01T12:00:00', 'transaction_id': 'foo', } Link.objects.create(resource=resource, name_id='yyy', dui=dui, person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') with open(filepath) as xml: content = xml.read().replace('XXX', dui) with mock_getdata(content, 'RefFactureAPayer'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.form_paiement_dui') as operation: resp = app.post_json( '/toulouse-axel/test/regie/MAREGIE/invoice/%s-42/pay?NameID=yyy' % dui, params=payload ) assert resp.json['err'] == 0 assert resp.json['data'] is True assert operation.call_args_list[0][0][1] == { 'PORTAIL': { 'DUI': { 'DATEPAIEMENT': '01/01/2020 13:00:00', 'IDFACTURE': 42, 'IDREGIEENCAISSEMENT': '', 'MONTANTPAYE': decimal.Decimal('4.94'), 'REFERENCE': 'foo', } } } @freezegun.freeze_time('2020-06-30') def test_clae_years_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/clae_years?NameID=yyy&pivot_date=06-15') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @pytest.mark.parametrize('value', ['foo', '20/01/2020', '15/06', '06']) def test_clae_years_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get('/toulouse-axel/test/clae_years?NameID=yyy&pivot_date=%s' % value, status=400) assert resp.json['err_desc'] == 'bad date format, should be MM-DD' assert resp.json['err'] == 'bad-request' def test_clae_years_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/clae_years?NameID=yyy&pivot_date=06-15') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' @pytest.mark.parametrize( 'today,pivot,next_year,next_date', [ ('2019-08-01', '08-01', True, '2020-08-01'), ('2019-08-01', '08-02', False, None), ('2020-07-31', '07-31', True, '2021-07-31'), ('2020-07-30', '07-31', False, None), ('2020-06-14', '06-15', False, None), ('2020-06-15', '06-15', True, '2021-06-15'), ('2020-06-16', '06-15', True, '2021-06-16'), ('2020-02-29', '02-01', True, '2021-03-01'), ], ) def test_clae_years_endpoint(app, resource, today, pivot, next_year, next_date): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with freezegun.freeze_time(today): resp = app.get('/toulouse-axel/test/clae_years?NameID=yyy&pivot_date=%s' % pivot) assert resp.json['data'][0] == {'id': '2019', 'text': '2019/2020', 'type': 'encours', 'refdate': today} if next_year: assert len(resp.json['data']) == 2 assert resp.json['data'][1] == { 'id': '2020', 'text': '2020/2021', 'type': 'suivante', 'refdate': next_date, } else: assert len(resp.json['data']) == 1 @freezegun.freeze_time('2020-06-30') def test_clae_years_endpoint_noactivities(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_children_activities', return_value={} ) as mock_activities: resp = app.get('/toulouse-axel/test/clae_years?NameID=yyy&pivot_date=06-15') assert mock_activities.call_args_list == [mock.call(dui='XXX', reference_year=2020)] assert len(resp.json['data']) == 1 def test_clae_children_activities_info_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get('/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=2020-01-20') assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020']) def test_clae_children_activities_info_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=%s' % value, status=400 ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' def test_clae_children_activities_info_endpoint_no_result(app, resource): resp = app.get('/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=2020-01-20') assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' def test_clae_children_activities_info_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): resp = app.get('/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=2020-01-20') assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'ACTIVITE': [ { 'COUTREVIENT': '99999', 'DATEDEBUT': '2019-08-01', 'DATEENTREE': '2019-08-01', 'DATEFIN': '2020-07-31', 'DATESORTIE': '2020-07-31', 'IDACTIVITE': 'A19P1M1', 'ISPAI': False, 'LIBELLEACTIVITE': 'Temps du matin', 'TARIF': '0.42', 'TYPEACTIVITE': 'MAT', }, { 'COUTREVIENT': '99999', 'DATEDEBUT': '2019-08-01', 'DATEENTREE': '2019-08-01', 'DATEFIN': '2020-07-31', 'DATESORTIE': '2020-07-31', 'IDACTIVITE': 'A19P1M2', 'ISPAI': False, 'LIBELLEACTIVITE': 'Temps du midi', 'TARIF': '0.43', 'TYPEACTIVITE': 'MIDI', }, { 'COUTREVIENT': '99999', 'DATEDEBUT': '2019-08-01', 'DATEENTREE': '2019-08-01', 'DATEFIN': '2020-07-31', 'DATESORTIE': '2020-07-31', 'IDACTIVITE': 'A19P1M3', 'ISPAI': False, 'LIBELLEACTIVITE': 'Temps du soir', 'TARIF': '0.44', 'TYPEACTIVITE': 'SOIR', }, { 'COUTREVIENT': '99999', 'DATEDEBUT': '2019-08-01', 'DATEENTREE': '2019-08-01', 'DATEFIN': '2020-07-31', 'DATESORTIE': '2020-07-31', 'IDACTIVITE': 'A19P1M4', 'ISPAI': False, 'LIBELLEACTIVITE': 'Temps mercredi apr\xe8s midi', 'TARIF': '0.45', 'TYPEACTIVITE': 'GARD', }, ], 'DATENAISSANCE': '2019-01-01', 'IDPERSONNE': '3535', 'LIBELLEECOLE': 'MATERNELLE 1', 'NOM': 'foo', 'PRENOM': 'foo', 'REGIME': 'SV', 'REGIME_label': 'Menu sans viande', 'id': '3535', 'text': 'foo foo', } ] # again - data are in cache resp = app.get('/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=2020-01-20') assert resp.json['err'] == 0 @pytest.mark.parametrize( 'activities, expected', [ # all activities except GARD - optional (['MAT', 'MIDI', 'SOIR'], True), # all activities (['MAT', 'MIDI', 'SOIR', 'GARD'], True), # duplicated activities (['MAT', 'MAT', 'MIDI', 'SOIR', 'GARD'], False), (['MAT', 'MIDI', 'MIDI', 'SOIR', 'GARD'], False), (['MAT', 'MIDI', 'SOIR', 'SOIR', 'GARD'], False), (['MAT', 'MIDI', 'SOIR', 'GARD', 'GARD'], False), # missing activity (['MIDI', 'SOIR'], False), (['MAT', 'SOIR'], False), (['MAT', 'MIDI'], False), ], ) def test_clae_children_activities_info_check(app, resource, activities, expected): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') result = [] for activity in activities: result.append({'IDACTIVITE': 'foo%s' % activity, 'TYPEACTIVITE': activity}) result = { 'DATA': { 'PORTAIL': { 'DUI': { 'ENFANT': [ { 'IDPERSONNE': '42', 'NOM': '', 'PRENOM': '', 'REGIME': '', 'LIBELLEECOLE': '', 'ACTIVITE': result, } ] } } } } with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.return_value = OperationResult(json_response=result, xml_request='', xml_response='') resp = app.get('/toulouse-axel/test/clae_children_activities_info?NameID=yyy&booking_date=2020-01-20') assert resp.json['err'] == 0 assert len(resp.json['data']) == int(expected) def test_clae_booking_activities_info_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020']) def test_clae_booking_activities_info_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=%s&end_date=2020-01-24' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=%s' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' def test_clae_booking_activities_info_endpoint_no_result(app, resource, child_activities_data): resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=4242&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' content = """ XXX 4242 2019 A19P1M1 00000 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' def test_clae_booking_activities_info_endpoint(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/booking_info.xml') with open(filepath) as xml: content = xml.read() activities = copy.deepcopy(child_activities_data['ENFANT'][0]) with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'day': '2020-01-20', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-20', 'activity_id': 'A19P1M2', 'activity_type': 'MIDI', 'activity_label': 'Temps du midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-20', 'activity_id': 'A19P1M3', 'activity_type': 'SOIR', 'activity_label': 'Temps du soir', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-21', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-21', 'activity_id': 'A19P1M2', 'activity_type': 'MIDI', 'activity_label': 'Temps du midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-21', 'activity_id': 'A19P1M3', 'activity_type': 'SOIR', 'activity_label': 'Temps du soir', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-22', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-22', 'activity_id': 'A19P1M2', 'activity_type': 'MIDI', 'activity_label': 'Temps du midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-22', 'activity_id': 'A19P1M4', 'activity_type': 'GARD', 'activity_label': 'Temps mercredi après midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-23', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-23', 'activity_id': 'A19P1M2', 'activity_type': 'MIDI', 'activity_label': 'Temps du midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-23', 'activity_id': 'A19P1M3', 'activity_type': 'SOIR', 'activity_label': 'Temps du soir', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-24', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-24', 'activity_id': 'A19P1M2', 'activity_type': 'MIDI', 'activity_label': 'Temps du midi', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-24', 'activity_id': 'A19P1M3', 'activity_type': 'SOIR', 'activity_label': 'Temps du soir', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, ] content = """ XXX 3535 2019 A19P1M1 10201 """ cache.clear() activities = copy.deepcopy(child_activities_data['ENFANT'][0]) activities['ACTIVITE'] = activities['ACTIVITE'][:1] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535&start_date=2020-01-20&end_date=2020-01-24' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'day': '2020-01-20', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-21', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-23', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': False, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, { 'day': '2020-01-24', 'activity_id': 'A19P1M1', 'activity_type': 'MAT', 'activity_label': 'Temps du matin', 'booked': True, 'bookable': False, 'week': 'week:2020-01-20:2020-01-24', }, ] @freezegun.freeze_time('2020-03-26') @pytest.mark.parametrize( 'start_date, end_date, last_date', [ # end date is a not a friday ('2020-04-07', '2020-04-13', '2020-04-13'), # except if end date is saturday or sunday => ends on previous friday ('2020-04-07', '2020-04-18', '2020-04-17'), ('2020-04-07', '2020-04-19', '2020-04-17'), # start date is after end date, same week => result is empty ('2020-04-16', '2020-04-15', None), # start date is after end date, not the same week => result is empty ('2020-04-16', '2020-04-12', None), ], ) def test_clae_booking_activities_info_period(app, resource, start_date, end_date, last_date): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data' ) as activities_info: activities_info.return_value = { 'ACTIVITE': [ { 'id': 'TOTO', 'booking': { 'days': { 'monday': True, 'tuesday': True, 'wednesday': True, 'thursday': True, 'friday': True, } }, 'TYPEACTIVITE': 'MAT', 'LIBELLEACTIVITE': 'Matin', } ] } resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535' '&start_date=%s&end_date=%s' % (start_date, end_date) ) if last_date is None: assert resp.json['data'] == [] else: assert resp.json['data'][0]['day'] == start_date assert resp.json['data'][-1]['day'] == last_date @freezegun.freeze_time('2020-04-15') def test_clae_booking_activities_info_bookable(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data' ) as activities_info: activities_info.return_value = { 'ACTIVITE': [ { 'id': 'TOTO', 'booking': { 'days': { 'monday': True, 'tuesday': True, 'wednesday': True, 'thursday': True, 'friday': True, } }, 'TYPEACTIVITE': 'MAT', 'LIBELLEACTIVITE': 'Matin', } ] } resp = app.get( '/toulouse-axel/test/clae_booking_activities_info?NameID=yyy&idpersonne=3535' '&start_date=2020-04-01&end_date=2020-04-30' ) activities = {a['day']: a['bookable'] for a in resp.json['data']} assert activities['2020-04-01'] is False assert activities['2020-04-02'] is False assert activities['2020-04-03'] is False assert activities['2020-04-06'] is False assert activities['2020-04-07'] is False assert activities['2020-04-08'] is False assert activities['2020-04-09'] is False assert activities['2020-04-10'] is False assert activities['2020-04-13'] is False assert activities['2020-04-14'] is False assert activities['2020-04-15'] is False assert activities['2020-04-16'] is False assert activities['2020-04-17'] is False assert activities['2020-04-20'] is False assert activities['2020-04-21'] is False assert activities['2020-04-22'] is False assert activities['2020-04-23'] is True assert activities['2020-04-24'] is True assert activities['2020-04-27'] is True assert activities['2020-04-28'] is True assert activities['2020-04-29'] is True assert activities['2020-04-30'] is True @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_possible_days_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @freezegun.freeze_time('2019-09-01') @pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020']) def test_clae_booking_activity_possible_days_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=%s&end_date=2020-01-24&activity_type=MAT' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-02-20&end_date=%s&activity_type=MAT' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_possible_days_endpoint_activity_type(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=FOO', status=400, ) assert resp.json['err_desc'] == 'bad activity_type, should be MAT, MIDI, SOIR or GARD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_possible_days_endpoint_no_result(app, resource, child_activities_data): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=4242' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' content = """ XXX 4242 2019 A19P1M1 00000 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data' ) as activities_info: activities_info.return_value = {'ACTIVITE': []} resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err'] == 0 assert resp.json['data'] == [] content = """ XXX 3535 2019 A19P1M1 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err'] == 0 assert len(resp.json['data']) == 5 assert ( list(d['details']['booking']['days'] for d in resp.json['data']) == [{'monday': False, 'tuesday': False, 'wednesday': False, 'thursday': False, 'friday': False}] * 5 ) content = """ XXX 3535 2019 A19P1M1 2 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert len(resp.json['data']) == 5 assert ( list(d['details']['booking']['days'] for d in resp.json['data']) == [{'monday': False, 'tuesday': False, 'wednesday': False, 'thursday': False, 'friday': False}] * 5 ) @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_possible_days_endpoint(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') content = """ XXX 3535 2019 A19P1M1 00000 2019 A19P1M2 10201 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MIDI' ) assert resp.json['err'] == 0 assert len(resp.json['data']) == 5 assert set(resp.json['data'][0].keys()) == {'id', 'text', 'disabled', 'prefill', 'details'} assert resp.json['data'][0]['id'] == '3535:MIDI:A19P1M2:2020-01-20' assert resp.json['data'][1]['id'] == '3535:MIDI:A19P1M2:2020-01-21' assert resp.json['data'][2]['id'] == '3535:MIDI:A19P1M2:2020-01-22' assert resp.json['data'][3]['id'] == '3535:MIDI:A19P1M2:2020-01-23' assert resp.json['data'][4]['id'] == '3535:MIDI:A19P1M2:2020-01-24' assert resp.json['data'][0]['text'] == 'Monday 20 January 2020' assert resp.json['data'][1]['text'] == 'Tuesday 21 January 2020' assert resp.json['data'][2]['text'] == 'Wednesday 22 January 2020' assert resp.json['data'][3]['text'] == 'Thursday 23 January 2020' assert resp.json['data'][4]['text'] == 'Friday 24 January 2020' assert resp.json['data'][0]['disabled'] is False assert resp.json['data'][1]['disabled'] is False assert resp.json['data'][2]['disabled'] is True assert resp.json['data'][3]['disabled'] is False assert resp.json['data'][4]['disabled'] is False assert resp.json['data'][0]['prefill'] is True assert resp.json['data'][1]['prefill'] is False assert resp.json['data'][2]['prefill'] is None assert resp.json['data'][3]['prefill'] is False assert resp.json['data'][4]['prefill'] is True # again - data are in cache with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err'] == 0 assert len(resp.json['data']) == 5 @pytest.mark.parametrize( 'today, start_date, first_date, end_date, last_date', [ # today is start date -> + 8 days ('2020-03-26', '2020-03-26', '2020-04-03', '2020-04-17', '2020-04-17'), # start date is a friday => starts friday ('2020-03-26', '2020-04-03', '2020-04-03', '2020-04-17', '2020-04-17'), # start date is a saturday => starts on next monday ('2020-03-26', '2020-04-04', '2020-04-06', '2020-04-17', '2020-04-17'), # start date is a sunday => starts on next monday ('2020-03-26', '2020-04-05', '2020-04-06', '2020-04-17', '2020-04-17'), # start date is a monday => starts on monday ('2020-03-26', '2020-04-06', '2020-04-06', '2020-04-17', '2020-04-17'), # start date is a tuesday => starts on tuesday ('2020-03-26', '2020-04-07', '2020-04-07', '2020-04-17', '2020-04-17'), # end date is a not a friday ('2020-03-26', '2020-04-07', '2020-04-07', '2020-04-13', '2020-04-13'), # except if end date is saturday or sunday => ends on previous friday ('2020-03-26', '2020-04-07', '2020-04-07', '2020-04-18', '2020-04-17'), ('2020-03-26', '2020-04-07', '2020-04-07', '2020-04-19', '2020-04-17'), # start date is after end date, same week => result is empty ('2020-03-26', '2020-04-16', None, '2020-04-15', None), # start date is after end date, not the same week => result is empty ('2020-03-26', '2020-04-16', None, '2020-04-12', None), ], ) def test_clae_booking_activity_possible_days_period( app, resource, today, start_date, first_date, end_date, last_date, child_activities_data ): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data' ) as activities_info: activities_info.return_value = { 'ACTIVITE': [ { 'id': 'TOTO', 'TYPEACTIVITE': 'MAT', 'booking': { 'days': { 'monday': True, 'tuesday': True, 'wednesday': True, 'thursday': True, 'friday': True, } }, } ] } with freezegun.freeze_time(today): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=%s&end_date=%s&activity_type=MAT' % (start_date, end_date) ) if first_date is None: assert resp.json['data'] == [] else: assert resp.json['data'][0]['id'] == '3535:MAT:TOTO:%s' % first_date assert resp.json['data'][-1]['id'] == '3535:MAT:TOTO:%s' % last_date def test_clae_booking_activity_possible_days_next_year(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with freezegun.freeze_time('2020-07-01'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities' ) as mock_activities: mock_activities.return_value = {} app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-09-01&end_date=2020-09-30&activity_type=MAT' ) assert mock_activities.call_args_list == [ mock.call(child_id='3535', dui='XXX', reference_year=2020), mock.call(child_id='3535', dui='XXX', reference_year=2020), ] @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_possible_days_endpoint_dates(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] # second activity starts after 2019-08-01 activities['ACTIVITE'][1]['DATEENTREE'] = '2019-10-01' # last activity ends before 2020-07-31 activities['ACTIVITE'][3]['DATESORTIE'] = '2020-06-30' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_booking_data' ) as activities_info: activities_info.return_value = { 'ACTIVITE': [ { 'id': 'TOTO', 'TYPEACTIVITE': 'MAT', 'booking': { 'days': { 'monday': True, 'tuesday': True, 'wednesday': True, 'thursday': True, 'friday': True, } }, } ] } # it is not possible to book before 2019-10-01 with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2019-09-01&end_date=2019-10-11&activity_type=MAT' ) assert resp.json['err'] == 0 assert len(resp.json['data']) == 9 assert resp.json['data'][0]['id'] == '3535:MAT:TOTO:2019-10-01' assert resp.json['data'][-1]['id'] == '3535:MAT:TOTO:2019-10-11' # it is not possible to book after 2020-06-30 with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_possible_days?NameID=yyy&idpersonne=3535' '&start_date=2020-06-20&end_date=2020-07-15&activity_type=MAT' ) assert resp.json['err'] == 0 assert len(resp.json['data']) == 7 assert resp.json['data'][0]['id'] == '3535:MAT:TOTO:2020-06-22' assert resp.json['data'][-1]['id'] == '3535:MAT:TOTO:2020-06-30' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_annual_possible_days_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MAT&booking_date=2019-09-01' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @freezegun.freeze_time('2019-09-01') @pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020']) def test_clae_booking_activity_annual_possible_days_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MAT&booking_date=%s' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_annual_possible_days_endpoint_activity_type(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=FOO&booking_date=2019-09-01', status=400, ) assert resp.json['err_desc'] == 'bad activity_type, should be MAT, MIDI, SOIR or GARD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_annual_possible_days_endpoint_no_result(app, resource): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MAT&booking_date=2019-09-01' ) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=4242' '&activity_type=MAT&booking_date=2019-09-01' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value={'ACTIVITE': []}, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MAT&booking_date=2019-09-01' ) assert resp.json['err'] == 0 assert resp.json['data'] == [] @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_annual_possible_days_endpoint(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MAT&booking_date=2019-09-01' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': '3535:MAT:A19P1M1:monday', 'text': 'Monday', 'disabled': False, }, { 'id': '3535:MAT:A19P1M1:tuesday', 'text': 'Tuesday', 'disabled': False, }, { 'id': '3535:MAT:A19P1M1:wednesday', 'text': 'Wednesday', 'disabled': False, }, { 'id': '3535:MAT:A19P1M1:thursday', 'text': 'Thursday', 'disabled': False, }, { 'id': '3535:MAT:A19P1M1:friday', 'text': 'Friday', 'disabled': False, }, ] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=MIDI&booking_date=2019-09-01' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': '3535:MIDI:A19P1M2:monday', 'text': 'Monday', 'disabled': False, }, { 'id': '3535:MIDI:A19P1M2:tuesday', 'text': 'Tuesday', 'disabled': False, }, { 'id': '3535:MIDI:A19P1M2:wednesday', 'text': 'Wednesday', 'disabled': False, }, { 'id': '3535:MIDI:A19P1M2:thursday', 'text': 'Thursday', 'disabled': False, }, { 'id': '3535:MIDI:A19P1M2:friday', 'text': 'Friday', 'disabled': False, }, ] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=SOIR&booking_date=2019-09-01' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': '3535:SOIR:A19P1M3:monday', 'text': 'Monday', 'disabled': False, }, { 'id': '3535:SOIR:A19P1M3:tuesday', 'text': 'Tuesday', 'disabled': False, }, { 'id': '3535:SOIR:A19P1M3:wednesday', 'text': 'Wednesday', 'disabled': True, }, { 'id': '3535:SOIR:A19P1M3:thursday', 'text': 'Thursday', 'disabled': False, }, { 'id': '3535:SOIR:A19P1M3:friday', 'text': 'Friday', 'disabled': False, }, ] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=GARD&booking_date=2019-09-01' ) assert resp.json['err'] == 0 assert resp.json['data'] == [ { 'id': '3535:GARD:A19P1M4:monday', 'text': 'Monday', 'disabled': True, }, { 'id': '3535:GARD:A19P1M4:tuesday', 'text': 'Tuesday', 'disabled': True, }, { 'id': '3535:GARD:A19P1M4:wednesday', 'text': 'Wednesday', 'disabled': False, }, { 'id': '3535:GARD:A19P1M4:thursday', 'text': 'Thursday', 'disabled': True, }, { 'id': '3535:GARD:A19P1M4:friday', 'text': 'Friday', 'disabled': True, }, ] def test_clae_booking_activity_annual_possible_days_next_year(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with freezegun.freeze_time('2020-07-01'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities' ) as mock_activities: mock_activities.return_value = {} app.get( '/toulouse-axel/test/clae_booking_activity_annual_possible_days?NameID=yyy&idpersonne=3535' '&activity_type=GARD&booking_date=2020-09-01' ) assert mock_activities.call_args_list == [ mock.call(child_id='3535', dui='XXX', reference_year=2020), ] @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_prefill_endpoint_axel_error(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' @freezegun.freeze_time('2019-09-01') @pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020']) def test_clae_booking_activity_prefill_endpoint_bad_date_format(app, resource, value): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=%s&end_date=2020-01-24&activity_type=MAT' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=%s&activity_type=MAT' % value, status=400, ) assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_prefill_endpoint_activity_type(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=FOO', status=400, ) assert resp.json['err_desc'] == 'bad activity_type, should be MAT, MIDI, SOIR or GARD' assert resp.json['err'] == 'bad-request' @freezegun.freeze_time('2019-09-01') def test_clae_booking_activity_prefill_endpoint_no_result(app, resource, child_activities_data): resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_periode') as operation: operation.side_effect = AxelError('FooBar') resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=4242' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' content = """ XXX 4242 2019 A19P1M1 00000 """ activities = child_activities_data['ENFANT'][0] with mock_getdata(content, 'ReservationPeriode'): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities, ): resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err_desc'] == 'Child not found' assert resp.json['err'] == 'not-found' with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.clae_booking_activity_possible_days' ) as possible_days: possible_days.return_value = {'data': []} resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err'] == 0 assert resp.json['data'] == [] def test_clae_booking_activity_prefill_endpoint(app, resource): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.clae_booking_activity_possible_days' ) as possible_days: possible_days.return_value = { 'data': [ { 'id': '3535:MAT:A19P1M1:2020-01-20', 'prefill': True, }, { 'id': '3535:MAT:A19P1M1:2020-01-21', 'prefill': False, }, { 'id': '3535:MAT:A19P1M1:2020-01-22', 'prefill': None, }, { 'id': '3535:MAT:A19P1M1:2020-01-23', 'prefill': False, }, { 'id': '3535:MAT:A19P1M1:2020-01-24', 'prefill': True, }, ] } resp = app.get( '/toulouse-axel/test/clae_booking_activity_prefill?NameID=yyy&idpersonne=3535' '&start_date=2020-01-20&end_date=2020-01-24&activity_type=MAT' ) assert resp.json['err'] == 0 assert resp.json['data'] == ['3535:MAT:A19P1M1:2020-01-20', '3535:MAT:A19P1M1:2020-01-24'] def test_are_children_registered_axel_error(resource): with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') assert resource.are_children_registered(dui='XXX') == {} @pytest.mark.parametrize( 'date_value, expected', [ ('2019-08-01', {'3535': True}), ('2020-07-31', {'3535': True}), ], ) def test_are_children_registered_reference_year(resource, date_value, expected): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_children_activities' ) as get_children_activities: get_children_activities.return_value = {'3535': {'ACTIVITE': [{}]}} with freezegun.freeze_time(date_value): assert resource.are_children_registered(dui='XXX') == expected @pytest.mark.parametrize( 'activities, expected', [ ({}, {}), ({'3535': {'ACTIVITE': []}}, {'3535': False}), ({'3535': {'ACTIVITE': [{}]}}, {'3535': True}), ({'3535': {'ACTIVITE': [{}]}, '4242': {}}, {'3535': True, '4242': False}), ], ) def test_are_children_registered(resource, activities, expected): with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_children_activities' ) as get_children_activities: get_children_activities.return_value = activities assert resource.are_children_registered(dui='XXX') == expected @freezegun.freeze_time('2019-09-01') def test_clae_booking_endpoint_axel_error(app, resource, booking_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_clae_booking_endpoint_date_error(app, resource, booking_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') # DATEDEBUT must be before DATEDFIN booking_params['booking_start_date'] = '2020-02-01' booking_params['booking_end_date'] = '2020-01-01' with freezegun.freeze_time('2019-09-01'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_start_date should be before booking_end_date' assert resp.json['err'] == 'bad-request' # today + 8j rule booking_params['booking_start_date'] = '2020-01-01' booking_params['booking_end_date'] = '2020-07-31' # date in the past with freezegun.freeze_time('2020-01-01'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_start_date min value: 2020-01-09' assert resp.json['err'] == 'bad-request' # too soon with freezegun.freeze_time('2019-12-25'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_start_date min value: 2020-01-02' assert resp.json['err'] == 'bad-request' with freezegun.freeze_time('2019-12-31'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_start_date min value: 2020-01-08' assert resp.json['err'] == 'bad-request' # bad reference year for end_date booking_params['booking_start_date'] = '2020-01-01' booking_params['booking_end_date'] = '2020-12-31' with freezegun.freeze_time('2019-09-01'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_end_date max value: 2020-07-31' assert resp.json['err'] == 'bad-request' booking_params['booking_start_date'] = '2021-01-01' booking_params['booking_end_date'] = '2021-12-31' with freezegun.freeze_time('2019-09-01'): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params, status=400) assert resp.json['err_desc'] == 'booking_end_date max value: 2021-07-31' assert resp.json['err'] == 'bad-request' def test_clae_booking_endpoint_no_result(app, resource, booking_params): resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' @freezegun.freeze_time('2019-09-01') def test_clae_booking_endpoint(app, resource, booking_params, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): content = '' with mock_getdata(content, 'ReservationAnnuelle'): with mock.patch('django.core.cache.cache.delete') as mock_cache_delete: resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) assert mock_cache_delete.call_args_list == [ mock.call('toulouse-axel-%s-children-activities-XXX-2019' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-04-13' % resource.pk), ] assert resp.json['err'] == 0 assert resp.json['updated'] is True assert 'data' in resp.json assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload == { 'DATEDEMANDE': '2019-09-01', 'ENFANT': [ { 'IDPERSONNE': '3535', 'REGIME': 'AV', 'ACTIVITE': [ { 'IDACTIVITE': 'A19P1M1', 'ANNEEREFERENCE': '2019', 'PERIODE': [ { 'DATEDEBUT': '2020-04-13', 'DATEDFIN': '2020-04-17', 'SEMAINETYPE': '11011', }, ], }, { 'IDACTIVITE': 'A19P1M2', 'ANNEEREFERENCE': '2019', 'PERIODE': [ { 'DATEDEBUT': '2020-04-13', 'DATEDFIN': '2020-04-17', 'SEMAINETYPE': '11011', }, ], }, { 'IDACTIVITE': 'A19P1M3', 'ANNEEREFERENCE': '2019', 'PERIODE': [ { 'DATEDEBUT': '2020-04-13', 'DATEDFIN': '2020-04-17', 'SEMAINETYPE': '10000', }, ], }, { 'IDACTIVITE': 'A19P1M4', 'ANNEEREFERENCE': '2019', 'PERIODE': [ { 'DATEDEBUT': '2020-04-13', 'DATEDFIN': '2020-04-17', 'SEMAINETYPE': '00100', }, ], }, ], } ], 'IDDUI': 'XXX', } # empty list new_booking_params = copy.deepcopy(booking_params) new_booking_params['booking_list_MAT'] = ['42:MAT:A19P1M1:2020-04-15'] # wrong child, ignored new_booking_params['booking_list_MIDI'] = [] new_booking_params['booking_list_SOIR'] = [] new_booking_params['booking_list_GARD'] = [] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert len(payload['ENFANT']) == 1 assert payload['ENFANT'][0]['IDPERSONNE'] == '3535' assert len(payload['ENFANT'][0]['ACTIVITE']) == 4 activity1 = payload['ENFANT'][0]['ACTIVITE'][0] assert activity1['IDACTIVITE'] == 'A19P1M1' assert len(activity1['PERIODE']) == 1 assert activity1['PERIODE'][0]['DATEDEBUT'] == '2020-04-13' assert activity1['PERIODE'][0]['DATEDFIN'] == '2020-04-17' assert activity1['PERIODE'][0]['SEMAINETYPE'] == '00000' activity2 = payload['ENFANT'][0]['ACTIVITE'][1] assert activity2['IDACTIVITE'] == 'A19P1M2' assert len(activity2['PERIODE']) == 1 assert activity2['PERIODE'][0]['DATEDEBUT'] == '2020-04-13' assert activity2['PERIODE'][0]['DATEDFIN'] == '2020-04-17' assert activity2['PERIODE'][0]['SEMAINETYPE'] == '00000' activity3 = payload['ENFANT'][0]['ACTIVITE'][2] assert activity3['IDACTIVITE'] == 'A19P1M3' assert len(activity3['PERIODE']) == 1 assert activity3['PERIODE'][0]['DATEDEBUT'] == '2020-04-13' assert activity3['PERIODE'][0]['DATEDFIN'] == '2020-04-17' assert activity3['PERIODE'][0]['SEMAINETYPE'] == '00000' activity4 = payload['ENFANT'][0]['ACTIVITE'][3] assert activity4['IDACTIVITE'] == 'A19P1M4' assert len(activity4['PERIODE']) == 1 assert activity4['PERIODE'][0]['DATEDEBUT'] == '2020-04-13' assert activity4['PERIODE'][0]['DATEDFIN'] == '2020-04-17' assert activity4['PERIODE'][0]['SEMAINETYPE'] == '00000' # null list new_booking_params = copy.deepcopy(booking_params) new_booking_params['booking_list_MAT'] = None new_booking_params['booking_list_MIDI'] = None new_booking_params['booking_list_SOIR'] = None new_booking_params['booking_list_GARD'] = None with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert 'ACTIVITE' not in payload['ENFANT'][0] # many weeks => many periods new_booking_params = copy.deepcopy(booking_params) new_booking_params['booking_start_date'] = '2020-04-01' new_booking_params['booking_end_date'] = '2020-04-30' new_booking_params['booking_list_MAT'].append('3535:MAT:A19P1M1:2020-04-01') new_booking_params['booking_list_MAT'].append( '3535:MAT:A19P1M1:2020-03-31' ) # before the period, ignored new_booking_params['booking_list_MAT'].append('3535:MAT:A19P1M1:2020-04-30') new_booking_params['booking_list_MAT'].append( '3535:MAT:A19P1M1:2020-05-01' ) # after the period, ignored new_booking_params['booking_list_MAT'].append('4242:MAT:A19P1M1:2020-04-15') # wrong child, ignored new_booking_params['booking_list_MAT'].append('3535:MAT:FOO:2020-04-15') # wrong activity id, ignored new_booking_params['booking_list_MIDI'] = None new_booking_params['booking_list_SOIR'] = None new_booking_params['booking_list_GARD'] = None with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') with mock.patch('django.core.cache.cache.delete') as mock_cache_delete: resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params) assert mock_cache_delete.call_args_list == [ mock.call('toulouse-axel-%s-children-activities-XXX-2019' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-03-30' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-04-06' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-04-13' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-04-20' % resource.pk), mock.call('toulouse-axel-%s-booking-data-XXX-3535-2020-04-27' % resource.pk), ] payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert len(payload['ENFANT']) == 1 assert payload['ENFANT'][0]['IDPERSONNE'] == '3535' assert len(payload['ENFANT'][0]['ACTIVITE']) == 1 activity = payload['ENFANT'][0]['ACTIVITE'][0] assert activity['IDACTIVITE'] == 'A19P1M1' assert len(activity['PERIODE']) == 5 assert activity['PERIODE'][0]['DATEDEBUT'] == '2020-04-01' assert activity['PERIODE'][0]['DATEDFIN'] == '2020-04-03' assert activity['PERIODE'][0]['SEMAINETYPE'] == '00100' assert activity['PERIODE'][1]['DATEDEBUT'] == '2020-04-06' assert activity['PERIODE'][1]['DATEDFIN'] == '2020-04-10' assert activity['PERIODE'][1]['SEMAINETYPE'] == '00000' assert activity['PERIODE'][2]['DATEDEBUT'] == '2020-04-13' assert activity['PERIODE'][2]['DATEDFIN'] == '2020-04-17' assert activity['PERIODE'][2]['SEMAINETYPE'] == '11011' assert activity['PERIODE'][3]['DATEDEBUT'] == '2020-04-20' assert activity['PERIODE'][3]['DATEDFIN'] == '2020-04-24' assert activity['PERIODE'][3]['SEMAINETYPE'] == '00000' assert activity['PERIODE'][4]['DATEDEBUT'] == '2020-04-27' assert activity['PERIODE'][4]['DATEDFIN'] == '2020-04-30' assert activity['PERIODE'][4]['SEMAINETYPE'] == '00010' @freezegun.freeze_time('2019-09-01') def test_clae_booking_regime(app, resource, booking_params, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): booking_params['regime'] = None with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV' booking_params['regime'] = '' with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV' del booking_params['regime'] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV' @freezegun.freeze_time('2019-09-01') def test_clae_booking_endpoint_next_year(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] for activity in activities['ACTIVITE']: activity['DATEDEBUT'] = '2020-08-01' activity['DATEENTREE'] = '2020-08-01' activity['DATEFIN'] = '2021-07-31' activity['DATESORTIE'] = '2021-07-31' booking_params = { 'booking_start_date': '2020-09-01', 'booking_end_date': '2020-09-04', 'booking_list_MAT': [], 'booking_list_MIDI': None, 'booking_list_SOIR': None, 'booking_list_GARD': None, 'child_id': '3535', 'regime': 'AV', } with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities' ) as mock_activities: mock_activities.return_value = activities with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params) assert mock_activities.call_args_list == [ mock.call(child_id='3535', dui='XXX', reference_year=2020), ] payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert len(payload['ENFANT']) == 1 assert payload['ENFANT'][0]['IDPERSONNE'] == '3535' assert len(payload['ENFANT'][0]['ACTIVITE']) == 1 activity = payload['ENFANT'][0]['ACTIVITE'][0] assert len(activity['PERIODE']) == 1 assert activity['PERIODE'][0]['DATEDEBUT'] == '2020-09-01' assert activity['PERIODE'][0]['DATEDFIN'] == '2020-09-04' @freezegun.freeze_time('2019-09-01') def test_clae_booking_annual_endpoint_axel_error(app, resource, annual_booking_params): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') with mock.patch('passerelle.contrib.toulouse_axel.schemas.enfants_activites') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/child_activities.xml') with open(filepath) as xml: content = xml.read() with mock_getdata(content, 'EnfantsActivites'): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.side_effect = AxelError('FooBar') resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params ) assert resp.json['err_desc'] == 'Axel error: FooBar' assert resp.json['err'] == 'error' def test_clae_booking_annual_endpoint_no_result(app, resource, annual_booking_params): resp = app.post_json('/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params) assert resp.json['err_desc'] == 'Person not found' assert resp.json['err'] == 'not-found' @freezegun.freeze_time('2019-09-01') def test_clae_booking_annual_endpoint(app, resource, annual_booking_params, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): content = '' with mock_getdata(content, 'ReservationAnnuelle'): with mock.patch('django.core.cache.cache.delete') as mock_cache_delete: resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params ) assert len(mock_cache_delete.call_args_list) == 48 assert mock_cache_delete.call_args_list[0] == mock.call( 'toulouse-axel-%s-children-activities-XXX-2019' % resource.pk ) assert mock_cache_delete.call_args_list[1] == mock.call( 'toulouse-axel-%s-booking-data-XXX-3535-2019-09-09' % resource.pk ) assert mock_cache_delete.call_args_list[-1] == mock.call( 'toulouse-axel-%s-booking-data-XXX-3535-2020-07-27' % resource.pk ) assert resp.json['err'] == 0 assert resp.json['updated'] is True assert 'data' in resp.json assert 'xml_request' in resp.json['data'] assert 'xml_response' in resp.json['data'] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params ) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload == { 'DATEDEMANDE': '2019-09-01', 'ENFANT': [ { 'IDPERSONNE': '3535', 'REGIME': 'AV', 'ACTIVITE': [ { 'ANNEEREFERENCE': '2019', 'IDACTIVITE': 'A19P1M1', 'PERIODE': [ {'DATEDEBUT': '2019-09-09', 'DATEDFIN': '2020-07-31', 'SEMAINETYPE': '11011'} ], }, { 'ANNEEREFERENCE': '2019', 'IDACTIVITE': 'A19P1M2', 'PERIODE': [ {'DATEDEBUT': '2019-09-09', 'DATEDFIN': '2020-07-31', 'SEMAINETYPE': '11011'} ], }, { 'ANNEEREFERENCE': '2019', 'IDACTIVITE': 'A19P1M3', 'PERIODE': [ {'DATEDEBUT': '2019-09-09', 'DATEDFIN': '2020-07-31', 'SEMAINETYPE': '10000'} ], }, { 'ANNEEREFERENCE': '2019', 'IDACTIVITE': 'A19P1M4', 'PERIODE': [ {'DATEDEBUT': '2019-09-09', 'DATEDFIN': '2020-07-31', 'SEMAINETYPE': '00100'} ], }, ], } ], 'IDDUI': 'XXX', } # empty list new_booking_params = copy.deepcopy(annual_booking_params) new_booking_params['booking_list_MAT'] = ['42:MAT:A19P1M1:monday'] # wrong child, ignored new_booking_params['booking_list_MIDI'] = [] new_booking_params['booking_list_SOIR'] = [] new_booking_params['booking_list_GARD'] = [] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=new_booking_params ) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert len(payload['ENFANT']) == 1 assert payload['ENFANT'][0]['IDPERSONNE'] == '3535' assert len(payload['ENFANT'][0]['ACTIVITE']) == 4 activity1 = payload['ENFANT'][0]['ACTIVITE'][0] assert activity1['IDACTIVITE'] == 'A19P1M1' assert len(activity1['PERIODE']) == 1 assert activity1['PERIODE'][0]['DATEDEBUT'] == '2019-09-09' assert activity1['PERIODE'][0]['DATEDFIN'] == '2020-07-31' assert activity1['PERIODE'][0]['SEMAINETYPE'] == '00000' activity2 = payload['ENFANT'][0]['ACTIVITE'][1] assert activity2['IDACTIVITE'] == 'A19P1M2' assert len(activity2['PERIODE']) == 1 assert activity2['PERIODE'][0]['DATEDEBUT'] == '2019-09-09' assert activity2['PERIODE'][0]['DATEDFIN'] == '2020-07-31' assert activity2['PERIODE'][0]['SEMAINETYPE'] == '00000' activity3 = payload['ENFANT'][0]['ACTIVITE'][2] assert activity3['IDACTIVITE'] == 'A19P1M3' assert len(activity3['PERIODE']) == 1 assert activity3['PERIODE'][0]['DATEDEBUT'] == '2019-09-09' assert activity3['PERIODE'][0]['DATEDFIN'] == '2020-07-31' assert activity3['PERIODE'][0]['SEMAINETYPE'] == '00000' activity4 = payload['ENFANT'][0]['ACTIVITE'][3] assert activity4['IDACTIVITE'] == 'A19P1M4' assert len(activity4['PERIODE']) == 1 assert activity4['PERIODE'][0]['DATEDEBUT'] == '2019-09-09' assert activity4['PERIODE'][0]['DATEDFIN'] == '2020-07-31' assert activity4['PERIODE'][0]['SEMAINETYPE'] == '00000' # null list new_booking_params = copy.deepcopy(annual_booking_params) new_booking_params['booking_list_MAT'] = None new_booking_params['booking_list_MIDI'] = None new_booking_params['booking_list_SOIR'] = None new_booking_params['booking_list_GARD'] = None with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') resp = app.post_json( '/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=new_booking_params ) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert 'ACTIVITE' not in payload['ENFANT'][0] @freezegun.freeze_time('2019-09-01') def test_clae_booking_annual_next_year(app, resource, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] for activity in activities['ACTIVITE']: activity['DATEDEBUT'] = '2020-08-01' activity['DATEENTREE'] = '2020-08-01' activity['DATEFIN'] = '2021-07-31' activity['DATESORTIE'] = '2021-07-31' annual_booking_params = { 'booking_list_MAT': [], 'booking_list_MIDI': None, 'booking_list_SOIR': None, 'booking_list_GARD': None, 'child_id': '3535', 'regime': 'AV', 'booking_date': '2020-08-01', } with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['DATEDEBUT'] == '2020-08-01' assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['DATEDFIN'] == '2021-07-31' @freezegun.freeze_time('2019-09-01') def test_clae_booking_annual_regime(app, resource, annual_booking_params, child_activities_data): Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') activities = child_activities_data['ENFANT'][0] with mock.patch( 'passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_child_activities', return_value=activities ): annual_booking_params['regime'] = None with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV' annual_booking_params['regime'] = '' with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV' del annual_booking_params['regime'] with mock.patch('passerelle.contrib.toulouse_axel.schemas.reservation_annuelle') as operation: operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='') app.post_json('/toulouse-axel/test/clae_booking_annual?NameID=yyy', params=annual_booking_params) payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI'] assert payload['ENFANT'][0]['REGIME'] == 'SV'