# Copyright (C) 2022 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import base64
import datetime
import logging
import os
from unittest import mock

import pytest
import responses
from requests.exceptions import ConnectionError
from zeep import Settings

from passerelle.contrib.toulouse_maelis.models import Link, Referential, ToulouseMaelis
from passerelle.utils.jsonresponse import APIError
from passerelle.utils.soap import SOAPError
from tests.utils import FakedResponse, ResponsesSoap, generic_endpoint_url, setup_access_rights

TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'toulouse_maelis')


def get_xml_file(filename):
    with open(os.path.join(TEST_BASE_DIR, filename), 'rb') as desc:
        return desc.read()


def get_media_file(filename):
    with open(os.path.join(TEST_BASE_DIR, "%s" % filename), 'rb') as desc:
        return desc.read()


CONNECTION_ERROR = ConnectionError('No address associated with hostname')
FAMILY_SERVICE_WSDL = FakedResponse(content=get_xml_file('FamilyService.wsdl'), status_code=200)
ACTIVITY_SERVICE_WSDL = FakedResponse(content=get_xml_file('ActivityService.wsdl'), status_code=200)
INVOICE_SERVICE_WSDL = FakedResponse(content=get_xml_file('InvoiceService.wsdl'), status_code=200)
SITE_SERVICE_WSDL = FakedResponse(content=get_xml_file('SiteService.wsdl'), status_code=200)
FAILED_AUTH = FakedResponse(content=get_xml_file('R_failed_authentication.xml'), status_code=500)
ISWSRUNNING_TRUE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'true', status_code=200)
ISWSRUNNING_FALSE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'false', status_code=200)


def get_endpoint(name):
    url = generic_endpoint_url('toulouse-maelis', name)
    assert url == '/toulouse-maelis/test/%s' % name
    return url


@pytest.fixture
def requests_mock():
    return responses.RequestsMock()


@pytest.fixture()
def family_service(requests_mock):
    responses_soap = ResponsesSoap(
        wsdl_url='https://example.org/FamilyService?wsdl',
        wsdl_content=get_xml_file('FamilyService.wsdl'),
        settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        requests_mock=requests_mock,
    )
    with responses_soap() as soap_mock:
        yield soap_mock


@pytest.fixture()
def activity_service(requests_mock):
    responses_soap = ResponsesSoap(
        wsdl_url='https://example.org/ActivityService?wsdl',
        wsdl_content=get_xml_file('ActivityService.wsdl'),
        settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        requests_mock=requests_mock,
    )
    with responses_soap() as soap_mock:
        yield soap_mock


@pytest.fixture()
def invoice_service(requests_mock):
    responses_soap = ResponsesSoap(
        wsdl_url='https://example.org/InvoiceService?wsdl',
        wsdl_content=get_xml_file('InvoiceService.wsdl'),
        settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        requests_mock=requests_mock,
    )
    with responses_soap() as soap_mock:
        yield soap_mock


@pytest.fixture()
def site_service(requests_mock):
    responses_soap = ResponsesSoap(
        wsdl_url='https://example.org/SiteService?wsdl',
        wsdl_content=get_xml_file('SiteService.wsdl'),
        settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        requests_mock=requests_mock,
    )
    with responses_soap() as soap_mock:
        yield soap_mock


@pytest.fixture(scope='module')
def django_db_setup(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        con = setup_access_rights(
            ToulouseMaelis.objects.get_or_create(
                slug='test',
                base_wsdl_url='https://example.org/',
                zeep_wsse_username='maelis-webservice',
                zeep_wsse_password='maelis-password',
            )[0]
        )

        site_service = ResponsesSoap(
            wsdl_url='https://example.org/SiteService?wsdl',
            wsdl_content=get_xml_file('SiteService.wsdl'),
            settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        )

        family_service = ResponsesSoap(
            wsdl_url='https://example.org/FamilyService?wsdl',
            wsdl_content=get_xml_file('FamilyService.wsdl'),
            settings=Settings(strict=False, xsd_ignore_sequence_order=True),
        )
        with family_service() as soap_mock:
            soap_mock.add_soap_response('readCategoryList', get_xml_file('R_read_category_list.xml'))
            soap_mock.add_soap_response(
                'readChildIndicatorList', get_xml_file('R_read_child_indicator_list.xml')
            )
            soap_mock.add_soap_response('readCivilityList', get_xml_file('R_read_civility_list.xml'))
            soap_mock.add_soap_response('readCountryList', get_xml_file('R_read_country_list.xml'))
            soap_mock.add_soap_response('readCSPList', get_xml_file('R_read_csp_list.xml'))
            soap_mock.add_soap_response('readDietCodeList', get_xml_file('R_read_dietcode_list.xml'))
            soap_mock.add_soap_response('readDocumentList', get_xml_file('R_read_document_list.xml'))
            soap_mock.add_soap_response('readOrganList', get_xml_file('R_read_organ_list.xml'))
            soap_mock.add_soap_response('readPAIList', get_xml_file('R_read_pai_list.xml'))
            soap_mock.add_soap_response('readQualityList', get_xml_file('R_read_quality_list.xml'))
            soap_mock.add_soap_response('readQuotientList', get_xml_file('R_read_quotient_list.xml'))
            soap_mock.add_soap_response('readRLIndicatorList', get_xml_file('R_read_rl_indicator_list.xml'))
            soap_mock.add_soap_response('readSituationList', get_xml_file('R_read_situation_list.xml'))
            soap_mock.add_soap_response('readStreetList', get_xml_file('R_read_street_list.xml'))
            soap_mock.add_soap_response('readVaccinList', get_xml_file('R_read_vaccin_list.xml'))
            con.update_family_referentials()
        with site_service() as site_mock:
            site_mock.add_soap_response('readYearSchoolList', get_xml_file('R_read_year_school_list.xml'))
            site_mock.add_soap_response('readLevelList', get_xml_file('R_read_level_list.xml'))
            site_mock.add_soap_response('readDerogReasonList', get_xml_file('R_read_derog_reason_list.xml'))
            con.update_site_referentials()

    # reset change in zeep private interface to bypass clear_cache fixture
    from zeep.cache import InMemoryCache

    InMemoryCache._cache = {}


@pytest.fixture()
def con(db):
    return ToulouseMaelis.objects.get()


@mock.patch('passerelle.utils.Request.get')
def test_call_with_wrong_wsdl_url(mocked_get, con):
    mocked_get.side_effect = CONNECTION_ERROR
    with pytest.raises(
        SOAPError,
        match='cannot be loaded: No address associated with hostname',
    ) as e:
        con.call('Family', 'isWSRunning')
    assert e.value.err == 1
    assert e.value.http_status == 200
    assert e.value.url == 'https://example.org/FamilyService?wsdl'


def test_call_with_wrong_credentials(family_service, con):
    family_service.add_soap_response('isWSRunning', get_xml_file('R_failed_authentication.xml'), status=500)
    with pytest.raises(
        APIError,
        match='The security token could not be authenticated or authorized',
    ) as e:
        con.call('Family', 'isWSRunning')
    assert e.value.__dict__ == {
        'err': 1,
        'log_error': False,
        'http_status': 200,
        'err_code': 'Family-isWSRunning-ns1:FailedAuthentication',
    }


def test_call(family_service, con):
    family_service.add_soap_response('isWSRunning', get_xml_file('R_is_ws_running.xml') % b'true')
    resp = con.call('Family', 'isWSRunning')
    assert resp is True


@pytest.mark.parametrize(
    'get_responses, post_responses, exception',
    [
        (
            [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL, SITE_SERVICE_WSDL],
            [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE],
            None,
        ),
        (
            [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, CONNECTION_ERROR],
            [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_TRUE],
            SOAPError,
        ),
        (
            [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL],
            [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, FAILED_AUTH],
            APIError,
        ),
        (
            [FAMILY_SERVICE_WSDL, ACTIVITY_SERVICE_WSDL, INVOICE_SERVICE_WSDL],
            [ISWSRUNNING_TRUE, ISWSRUNNING_TRUE, ISWSRUNNING_FALSE],
            AssertionError,
        ),
    ],
)
@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_check_status(mocked_post, mocked_get, get_responses, post_responses, exception, con):
    mocked_get.side_effect = get_responses
    mocked_post.side_effect = post_responses
    if exception:
        with pytest.raises(Exception):
            con.check_status()
    else:
        con.check_status()


def test_replace_null_values(con):
    payload = {
        'adresse': {
            'num': '169',
            'numComp': None,
            'street1': 'Chateau',
            'street2': None,
            'town': 'Paris',
            'zipcode': '75014',
        }
    }
    con.replace_null_values(payload)
    assert payload == {
        'adresse': {
            'num': '169',
            'numComp': '',
            'street1': 'Chateau',
            'street2': '',
            'town': 'Paris',
            'zipcode': '75014',
        }
    }


@mock.patch('passerelle.utils.Request.get')
def test_update_referential(mocked_get, con):
    mocked_get.return_value = FAMILY_SERVICE_WSDL

    with mock.patch('passerelle.utils.Request.post') as mocked_post:
        mocked_post.return_value = FakedResponse(
            content=get_xml_file('R_read_category_list.xml'), status_code=200
        )
        data = con.get_referential_data('Family', 'Category')
        con.update_referential('Category', data, 'code', 'libelle')
        assert [
            (x.item_id, x.item_text) for x in Referential.objects.filter(referential_name='Category')
        ] == [('BI', 'BIPARENTALE'), ('ACCEUI', "FAMILLE D'ACCUEIL"), ('MONO', 'MONOPARENTALE')]

    with mock.patch('passerelle.utils.Request.post') as mocked_post:
        mocked_post.return_value = FakedResponse(
            content=get_xml_file('R_read_category_list_2_items.xml'), status_code=200
        )
        data = con.get_referential_data('Family', 'Category')
        con.update_referential('Category', data, 'code', 'libelle')

        assert [
            (x.item_id, x.item_text) for x in Referential.objects.filter(referential_name='Category')
        ] == [('BI', 'BIPARENTALE'), ('ACCEUI', 'Famille acceuillante')]

    # referential are not shared by connectors
    new_con = setup_access_rights(
        ToulouseMaelis.objects.get_or_create(
            slug='test2',
            zeep_wsse_username='maelis-webservice',
            zeep_wsse_password='maelis-password',
        )[0]
    )
    assert new_con.referential.filter(referential_name='Category').count() == 0
    with mock.patch('passerelle.utils.Request.post') as mocked_post:
        mocked_post.return_value = FakedResponse(
            content=get_xml_file('R_read_category_list.xml'), status_code=200
        )
        data = new_con.get_referential_data('Family', 'Category')
        new_con.update_referential('Category', data, 'code', 'libelle')
    assert new_con.referential.filter(referential_name='Category').count() == 3
    assert con.referential.filter(referential_name='Category').count() == 2


def test_cron(db):
    assert Referential.objects.filter(referential_name='Category').count() == 3
    assert sorted(list({x.referential_name for x in Referential.objects.all()})) == [
        'CSP',
        'Category',
        'ChildIndicator',
        'Civility',
        'Complement',
        'Country',
        'DerogReason',
        'DietCode',
        'Document',
        'Level',
        'Organ',
        'PAI',
        'Quality',
        'Quotient',
        'RLIndicator',
        'Sex',
        'Situation',
        'Street',
        'Vaccin',
        'YearSchool',
    ]


def test_link(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312

    family_service.add_soap_response(
        'readFamily', get_xml_file('R_read_family.xml'), request_check=request_check
    )
    url = get_endpoint('link')
    assert Link.objects.count() == 0

    params = {
        'family_id': '1312',
        'firstname': 'Jhon',
        'lastname': 'Doe',
        'dateBirth': '1938-07-26',
    }
    resp = app.post_json(url + '?NameID=local', params=params)
    assert Link.objects.count() == 1
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'

    params['lastname'] = 'John'
    resp = app.post_json(url + '?NameID=local', params=params)
    assert Link.objects.count() == 1
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "RL1 does not match '1312' family"


def test_link_additional_properties_error(con, app):
    url = get_endpoint('link')
    params = {
        'family_id': '1312',
        'firstname': 'Jhon',
        'lastname': 'Doe',
        'dateBirth': '1938-07-26',
        'plop': 42,
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "Additional properties are not allowed ('plop' was unexpected)"


def test_unlink(con, app):
    url = get_endpoint('unlink')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local')
    assert Link.objects.count() == 0
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'

    resp = app.post_json(url + '?NameID=local')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_referential(con):
    assert con.get_referential('Category') == [
        {'code': 'BI', 'id': 'BI', 'libelle': 'BIPARENTALE', 'text': 'BIPARENTALE'},
        {'code': 'ACCEUI', 'id': 'ACCEUI', 'libelle': "FAMILLE D'ACCUEIL", 'text': "FAMILLE D'ACCUEIL"},
        {'code': 'MONO', 'id': 'MONO', 'libelle': 'MONOPARENTALE', 'text': 'MONOPARENTALE'},
    ]


def test_get_referential_value(con):
    assert con.get_referential_value('CSP', '1') == 'AGRICULTEUR'
    assert con.get_referential_value('CSP', 'AGR') == 'AGRICULTEUR'


def test_get_referential_value_not_found(con, caplog):
    assert con.get_referential_value('Civility', 'MR') == 'MR'
    assert len(caplog.records) == 1
    assert caplog.records[0].levelno == logging.WARNING
    assert caplog.records[0].message == "No 'MR' key into Maelis 'Civility' referential"


def test_read_category_list(con, app):
    url = get_endpoint('read-category-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'BI', 'text': 'BIPARENTALE', 'code': 'BI', 'libelle': 'BIPARENTALE'},
        {'id': 'ACCEUI', 'text': "FAMILLE D'ACCUEIL", 'code': 'ACCEUI', 'libelle': "FAMILLE D'ACCUEIL"},
        {'id': 'MONO', 'text': 'MONOPARENTALE', 'code': 'MONO', 'libelle': 'MONOPARENTALE'},
    ]


def test_read_country_list(con, app):
    url = get_endpoint('read-country-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 3
    assert resp.json['data'] == [
        {'id': '212', 'code': '212', 'text': 'AFGHANISTAN', 'libelle': 'AFGHANISTAN'},
        {'id': '303', 'code': '303', 'text': 'AFRIQUE DU SUD', 'libelle': 'AFRIQUE DU SUD'},
        {'id': '125', 'code': '125', 'text': 'ALBANIE', 'libelle': 'ALBANIE'},
    ]


def test_read_child_indicator_list(con, app):
    url = get_endpoint('read-child-indicator-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 8
    assert resp.json['data'][0:2] == [
        {
            'id': 'AUTRE',
            'text': 'Autre',
            'choiceList': [],
            'code': 'AUTRE',
            'libelle': 'Autre',
            'typeDesc': 'NOTE',
        },
        {
            'id': 'AVL',
            'text': 'Auxiliaire de Vie loisirs',
            'choiceList': [],
            'code': 'AVL',
            'libelle': 'Auxiliaire de Vie loisirs',
            'typeDesc': 'NONE',
        },
    ]


def test_read_civility_list(con, app):
    url = get_endpoint('read-civility-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'MME', 'code': 'MME', 'text': 'Madame', 'libelle': 'Madame'},
        {'id': 'M.', 'code': 'M.', 'text': 'Monsieur', 'libelle': 'Monsieur'},
    ]


def test_read_complement_list(con, app):
    url = get_endpoint('read-complement-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'B', 'text': 'bis'},
        {'id': 'Q', 'text': 'quater'},
        {'id': 'T', 'text': 'ter'},
    ]


def test_read_csp_list(con, app):
    url = get_endpoint('read-csp-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 27
    assert resp.json['data'][:5] == [
        {'code': '14', 'id': '14', 'libelle': 'AGENT DE MAITRISE', 'text': 'AGENT DE MAITRISE'},
        {'code': '1', 'id': '1', 'libelle': 'AGRICULTEUR', 'text': 'AGRICULTEUR'},
        {'code': 'ART', 'id': 'ART', 'libelle': 'ARTISAN', 'text': 'ARTISAN'},
        {'code': '2', 'id': '2', 'libelle': 'ARTISAN-COMMERCANT', 'text': 'ARTISAN-COMMERCANT'},
        {'code': '15', 'id': '15', 'libelle': 'AUTRES', 'text': 'AUTRES'},
    ]

    resp = app.get(url + '?distinct=False')
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 43
    assert resp.json['data'][:5] == [
        {'id': '14', 'code': '14', 'text': 'AGENT DE MAITRISE', 'libelle': 'AGENT DE MAITRISE'},
        {'id': '1', 'code': '1', 'text': 'AGRICULTEUR', 'libelle': 'AGRICULTEUR'},
        {'id': 'AGR', 'code': 'AGR', 'text': 'AGRICULTEUR', 'libelle': 'AGRICULTEUR'},
        {'id': 'ART', 'code': 'ART', 'text': 'ARTISAN', 'libelle': 'ARTISAN'},
        {'id': 'ARTI', 'code': 'ARTI', 'text': 'ARTISAN', 'libelle': 'ARTISAN'},
    ]


def test_read_dietcode_list(con, app):
    url = get_endpoint('read-dietcode-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'STD', 'code': 'STD', 'text': '1- REPAS STANDARD', 'libelle': '1- REPAS STANDARD'},
        {'id': 'RSP', 'code': 'RSP', 'text': '2- RÉGIME SANS PORC', 'libelle': '2- RÉGIME SANS PORC'},
        {'id': 'RSV', 'code': 'RSV', 'text': '3- RÉGIME SANS VIANDE', 'libelle': '3- RÉGIME SANS VIANDE'},
        {
            'id': 'PAI',
            'code': 'PAI',
            'text': "4- PROTOCOLE D'ACCUEIL INDIVIDUALISÉ",
            'libelle': "4- PROTOCOLE D'ACCUEIL INDIVIDUALISÉ",
        },
        {'id': 'BB', 'code': 'BB', 'text': 'REPAS BEBE', 'libelle': 'REPAS BEBE'},
        {'id': 'MSP', 'code': 'MSP', 'text': 'REPAS MOYEN SANS PORC', 'libelle': 'REPAS MOYEN SANS PORC'},
        {'id': 'MSV', 'code': 'MSV', 'text': 'REPAS MOYEN SANS VIANDE', 'libelle': 'REPAS MOYEN SANS VIANDE'},
        {'id': 'MST', 'code': 'MST', 'text': 'REPAS MOYEN STANDARD', 'libelle': 'REPAS MOYEN STANDARD'},
    ]


def test_read_document_list(con, app):
    url = get_endpoint('read-document-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'][:5] == [
        {
            'id': '43',
            'code': '43',
            'rang': 'FAMILY',
            'text': 'Acte notarié de divorce',
            'libelle': 'Acte notarié de divorce',
        },
        {
            'id': '44',
            'code': '44',
            'rang': 'PERSON',
            'text': "Attestation aide médicale de l'état CPAM",
            'libelle': "Attestation aide médicale de l'état CPAM",
        },
        {'id': '45', 'code': '45', 'rang': 'FAMILY', 'text': 'Attestation CAF', 'libelle': 'Attestation CAF'},
        {
            'id': '46',
            'code': '46',
            'rang': 'FAMILY',
            'text': 'Attestation CD31',
            'libelle': 'Attestation CD31',
        },
        {
            'id': '47',
            'code': '47',
            'rang': 'FAMILY',
            'text': "Attestation d'attribution ou non de bourse",
            'libelle': "Attestation d'attribution ou non de bourse",
        },
    ]


def test_read_organ_list(con, app):
    url = get_endpoint('read-organ-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 92
    assert resp.json['data'][:5] == [
        {'id': 'A10000979374', 'code': 'ALC L OLIVIER', 'text': 'ALC L OLIVIER', 'libelle': None},
        {'id': 'A10000979372', 'code': 'ALVA 06', 'text': 'ALVA 06', 'libelle': None},
        {'id': 'A10000980566', 'code': 'ANTIBES', 'text': 'ANTIBES', 'libelle': None},
        {'id': 'A10000980388', 'code': 'APAJH', 'text': 'APAJH', 'libelle': None},
        {'id': 'A10016401771', 'code': 'ASCROS', 'text': 'ASCROS', 'libelle': None},
    ]


def test_read_pai_list(con, app):
    url = get_endpoint('read-pai-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'PAIALI', 'code': 'PAIALI', 'text': 'ALIMENTAIRE', 'libelle': 'ALIMENTAIRE'},
        {'id': 'PAIO', 'code': 'PAIO', 'text': 'AUTRE', 'libelle': 'AUTRE'},
        {'id': 'PAIMED', 'code': 'PAIMED', 'text': 'MEDICAL', 'libelle': 'MEDICAL'},
        {'id': 'PAI2', 'code': 'PAI2', 'text': 'MEDICAL ET ALIMENTAIRE', 'libelle': 'MEDICAL ET ALIMENTAIRE'},
    ]


def test_read_quality_list(con, app):
    url = get_endpoint('read-quality-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'][:5] == [
        {'id': 'AU', 'code': 'AU', 'text': 'AUTRE', 'libelle': 'AUTRE'},
        {'id': 'BP', 'code': 'BP', 'text': 'BEAU PERE', 'libelle': 'BEAU PERE'},
        {'id': 'BM', 'code': 'BM', 'text': 'BELLE MERE', 'libelle': 'BELLE MERE'},
        {'id': 'CONSO', 'code': 'CONSO', 'text': 'CONSOMMATEUR', 'libelle': 'CONSOMMATEUR'},
        {'id': 'EN', 'code': 'EN', 'text': 'ENFANT', 'libelle': 'ENFANT'},
    ]


def test_read_quotient_list(con, app):
    url = get_endpoint('read-quotient-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'QF', 'code': 'QF', 'text': 'GRILLE DE QUOTIENT', 'libelle': 'GRILLE DE QUOTIENT'},
        {'id': 'QCLSH', 'code': 'QCLSH', 'text': 'QUOTIENT CENTRE AERE', 'libelle': 'QUOTIENT CENTRE AERE'},
        {'id': 'QJEU', 'code': 'QJEU', 'text': 'QUOTIENT JEUNESSE', 'libelle': 'QUOTIENT JEUNESSE'},
        {'id': 'QS', 'code': 'QS', 'text': 'QUOTIENT SCOLAIRE', 'libelle': 'QUOTIENT SCOLAIRE'},
        {'id': 'QSPORT', 'code': 'QSPORT', 'text': 'QUOTIENT SPORT', 'libelle': 'QUOTIENT SPORT'},
        {
            'id': 'MOY ECO',
            'code': 'MOY ECO',
            'text': 'REVENU MOYEN ( MENSUEL OU ANNUEL)',
            'libelle': 'REVENU MOYEN ( MENSUEL OU ANNUEL)',
        },
    ]


def test_read_rl_indicator_list(con, app):
    url = get_endpoint('read-rl-indicator-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 4
    assert resp.json['data'][1:3] == [
        {
            'id': 'AVS',
            'text': 'Auxiliaire de Vie scolaire',
            'choiceList': [],
            'code': 'AVS',
            'libelle': 'Auxiliaire de Vie scolaire ',
            'typeDesc': 'NONE',
        },
        {
            'id': 'ETABSPEC',
            'text': 'Etablissement spécialisé',
            'choiceList': [],
            'code': 'ETABSPEC',
            'libelle': 'Etablissement spécialisé',
            'typeDesc': 'NOTE',
        },
    ]


def test_read_sex_list(con, app):
    url = get_endpoint('read-sex-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'F', 'text': 'Féminin'},
        {'id': 'M', 'text': 'Masculin'},
    ]


def test_read_situation_list(con, app):
    url = get_endpoint('read-situation-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 9
    assert resp.json['data'][:5] == [
        {'id': 'C', 'code': 'C', 'text': 'Célibataire', 'libelle': 'Célibataire'},
        {'id': 'D', 'code': 'D', 'text': 'Divorcé (e)', 'libelle': 'Divorcé (e)'},
        {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'},
        {'id': 'M', 'code': 'M', 'text': 'Marié (e)', 'libelle': 'Marié (e)'},
        {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'},
    ]

    resp = app.get(url + '?q= ')
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 9

    resp = app.get(url + '?id=V')
    assert resp.json['err'] == 0
    assert resp.json['data'] == [{'id': 'V', 'code': 'V', 'text': 'Veuf (ve)', 'libelle': 'Veuf (ve)'}]

    resp = app.get(url + '?q= sÉ ')
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'},
        {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'},
        {'id': 'S', 'code': 'S', 'text': 'Séparé (e)', 'libelle': 'Séparé (e)'},
    ]

    resp = app.get(url + '?q= sÉ &limit=2')
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {'id': 'CS', 'code': 'CS', 'text': 'EN COURS DE SEPARATION', 'libelle': 'EN COURS DE SEPARATION'},
        {'id': 'P', 'code': 'P', 'text': 'Pacsé (e)', 'libelle': 'Pacsé (e)'},
    ]


def test_read_street_list(con, app):
    url = get_endpoint('read-street-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 3
    assert resp.json['data'] == [
        {'id': 'AP0594', 'text': 'AVENUE PAULIANI', 'idStreet': 'AP0594', 'libelleStreet': 'AVENUE PAULIANI'},
        {
            'id': 'AS0264',
            'text': 'RUE SAINT FRANCOIS DE PAULE',
            'idStreet': 'AS0264',
            'libelleStreet': 'RUE SAINT FRANCOIS DE PAULE',
        },
        {
            'id': 'AM0330',
            'text': 'TRAVERSE DES MARAICHERS',
            'idStreet': 'AM0330',
            'libelleStreet': 'TRAVERSE DES MARAICHERS',
        },
    ]


def test_read_vaccin_list(con, app):
    url = get_endpoint('read-vaccin-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 20
    assert resp.json['data'][:5] == [
        {'id': 'BCG', 'code': 'BCG', 'text': 'BCG', 'libelle': 'BCG'},
        {
            'id': 'CIB',
            'code': 'CIB',
            'text': 'CONTRE-INDICATION  TEMPORAIRE AU BCG',
            'libelle': 'CONTRE-INDICATION  TEMPORAIRE AU BCG',
        },
        {'id': 'MONO', 'code': 'MONO', 'text': 'CONTROLE DU BCG (+)', 'libelle': 'CONTROLE DU BCG (+)'},
        {'id': 'MONON', 'code': 'MONON', 'text': 'CONTROLE DU BCG (-)', 'libelle': 'CONTROLE DU BCG (-)'},
        {
            'id': 'DTC',
            'code': 'DTC',
            'text': 'DIPHTERIE TETANOS COQUELUCHE',
            'libelle': 'DIPHTERIE TETANOS COQUELUCHE',
        },
    ]


def test_read_rl_list(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-rl-list')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('613878', 'DOE JHON'),
        ('613879', 'DOE JANE'),
    ]

    resp = app.get(url + '?NameID=local&text_template={{ birth.dateBirth|date:"d/m/Y" }}')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('613878', '25/07/1938'),
        ('613879', '21/06/1940'),
    ]


def test_read_rl_list_not_linked_error(con, app):
    url = get_endpoint('read-rl-list')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_person_list(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-person-list')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [(614059, 'ARKANA KENY')]

    resp = app.get(url + '?NameID=local&text_template={{ dateBirth|date:"d/m/Y" }}')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [(614059, '19/12/1982')]


def test_read_person_list_not_linked_error(con, app):
    url = get_endpoint('read-person-list')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_list(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-list')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('613880', 'DOE JANNIS'),
        ('613987', 'DOE JOHNNY ALLEN'),
        ('614051', 'DOE ROBERT'),
    ]

    resp = app.get(url + '?NameID=local&text_template={{ birth.dateBirth|date:"d/m/Y" }}')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('613880', '18/01/1943'),
        ('613987', '26/11/1942'),
        ('614051', '23/05/1941'),
    ]


def test_read_child_list_not_linked_error(con, app):
    url = get_endpoint('read-child-list')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_person_list(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-person-list')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880')
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [(614719, 'BENT AMEL')]

    resp = app.get(
        url + '?NameID=local&child_id=613880&text_template={{ personInfo.dateBirth|date:"d/m/Y" }}'
    )
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [(614719, '20/06/1985')]


def test_read_child_person_list_not_linked_error(con, app):
    url = get_endpoint('read-child-person-list')

    resp = app.get(url + '?NameID=local&child_id=613880')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_person_list_not_exists_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-person-list')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=42')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '42' child on '1312' family"


@pytest.mark.parametrize(
    "xml", ['R_read_family.xml', 'R_read_family_relax.xml', 'R_read_family_reordered.xml']
)
def test_read_family(family_service, xml, con, app):
    family_service.add_soap_response('readFamily', get_xml_file(xml))
    url = get_endpoint('read-family')

    resp = app.get(url + '?family_id=1312')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local')
    assert resp.json['err'] == 0
    data = resp.json['data']
    del data['RL1']
    del data['RL2']
    del data['childList']
    del data['emergencyPersonList']
    assert data == {
        'family_id': '1312',
        'number': 1312,
        'category': 'BI',
        'situation': 'M',
        'flagCom': True,
        'nbChild': 2,
        'nbTotalChild': None,
        'nbAES': None,
        'quotientList': [],
        'indicatorList': [],
        'childErrorList': [],
        'category_text': 'BIPARENTALE',
        'situation_text': 'Marié (e)',
    }
    data = resp.json['data']['RL1']
    del data['profession']
    del data['indicatorList']
    del data['indicators']
    assert data == {
        'num': '613878',
        'lastname': 'DOE',
        'firstname': 'JHON',
        'maidenName': None,
        'quality': 'PERE',
        'civility': 'M.',
        'birth': {
            'communeCode': None,
            'countryCode': '99350',
            'dateBirth': '1938-07-26T00:00:00+01:00',
            'place': 'Rabbat',
        },
        'adresse': {
            'idStreet': 'AM0330',
            'idStreet_text': 'TRAVERSE DES MARAICHERS',
            'num': 170,
            'numComp': None,
            'street1': 'TRAVERSE DES MARAICHERS',
            'street2': None,
            'town': 'Paris',
            'zipcode': '75014',
        },
        'contact': {
            'phone': 'non',
            'mobile': '0777777777',
            'mail': 'djhon@example.org',
            'isContactMail': True,
            'isContactSms': True,
            'isInvoicePdf': True,
        },
        'CAFInfo': None,
        'civility_text': 'Monsieur',
        'quality_text': 'PERE',
        'quotientList': [
            {
                'cdquo': 'QS',
                'cdquo_text': 'QUOTIENT SCOLAIRE',
                'codeUti': None,
                'dateEnd': '2021-12-31T00:00:00+01:00',
                'dateStart': '2021-01-01T00:00:00+01:00',
                'mtt': 1500.33,
                'yearRev': 2020,
            },
            {
                'cdquo': 'MOY ECO',
                'cdquo_text': 'REVENU MOYEN ( MENSUEL OU ANNUEL)',
                'codeUti': None,
                'dateEnd': '2022-12-31T00:00:00+01:00',
                'dateStart': '2022-01-01T00:00:00+01:00',
                'mtt': 1500.44,
                'yearRev': 2021,
            },
        ],
        'subscribeActivityList': [],
    }
    assert sorted(resp.json['data']['RL1']['indicatorList'], key=lambda x: x['code']) == [
        {
            'choice': None,
            'code': 'AVL',
            'code_text': 'Auxiliaire de Vie loisirs',
            'libelle': 'Auxiliaire de Vie loisirs',
            'note': None,
        },
        {
            'choice': None,
            'code': 'ETABSPEC',
            'code_text': 'Etablissement spécialisé',
            'libelle': 'Etablissement spécialisé',
            'note': 'SNPP',
        },
    ]
    assert resp.json['data']['RL1']['indicators'] == {
        'AVL': {
            'code': 'AVL',
            'id': 'AVL',
            'isActive': True,
            'libelle': 'Auxiliaire de Vie loisirs',
            'text': 'Auxiliaire de Vie loisirs',
            'typeDesc': 'NONE',
        },
        'AVS': {
            'code': 'AVS',
            'id': 'AVS',
            'isActive': False,
            'libelle': 'Auxiliaire de Vie scolaire ',
            'text': 'Auxiliaire de Vie scolaire',
            'typeDesc': 'NONE',
        },
        'ETABSPEC': {
            'code': 'ETABSPEC',
            'id': 'ETABSPEC',
            'isActive': True,
            'libelle': 'Etablissement spécialisé',
            'note': 'SNPP',
            'text': 'Etablissement spécialisé',
            'typeDesc': 'NOTE',
        },
        'MDPH': {
            'code': 'MDPH',
            'id': 'MDPH',
            'isActive': False,
            'libelle': 'Notification MDPH',
            'text': 'Notification MDPH',
            'typeDesc': 'NONE',
        },
    }
    data = resp.json['data']['childList'][0]
    del data['medicalRecord']
    del data['authorizedPersonList']
    del data['paiInfoBean']
    del data['indicatorList']
    del data['indicators']
    assert data == {
        'num': '613880',
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'sexe_text': 'Féminin',
        'birth': {
            'dateBirth': '1943-01-19T00:00:00+01:00',
            'place': 'Saint-louis',
            'communeCode': '91122',
            'countryCode': '99100',
        },
        'dietcode': 'RSV',
        'dietcode_text': '3- RÉGIME SANS VIANDE',
        'bPhoto': True,
        'bLeaveAlone': False,
        'insurance': {
            'company': 'Total Disaster Insurance',
            'contractEnd': '2022-12-31T00:00:00+01:00',
            'contractNumber': '123',
            'contractStart': '2022-01-01T00:00:00+01:00',
            'memberNumber': '456',
        },
        'subscribeSchoolList': [],
        'mother': {'num': 613963, 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE'},
        'father': {'num': 613878, 'civility': 'M.', 'firstname': 'JHON', 'lastname': 'DOE'},
        'rl': None,
        'subscribeActivityList': [],
    }
    if xml != 'R_read_family_relax.xml':
        assert resp.json['data']['childList'][0]['paiInfoBean'] == {
            'code': 'PAIALI',
            'code_text': 'ALIMENTAIRE',
            'dateDeb': '2022-01-01T00:00:00+01:00',
            'dateFin': '2022-12-31T00:00:00+01:00',
            'description': 'bla bla PAI',
        }
    else:
        assert resp.json['data']['childList'][0]['paiInfoBean'] == {
            'code': None,
            'dateDeb': '2022-01-01T00:00:00+01:00',
            'dateFin': '2022-12-31T00:00:00+01:00',
            'description': 'bla bla PAI',
        }
    assert resp.json['data']['childList'][0]['medicalRecord'] == {
        "familyDoctor": {
            "name": "DRE",
            "phone": "0612341234",
            "address": {"street1": "Alameda", "zipcode": "90220", "town": "Compton"},
        },
        'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up',
        'allergy2': 'shrimp and cauliflower',
        'comment1': "the shrimp allergy isn't fully identified",
        'comment2': None,
        'observ1': 'Ay Caramba!',
        'observ2': 'Eat my shorts!',
        'isAuthHospital': True,
        'hospital': 'Springfield General Hospital',
        "vaccinList": [
            {
                "code": "ROR",
                "libelle": "ROUGEOLE-OREILLONS-RUBEOLE",
                "vaccinationDate": "2012-02-22T00:00:00+01:00",
            },
            {
                "code": "DTC",
                "libelle": "DIPHTERIE TETANOS COQUELUCHE",
                "vaccinationDate": "2011-01-11T00:00:00+01:00",
            },
            {
                "code": "ROR",
                "libelle": "ROUGEOLE-OREILLONS-RUBEOLE",
                "vaccinationDate": "1970-01-11T00:00:00+01:00",
            },
        ],
    }
    assert resp.json['data']['emergencyPersonList'][0] == {
        'firstname': 'KENY',
        'lastname': 'ARKANA',
        'dateBirth': '1982-12-20T00:00:00+01:00',
        'quality': 'T',
        'civility': 'MME',
        'sexe': None,
        'contact': {'phone': '0123456789', 'mobile': None, 'mail': 'pueblo@example.org'},
        'numPerson': 614059,
        'civility_text': 'Madame',
        'quality_text': 'TANTE',
    }
    assert resp.json['data']['childList'][0]['authorizedPersonList'][0] == {
        'personInfo': {
            'num': 614719,
            'lastname': 'BENT',
            'firstname': 'AMEL',
            'dateBirth': '1985-06-21T00:00:00+02:00',
            'civility': 'MME',
            'civility_text': 'Madame',
            'sexe': 'F',
            'sexe_text': 'Féminin',
            'contact': {'phone': '0123456789', 'mobile': '0623456789', 'mail': 'abent@example.org'},
        },
        'personQuality': {
            'code': 'T',
            'code_text': 'TANTE',
            'libelle': 'TANTE',
        },
    }
    assert sorted(resp.json['data']['childList'][0]['indicatorList'], key=lambda x: x['code']) == [
        {'choice': None, 'code': 'AUTRE', 'code_text': 'Autre', 'libelle': 'Autre', 'note': 'rebellious'},
        {
            'choice': None,
            'code': 'LUNETTE',
            'code_text': 'Port de lunettes',
            'libelle': 'Port de lunettes',
            'note': None,
        },
    ]
    indicators = resp.json['data']['childList'][0]['indicators']
    assert len(indicators) == 8
    assert len([x for x in indicators.values() if x['isActive']]) == 2
    assert [x for x in indicators.values() if x['typeDesc'] == 'NOTE'] == [
        {
            'id': 'AUTRE',
            'code': 'AUTRE',
            'text': 'Autre',
            'libelle': 'Autre',
            'typeDesc': 'NOTE',
            'isActive': True,
            'note': 'rebellious',
        },
        {
            'id': 'ETABSPEC',
            'code': 'ETABSPEC',
            'text': 'Etablissement spécialisé',
            'libelle': 'Etablissement spécialisé',
            'typeDesc': 'NOTE',
            'isActive': False,
            'note': None,
        },
    ]


def test_read_family_not_linked_error(con, app):
    url = get_endpoint('read-family')

    resp = app.get(url + '?NameID=')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_rl1(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-rl')

    resp = app.get(url + '?family_id=1312&rl_id=613878')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&rl_id=613878')
    assert resp.json['err'] == 0
    assert resp.json['data']['firstname'] == 'JHON'


def test_read_rl1_with_income_year(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_income_year.xml'))
    url = get_endpoint('read-rl')

    resp = app.get(url + '?family_id=1312&rl_id=613878&income_year=2020')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&rl_id=613878&income_year=2020')
    assert resp.json['err'] == 0
    assert resp.json['data']['quotientList'] == [
        {
            'yearRev': 2020,
            'dateStart': '2021-01-01T00:00:00+01:00',
            'dateEnd': '2021-12-31T00:00:00+01:00',
            'mtt': 1500.33,
            'cdquo': 'QS',
            'cdquo_text': 'QUOTIENT SCOLAIRE',
            'codeUti': None,
        }
    ]


def test_read_rl2(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-rl')

    resp = app.get(url + '?family_id=1312&rl_id=613879')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&rl_id=613879')
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'family_id': '1312',
        'num': '613879',
        'lastname': 'DOE',
        'firstname': 'JANE',
        'maidenName': 'SMITH',
        'quality': 'MERE',
        'civility': 'MME',
        'birth': {
            'communeCode': None,
            'countryCode': '99351',
            'dateBirth': '1940-06-22T00:00:00+02:00',
            'place': 'Bardot',
        },
        'adresse': {
            'idStreet': None,
            'num': 170,
            'numComp': None,
            'street1': "Chateau d'eau",
            'street2': None,
            'town': 'Paris',
            'zipcode': '75014',
        },
        'contact': {
            'phone': None,
            'mobile': None,
            'mail': None,
            'isContactMail': False,
            'isContactSms': False,
            'isInvoicePdf': False,
        },
        'profession': {
            'codeCSP': 'ART',
            'profession': 'informaticien',
            'employerName': 'EO',
            'phone': '0123456789',
            'addressPro': {'num': None, 'street': None, 'zipcode': None, 'town': 'Orléans'},
            'codeCSP_text': 'ARTISAN',
        },
        'CAFInfo': {
            'number': '789',
            'organ': 'A10007752822',
            'organ_text': 'LA COLLE SUR LOUP',
        },
        'civility_text': 'Madame',
        'quality_text': 'MERE',
        'quotientList': [],
        'indicatorList': [],
        'indicators': {
            'AVL': {
                'code': 'AVL',
                'id': 'AVL',
                'isActive': False,
                'libelle': 'Auxiliaire de Vie loisirs',
                'text': 'Auxiliaire de Vie loisirs',
                'typeDesc': 'NONE',
            },
            'AVS': {
                'code': 'AVS',
                'id': 'AVS',
                'isActive': False,
                'libelle': 'Auxiliaire de Vie scolaire ',
                'text': 'Auxiliaire de Vie scolaire',
                'typeDesc': 'NONE',
            },
            'ETABSPEC': {
                'code': 'ETABSPEC',
                'id': 'ETABSPEC',
                'isActive': False,
                'libelle': 'Etablissement spécialisé',
                'note': None,
                'text': 'Etablissement spécialisé',
                'typeDesc': 'NOTE',
            },
            'MDPH': {
                'code': 'MDPH',
                'id': 'MDPH',
                'isActive': False,
                'libelle': 'Notification MDPH',
                'text': 'Notification MDPH',
                'typeDesc': 'NONE',
            },
        },
        'subscribeActivityList': [],
    }


def test_read_rl_not_linked_error(con, app):
    url = get_endpoint('read-rl')

    resp = app.get(url + '?NameID=local&rl_id=613879')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_rl_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-rl')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&rl_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' RL on '1312' family"


def test_read_person(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-person')

    resp = app.get(url + '?family_id=1312&person_id=614059')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&person_id=614059')
    assert resp.json['err'] == 0
    assert resp.json['data']['firstname'] == 'KENY'


def test_read_person_not_linked_error(con, app):
    url = get_endpoint('read-person')

    resp = app.get(url + '?NameID=local&person_id=614059')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_person_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-person')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&person_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' emergency person on '1312' family"


def test_read_child(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child')

    resp = app.get(url + '?family_id=1312&child_id=613880')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880')
    assert resp.json['err'] == 0
    assert resp.json['data']['firstname'] == 'JANNIS'


def test_read_child_not_linked_error(con, app):
    url = get_endpoint('read-child')

    resp = app.get(url + '?NameID=local&child_id=613880')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' child on '1312' family"


def test_read_child_person(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-person')

    resp = app.get(url + '?family_id=1312&child_id=613880&person_id=614719')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880&person_id=614719')
    assert resp.json['err'] == 0
    assert resp.json['data']['personInfo']['firstname'] == 'AMEL'


def test_read_child_person_not_linked_error(con, app):
    url = get_endpoint('read-child-person')

    resp = app.get(url + '?NameID=local&child_id=613880&person_id=614719')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_person_no_child_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-person')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=42&person_id=614719')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '42' child on '1312' family"


def test_read_child_person_no_person_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('read-child-person')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880&person_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' authorized person on '613880' child"


@pytest.mark.parametrize('string, result', [(b'true', True), (b'false', False)])
def test_is_rl_exists(string, result, family_service, con, app):
    family_service.add_soap_response('isRLExists', get_xml_file('R_is_rl_exists.xml') % string)
    url = get_endpoint('is-rl-exists')
    params = {
        'firstname': 'Jhon',
        'lastname': 'Doe',
        'dateBirth': '1938-07-26',
    }

    resp = app.post_json(url, params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == result


def test_is_rl_exists_schema_error(con, app):
    url = get_endpoint('is-rl-exists')
    params = {
        'firstname': 'Jhon',
        'lastname': 'Doe',
        'dateBirth': '1938-07-26 more text',
    }

    resp = app.post_json(url, params=params, status=400)
    assert resp.json['err'] == 1
    assert "does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'" in resp.json['err_desc']


@pytest.mark.parametrize('string, result', [(b'true', True), (b'false', False)])
def test_is_child_exists(family_service, string, result, con, app):
    family_service.add_soap_response('isChildExists', get_xml_file('R_is_rl_exists.xml') % string)
    url = get_endpoint('is-child-exists')
    params = {
        'firstname': 'Doe',
        'lastname': 'Jhonny allen',
        'dateBirth': '1942-11-27',
    }

    resp = app.post_json(url, params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == result


def test_create_family(family_service, con, app):
    def request_check(request):
        assert request.emergencyPersonList[0]['firstname'] == 'Keny'

    family_service.add_soap_response(
        'createFamily', get_xml_file('R_create_family.xml'), request_check=request_check
    )
    url = get_endpoint('create-family')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'flagCom': False,
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/communeCode': None,
        'rl1/birth/countryCode': '99350',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/birth/place': 'Rabbat',
        'rl1/adresse/idStreet': 'AM0330',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
        'rl1/adresse/numComp': 'B',
        'rl1/contact/isContactMail': True,
        'rl1/profession/codeCSP': 'ART',
        'rl1/CAFInfo/organ': 'A10007752822',
        'emergencyPersonList/0/civility': 'MME',
        'emergencyPersonList/0/firstname': 'Keny',
        'emergencyPersonList/0/lastname': 'Arkana',
        'emergencyPersonList/0/sexe': 'F',
        'emergencyPersonList/0/dateBirth': '1982-12-20',
        'emergencyPersonList/0/quality': 'T',
        'childList/0/lastname': 'Zimmerman',
        'childList/0/firstname': 'Robert',
        'childList/0/sexe': 'M',
        'childList/0/birth/dateBirth': '1941-05-24',
        'childList/0/birth/place': 'Saint-louis',
        'childList/0/birth/communeCode': '91122',
        'childList/0/birth/countryCode': '99100',
        'childList/0/dietcode': 'RSV',
        'childList/0/medicalRecord/vaccinList/0/code': 'DTC',
        'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26',
        'childList/0/insurance/company': 'Total Disaster Insurance',
        'childList/0/insurance/contractNumber': '123',
        'childList/0/insurance/memberNumber': '456',
        'childList/0/insurance/contractStart': '2022-01-01',
        'childList/0/insurance/contractEnd': '2022-12-31',
    }

    resp = app.post_json(url, params=params)
    assert resp.json['err'] == 0
    assert not Link.objects.exists()

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'number': 196545,
        'password': '394634V2',
        'rl1ErrorList': [],
        'childErrorList': [],
    }
    assert Link.objects.get(resource=con, family_id='196545', name_id='local')


def test_create_family_empty_referential_key_error(con, app):
    url = get_endpoint('create-family')
    params = {
        'category': '',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "category: '' does not match '.+'"


def test_create_family_already_linked_error(con, app):
    url = get_endpoint('create-family')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'already-linked'
    assert resp.json['err_desc'] == 'User already linked to family'


def test_create_family_maelis_error(family_service, con, app):
    family_service.add_soap_response('createFamily', get_xml_file('R_create_family_error.xml'))
    url = get_endpoint('create-family')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'E54a, E54a'
    assert 'Il existe déjà' in resp.json['err_desc']


def test_create_family_wrong_referential_key_error(con, app):
    url = get_endpoint('create-family')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/communeCode': None,
        'rl1/birth/countryCode': '99350',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/birth/place': 'Rabbat',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
        'rl1/adresse/numComp': 'B',
        'rl1/profession/codeCSP': 'ART',
        'rl1/CAFInfo/organ': 'A10007752822',
        'childList/0/lastname': 'Zimmerman',
        'childList/0/firstname': 'Robert',
        'childList/0/sexe': 'M',
        'childList/0/birth/dateBirth': '1941-05-24',
        'childList/0/birth/place': 'Saint-louis',
        'childList/0/birth/communeCode': '91122',
        'childList/0/birth/countryCode': '99100',
        'childList/0/dietcode': 'RSV',
        'childList/0/medicalRecord/vaccinList/0/code': 'plop',
        'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "childList/0/medicalRecord/vaccinList/0/code key value 'plop' do not belong to 'Vaccin' referential"
    )


def test_update_family(family_service, con, app):
    def request_check(request):
        assert request.emergencyPersonList['personList'][0]['firstname'] == 'Keny'

    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('update-family')
    params = {
        'category': 'BI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/communeCode': None,
        'rl1/birth/countryCode': '99350',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/birth/place': 'Rabbat',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
        'rl1/adresse/numComp': 'B',
        'rl1/profession/codeCSP': 'ART',
        'rl1/CAFInfo/organ': 'A10007752822',
        'emergencyPersonList/0/civility': 'MME',
        'emergencyPersonList/0/firstname': 'Keny',
        'emergencyPersonList/0/lastname': 'Arkana',
        'emergencyPersonList/0/sexe': 'F',
        'emergencyPersonList/0/dateBirth': '1982-12-20',
        'emergencyPersonList/0/quality': 'T',
        'childList/0/lastname': 'Zimmerman',  # add child
        'childList/0/firstname': 'Robert',
        'childList/0/sexe': 'M',
        'childList/0/birth/dateBirth': '1941-05-24',
        'childList/0/birth/place': 'Duluth',
        'childList/0/dietcode': 'RSV',
        'childList/0/paiInfoBean/code': 'PAIALI',
        'childList/0/medicalRecord/vaccinList/0/code': 'DTC',
        'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26',
        'childList/0/insurance/company': 'Armagedon Colapse',
        'childList/0/insurance/contractNumber': '444',
        'childList/0/insurance/memberNumber': '555',
        'childList/0/insurance/contractStart': '2022-01-02',
        'childList/0/insurance/contractEnd': '2022-12-31',
        'childList/1/num': '613880',  # update child
        'childList/1/firstname': 'Brunelle',
        'childList/1/lastname': 'Doe',
        'childList/1/birth/dateBirth': '1943-01-19',
        'childList/1/sexe': 'F',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data']['number'] == 196544
    assert not resp.json['data']['childErrorList']


def test_update_family_not_linked_error(con, app):
    url = get_endpoint('update-family')
    params = {
        'category': 'BI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_family_maelis_error(family_service, con, app):
    family_service.add_soap_response('updateFamily', get_xml_file('R_update_family_error.xml'))
    url = get_endpoint('update-family')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'childList/0/lastname': 'Zimmerman',
        'childList/0/firstname': 'Robert',
        'childList/0/sexe': 'M',
        'childList/0/birth/dateBirth': '1941-05-24',
        'childList/0/birth/place': 'Duluth',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'E65a'
    assert "E65a : Il existe déjà un enfant" in resp.json['err_desc']


def test_update_family_soap_error(family_service, con, app):
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family_soap_error.xml'), status=500
    )
    url = get_endpoint('update-family')
    params = {
        'nbChild': '100',
        'category': 'BI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'Family-updateFamily-soap:Server'
    assert 'Une erreur est survenue' in resp.json['err_desc']


def test_update_family_wrong_referential_key_error(con, app):
    url = get_endpoint('update-family')
    params = {
        'category': 'BI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/communeCode': None,
        'rl1/birth/countryCode': '99350',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/birth/place': 'Rabbat',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
        'rl1/adresse/numComp': 'B',
        'rl1/profession/codeCSP': 'ART',
        'rl1/CAFInfo/organ': 'A10007752822',
        'emergencyPersonList/0/civility': 'MME',
        'emergencyPersonList/0/firstname': 'Keny',
        'emergencyPersonList/0/lastname': 'Arkana',
        'emergencyPersonList/0/sexe': 'F',
        'emergencyPersonList/0/dateBirth': '1982-12-20',
        'emergencyPersonList/0/quality': 'T',
        'childList/0/lastname': 'Zimmerman',
        'childList/0/firstname': 'Robert',
        'childList/0/sexe': 'M',
        'childList/0/birth/dateBirth': '1941-05-24',
        'childList/0/birth/place': 'Duluth',
        'childList/0/dietcode': 'RSV',
        'childList/0/paiInfoBean/code': 'PAIALI',
        'childList/0/medicalRecord/vaccinList/0/code': 'plop',
        'childList/0/medicalRecord/vaccinList/0/vaccinationDate': '1940-07-26',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "childList/0/medicalRecord/vaccinList/0/code key value 'plop' do not belong to 'Vaccin' referential"
    )


def test_create_rl1(family_service, con, app):
    family_service.add_soap_response('createFamily', get_xml_file('R_create_family.xml'))
    url = get_endpoint('create-rl1')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url, params=params)
    assert resp.json['err'] == 0
    assert not Link.objects.exists()

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == {'family_id': 196545}
    assert Link.objects.get(resource=con, family_id='196545', name_id='local')


def test_create_rl1_empty_referential_key_error(con, app):
    url = get_endpoint('create-rl1')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': '',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': '',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "rl1/civility: '' does not match '.+'"


def test_create_rl1_already_linked_error(con, app):
    url = get_endpoint('create-rl1')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'already-linked'
    assert resp.json['err_desc'] == 'User already linked to family'


def test_create_rl1_wrong_referential_key_error(con, app):
    url = get_endpoint('create-rl1')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/numComp': 'plop',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "rl1/adresse/numComp key value 'plop' do not belong to 'Complement' referential"
    )


def test_create_rl1_maelis_error(family_service, con, app):
    family_service.add_soap_response('createFamily', get_xml_file('R_create_family_error.xml'))
    url = get_endpoint('create-rl1')
    params = {
        'category': 'ACCEUI',
        'situation': 'C',
        'rl1/civility': 'M.',
        'rl1/firstname': 'Jhon',
        'rl1/lastname': 'Doe',
        'rl1/quality': 'AU',
        'rl1/birth/dateBirth': '1938-07-26',
        'rl1/adresse/street1': 'Chateau',
        'rl1/adresse/town': 'Paris',
        'rl1/adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'already-rl1'
    assert 'Il existe déjà' in resp.json['err_desc']


def test_update_rl1(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312
        assert request.rl1['adresse']['street1'] == "Chateau d'eau"

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('update-rl1')
    params = {
        'civility': 'M.',
        'firstname': 'Jhonny',
        'lastname': 'Doe',
        'quality': 'PERE',
        'birth/dateBirth': '1943-06-15',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0


def test_update_rl1_not_linked_error(con, app):
    url = get_endpoint('update-rl1')
    params = {
        'civility': 'M.',
        'firstname': 'Jhonny',
        'lastname': 'Doe',
        'quality': 'PERE',
        'birth/dateBirth': '1943-06-15',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_rl1_connection_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname'))
    url = get_endpoint('update-rl1')
    params = {
        'civility': 'M.',
        'firstname': 'Jhonny',
        'lastname': 'Doe',
        'quality': 'PERE',
        'birth/dateBirth': '1943-06-15',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params, status=500)
    assert resp.json['err']
    assert resp.json['err_desc'] == 'No address associated with hostname'


def test_update_rl1_wrong_referential_key_error(con, app):
    url = get_endpoint('update-rl1')
    params = {
        'civility': 'M.',
        'firstname': 'Jhonny',
        'lastname': 'Doe',
        'quality': 'plop',
        'birth/dateBirth': '1943-06-15',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential"


def test_create_rl2(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('create-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
        'adresse/num': '170',
        'adresse/street1': "Chateau d'eau",
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == {'id': '614062'}


def test_create_rl2_not_linked_error(con, app):
    url = get_endpoint('create-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
        'adresse/num': '170',
        'adresse/street1': "Chateau d'eau",
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_create_rl2_connection_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname'))
    url = get_endpoint('create-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
        'adresse/num': '170',
        'adresse/street1': "Chateau d'eau",
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params, status=500)
    assert resp.json['err']
    assert resp.json['err_desc'] == 'No address associated with hostname'


def test_create_rl2_already_exists_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('create-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
        'adresse/num': '170',
        'adresse/street1': "Chateau d'eau",
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'already-rl2'
    assert resp.json['err_desc'] == 'RL2 already defined on family'


def test_create_rl2_wrong_referential_key_error(con, app):
    url = get_endpoint('create-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'plop',
        'birth/dateBirth': '1940-06-22',
        'adresse/num': '170',
        'adresse/street1': "Chateau d'eau",
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential"


def test_update_rl2(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312
        assert request.rl2['adresse']['street1'] == "Chateau d'eau"

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('update-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0


def test_update_rl2_not_linked_error(con, app):
    url = get_endpoint('update-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'quality': 'MERE',
        'maidenName': 'Smith',
        'birth/dateBirth': '1940-06-22',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_rl2_connection_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response('updateFamily', ConnectionError('No address associated with hostname'))
    url = get_endpoint('update-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params, status=500)
    assert resp.json['err']
    assert resp.json['err_desc'] == 'No address associated with hostname'


def test_update_rl2_not_exists_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    url = get_endpoint('update-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'MERE',
        'birth/dateBirth': '1940-06-22',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'no-rl2'
    assert resp.json['err_desc'] == 'No RL2 to update on family'


def test_update_rl2_wrong_referential_key_error(con, app):
    url = get_endpoint('update-rl2')
    params = {
        'civility': 'MME',
        'firstname': 'JANE',
        'lastname': 'DOE',
        'maidenName': 'Smith',
        'quality': 'plop',
        'birth/dateBirth': '1940-06-22',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "quality key value 'plop' do not belong to 'Quality' required referential"


def test_create_child(family_service, con, app):
    family_service.add_soap_response('createChild', get_xml_file('R_create_child.xml'))
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
        'insurance/company': 'Total Disaster Insurance',
        'insurance/contractNumber': '123',
        'insurance/memberNumber': '456',
        'insurance/contractStart': '2022-01-01',
        'insurance/contractEnd': '2022-12-31',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == {'child_id': 613880}


def test_create_child_empty_referential_key_error(con, app):
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': '',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "sexe: '' does not match '.+'"


def test_create_child_not_linked_error(con, app):
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_create_child_wrong_referential_key_error(con, app):
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'plop',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' required referential"


def test_create_child_connection_error(family_service, con, app):
    family_service.add_soap_response('createChild', ConnectionError('No address associated with hostname'))
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params, status=500)
    assert resp.json['err']
    assert resp.json['err_desc'] == 'No address associated with hostname'


def test_create_child_maelis_error(family_service, con, app):
    family_service.add_soap_response('createChild', get_xml_file('R_create_child_error.xml'))
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'already-child'
    assert 'Il existe déjà' in resp.json['err_desc']


def test_update_child(family_service, con, app):
    def request_check(request):
        assert request.childList[0]['num'] == '613880'
        assert request.childList[0]['authorizedPersonList'][0]['personInfo']['firstname'] == 'AMEL'

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('update-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
        'bPhoto': True,
        'bLeaveAlone': False,
        'insurance/company': 'Armagedon Colapse',
        'insurance/contractNumber': '444',
        'insurance/memberNumber': '555',
        'insurance/contractStart': '2022-01-02',
        'insurance/contractEnd': '2022-12-31',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 0


def test_update_child_not_linked_error(con, app):
    url = get_endpoint('update-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_wrong_referential_key_error(con, app):
    url = get_endpoint('create-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'plop',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' required referential"


def test_update_child_connection_error(family_service, con, app):
    family_service.add_soap_response('readFamily', ConnectionError('No address associated with hostname'))
    url = get_endpoint('update-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=500)
    assert resp.json['err']
    assert resp.json['err_desc'] == 'No address associated with hostname'


def test_update_child_not_exists_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family_with_only_rl1.xml'))
    url = get_endpoint('update-child')
    params = {
        'lastname': 'DOE',
        'firstname': 'JANNIS',
        'sexe': 'F',
        'birth/dateBirth': '1943-01-19',
        'birth/place': 'Port Arthur',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=42', params=params)
    assert resp.json['err'] == 'no-child'
    assert resp.json['err_desc'] == 'No child 42 to update on family'


def test_update_coordinate(family_service, con, app):
    family_service.add_soap_response('updateCoordinate', get_xml_file('R_update_family.xml'))
    url = get_endpoint('update-coordinate')
    params = {
        'adresse/num': '169',
        'adresse/numComp': 'B',
        'adresse/idStreet': 'AM0330',
        'adresse/street1': 'Château',
        'adresse/street2': None,
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
        'contact/isContactMail': True,
        'profession/codeCSP': 'ART',
        'profession/profession': 'informaticien',
        'profession/employerName': 'EO',
        'profession/phone': '0123456789',
        'profession/addressPro': {'num': None, 'street': None, 'zipcode': None, 'town': 'Orléans'},
        'CAFInfo/number': '789',
        'CAFInfo/organ': 'A10007752822',
    }

    resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_coordinate_schema_error(con, app):
    url = get_endpoint('update-coordinate')
    params = {
        'contact/isContactMail': 'true more text',
    }

    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "'adresse' is a required property"

    params = {
        'contact/isContactMail': 'true more text',
        'adresse/street1': 'Château',
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "'true more text' is not of type 'boolean'"


def test_update_coordinate_wrong_referential_key_error(con, app):
    url = get_endpoint('update-coordinate')
    params = {
        'adresse/num': '169',
        'adresse/numComp': 'plop',
        'adresse/street1': 'Château',
        'adresse/street2': None,
        'adresse/town': 'Paris',
        'adresse/zipcode': '75014',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc'] == "adresse/numComp key value 'plop' do not belong to 'Complement' referential"
    )


def test_update_quotient(family_service, con, app):
    family_service.add_soap_response('createUpdateQuotient', get_xml_file('R_create_update_quotient.xml'))
    url = get_endpoint('update-quotient')
    params = {
        'yearRev': '2021',
        'dateStart': '2022-10-01',
        'dateEnd': '2023-01-31',
        'mtt': '1500.33',
        'cdquo': 'QS',
    }

    resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_quotient_schema_error(con, app):
    url = get_endpoint('update-quotient')
    params = {
        'yearRev': '2021',
        'dateStart': '2022-10-01',
        'dateEnd': '2023-01-31',
        'mtt': '1500,33',
        'cdquo': 'QS',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "mtt: '1500,33' does not match '^[0-9]+\\\\.?[0-9]*$'"


def test_update_quotient_soap_error(family_service, con, app):
    family_service.add_soap_response(
        'createUpdateQuotient', get_xml_file('R_create_update_quotient_soap_error.xml'), status=500
    )
    url = get_endpoint('update-quotient')
    params = {
        'yearRev': '2021',
        'dateStart': '2022-10-01',
        'dateEnd': '2023-01-31',
        'mtt': '1500.33',
        'cdquo': 'QS',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 'Family-createUpdateQuotient-soap:Server'
    assert 'E07 : Il existe déjà un quotient postérieur' in resp.json['err_desc']


def test_update_quotient_wrong_referential_key_error(con, app):
    url = get_endpoint('update-quotient')
    params = {
        'yearRev': '2021',
        'dateStart': '2023-10-01',
        'dateEnd': '2023-01-31',
        'mtt': '1500.33',
        'cdquo': 'plop',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "cdquo key value 'plop' do not belong to 'Quotient' required referential"


def test_create_person(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312
        assert len(request.emergencyPersonList['personList']) == 2
        assert request.emergencyPersonList['personList'][0]['numPerson'] == 614059
        assert request.emergencyPersonList['personList'][0]['firstname'] == 'KENY'
        assert request.emergencyPersonList['personList'][1]['numPerson'] is None
        assert request.emergencyPersonList['personList'][1]['firstname'] == 'Mathias'

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('create-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0


def test_create_person_required_field_error(con, app):
    url = get_endpoint('create-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "'quality' is a required property"


def test_create_person_empty_referential_key_error(con, app):
    url = get_endpoint('create-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': '',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "quality: '' does not match '.+'"


def test_create_person_not_linked_error(con, app):
    url = get_endpoint('create-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_create_person_wrong_referential_key_error(con, app):
    url = get_endpoint('create-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'plop',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "sexe key value 'plop' do not belong to 'Sex' referential"


def test_update_person(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312
        assert len(request.emergencyPersonList['personList']) == 1
        assert request.emergencyPersonList['personList'][0]['numPerson'] == 614059
        assert request.emergencyPersonList['personList'][0]['firstname'] == 'Mathias'

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('update-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?family_id=1312&person_id=614059', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&person_id=614059', params=params)
    assert resp.json['err'] == 0


def test_update_person_not_linked_error(con, app):
    url = get_endpoint('update-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }

    resp = app.post_json(url + '?NameID=local&person_id=614059', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_person_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('update-person')
    params = {
        'civility': None,
        'firstname': 'Mathias',
        'lastname': 'Cassel',
        'quality': 'O',
        'sexe': 'M',
        'dateBirth': '1972-01-01',
        'contact/phone': None,
        'contact/mobile': '0623456789',
        'contact/mail': None,
    }
    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&person_id=000000', params=params)
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' authorized person on '1312' family"


def test_delete_person(family_service, con, app):
    def request_check(request):
        assert request.dossierNumber == 1312
        assert request.emergencyPersonList is None

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateFamily', get_xml_file('R_update_family.xml'), request_check=request_check
    )
    url = get_endpoint('delete-person')

    resp = app.post_json(url + '?family_id=1312&person_id=614059')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&person_id=614059')
    assert resp.json['err'] == 0


def test_delete_person_not_linked_error(con, app):
    url = get_endpoint('delete-person')

    resp = app.post_json(url + '?NameID=local&person_id=614059')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_delete_person_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('delete-person')

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&person_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '000000' authorized person on '1312' family"


def test_create_child_person(family_service, con, app):
    def request_check(request):
        assert request.numFamily == '1312'
        assert request.numPerson == 613880
        assert len(request.personList) == 2
        assert request.personList[0]['personInfo']['num'] == 614719
        assert request.personList[0]['personInfo']['firstname'] == 'AMEL'
        assert request.personList[1]['personInfo']['num'] is None
        assert request.personList[1]['personInfo']['firstname'] == 'Diana'

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateChildAutorization',
        get_xml_file('R_update_child_authorization.xml'),
        request_check=request_check,
    )
    url = get_endpoint('create-child-person')
    params = {
        'personInfo/civility': 'MME',
        'personInfo/firstname': 'Diana',
        'personInfo/lastname': 'Ross',
        'personInfo/sexe': 'F',
        'personInfo/dateBirth': '1944-03-26',
        'personInfo/contact/phone': '0199999999',
        'personInfo/contact/mobile': '0723456789',
        'personInfo/contact/mail': 'dross@example.org',
        'personQuality/code': 'TUTEUR',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 0


def test_create_child_person_empty_referential_key_error(con, app):
    url = get_endpoint('create-child-person')
    params = {
        'personInfo/civility': 'MME',
        'personInfo/firstname': 'Diana',
        'personInfo/lastname': 'Ross',
        'personInfo/sexe': 'F',
        'personInfo/dateBirth': '1944-03-26',
        'personInfo/contact/phone': '01999999999',
        'personInfo/contact/mobile': '0723456789',
        'personInfo/contact/mail': 'dross@example.org',
        'personQuality/code': '',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "personQuality/code: '' does not match '.+'"


def test_create_child_person_not_linked_error(con, app):
    url = get_endpoint('create-child-person')
    params = {
        'personInfo/civility': 'MME',
        'personInfo/firstname': 'Diana',
        'personInfo/lastname': 'Ross',
        'personInfo/sexe': 'F',
        'personInfo/dateBirth': '1944-03-26',
        'personInfo/contact/phone': '01999999999',
        'personInfo/contact/mobile': '0723456789',
        'personInfo/contact/mail': 'dross@example.org',
        'personQuality/code': 'TUTEUR',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_create_child_person_wrong_referential_key_error(con, app):
    url = get_endpoint('create-child-person')
    params = {
        'personInfo/civility': 'MME',
        'personInfo/firstname': 'Diana',
        'personInfo/lastname': 'Ross',
        'personInfo/sexe': 'plop',
        'personInfo/dateBirth': '1944-03-26',
        'personInfo/contact/phone': '0199999999',
        'personInfo/contact/mobile': '0723456789',
        'personInfo/contact/mail': 'dross@example.org',
        'personQuality/code': 'TUTEUR',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "personInfo/sexe key value 'plop' do not belong to 'Sex' referential"


def test_create_child_person_no_child_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('create-child-person')
    params = {
        'personInfo/civility': 'MME',
        'personInfo/firstname': 'Diana',
        'personInfo/lastname': 'Ross',
        'personInfo/sexe': 'F',
        'personInfo/dateBirth': '1944-03-26',
        'personInfo/contact/phone': '01999999999',
        'personInfo/contact/mobile': '0723456789',
        'personInfo/contact/mail': 'dross@example.org',
        'personQuality/code': 'TUTEUR',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=42', params=params)
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '42' child on '1312' family"


def test_update_child_person(family_service, con, app):
    def request_check(request):
        assert request.numFamily == '1312'
        assert request.numPerson == 613880
        assert len(request.personList) == 1
        assert request.personList[0]['personInfo']['num'] == 614719
        assert request.personList[0]['personInfo']['firstname'] == 'Angelo'

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateChildAutorization',
        get_xml_file('R_update_child_authorization.xml'),
        request_check=request_check,
    )
    url = get_endpoint('update-child-person')
    params = {
        'personInfo/civility': 'M.',
        'personInfo/firstname': 'Angelo',
        'personInfo/lastname': 'Bent',
        'personInfo/sexe': 'M',
        'personInfo/dateBirth': '1985-06-22',
        'personInfo/contact/phone': '0102030405',
        'personInfo/contact/mobile': None,
        'personInfo/contact/mail': None,
        'personQuality/code': 'O',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613880&person_id=614719', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params)
    assert resp.json['err'] == 0


def test_update_child_person_not_linked_error(con, app):
    url = get_endpoint('update-child-person')
    params = {
        'personInfo/civility': 'M.',
        'personInfo/firstname': 'Angelo',
        'personInfo/lastname': 'Bent',
        'personInfo/dateBirth': '1985-06-22',
        'personInfo/contact/phone': '0102030405',
        'personInfo/contact/mobile': None,
        'personInfo/contact/mail': None,
        'personQuality/code': 'O',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_person_wrong_referential_key_error(con, app):
    url = get_endpoint('update-child-person')
    params = {
        'personInfo/civility': 'M.',
        'personInfo/firstname': 'Angelo',
        'personInfo/lastname': 'Bent',
        'personInfo/sexe': 'plop',
        'personInfo/dateBirth': '1985-06-22',
        'personInfo/contact/phone': '0102030405',
        'personInfo/contact/mobile': None,
        'personInfo/contact/mail': None,
        'personQuality/code': 'O',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "personInfo/sexe key value 'plop' do not belong to 'Sex' referential"


def test_update_child_person_no_child_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('update-child-person')
    params = {
        'personInfo/civility': 'M.',
        'personInfo/firstname': 'Angelo',
        'personInfo/lastname': 'Bent',
        'personInfo/dateBirth': '1985-06-22',
        'personInfo/contact/phone': '0102030405',
        'personInfo/contact/mobile': None,
        'personInfo/contact/mail': None,
        'personQuality/code': 'O',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=42&person_id=614719', params=params)
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '42' child on '1312' family"


def test_update_child_person_not_found(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('update-child-person')
    params = {
        'personInfo/civility': 'M.',
        'personInfo/firstname': 'Angelo',
        'personInfo/lastname': 'Bent',
        'personInfo/dateBirth': '1985-06-22',
        'personInfo/contact/phone': '0102030405',
        'personInfo/contact/mobile': None,
        'personInfo/contact/mail': None,
        'personQuality/code': 'O',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=000000', params=params)
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "No '000000' authorized person on '613880' child"


def test_delete_child_person(family_service, con, app):
    def request_check(request):
        assert request.numFamily == '1312'
        assert request.numPerson == 613880
        assert len(request.personList) == 0

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    family_service.add_soap_response(
        'updateChildAutorization',
        get_xml_file('R_update_child_authorization.xml'),
        request_check=request_check,
    )
    url = get_endpoint('delete-child-person')

    resp = app.post_json(url + '?family_id=1312&child_id=613880&person_id=614719')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719')
    assert resp.json['err'] == 0


def test_delete_child_person_not_linked_error(con, app):
    url = get_endpoint('delete-child-person')

    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=614719')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_delete_child_person_no_child_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('delete-child-person')

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=42&person_id=614719')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "no '42' child on '1312' family"


def test_delete_child_person_no_person_error(family_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    url = get_endpoint('delete-child-person')

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880&person_id=000000')
    assert resp.json['err'] == 'not-found'
    assert resp.json['err_desc'] == "No '000000' authorized person on '613880' child"


def test_update_child_dietcode(family_service, con, app):
    family_service.add_soap_response('createOrUpdateChildDiet', get_xml_file('R_update_child_dietcode.xml'))
    url = get_endpoint('update-child-dietcode')

    resp = app.post_json(url + '?family_id=1312&child_id=613878&dietcode=RSV')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=RSV')
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_child_dietcode_not_linked_error(con, app):
    url = get_endpoint('update-child-dietcode')

    resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=RVS')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_dietcode_wrong_referential_key_error(con, app):
    url = get_endpoint('update-child-dietcode')

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613878&dietcode=plop')
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc'] == "dietcode parameter key value 'plop' do not belong to 'DietCode' referential"
    )


def test_update_child_pai(family_service, con, app):
    family_service.add_soap_response('updateChildPAI', get_xml_file('R_update_child_pai.xml'))
    url = get_endpoint('update-child-pai')
    params = {
        'code': 'PAIALI',
        'dateDeb': '2022-01-01',
        'dateFin': '',
        'description': 'some text',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613878', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_child_pai_empty_payload_error(con, app):
    url = get_endpoint('update-child-pai')
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=None, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "None is not of type 'object'"


def test_update_child_pai_wrong_payload_type_error(con, app):
    url = get_endpoint('update-child-pai')
    params = {
        'code': 'PAIALI',
        'dateDeb': '2022-01-01',
        'dateFin': '',
        'description': 42,
    }

    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "42 is not of type 'string'"


def test_update_child_pai_empty_referential_key_error(con, app):
    url = get_endpoint('update-child-pai')
    params = {
        'code': '',
        'dateDeb': '2022-01-01',
        'dateFin': '',
        'description': 'some text',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "code: '' does not match '.+'"


def test_update_child_pai_not_linked_error(con, app):
    url = get_endpoint('update-child-pai')
    params = {
        'code': 'PAIALI',
        'dateDeb': '2022-01-01',
        'dateFin': '',
        'description': 'some text',
    }

    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_pai_soap_error(family_service, con, app):
    family_service.add_soap_response(
        'updateChildPAI', get_xml_file('R_update_child_pai_soap_error.xml'), status=500
    )
    url = get_endpoint('update-child-pai')
    params = {
        'code': 'PAIALI',
        'dateDeb': '2022-01-01',
        'dateFin': '',
        'description': 'a' * 501,
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 'Family-updateChildPAI-soap:Server'
    assert 'Une erreur est survenue' in resp.json['err_desc']
    assert 'valeur trop grande' in resp.json['err_desc']
    assert 'maximum : 500' in resp.json['err_desc']


def test_update_child_medical_record(family_service, con, app):
    family_service.add_soap_response(
        'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record.xml')
    )
    url = get_endpoint('update-child-medical-record')
    params = {
        'familyDoctor/name': 'Dre',
        'familyDoctor/phone': '0612341234',
        'familyDoctor/address/street1': 'Alameda',
        'familyDoctor/address/zipcode': '90220',
        'familyDoctor/address/town': 'Compton',
        'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up, and shrimp',
        'allergy2': 'cauliflower',
        'comment1': "the shrimp allergy isn't fully identified",
        'comment2': None,
        'observ1': 'Ay Caramba!',
        'observ2': None,
        'isAuthHospital': True,
        'hospital': 'Springfield General Hospital',
        'vaccinList/0/code': 'DTC',
        'vaccinList/0/vaccinationDate': '2011-01-11',
        'vaccinList/1/code': 'ROR',
        'vaccinList/1/vaccinationDate': '2022-02-22',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613878', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_child_medical_record_with_empty_vaccin_list(family_service, con, app):
    family_service.add_soap_response(
        'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record.xml')
    )
    url = get_endpoint('update-child-medical-record')
    params = {
        'familyDoctor/name': 'Dre',
        'familyDoctor/phone': '0612341234',
        'familyDoctor/address/street1': 'Alameda',
        'familyDoctor/address/zipcode': '90220',
        'familyDoctor/address/town': 'Compton',
        'allergy1': 'butterscotch, imitation butterscotch, glow-in-the-dark monster make-up, and shrimp',
        'allergy2': 'cauliflower',
        'comment1': "the shrimp allergy isn't fully identified",
        'comment2': None,
        'observ1': 'Ay Caramba!',
        'observ2': None,
        'isAuthHospital': True,
        'hospital': 'Springfield General Hospital',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_child_medical_record_not_linked_error(con, app):
    url = get_endpoint('update-child-medical-record')

    resp = app.post_json(url + '?NameID=local&child_id=613878', params={})
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_medical_record_soap_error(family_service, con, app):
    family_service.add_soap_response(
        'updateChildMedicalRecord', get_xml_file('R_update_child_medical_record_soap_error.xml'), status=500
    )
    url = get_endpoint('update-child-medical-record')
    params = {
        'vaccinList/0/code': 'DTC',
        'vaccinList/0/vaccinationDate': '2022-02-31',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 'Family-updateChildMedicalRecord-soap:Client'
    assert 'Unmarshalling Error' in resp.json['err_desc']
    assert 'pas une valeur de calendrier grégorien' in resp.json['err_desc']


def test_update_child_medical_record_wrong_referential_key_error(con, app):
    url = get_endpoint('update-child-medical-record')
    params = {
        'familyDoctor/name': 'Dre',
        'familyDoctor/phone': '0612341234',
        'familyDoctor/address/street1': 'Alameda',
        'familyDoctor/address/zipcode': '90220',
        'familyDoctor/address/town': 'Compton',
        'vaccinList/0/code': 'DTC',
        'vaccinList/0/vaccinationDate': '2011-01-11',
        'vaccinList/1/code': 'plop',
        'vaccinList/1/vaccinationDate': '2022-02-22',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert resp.json['err_desc'] == "vaccinList/1/code key value 'plop' do not belong to 'Vaccin' referential"


def test_update_rl_indicator(family_service, con, app):
    def request_check(request):
        assert [(x['code'], x['isActive']) for x in request.indicatorList] == [
            ('AVL', True),
            ('AVS', False),
            ('ETABSPEC', True),
            ('MDPH', False),
        ]

    family_service.add_soap_response(
        'updatePersonIndicatorList',
        get_xml_file('R_update_indicator.xml'),
        request_check=request_check,
    )
    url = get_endpoint('update-rl-indicator')
    params = {
        'indicatorList/0/code': 'AVL',
        'indicatorList/0/isActive': True,
        'indicatorList/1/code': 'AVS',
        'indicatorList/1/isActive': False,
        'indicatorList/2/code': 'ETABSPEC',
        'indicatorList/2/note': 'SNPP',
        'indicatorList/2/isActive': 'True',
        'indicatorList/3/code': 'MDPH',
        'indicatorList/3/isActive': 'False',
    }

    resp = app.post_json(url + '?family_id=1312&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_rl_indicator_not_linked_error(con, app):
    url = get_endpoint('update-rl-indicator')
    params = {
        'indicatorList': [
            {
                'code': 'AVL',
                'isActive': True,
            },
        ],
    }

    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


@pytest.mark.parametrize('value', ['plop', '', 2, 0.5, 'N'])
def test_update_rl_indicator_schema_error(value, con, app):
    url = get_endpoint('update-rl-indicator')
    params = {
        'indicatorList/0/code': 'AVL',
        'indicatorList/0/isActive': value,
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
    assert "is not of type 'boolean'" in resp.json['err_desc']


def test_update_rl_indicator_no_indicator_error(con, app):
    url = get_endpoint('update-rl-indicator')
    params = {'indicatorList': []}

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == 'indicatorList: [] is too short'


def test_update_rl_indicator_empty_referential_key_error(con, app):
    url = get_endpoint('update-rl-indicator')
    params = {
        'indicatorList': [
            {
                'code': '',
                'isActive': True,
            },
        ],
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'"


def test_update_rl_indicator_wrong_referential_key_error(con, app):
    url = get_endpoint('update-rl-indicator')
    params = {
        'indicatorList': [
            {
                'code': 'plop',
                'isActive': True,
            },
        ],
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "indicatorList/0/code key value 'plop' do not belong to 'RLIndicator' required referential"
    )


def test_update_child_indicator(family_service, con, app):
    def request_check(request):
        assert [(x['code'], x['isActive']) for x in request.indicatorList] == [
            ('APPDENTAIRE', True),
            ('AUTRE', False),
            ('AVL', True),
            ('AVS', False),
            ('ETABSPEC', True),
            ('LENTILLE', False),
            ('LUNETTE', True),
            ('MDPH', False),
        ]

    family_service.add_soap_response(
        'updatePersonIndicatorList',
        get_xml_file('R_update_indicator.xml'),
        request_check=request_check,
    )
    url = get_endpoint('update-child-indicator')
    params = {
        'indicatorList/0/code': 'APPDENTAIRE',
        'indicatorList/0/isActive': 1,
        'indicatorList/1/code': 'AUTRE',
        'indicatorList/1/note': 'rebellious',
        'indicatorList/1/isActive': 0,
        'indicatorList/2/code': 'AVL',
        'indicatorList/2/isActive': '1',
        'indicatorList/3/code': 'AVS',
        'indicatorList/3/isActive': '0',
        'indicatorList/4/code': 'ETABSPEC',
        'indicatorList/4/note': None,
        'indicatorList/4/isActive': 'Oui',
        'indicatorList/5/code': 'LENTILLE',
        'indicatorList/5/isActive': 'Non',
        'indicatorList/6/code': 'LUNETTE',
        'indicatorList/6/isActive': 'TRUE',
        'indicatorList/7/code': 'MDPH',
        'indicatorList/7/isActive': 'FALSE',
    }

    resp = app.post_json(url + '?family_id=1312&child_id=613880', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_update_child_indicator_not_linked_error(con, app):
    url = get_endpoint('update-child-indicator')
    params = {
        'indicatorList': [
            {
                'code': 'LUNETTE',
                'isActive': True,
            },
        ],
    }

    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_indicator_no_indicator_error(con, app):
    url = get_endpoint('update-child-indicator')
    params = {'indicatorList': []}

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == 'indicatorList: [] is too short'


def test_update_child_indicator_empty_referential_key_error(con, app):
    url = get_endpoint('update-child-indicator')
    params = {
        'indicatorList': [
            {
                'code': '',
                'isActive': True,
            },
        ],
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'"


def test_update_child_indicator_wrong_referential_key_error(con, app):
    url = get_endpoint('update-child-indicator')
    params = {
        'indicatorList': [
            {
                'code': 'plop',
                'isActive': True,
            },
        ],
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "indicatorList/0/code key value 'plop' do not belong to 'ChildIndicator' required referential"
    )


def test_add_supplied_document(family_service, con, app):
    def request_check(request):
        assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg')

    family_service.add_soap_response(
        'addSuppliedDocument',
        get_xml_file('R_add_supplied_document.xml') % b'OK',
        request_check=request_check,
    )
    url = get_endpoint('add-supplied-document')
    params = {
        'numPerson': '613880',
        'documentList/0/code': '46',
        'documentList/0/depositDate': '2022-12-20',
        'documentList/0/file': {  # w.c.s. file field
            'filename': '201x201.jpg',
            'content_type': 'image/jpeg',
            'content': base64.b64encode(get_media_file('201x201.jpg')).decode(),
        },
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_add_supplied_document_not_linked_error(con, app):
    url = get_endpoint('add-supplied-document')
    params = {
        'documentList': [],
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_add_supplied_document_empty_referential_key_error(con, app):
    url = get_endpoint('add-supplied-document')
    params = {
        'documentList/0/code': '',
        'documentList/0/depositDate': '2022-12-20',
        'documentList/0/file': {  # w.c.s. file field
            'filename': '201x201.jpg',
            'content_type': 'image/jpeg',
            'content': base64.b64encode(get_media_file('201x201.jpg')).decode(),
        },
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "documentList/0/code: '' does not match '.+'"


def test_add_supplied_document_wrong_referential_key_error(con, app):
    url = get_endpoint('add-supplied-document')
    params = {
        'documentList/0/code': 'plop',
        'documentList/0/depositDate': '2022-12-20',
        'documentList/0/file': {  # w.c.s. file field
            'filename': '201x201.jpg',
            'content_type': 'image/jpeg',
            'content': base64.b64encode(get_media_file('201x201.jpg')).decode(),
        },
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'wrong-key'
    assert (
        resp.json['err_desc']
        == "documentList/0/code key value 'plop' do not belong to 'Document' required referential"
    )


def test_add_supplied_document_maelis_error(family_service, con, app):
    def request_check(request):
        assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg')

    family_service.add_soap_response(
        'addSuppliedDocument',
        get_xml_file('R_add_supplied_document.xml') % b'KO',
        request_check=request_check,
    )
    url = get_endpoint('add-supplied-document')
    params = {
        'documentList/0/code': '46',
        'documentList/0/depositDate': '2022-12-20',
        'documentList/0/file': {  # w.c.s. file field
            'filename': '201x201.jpg',
            'content_type': 'image/jpeg',
            'content': base64.b64encode(get_media_file('201x201.jpg')).decode(),
        },
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == 'maelis fails to add the supplied document'


def test_add_rl1_direct_debit_order(family_service, invoice_service, con, app):
    def request_check(request):
        assert request.numDossier == 1312
        assert request.bank['dateStart'] == datetime.datetime(2023, 1, 1, 0, 0)

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    invoice_service.add_soap_response(
        'addDirectDebitOrder',
        get_xml_file('R_add_direct_debit_order.xml'),
        request_check=request_check,
    )
    url = get_endpoint('add-rl1-direct-debit-order')
    params = {
        'codeRegie': '22',
        'bank/bankBIC': 'BDFEFR2T',
        'bank/bankIBAN': 'FR7630001007941234567890185',
        'bank/bankRUM': 'xxx',
        'bank/dateStart': '2023-01-01',
        'bank/bankAddress': '75049 PARIS cedex 01',
        'bank/civility': 'x',
        'bank/lastName': 'Ewing',
        'bank/firstName': 'John Ross',
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == 'ok'


def test_add_rl1_direct_debit_order_not_linked_error(con, app):
    url = get_endpoint('add-rl1-direct-debit-order')
    params = {
        'codeRegie': '22',
        'bank/bankBIC': 'BDFEFR2T',
        'bank/bankIBAN': 'FR7630001007941234567890185',
        'bank/bankRUM': 'xxx',
        'bank/dateStart': '2023-01-01',
        'bank/bankAddress': '75049 PARIS cedex 01',
        'bank/civility': 'x',
        'bank/lastName': 'Ewing',
        'bank/firstName': 'John Ross',
    }

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_add_rl1_direct_debit_order_soap_error(family_service, invoice_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    invoice_service.add_soap_response(
        'addDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500
    )
    url = get_endpoint('add-rl1-direct-debit-order')
    params = {
        'codeRegie': '12345',
        'bank/bankBIC': 'BDFEFR2T',
        'bank/bankIBAN': 'FR7630001007941234567890185',
        'bank/bankRUM': 'xxx',
        'bank/dateStart': '2023-01-01',
        'bank/bankAddress': '75049 PARIS cedex 01',
        'bank/civility': 'x',
        'bank/lastName': 'Ewing',
        'bank/firstName': 'John Ross',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'Invoice-addDirectDebitOrder-soap:Server'
    assert resp.json['err_desc'] == "E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis"


def test_get_rl1_direct_debit_order(family_service, invoice_service, con, app):
    def request_check(request):
        assert request.numDossier == 1312

    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    invoice_service.add_soap_response(
        'getDirectDebitOrder',
        get_xml_file('R_get_direct_debit_order.xml'),
        request_check=request_check,
    )
    url = get_endpoint('get-rl1-direct-debit-order')
    params = {
        'codeRegie': '22',
        'dateRef': '2023-01-01',
    }

    resp = app.get(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'bankBIC': 'BDFEFR2T',
        'bankIBAN': 'FR7630001007941234567890185',
        'bankRUM': 'xxx',
        'dateStart': '2023-01-01T00:00:00+01:00',
        'bankAddress': '75049 PARIS cedex 01',
        'civility': 'x',
        'lastName': 'Ewing',
        'firstName': 'John Ross',
    }


def test_get_rl1_direct_debit_order_parameter_error(con, app):
    url = get_endpoint('get-rl1-direct-debit-order')
    params = {
        'codeRegie': '22',
        'dateRef': 'plop',
    }

    resp = app.get(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_class'] == 'passerelle.views.InvalidParameterValue'
    assert resp.json['err_desc'] == 'invalid value for parameter "dateRef (YYYY-MM-DD expected)"'


def test_get_rl1_direct_debit_order_not_linked_error(con, app):
    url = get_endpoint('get-rl1-direct-debit-order')
    params = {
        'codeRegie': '22',
        'dateRef': '2023-01-01',
    }

    resp = app.get(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_rl1_direct_debit_order_soap_error(family_service, invoice_service, con, app):
    family_service.add_soap_response('readFamily', get_xml_file('R_read_family.xml'))
    invoice_service.add_soap_response(
        'getDirectDebitOrder', get_xml_file('R_direct_debit_order_soap_error.xml'), status=500
    )
    url = get_endpoint('get-rl1-direct-debit-order')
    params = {
        'codeRegie': '12345',
        'dateRef': '2023-01-01',
    }

    Link.objects.create(resource=con, family_id='1312', name_id='local')
    resp = app.get(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'Invoice-getDirectDebitOrder-soap:Server'
    assert resp.json['err_desc'] == "E520 : La REGIE CS [{0}] n''existe pas dans la base Maelis"


def test_read_school_year_list(con, app):
    url = get_endpoint('read-school-years-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 2
    assert resp.json['data'] == [
        {
            'id': 2022,
            'text': '2022',
            'schoolYear': 2022,
            'dateStartYearSchool': '2022-09-01T00:00:00+02:00',
            'dateEndYearSchool': '2023-07-07T00:00:00+02:00',
            'dateStartSubscribeSchool': '2022-04-01T00:00:00+02:00',
            'dateEndSubscribeSchool': '2023-07-08T00:00:00+02:00',
        },
        {
            'id': 2023,
            'text': '2023',
            'schoolYear': 2023,
            'dateStartYearSchool': '2023-09-01T00:00:00+02:00',
            'dateEndYearSchool': '2024-07-07T00:00:00+02:00',
            'dateStartSubscribeSchool': '2022-12-01T00:00:00+01:00',
            'dateEndSubscribeSchool': '2023-07-08T00:00:00+02:00',
        },
    ]


def test_read_school_levels_list(con, app):
    url = get_endpoint('read-school-levels-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 22
    for item in resp.json['data']:
        assert 'id' in item
        assert 'text' in item

    resp = app.get(url, params={'age': '8'})
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 1
    level = resp.json['data'][0]
    assert level['id'] == 'CE2'
    assert level['code'] == 'CE2'
    assert level['text'] == 'Cours élémentaire 2'
    assert level['libelle'] == 'Cours élémentaire 2'


def test_read_exemption_reasons_list(con, app):
    url = get_endpoint('read-exemption-reasons-list')
    resp = app.get(url)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 4
    for item in resp.json['data']:
        assert 'id' in item
        assert 'text' in item


def test_read_child_agenda(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml')
    )
    url = get_endpoint('read-child-agenda')

    resp = app.get(url + '?family_id=1312&child_id=613880&start_date=2023-01-01&end_date=2023-01-15')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880&start_date=2023-01-01&end_date=2023-01-15')

    assert resp.json['err'] == 0
    assert resp.json['extra_data'] == {
        'start_date': '2023-01-01',
        'end_date': '2023-01-15',
        'school_year': '2022/2023',
    }
    assert len(resp.json['data']) == 16
    assert resp.json['data'] == [
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327690',
            },
            'disabled': True,
            'id': '613880:A10049327689:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327683',
            },
            'disabled': True,
            'id': '613880:A10049327682:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-03T00:00:00+01:00',
                'day_str': '2023-01-03',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327690',
            },
            'disabled': True,
            'id': '613880:A10049327689:2023-01-03',
            'prefill': False,
            'text': 'Tuesday 3 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-03T00:00:00+01:00',
                'day_str': '2023-01-03',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'READ_ONLY',
                'status_color': 'green',
                'unit_id': 'A10049327683',
            },
            'disabled': True,
            'id': '613880:A10049327682:2023-01-03',
            'prefill': True,
            'text': 'Tuesday 3 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_ABSENCE',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-05T00:00:00+01:00',
                'day_str': '2023-01-05',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-05',
            'prefill': True,
            'text': 'Thursday 5 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_ABSENCE',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-05T00:00:00+01:00',
                'day_str': '2023-01-05',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-05',
            'prefill': True,
            'text': 'Thursday 5 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_ABSENCE',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-06T00:00:00+01:00',
                'day_str': '2023-01-06',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-06',
            'prefill': True,
            'text': 'Friday 6 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_PRES_REAL',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-06T00:00:00+01:00',
                'day_str': '2023-01-06',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'WRITABLE',
                'status_color': 'white',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-06',
            'prefill': False,
            'text': 'Friday 6 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_PRES_PREVI',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-09T00:00:00+01:00',
                'day_str': '2023-01-09',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'WRITABLE',
                'status_color': 'white',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-09',
            'prefill': False,
            'text': 'Monday 9 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_PRES_PREVI',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-09T00:00:00+01:00',
                'day_str': '2023-01-09',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'WRITABLE',
                'status_color': 'white',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-09',
            'prefill': False,
            'text': 'Monday 9 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_PRES_PREVI',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-10T00:00:00+01:00',
                'day_str': '2023-01-10',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'WRITABLE',
                'status_color': 'white',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-10',
            'prefill': False,
            'text': 'Tuesday 10 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'DEL_PRES_PREVI',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-10T00:00:00+01:00',
                'day_str': '2023-01-10',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-10',
            'prefill': True,
            'text': 'Tuesday 10 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'DEL_PRES_PREVI',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-12T00:00:00+01:00',
                'day_str': '2023-01-12',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-12',
            'prefill': True,
            'text': 'Thursday 12 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'DEL_PRES_PREVI',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-12T00:00:00+01:00',
                'day_str': '2023-01-12',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-12',
            'prefill': True,
            'text': 'Thursday 12 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'DEL_PRES_PREVI',
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-13T00:00:00+01:00',
                'day_str': '2023-01-13',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 1,
                'status': 'WRITABLE',
                'status_color': 'green',
                'unit_id': 'A10049327690',
            },
            'disabled': False,
            'id': '613880:A10049327689:2023-01-13',
            'prefill': True,
            'text': 'Friday 13 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': 'ADD_PRES_PREVI',
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-13T00:00:00+01:00',
                'day_str': '2023-01-13',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'WRITABLE',
                'status_color': 'white',
                'unit_id': 'A10049327683',
            },
            'disabled': False,
            'id': '613880:A10049327682:2023-01-13',
            'prefill': False,
            'text': 'Friday 13 January 2023',
        },
    ]


def test_read_child_agenda_multi_units(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonScheduleList', get_xml_file('R_get_person_schedule_list_with_multi_units.xml')
    )
    url = get_endpoint('read-child-agenda')

    resp = app.get(url + '?family_id=1312&child_id=613880&start_date=2023-01-01&end_date=2023-01-15')
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880&start_date=2023-01-01&end_date=2023-01-15')

    assert resp.json['err'] == 0
    assert resp.json['extra_data'] == {
        'start_date': '2023-01-01',
        'end_date': '2023-01-15',
        'school_year': '2022/2023',
    }
    assert len(resp.json['data']) == 5
    assert resp.json['data'] == [
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'activity_type': 'ACCMAT',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327690',
            },
            'disabled': True,
            'id': '613880:A10049327689:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire (PAI PANIER 22/23)',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327684',
            },
            'disabled': True,
            'id': '613880:A10049327682:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire (RESTAURATION SCOLAIRE 22/23)',
                'activity_type': 'RESTSCOL',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327683',
            },
            'disabled': True,
            'id': '613880:A10049327682:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327693',
                'activity_label': 'Accueil p\\xc3\\xa9riscolaire',
                'activity_type': 'ACCPERI',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327694',
            },
            'disabled': True,
            'id': '613880:A10049327693:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
        {
            'details': {
                'absence': None,
                'action': None,
                'activity_id': 'A10049327691',
                'activity_label': 'Accueil du soir',
                'activity_type': 'ACCSOIR',
                'child_id': '613880',
                'day': '2023-01-02T00:00:00+01:00',
                'day_str': '2023-01-02',
                'hasPlace': None,
                'realPresence': 0,
                'scheduledPresence': 0,
                'status': 'READ_ONLY',
                'status_color': 'white',
                'unit_id': 'A10049327692',
            },
            'disabled': True,
            'id': '613880:A10049327691:2023-01-02',
            'prefill': False,
            'text': 'Monday 2 January 2023',
        },
    ]


def test_read_child_agenda_not_linked_error(con, app):
    url = get_endpoint('read-child-agenda')

    resp = app.get(url + '?NameID=local&child_id=613880&start_date=2022-09-01&end_date=2023-08-31')
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_read_child_agenda_date_error(con, app):
    url = get_endpoint('read-child-agenda')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.get(url + '?NameID=local&child_id=613880&start_date=bad&end_date=2023-08-31', status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    resp = app.get(url + '?NameID=local&child_id=613880&start_date=2022-09-01&end_date=bad', status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    resp = app.get(
        url + '?NameID=local&child_id=613880&start_date=2023-09-01&end_date=2023-08-31', status=400
    )
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    resp = app.get(
        url + '?NameID=local&child_id=613880&start_date=2022-09-01&end_date=2024-08-31', status=400
    )
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'


def test_update_child_agenda(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml')
    )
    url = get_endpoint('update-child-agenda')

    def request_check(request):
        assert request.numDossier == 1312
        assert len(request.unitPersonDayInfoList) == 4
        assert request.unitPersonDayInfoList[0].numPerson == 613880
        assert request.unitPersonDayInfoList[0].idAct == 'A10049327689'
        assert request.unitPersonDayInfoList[0].idUni == 'A10049327690'
        assert request.unitPersonDayInfoList[0].date == datetime.datetime(2023, 1, 5, 0, 0)
        assert request.unitPersonDayInfoList[0].action == 'ADD_ABSENCE'
        assert request.unitPersonDayInfoList[1].numPerson == 613880
        assert request.unitPersonDayInfoList[1].idAct == 'A10049327682'
        assert request.unitPersonDayInfoList[1].idUni == 'A10049327683'
        assert request.unitPersonDayInfoList[1].date == datetime.datetime(2023, 1, 6, 0, 0)
        assert request.unitPersonDayInfoList[1].action == 'ADD_PRES_REAL'
        assert request.unitPersonDayInfoList[2].numPerson == 613880
        assert request.unitPersonDayInfoList[2].idAct == 'A10049327682'
        assert request.unitPersonDayInfoList[2].idUni == 'A10049327683'
        assert request.unitPersonDayInfoList[2].date == datetime.datetime(2023, 1, 10, 0, 0)
        assert request.unitPersonDayInfoList[2].action == 'DEL_PRES_PREVI'
        assert request.unitPersonDayInfoList[3].numPerson == 613880
        assert request.unitPersonDayInfoList[3].idAct == 'A10049327682'
        assert request.unitPersonDayInfoList[3].idUni == 'A10049327683'
        assert request.unitPersonDayInfoList[3].date == datetime.datetime(2023, 1, 13, 0, 0)
        assert request.unitPersonDayInfoList[3].action == 'ADD_PRES_PREVI'

    activity_service.add_soap_response(
        'updatePersonSchedule', get_xml_file('R_update_person_schedule.xml'), request_check=request_check
    )

    params = {
        'child_id': '613880',
        'start_date': '2023-01-01',
        'end_date': '2023-01-15',
        'booking_list': [
            # '613880:A10049327689:2023-01-05', # remove this one
            '613880:A10049327682:2023-01-05',
            '613880:A10049327689:2023-01-06',
            # '613880:A10049327682:2023-01-10', # and this one
            '613880:A10049327689:2023-01-12',
            '613880:A10049327682:2023-01-12',
            '613880:A10049327689:2023-01-13',
            # but add:
            '613880:A10049327682:2023-01-06',
            '613880:A10049327682:2023-01-13',
        ],
    }

    resp = app.post_json(url + '?family_id=1312', params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json == {
        'changes': [
            {
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'booked': True,
                'day': '2023-01-06',
            },
            {
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'booked': True,
                'day': '2023-01-13',
            },
            {
                'activity_id': 'A10049327689',
                'activity_label': 'Accueil du matin',
                'booked': False,
                'day': '2023-01-05',
            },
            {
                'activity_id': 'A10049327682',
                'activity_label': 'Restauration scolaire',
                'booked': False,
                'day': '2023-01-10',
            },
        ],
        'count': 4,
        'err': 0,
        'updated': True,
    }


def test_update_child_agenda_no_changes(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml')
    )
    url = get_endpoint('update-child-agenda')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    params = {
        'child_id': '613880',
        'start_date': '2023-01-01',
        'end_date': '2023-01-15',
        'booking_list': [
            '613880:A10049327689:2023-01-05',
            '613880:A10049327682:2023-01-05',
            '613880:A10049327689:2023-01-06',
            '613880:A10049327682:2023-01-10',
            '613880:A10049327689:2023-01-12',
            '613880:A10049327682:2023-01-12',
            '613880:A10049327689:2023-01-13',
        ],
    }
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json == []


def test_update_child_agenda_maelis_error(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonScheduleList', get_xml_file('R_get_person_schedule_list.xml')
    )
    url = get_endpoint('update-child-agenda')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    activity_service.add_soap_response(
        'updatePersonSchedule', get_xml_file('R_update_person_schedule_error.xml')
    )

    params = {
        'child_id': '613880',
        'start_date': '2023-01-01',
        'end_date': '2023-01-15',
        'booking_list': [
            '613880:A10049327682:2023-01-13',
        ],
    }
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'agenda-child-error'
    assert resp.json['err_desc'] == 'Foo ; Bar'


def test_update_child_agenda_not_linked_error(con, app):
    url = get_endpoint('update-child-agenda')

    params = {
        'child_id': '613880',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'booking_list': [],
    }
    resp = app.post_json(url + '?NameID=local', params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_update_child_agenda_date_error(con, app):
    url = get_endpoint('update-child-agenda')
    Link.objects.create(resource=con, family_id='1312', name_id='local')

    params = {
        'child_id': '613880',
        'start_date': 'bad',
        'end_date': '2023-08-31',
        'booking_list': [],
    }
    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "start_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'"

    params = {
        'child_id': '613880',
        'start_date': '2022-09-01',
        'end_date': 'bad',
        'booking_list': [],
    }
    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 1
    assert resp.json['err_desc'] == "end_date: 'bad' does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'"

    params = {
        'child_id': '613880',
        'start_date': '2023-09-01',
        'end_date': '2023-08-31',
        'booking_list': [],
    }
    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    params = {
        'child_id': '613880',
        'start_date': '2022-09-01',
        'end_date': '2024-08-31',
        'booking_list': [],
    }
    resp = app.post_json(url + '?NameID=local', params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'


def test_read_school_list_address_and_level(site_service, con, app):
    site_service.add_soap_response(
        'readSchoolForAdressAndLevel', get_xml_file('R_read_school_for_adress_and_level.xml')
    )
    url = get_endpoint('read-schools-for-address-and-level')
    resp = app.get(url, params={'id_street': '2317', 'num': '4', 'year': '2022'})
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 8
    for item in resp.json['data']:
        assert 'id' in item
        assert 'text' in item


def test_read_school_list_child_and_level(family_service, con, app):
    family_service.add_soap_response(
        'readSchoolForChildAndLevel', get_xml_file('R_read_school_for_child_and_level.xml')
    )
    url = get_endpoint('read-schools-for-child-and-level')
    resp = app.get(url, params={'child_id': '190115', 'year': '2023'})
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 1
    for item in resp.json['data']:
        assert 'id' in item
        assert 'text' in item


def test_read_child_school_subscription_information(family_service, con, app):
    family_service.add_soap_response(
        'getChildSubscribeSchoolInformation', get_xml_file('R_get_child_subscribe_school_information.xml')
    )
    url = get_endpoint('read-child-school-informations')

    resp = app.get(url, params={'family_id': '47916', 'child_id': '190115', 'year': '2023', 'level': 'CP'})
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='47916', name_id='local')

    resp = app.get(url, params={'NameID': 'local', 'child_id': '190115', 'year': '2023', 'level': 'CP'})
    assert resp.json['err'] == 0
    assert 'rl1Info' in resp.json['data']
    assert 'childSubscribeSchoolInformation' in resp.json['data']
    assert 'personSubscribeSchoolList' in resp.json['data']


def test_create_child_school_pre_registration(family_service, con, app):
    family_service.add_soap_response(
        'preSubscribeSchoolPerim', get_xml_file('R_create_child_school_pre_registration.xml')
    )
    url = get_endpoint('create-child-school-pre-registration')
    resp = app.post_json(
        url,
        params={
            'numPerson': '248460',
            'schoolYear': '2023',
            'levelCode': 'CM1',
            'dateSubscribe': '2023-09-01T00:00:00+02:00',
        },
    )
    assert resp.json['err'] == 0
    assert resp.json['data']['subscribeSchoolBean']['idSchool'] == '2435'
    assert resp.json['data']['subscribeSchoolBean']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE'
    assert resp.json['data']['subscribeSchoolBean']['isWaitList']


def test_create_child_school_pre_registration_with_exemption(family_service, con, app):
    family_service.add_soap_response(
        'presubscribeSchoolDerog', get_xml_file('R_create_child_school_pre_registration_with_exemption.xml')
    )
    url = get_endpoint('create-child-school-pre-registration-with-exemption')
    resp = app.post_json(
        url,
        params={
            'numPerson': '248460',
            'schoolYear': '2023',
            'levelCode': 'CM1',
            'datePresubscribe': '2023-09-01T00:00:00+02:00',
            'idRequestSchool1': '2435',
            'derogReasonCode': '11DERO-1',
            'derogComment': 'exemption comment',
        },
    )
    assert resp.json['err'] == 0
    assert resp.json['data']['idSchool'] == '2435'
    assert resp.json['data']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE'
    assert resp.json['data']['isWaitList']
    assert resp.json['data']['isDerog']
    assert resp.json['data']['derogReason'] == '11DERO-1'
    assert resp.json['data']['derogComment'] == 'exemption comment'


def test_create_child_school_pre_registration_with_sibling(family_service, con, app):
    family_service.add_soap_response(
        'presubscribeSchoolSibling', get_xml_file('R_create_child_school_pre_registration_with_sibling.xml')
    )
    url = get_endpoint('create-child-school-pre-registration-with-sibling')
    resp = app.post_json(
        url,
        params={
            'numPerson': '248565',
            'schoolYear': '2023',
            'levelCode': 'CM1',
            'datePresubscribe': '2023-09-01T00:00:00+02:00',
            'idSchoolRequested': '2435',
            'numPersonSibling': '248562',
        },
    )
    assert resp.json['err'] == 0
    assert resp.json['data']['idSchool'] == '2435'
    assert resp.json['data']['schoolName'] == 'DUPONT PIERRE ELEMENTAIRE'
    assert resp.json['data']['isWaitList']
    assert resp.json['data']['isDerog']
    assert resp.json['data']['codeWait'] == 'MO_FRATERIE'
    assert resp.json['data']['derogReason'] == '01PRIO-5'
    assert resp.json['data']['derogComment'] == 'SERGHEI3 LISA'


def test_get_person_activity_list(activity_service, con, app):
    def request_check(request):
        assert request.yearSchool == 2022

    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
        request_check=request_check,
    )
    url = get_endpoint('get-person-activity-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'nature_id': '',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='311323', name_id='local')

    params['NameID'] = 'local'
    params['family_id'] = ''
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('A10051141965', 'Activité modèle'),
        ('A10053187087', 'Vacances Ete 2023'),
        ('A10053187065', 'Vacances Hivers 2023'),
    ]
    data = resp.json['data'][1]
    del data['unitInfoList'][1]
    assert data == {
        'activity': {
            'activityType': {
                'code': 'LOI_VAC',
                'libelle': 'Loisirs - Vacances',
                'natureSpec': {'code': 'V', 'libelle': 'Vacances Enfants'},
            },
            'idActivity': 'A10053187087',
            'libelle1': 'Vacances Ete 2023',
            'libelle2': None,
            'paiementPortal': 'I',
            'typInsPortal': 'I',
        },
        'id': 'A10053187087',
        'incompleteFamilyFile': False,
        'indicatorBlockSubscribeList': [],
        'text': 'Vacances Ete 2023',
        'unitInfoList': [
            {
                'dateEnd': '2023-07-31T00:00:00+02:00',
                'dateStart': '2023-07-10T00:00:00+02:00',
                'idIns': None,
                'idUnit': 'A10053187241',
                'libelle': 'Juillet',
                'placeInfoList': [
                    {
                        'capacityInfo': {'controlOK': True, 'message': None},
                        'idIns': None,
                        'place': {
                            'ageEnd': None,
                            'ageStart': None,
                            'ctrlPlaces': 'H',
                            'etatIns': None,
                            'idIns': None,
                            'idPlace': 'A10053179604',
                            'latitude': 1,
                            'lib1': 'ALEX JANY',
                            'lib2': None,
                            'listBlocNoteBean': [],
                            'longitude': 2,
                        },
                    }
                ],
            },
        ],
    }
    assert resp.json['meta']['person']['numPerson'] == 246423

    params['text_template'] = '{{ unitInfoList.0.libelle }}'
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('A10051141965', 'Inscription 2ème semestre'),
        ('A10053187087', 'Juillet'),
        ('A10053187065', 'Semaine 2'),
    ]


def test_get_person_activity_list_not_linked_error(con, app):
    url = get_endpoint('get-person-activity-list')
    params = {
        'NameID': 'local',
        'family_id': '',
        'person_id': '246423',
        'nature_id': '',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_person_activity_list_date_error(con, app):
    url = get_endpoint('get-person-activity-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'nature_id': '',
        'start_date': 'bad',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2022-09-01'
    params['end_date'] = 'bad'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2023-09-01'
    params['end_date'] = '2023-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    params['start_date'] = '2022-09-01'
    params['end_date'] = '2024-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'


def test_get_person_unit_list(activity_service, con, app):
    def request_check(request):
        assert request.yearSchool == 2022

    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
        request_check=request_check,
    )
    url = get_endpoint('get-person-unit-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='311323', name_id='local')

    params['NameID'] = 'local'
    params['family_id'] = ''
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('A10053187241', 'Juillet'),
        ('A10053187242', 'Aout'),
    ]
    assert resp.json['data'][0] == {
        'dateEnd': '2023-07-31T00:00:00+02:00',
        'dateStart': '2023-07-10T00:00:00+02:00',
        'id': 'A10053187241',
        'idIns': None,
        'idUnit': 'A10053187241',
        'libelle': 'Juillet',
        'placeInfoList': [
            {
                'capacityInfo': {'controlOK': True, 'message': None},
                'idIns': None,
                'place': {
                    'ageEnd': None,
                    'ageStart': None,
                    'ctrlPlaces': 'H',
                    'etatIns': None,
                    'idIns': None,
                    'idPlace': 'A10053179604',
                    'latitude': 1,
                    'lib1': 'ALEX JANY',
                    'lib2': None,
                    'listBlocNoteBean': [],
                    'longitude': 2,
                },
            }
        ],
        'text': 'Juillet',
    }
    assert resp.json['meta']['person']['numPerson'] == 246423
    assert resp.json['meta']['activity']['activity']['idActivity'] == 'A10053187087'

    params['text_template'] = '{{ meta.activity.activity.activityType.natureSpec.libelle }} - {{ libelle }}'
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [
        ('A10053187241', 'Vacances Enfants - Juillet'),
        ('A10053187242', 'Vacances Enfants - Aout'),
    ]


def test_get_person_unit_list_not_linked_error(con, app):
    url = get_endpoint('get-person-unit-list')
    params = {
        'NameID': 'local',
        'family_id': '',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_person_unit_list_date_error(con, app):
    url = get_endpoint('get-person-unit-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'start_date': 'bad',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2022-09-01'
    params['end_date'] = 'bad'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2023-09-01'
    params['end_date'] = '2023-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    params['start_date'] = '2022-09-01'
    params['end_date'] = '2024-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'


def test_get_person_unit_list_no_activity_error(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
    )
    url = get_endpoint('get-person-unit-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'plop',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'no-activity'
    assert resp.json['err_desc'] == 'No activity plop for person'


def test_get_person_place_list(activity_service, con, app):
    def request_check(request):
        assert request.yearSchool == 2022

    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
        request_check=request_check,
    )
    url = get_endpoint('get-person-place-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'unit_id': 'A10053187241',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='311323', name_id='local')

    params['NameID'] = 'local'
    params['family_id'] = ''
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [('A10053179604', 'ALEX JANY')]
    assert resp.json['data'] == [
        {
            'capacityInfo': {'controlOK': True, 'message': None},
            'id': 'A10053179604',
            'idIns': None,
            'place': {
                'ageEnd': None,
                'ageStart': None,
                'ctrlPlaces': 'H',
                'etatIns': None,
                'idIns': None,
                'idPlace': 'A10053179604',
                'latitude': 1.0,
                'lib1': 'ALEX JANY',
                'lib2': None,
                'listBlocNoteBean': [],
                'longitude': 2.0,
            },
            'text': 'ALEX JANY',
        }
    ]
    assert resp.json['meta']['person']['numPerson'] == 246423
    assert resp.json['meta']['activity']['activity']['idActivity'] == 'A10053187087'
    assert resp.json['meta']['unit']['idUnit'] == 'A10053187241'

    params['text_template'] = '{{ meta.unit.libelle }} - {{ place.lib1 }}'
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    assert [(x['id'], x['text']) for x in resp.json['data']] == [('A10053179604', 'Juillet - ALEX JANY')]


def test_get_person_place_list_not_linked_error(con, app):
    url = get_endpoint('get-person-place-list')
    params = {
        'NameID': 'local',
        'family_id': '',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'unit_id': 'A10053187241',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_person_place_list_date_error(con, app):
    url = get_endpoint('get-person-place-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'A10053187087',
        'unit_id': 'A10053187241',
        'start_date': 'bad',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2022-09-01'
    params['end_date'] = 'bad'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2023-09-01'
    params['end_date'] = '2023-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    params['start_date'] = '2022-09-01'
    params['end_date'] = '2024-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'


def test_get_person_place_list_no_unit_error(activity_service, con, app):
    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
    )
    url = get_endpoint('get-person-place-list')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'activity_id': 'plop',
        'unit_id': 'plop',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'text_template': '',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'no-activity'
    assert resp.json['err_desc'] == 'No activity plop for person'

    params['activity_id'] = 'A10053187087'
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'no-unit'
    assert resp.json['err_desc'] == 'No unit plop for person'


def test_get_person_catalog_geojson(activity_service, con, app):
    def request_check(request):
        assert request.yearSchool == 2022

    activity_service.add_soap_response(
        'getPersonCatalogueActivity',
        get_xml_file('R_read_person_catalog_activity.xml'),
        request_check=request_check,
    )
    url = get_endpoint('get-person-catalog-geojson')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'nature_id': '',
        'start_date': '2022-09-01',
        'end_date': '2023-08-31',
        'activity_id': 'A10053187087',
        'unit_id': 'A10053187241',
        'place_id': 'A10053179604',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 0
    Link.objects.create(resource=con, family_id='311323', name_id='local')

    params['NameID'] = 'local'
    params['family_id'] = ''
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 1
    assert resp.json == {
        'err': 0,
        'features': [
            {
                'geometry': {'coordinates': [2.0, 1.0], 'type': 'Point'},
                'properties': {
                    'id': 'A10053187087:A10053187241:A10053179604',
                    'text': 'Vacances Ete 2023 / Juillet / ALEX JANY',
                    'activity_id': 'A10053187087',
                    'unit_id': 'A10053187241',
                    'place_id': 'A10053179604',
                    'person': {
                        'dateBirth': '2014-04-01T00:00:00+02:00',
                        'firstname': 'BART',
                        'lastname': 'SIMPSON',
                        'numPerson': 246423,
                        'sexe': 'M',
                    },
                    'activity': {
                        'activity': {
                            'activityType': {
                                'code': 'LOI_VAC',
                                'libelle': 'Loisirs - Vacances',
                                'natureSpec': {'code': 'V', 'libelle': 'Vacances ' 'Enfants'},
                            },
                            'idActivity': 'A10053187087',
                            'libelle1': 'Vacances ' 'Ete 2023',
                            'libelle2': None,
                            'paiementPortal': 'I',
                            'typInsPortal': 'I',
                        },
                        'incompleteFamilyFile': False,
                        'indicatorBlockSubscribeList': [],
                    },
                    'unit': {
                        'dateEnd': '2023-07-31T00:00:00+02:00',
                        'dateStart': '2023-07-10T00:00:00+02:00',
                        'idIns': None,
                        'idUnit': 'A10053187241',
                        'libelle': 'Juillet',
                    },
                    'place': {
                        'capacityInfo': {'controlOK': True, 'message': None},
                        'idIns': None,
                        'place': {
                            'ageEnd': None,
                            'ageStart': None,
                            'ctrlPlaces': 'H',
                            'etatIns': None,
                            'idIns': None,
                            'idPlace': 'A10053179604',
                            'latitude': 1.0,
                            'lib1': 'ALEX JANY',
                            'lib2': None,
                            'listBlocNoteBean': [],
                            'longitude': 2.0,
                        },
                    },
                },
                'type': 'Feature',
            },
        ],
        'type': 'FeatureCollection',
    }

    params['place_id'] = 'plop'
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 0

    del params['place_id']
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 1

    params['unit_id'] = 'plop'
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 0

    del params['unit_id']
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 2

    params['activity_id'] = 'plop'
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 0

    del params['activity_id']
    resp = app.get(url, params=params)
    assert len(resp.json['features']) == 4


def test_get_person_catalog_geojson_not_linked_error(con, app):
    url = get_endpoint('get-person-catalog-geojson')
    params = {
        'NameID': '',
        'family_id': '',
        'person_id': '246423',
    }
    resp = app.get(url, params=params)
    assert resp.json['err'] == 'not-linked'
    assert resp.json['err_desc'] == 'User not linked to family'


def test_get_person_catalog_geojson_date_error(con, app):
    url = get_endpoint('get-person-catalog-geojson')

    params = {
        'NameID': '',
        'family_id': '311323',
        'person_id': '246423',
        'start_date': 'bad',
        'end_date': '2023-08-31',
    }
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2022-09-01'
    params['end_date'] = 'bad'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'bad date format, should be YYYY-MM-DD'

    params['start_date'] = '2023-09-01'
    params['end_date'] = '2023-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date should be before end_date'

    params['start_date'] = '2022-09-01'
    params['end_date'] = '2024-08-31'
    resp = app.get(url, params=params, status=400)
    assert resp.json['err'] == 'bad-request'
    assert resp.json['err_desc'] == 'start_date and end_date are in different reference year (2022 != 2023)'
