# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2021 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 datetime
import os
import xml.etree.ElementTree as ET
from contextlib import contextmanager
from unittest import mock

import freezegun
import pytest
import xmlschema

import tests.utils
from passerelle.contrib.caluire_axel import schemas
from passerelle.contrib.caluire_axel.models import CaluireAxel, Link
from passerelle.contrib.utils.axel import AxelError, OperationResult, json_date_format, xml_date_format
from passerelle.utils.soap import SOAPError

XML_RESPONSE_TEMPLATE = '''<?xml version="1.0"?>
<PORTAILSERVICE>
  <RESULTAT>
    <TYPE>%s</TYPE>
    <STATUS>OK</STATUS>
    <DATE>10/10/2010 10:10:01</DATE>
    <COMMENTAIRES><![CDATA[]]></COMMENTAIRES>
  </RESULTAT>
  <DATA>
    %s
  </DATA>
</PORTAILSERVICE>'''


@pytest.fixture
def resource(db):
    return tests.utils.make_resource(
        CaluireAxel, slug='test', wsdl_url='http://example.net/AXEL_WS/AxelWS.php?wsdl'
    )


@pytest.fixture
def link_params():
    return {
        'IDENTFAMILLE': '12345',
        'NOM': 'Doe',
        'PRENOM': 'John',
    }


@pytest.fixture
def family_data():
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    resp = XML_RESPONSE_TEMPLATE % ('GetFamilleIndividus', content)
    return schemas.get_famille_individus.response_converter.decode(ET.fromstring(resp))['DATA']['PORTAIL'][
        'GETFAMILLE'
    ]


@pytest.fixture
def register_activity_params():
    return {
        'activity_id': 'CANTINE',
        'child_id': '50632',
        'registration_start_date': '2020-09-01',
        'registration_end_date': '2021-08-31',
    }


@pytest.fixture
def activities():
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    resp = XML_RESPONSE_TEMPLATE % ('GetListActivites', content)
    return schemas.get_list_activites.response_converter.decode(ET.fromstring(resp))['DATA']['PORTAIL'][
        'GETLISTACTIVITES'
    ]


@pytest.fixture
def activities_full():
    return {
        'ACTIVITE': [
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'GARDERIES',
                'LIBELLEACTIVITE': 'Garderie',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'ACCMAT',
                'LIBELLEACTIVITE': 'Matin',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'CJ MER',
                'LIBELLEACTIVITE': 'Mercredi',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'ETUDES',
                'LIBELLEACTIVITE': 'Etudes',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'CJ1',
                'LIBELLEACTIVITE': 'Des vacances',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'ECOLELEM',
                'LIBELLEACTIVITE': 'Cantine',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'NAV MATIN',
                'LIBELLEACTIVITE': 'Navette du matin',
            },
            {
                'ENTREE': '2020-09-02',
                'SORTIE': '2021-08-31',
                'IDENTACTIVITE': 'NAV SOIR',
                'LIBELLEACTIVITE': 'Navette du soir',
            },
        ]
    }


@pytest.fixture
def booking_params():
    return {
        'child_id': '50632',
        'booking_list': [],
        'start_date': '2020-09-01',
        'end_date': '2021-08-31',
    }


@pytest.fixture
def changes_params():
    return {
        'child_id': '50632',
        'changes': [],
        'start_date': '2020-09-01',
        'end_date': '2021-08-31',
    }


@pytest.fixture
def week_booking_params():
    return {
        'child_id': '50632',
        'activity_id': 'ELEM',
        'booking_list': [],
        'start_date': '2020-09-01',
        'end_date': '2021-08-31',
    }


@pytest.fixture
def upload_attachments_params():
    return {
        'child_id': '50632',
        'reference_date': '2020-09-01',
        'attachments': [
            {
                'attachment_type': '1234',
                'label': 'ID card',
                'url': 'https://example.org/file1.pdf',
            },
            {
                'attachment_type': '1234',
                'label': 'Passport',
                'url': 'https://example.org/file2.pdf',
            },
        ],
    }


@contextmanager
def mock_data(content, operation, data_method='getData'):
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        resp = XML_RESPONSE_TEMPLATE % (operation, content)
        getattr(client.return_value.service, data_method).return_value = resp
        yield


def test_operation_status_error(resource):
    resp = '''
    <?xml version="1.0"?>
    <PORTAILSERVICE>
      <RESULTAT>
        <TYPE>FindIndividus</TYPE>
        <STATUS>NOK</STATUS>
        <COMMENTAIRES><![CDATA[Foo reason]]></COMMENTAIRES>
      </RESULTAT>
      <DATA>
        <PORTAIL/>
      </DATA>
    </PORTAILSERVICE>
    '''.strip()
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        client.return_value.service.getData.return_value = resp
        with pytest.raises(AxelError, match='Foo reason'):
            schemas.find_individus(
                resource,
                {
                    'PORTAIL': {
                        'FINDINDIVIDU': {
                            'NOM': 'Doe',
                            'PRENOM': 'John',
                            'NAISSANCE': None,
                            'CODEPOSTAL': None,
                            'VILLE': None,
                            'TEL': None,
                            'MAIL': None,
                        }
                    }
                },
            )


def test_link_endpoint_nameid_empty(app, resource, link_params):
    resp = app.post_json('/caluire-axel/test/link?NameID=', params=link_params, status=400)
    assert resp.json['err_desc'] == "NameID is empty"
    assert resp.json['err'] == 'bad-request'


def test_link_endpoint_axel_error(app, resource, link_params):
    with mock.patch('passerelle.contrib.caluire_axel.schemas.find_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'
    assert resp.json['data'] == {'xml_request': None, 'xml_response': None}

    # test xml_request and xml_response only for this endpoint
    xml_request = """<PORTAIL>
  <FINDINDIVIDU>
    <NOM>Doe</NOM>
    <PRENOM>John</PRENOM>
    <NAISSANCE />
    <CODEPOSTAL />
    <VILLE />
    <TEL />
    <MAIL />
  </FINDINDIVIDU>
</PORTAIL>
"""

    with mock_data('', 'FindIndividus'):
        with mock.patch('xmlschema.XMLSchema.validate') as xml_validate:
            xml_validate.side_effect = xmlschema.XMLSchemaValidationError(None, None)
            resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'].startswith("Axel error: invalid request")
    assert resp.json['err'] == 'error'
    assert resp.json['data']['xml_request'] == xml_request
    assert resp.json['data']['xml_response'] is None

    xml_response = """<PORTAILSERVICE>
  <RESULTAT>
    <TYPE>FINDINDIVIDUS</TYPE>
    <STATUS>NOK</STATUS>
    <COMMENTAIRES>Foo reason</COMMENTAIRES>
  </RESULTAT>
  <DATA>
    <PORTAIL />
  </DATA>
</PORTAILSERVICE>"""
    response = """
    <?xml version="1.0"?>
    <PORTAILSERVICE>
      <RESULTAT>
        <TYPE>FINDINDIVIDUS</TYPE>
        <STATUS>NOK</STATUS>
        <COMMENTAIRES><![CDATA[Foo reason]]></COMMENTAIRES>
      </RESULTAT>
      <DATA>
        <PORTAIL/>
      </DATA>
    </PORTAILSERVICE>
    """.strip()
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        client.return_value.service.getData.return_value = response
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == 'Axel error: Foo reason'
    assert resp.json['err'] == 'error'
    assert resp.json['data']['xml_request'] == xml_request
    assert resp.json['data']['xml_response'] == xml_response

    content = """<PORTAIL>
      <FINDINDIVIDUS>
        <INDIVIDU>
          <IDENT>123</IDENT>
          <NOM>Doe</NOM>
          <PRENOM>John</PRENOM>
          <FAMILLE>
            <IDENTFAMILLE>12345</IDENTFAMILLE>
            <PLACE>2</PLACE>
          </FAMILLE>
        </INDIVIDU>
      </FINDINDIVIDUS>
    </PORTAIL>"""
    xml_response = (
        """<PORTAILSERVICE>
  <RESULTAT>
    <TYPE>FindIndividus</TYPE>
    <STATUS>OK</STATUS>
    <DATE>10/10/2010 10:10:01</DATE>
    <COMMENTAIRES />
  </RESULTAT>
  <DATA>
    %s
  </DATA>
</PORTAILSERVICE>"""
        % content
    )

    with mock_data(content, 'FindIndividus'):
        with mock.patch('passerelle.contrib.utils.axel.AxelSchema.decode') as decode:
            decode.side_effect = xmlschema.XMLSchemaValidationError(None, None)
            resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'].startswith("Axel error: invalid response")
    assert resp.json['err'] == 'error'
    assert resp.json['data']['xml_request'] == xml_request
    assert resp.json['data']['xml_response'] == xml_response

    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        client.side_effect = SOAPError('SOAP service is down')
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == "SOAP service is down"


@pytest.mark.parametrize(
    'xml_response',
    [
        '',
        """<INDIVIDU>
  <IDENT>123</IDENT>
  <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
  <FAMILLE>
    <IDENTFAMILLE>12346</IDENTFAMILLE>
    <PLACE>2</PLACE>
    <SITUATION/>
  </FAMILLE>
  <FAMILLE>
    <IDENTFAMILLE>12347</IDENTFAMILLE>
    <PLACE>1</PLACE>
  </FAMILLE>
  </INDIVIDU>""",
        """<INDIVIDU>
  <IDENT>123</IDENT>
  <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
  <FAMILLE>
    <IDENTFAMILLE>12345</IDENTFAMILLE>
    <PLACE>3</PLACE>
    <SITUATION/>
  </FAMILLE>
  </INDIVIDU>""",
    ],
)
def test_link_endpoint_no_result(app, resource, link_params, xml_response):
    content = (
        '''<PORTAIL>
    <FINDINDIVIDUS>
        <CODE>42</CODE>
        %s
    </FINDINDIVIDUS>
</PORTAIL>'''
        % xml_response
    )
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_link_endpoint_conflict(app, resource, link_params):
    content = """<PORTAIL><FINDINDIVIDUS>
  <CODE>42</CODE>
  <INDIVIDU>
    <IDENT>123</IDENT>
    <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
    <FAMILLE>
      <IDENTFAMILLE>12345</IDENTFAMILLE>
      <PLACE>2</PLACE>
      <SITUATION/>
    </FAMILLE>
  </INDIVIDU>
</FINDINDIVIDUS></PORTAIL>"""
    # existing link but family_id is wrong
    link = Link.objects.create(resource=resource, name_id='yyy', family_id='YYY', person_id='42')
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == "Data conflict"
    assert resp.json['err'] == 'conflict'

    # existing link but person_id is wrong
    link.family_id = '12345'
    link.person_id = '35'
    link.save()
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err_desc'] == "Data conflict"
    assert resp.json['err'] == 'conflict'


@pytest.mark.parametrize('place', [1, 2])
def test_link_endpoint(app, resource, link_params, place):
    content = (
        """<PORTAIL><FINDINDIVIDUS>
  <CODE>42</CODE>
  <INDIVIDU>
    <IDENT>123</IDENT>
    <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
    <FAMILLE>
      <IDENTFAMILLE>12345</IDENTFAMILLE>
      <PLACE>%s</PLACE>
      <SITUATION/>
    </FAMILLE>
  </INDIVIDU>
</FINDINDIVIDUS></PORTAIL>"""
        % place
    )
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert set(resp.json.keys()) == {'err', 'link', 'created', 'family_id', 'data'}
    assert resp.json['err'] == 0
    assert resp.json['family_id'] == '12345'
    assert resp.json['created'] is True
    assert 'xml_request' in resp.json['data']
    assert 'xml_response' in resp.json['data']

    # again
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert set(resp.json.keys()) == {'err', 'link', 'created', 'family_id', 'data'}
    assert resp.json['err'] == 0
    assert resp.json['family_id'] == '12345'
    assert resp.json['created'] is False  # link already exists
    assert 'xml_request' in resp.json['data']
    assert 'xml_response' in resp.json['data']


def test_link_endpoint_having_homonyme_with_empty_familly(app, resource, link_params):
    content = """<PORTAIL><FINDINDIVIDUS>
  <CODE>42</CODE>
  <INDIVIDU>
    <IDENT>123</IDENT>
    <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
  </INDIVIDU>
  <INDIVIDU>
    <IDENT>456</IDENT>
    <CIVILITE/><NOM>A</NOM><PRENOM/><NAISSANCE/><SEXE/><NOMJF/><TELFIXE/><TELPORTABLE/><MAIL/><CSP/><EMPLOYEUR/><VILLEEMP/><PAI>N</PAI><GARDEALTERNEE/>
    <FAMILLE>
      <IDENTFAMILLE>12345</IDENTFAMILLE>
      <PLACE>2</PLACE>
      <SITUATION/>
    </FAMILLE>
  </INDIVIDU>
</FINDINDIVIDUS></PORTAIL>"""
    with mock_data(content, 'FindIndividus'):
        resp = app.post_json('/caluire-axel/test/link?NameID=yyy', params=link_params)
    assert resp.json['err'] == 0
    assert resp.json['family_id'] == '12345'
    assert resp.json['created'] is True


def test_unlink_endpoint_no_result(app, resource):
    resp = app.post('/caluire-axel/test/unlink?NameID=yyy')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_unlink_endpoint(app, resource):
    link = Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.post('/caluire-axel/test/unlink?NameID=yyy')
    assert Link.objects.exists() is False
    assert resp.json['err'] == 0
    assert resp.json['link'] == link.pk
    assert resp.json['family_id'] == 'XXX'
    assert resp.json['deleted'] is True


def test_family_info_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/family_info?NameID=yyy')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_family_info_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/family_info?NameID=yyy')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_family_info_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get('/caluire-axel/test/family_info?NameID=yyy')
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {'family_id', 'CODE', 'MEMBRE', 'RESPONSABLE1', 'RESPONSABLE2'}
    assert resp.json['data']['CODE'] == 0
    assert resp.json['data']['family_id'] == 'XXX'
    assert resp.json['data']['MEMBRE'][0]['id'] == '50632'
    assert resp.json['data']['MEMBRE'][0]['text'] == 'Enfant 1 CALUIRE TEST'
    assert resp.json['data']['MEMBRE'][1]['id'] == '50633'
    assert resp.json['data']['MEMBRE'][1]['text'] == 'Enfant 2 CALUIRE TEST'
    assert resp.json['data']['MEMBRE'][2]['id'] == '54621'
    assert resp.json['data']['MEMBRE'][2]['text'] == 'Enfant 3 CALUIRE TEST'
    assert resp.json['data']['MEMBRE'][3]['id'] == '59509'
    assert resp.json['data']['MEMBRE'][3]['text'] == 'Enfant 5 CALUIRE TEST'
    assert resp.json['data']['RESPONSABLE1']['IDENT'] == '50630'

    # again - data are in cache
    resp = app.get('/caluire-axel/test/family_info?NameID=yyy')
    assert resp.json['err'] == 0

    # misordered XML (one MEMBER before RESPONSABLE1)
    Link.objects.create(resource=resource, name_id='bar', family_id='YYY', person_id='24')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info_misordered.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get('/caluire-axel/test/family_info?NameID=bar')
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {'family_id', 'CODE', 'MEMBRE', 'RESPONSABLE1', 'RESPONSABLE2'}
    assert resp.json['data']['family_id'] == 'YYY'
    assert resp.json['data']['MEMBRE'][0]['id'] == '11111'
    assert resp.json['data']['MEMBRE'][0]['text'] == 'Enfant 1 CALUIRE TEST'
    assert resp.json['data']['MEMBRE'][1]['id'] == '22222'
    assert resp.json['data']['MEMBRE'][1]['text'] == 'Enfant 2 CALUIRE TEST'


def test_children_info_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/children_info?NameID=yyy')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_children_info_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/children_info?NameID=yyy')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_children_info_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get('/caluire-axel/test/children_info?NameID=yyy')
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 4
    assert resp.json['data'][0]['id'] == '50632'
    assert resp.json['data'][0]['text'] == 'Enfant 1 CALUIRE TEST'
    assert resp.json['data'][1]['id'] == '50633'
    assert resp.json['data'][1]['text'] == 'Enfant 2 CALUIRE TEST'
    assert resp.json['data'][2]['id'] == '54621'
    assert resp.json['data'][2]['text'] == 'Enfant 3 CALUIRE TEST'
    assert resp.json['data'][3]['id'] == '59509'
    assert resp.json['data'][3]['text'] == 'Enfant 5 CALUIRE TEST'

    # again - data are in cache
    resp = app.get('/caluire-axel/test/children_info?NameID=yyy')
    assert resp.json['err'] == 0


def test_child_info_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/child_info?NameID=yyy&idpersonne=50632')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_child_info_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/child_info?NameID=yyy&idpersonne=50632')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get('/caluire-axel/test/child_info?NameID=yyy&idpersonne=zzz')
    assert resp.json['err_desc'] == "Child not found"
    assert resp.json['err'] == 'not-found'


def test_child_info_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get('/caluire-axel/test/child_info?NameID=yyy&idpersonne=50632')
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {
        'ADRESSE',
        'CIVILITE',
        'FAMILLE',
        'GARDEALTERNEE',
        'IDENT',
        'MAIL',
        'NAISSANCE',
        'NOM',
        'NOMJF',
        'PAI',
        'PRENOM',
        'SEXE',
        'TELFIXE',
        'TELPORTABLE',
        'id',
        'text',
    }
    assert resp.json['data']['id'] == '50632'
    assert resp.json['data']['text'] == 'Enfant 1 CALUIRE TEST'

    # again - data are in cache
    resp = app.get('/caluire-axel/test/child_info?NameID=yyy&idpersonne=50632')
    assert resp.json['err'] == 0


def test_school_list_endpoint_axel_error(app, resource):
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_ecole') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/school_list?num=42&street=street=rue%20Pasteur&zipcode=69300&city=Caluire%20et%20Cuire&schooling_date=2021-05-10'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_school_list_endpoint(app, resource):
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/school_list.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListEcole'):
        resp = app.get(
            '/caluire-axel/test/school_list?num=42&street=street=rue%20Pasteur&zipcode=69300&city=Caluire%20et%20Cuire&schooling_date=2021-05-10'
        )
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {'CODE', 'ECOLE'}
    assert len(resp.json['data']['ECOLE']) == 2
    assert resp.json['data']['ECOLE'][0]['id'] == 'MAT'
    assert resp.json['data']['ECOLE'][0]['text'] == 'Ecole Maternelle'
    assert resp.json['data']['ECOLE'][1]['id'] == 'ELEM'
    assert resp.json['data']['ECOLE'][1]['text'] == 'Ecole Elémentaire'


def test_child_schooling_info_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_individu') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get(
                '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_child_schooling_info_endpoint_bad_date_format(app, resource, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.get(
        '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=50632&schooling_date=%s' % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'


def test_child_schooling_info_endpoint_no_result(app, resource):
    resp = app.get(
        '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=zzz&schooling_date=2021-05-10'
        )
    assert resp.json['err_desc'] == "Child not found"
    assert resp.json['err'] == 'not-found'


def test_child_schooling_info(app, resource, family_data):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/schooling_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetIndividu'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.get(
                '/caluire-axel/test/child_schooling_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
            )
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {'CODE', 'INDIVIDU', 'SCOLAIRE'}


def test_child_activities_info_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get(
                '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_child_activities_info_endpoint_bad_date_format(app, resource, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.get(
        '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=%s' % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'


def test_child_activities_info_endpoint_no_result(app, resource):
    resp = app.get(
        '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=zzz&schooling_date=2021-05-10'
        )
    assert resp.json['err_desc'] == "Child not found"
    assert resp.json['err'] == 'not-found'


def test_child_activities_info(app, resource, family_data):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.get(
                '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
            )
    assert resp.json['err'] == 0
    assert set(resp.json['data'].keys()) == {'CODE', 'ACTIVITE'}

    # again - data are in cache
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        resp = app.get(
            '/caluire-axel/test/child_activities_info?NameID=yyy&idpersonne=50632&schooling_date=2021-05-10'
        )
    assert resp.json['err'] == 0


def test_register_activity_endpoint_axel_error(app, resource, register_activity_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json(
            '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.create_inscription_activite') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json(
                '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_register_activity_endpoint_no_result(app, resource, register_activity_params):
    register_activity_params['child_id'] = 'zzz'
    resp = app.post_json('/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.post_json(
            '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params
        )
    assert resp.json['err_desc'] == "Child not found"
    assert resp.json['err'] == 'not-found'


def test_register_activity_endpoint_date_error(app, resource, register_activity_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        register_activity_params['registration_start_date'] = '2021-09-01'
        register_activity_params['registration_end_date'] = '2021-08-31'
        resp = app.post_json(
            '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params, status=400
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        register_activity_params['registration_end_date'] = '2022-09-01'
        resp = app.post_json(
            '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params, status=400
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_register_activity_endpoint(app, resource, family_data, register_activity_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <CREATEINSCRIPTIONACTIVITE>
        <CODE>0</CODE>
        <IDENTINDIVIDU>50632</IDENTINDIVIDU>
    </CREATEINSCRIPTIONACTIVITE>
</PORTAIL>'''
    with mock_data(content, 'CreateInscriptionActivite', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('django.core.cache.cache.delete') as mock_cache_delete:
                resp = app.post_json(
                    '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params
                )
    assert mock_cache_delete.call_args_list == [
        mock.call('caluire-axel-%s-child-activities-50632-2020' % resource.pk),
    ]
    assert resp.json['err'] == 0
    assert resp.json['created'] is True
    assert 'xml_request' in resp.json['data']
    assert 'xml_response' in resp.json['data']


@pytest.mark.parametrize('code', [-1, -2, -3, -4])
def test_register_activity_endpoint_wrong_code(app, resource, family_data, register_activity_params, code):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <CREATEINSCRIPTIONACTIVITE>
        <CODE>%s</CODE>
    </CREATEINSCRIPTIONACTIVITE>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'CreateInscriptionActivite', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.post_json(
                '/caluire-axel/test/register_activity?NameID=yyy', params=register_activity_params
            )
    if code == -1:
        assert resp.json['err'] == 0
        assert resp.json['created'] is False
    else:
        assert resp.json['err_desc'] == "Wrong register-activity status"
        assert resp.json['err'] == 'register-activity-code-error-%s' % code


def test_get_agenda_endpoint_axel_error(app, resource, family_data):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2020-09-01&end_date=2021-08-31'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get(
                '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2020-09-01&end_date=2021-08-31'
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.get(
                    '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_get_agenda_endpoint_bad_date_format(app, resource, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.get(
        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=%s&end_date=2021-08-31'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'
    resp = app.get(
        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2020-09-01&end_date=%s'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'


def test_get_agenda_endpoint_no_result(app, resource, family_data):
    resp = app.get(
        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2020-09-01&end_date=2021-08-31'
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=zzz&activity_id=FOOBAR&start_date=2020-09-01&end_date=2021-08-31'
        )
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.get(
                '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2020-09-01&end_date=2021-08-31'
            )
            assert resp.json['err_desc'] == "Activity not found"
            assert resp.json['err'] == 'not-found'


def test_get_agenda_endpoint_date_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2021-05-31&end_date=2021-05-30',
            status=400,
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        resp = app.get(
            '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=FOOBAR&start_date=2021-09-01&end_date=2022-09-01',
            status=400,
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


@freezegun.freeze_time('2020-09-01')
def test_get_agenda_endpoint(app, resource, family_data, activities):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {
            'id': '50632:ELEM:2020-10-30',
            'text': 'Friday 30 October 2020',
            'disabled': False,
            'prefill': False,
            'details': {
                'JOURDATE': '2020-10-30',
                'MATIN': '.',
                'MIDI': None,
                'APRESMIDI': None,
                'FERME': False,
                'status_color': 'white',
                'out_of_delay': False,
                'activity_id': 'ELEM',
                'activity_label': 'Restaurant Elémentaire',
                'activity_type': 'midi',
                'child_id': '50632',
            },
        },
    ]


@pytest.mark.parametrize(
    'value, ignored',
    [
        ('O', True),
        ('N', False),
    ],
)
def test_get_agenda_endpoint_closed(app, resource, family_data, activities, value, ignored):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>%s</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
        % value
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                )
    if ignored:
        assert len(resp.json['data']) == 0
    else:
        assert resp.json['data'][0]


@pytest.mark.parametrize(
    'value, expected',
    [
        ['<MATIN>X</MATIN>', True],
        ['<MATIN>H</MATIN>', True],
        ['<MATIN>R</MATIN>', True],
        ['<MATIN/>', False],
        ['<MATIN></MATIN>', False],
        ['<MATIN>.</MATIN>', False],
        ['<MATIN>F</MATIN>', False],
        ['<MATIN>S</MATIN>', False],
        ['<MATIN>T</MATIN>', False],
        ['<MATIN>D</MATIN>', False],
        ['<MATIN>C</MATIN>', False],
        ['<MATIN>M</MATIN>', False],
        ['<MATIN>A</MATIN>', False],
        ['<MATIN>N</MATIN>', False],
        ['<MATIN>Z</MATIN>', False],  # unknown
    ],
)
@freezegun.freeze_time('2020-09-01')
def test_get_agenda_endpoint_prefill(app, resource, family_data, activities, value, expected):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          %s
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
        % value
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['data'][0]['prefill'] == expected


@pytest.mark.parametrize(
    'value, color, disabled_future',
    [
        ['<MATIN>X</MATIN>', 'green', False],
        ['<MATIN>H</MATIN>', 'yellow', True],
        ['<MATIN>R</MATIN>', 'green', False],
        ['<MATIN/>', 'grey', True],
        ['<MATIN></MATIN>', 'grey', True],
        ['<MATIN>.</MATIN>', 'white', False],
        ['<MATIN>F</MATIN>', 'grey', True],
        ['<MATIN>S</MATIN>', 'grey', True],
        ['<MATIN>T</MATIN>', 'grey', True],
        ['<MATIN>D</MATIN>', 'orange', False],
        ['<MATIN>C</MATIN>', 'orange', True],
        ['<MATIN>M</MATIN>', 'orange', True],
        ['<MATIN>A</MATIN>', 'red', True],
        ['<MATIN>N</MATIN>', 'red', True],
        ['<MATIN>Z</MATIN>', 'grey', True],  # unknown
    ],
)
def test_get_agenda_endpoint_status(app, resource, family_data, activities, value, color, disabled_future):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          %s
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
        % value
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                with freezegun.freeze_time('2020-10-31'):
                    resp = app.get(
                        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                    )
                assert resp.json['data'][0]['details']['status_color'] == color
                assert resp.json['data'][0]['disabled'] is True
                assert resp.json['data'][0]['details']['out_of_delay'] is True

                with freezegun.freeze_time('2020-10-20'):
                    resp = app.get(
                        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                    )
                assert resp.json['data'][0]['details']['status_color'] == color
                assert resp.json['data'][0]['disabled'] == disabled_future
                assert resp.json['data'][0]['details']['out_of_delay'] is False


@pytest.mark.parametrize(
    'today, hour, booking_date, out_of_delay',
    [
        # monday 12H => thursday
        ('2021-05-31', '09:59:59', '2021-06-03', False),
        ('2021-05-31', '10:00:00', '2021-06-03', True),
        # tuesday 12H => friday
        ('2021-06-01', '09:59:59', '2021-06-04', False),
        ('2021-06-01', '10:00:00', '2021-06-04', True),
        # wednesday => monday
        ('2021-06-02', '09:59:59', '2021-06-04', True),
        ('2021-06-02', '10:00:00', '2021-06-04', True),
        ('2021-06-02', '09:59:59', '2021-06-05', True),
        ('2021-06-02', '10:00:00', '2021-06-05', True),
        ('2021-06-02', '09:59:59', '2021-06-06', True),
        ('2021-06-02', '10:00:00', '2021-06-06', True),
        ('2021-06-02', '09:59:59', '2021-06-07', False),
        ('2021-06-02', '10:00:00', '2021-06-07', False),
        # thursday 12H => monday
        ('2021-06-03', '09:59:59', '2021-06-07', False),
        ('2021-06-03', '10:00:00', '2021-06-07', True),
        # friday 12H => tuesday
        ('2021-06-04', '09:59:59', '2021-06-08', False),
        ('2021-06-04', '10:00:00', '2021-06-08', True),
        # saturday => thursday
        ('2021-06-05', '09:59:59', '2021-06-08', True),
        ('2021-06-05', '10:00:00', '2021-06-08', True),
        ('2021-06-05', '09:59:59', '2021-06-09', True),
        ('2021-06-05', '10:00:00', '2021-06-09', True),
        ('2021-06-05', '09:59:59', '2021-06-10', False),
        ('2021-06-05', '10:00:00', '2021-06-10', False),
        # sunday => thursday
        ('2021-06-06', '09:59:59', '2021-06-08', True),
        ('2021-06-06', '10:00:00', '2021-06-08', True),
        ('2021-06-06', '09:59:59', '2021-06-09', True),
        ('2021-06-06', '10:00:00', '2021-06-09', True),
        ('2021-06-06', '09:59:59', '2021-06-10', False),
        ('2021-06-06', '10:00:00', '2021-06-10', False),
    ],
)
def test_get_agenda_endpoint_delay_periscolaire(
    settings, app, resource, family_data, activities_full, today, hour, booking_date, out_of_delay
):
    settings.TIME_ZONE = 'Europe/Paris'
    settings.USE_TZ = True
    booking = datetime.datetime.strptime(booking_date, json_date_format).date()
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>%s</JOURDATE>
          <MATIN>X</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>''' % booking.strftime(
        xml_date_format
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities_full,
            ):
                with freezegun.freeze_time('%s %s' % (today, hour)):
                    for activity_id, activity_type in [
                        ('ACCMAT', 'matin'),
                        ('GARDERIES', 'soir'),
                        ('ETUDES', 'soir'),
                        ('ECOLELEM', 'midi'),
                        ('NAV MATIN', 'matin'),
                        ('NAV SOIR', 'soir'),
                    ]:
                        resp = app.get(
                            '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=%s&start_date=%s&end_date=%s'
                            % (activity_id, booking_date, booking_date)
                        )
                        assert resp.json['data'][0]['disabled'] == out_of_delay
                        assert resp.json['data'][0]['details']['out_of_delay'] == out_of_delay
                        assert resp.json['data'][0]['details']['activity_type'] == activity_type


@pytest.mark.parametrize(
    'activity_id, activity_type',
    [
        ('CJ MER', 'mercredi'),
        ('CJ1', 'vacances'),
    ],
)
def test_get_agenda_endpoint_delay_extrascolaire(
    app, resource, family_data, activities_full, activity_id, activity_type
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>12/07/2021</JOURDATE>
          <MATIN>X</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities_full,
            ):
                # always disabled
                with freezegun.freeze_time('2021-05-31'):
                    resp = app.get(
                        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=%s&start_date=2021-06-02&end_date=2021-06-02'
                        % activity_id
                    )
                assert resp.json['data'][0]['disabled'] is True
                assert resp.json['data'][0]['details']['out_of_delay'] is True
                assert resp.json['data'][0]['details']['activity_type'] == activity_type
                with freezegun.freeze_time('2021-07-11'):
                    resp = app.get(
                        '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=%s&start_date=2021-06-02&end_date=2021-06-02'
                        % activity_id
                    )
                assert resp.json['data'][0]['disabled'] is True
                assert resp.json['data'][0]['details']['out_of_delay'] is True
                assert resp.json['data'][0]['details']['activity_type'] == activity_type


@pytest.mark.parametrize('code', [0, -1, -2, -3, -4])
def test_get_agenda_endpoint_wrong_code(app, resource, family_data, activities, code):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <GETAGENDA>
        <CODE>%s</CODE>
    </GETAGENDA>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda?NameID=yyy&idpersonne=50632&activity_id=ELEM&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err_desc'] == "Wrong agenda status"
    assert resp.json['err'] == 'agenda-code-error-%s' % code


def test_get_agenda_periscolaire_endpoint_axel_error(app, resource, family_data):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get(
                '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.get(
                    '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_get_agenda_periscolaire_endpoint_bad_date_format(app, resource, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.get(
        '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=%s&end_date=2021-08-31'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'
    resp = app.get(
        '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=%s'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'


def test_get_agenda_periscolaire_endpoint_no_result(app, resource):
    resp = app.get(
        '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=zzz&start_date=2020-09-01&end_date=2021-08-31'
        )
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'


def test_get_agenda_periscolaire_endpoint_date_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2021-05-31&end_date=2021-05-30',
            status=400,
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        resp = app.get(
            '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2021-09-01&end_date=2022-09-01',
            status=400,
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_get_agenda_periscolaire_endpoint(app, resource, family_data, activities_full):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>7</CODE>
        <JOUR>
          <JOURDATE>26/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>27/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>28/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>29/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>31/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>01/11/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities_full,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert len(resp.json['data']) == 24
    assert resp.json['data'][0]['id'] == '50632:NAV MATIN:2020-10-26'
    assert resp.json['data'][1]['id'] == '50632:ACCMAT:2020-10-26'
    assert resp.json['data'][2]['id'] == '50632:ECOLELEM:2020-10-26'
    assert resp.json['data'][3]['id'] == '50632:ETUDES:2020-10-26'
    assert resp.json['data'][4]['id'] == '50632:GARDERIES:2020-10-26'
    assert resp.json['data'][5]['id'] == '50632:NAV SOIR:2020-10-26'
    assert resp.json['data'][6]['id'] == '50632:NAV MATIN:2020-10-27'
    assert resp.json['data'][7]['id'] == '50632:ACCMAT:2020-10-27'
    assert resp.json['data'][8]['id'] == '50632:ECOLELEM:2020-10-27'
    assert resp.json['data'][9]['id'] == '50632:ETUDES:2020-10-27'
    assert resp.json['data'][10]['id'] == '50632:GARDERIES:2020-10-27'
    assert resp.json['data'][11]['id'] == '50632:NAV SOIR:2020-10-27'
    assert resp.json['data'][12]['id'] == '50632:NAV MATIN:2020-10-29'
    assert resp.json['data'][13]['id'] == '50632:ACCMAT:2020-10-29'
    assert resp.json['data'][14]['id'] == '50632:ECOLELEM:2020-10-29'
    assert resp.json['data'][15]['id'] == '50632:ETUDES:2020-10-29'
    assert resp.json['data'][16]['id'] == '50632:GARDERIES:2020-10-29'
    assert resp.json['data'][17]['id'] == '50632:NAV SOIR:2020-10-29'
    assert resp.json['data'][18]['id'] == '50632:NAV MATIN:2020-10-30'
    assert resp.json['data'][19]['id'] == '50632:ACCMAT:2020-10-30'
    assert resp.json['data'][20]['id'] == '50632:ECOLELEM:2020-10-30'
    assert resp.json['data'][21]['id'] == '50632:ETUDES:2020-10-30'
    assert resp.json['data'][22]['id'] == '50632:GARDERIES:2020-10-30'
    assert resp.json['data'][23]['id'] == '50632:NAV SOIR:2020-10-30'


@pytest.mark.parametrize('code', [0, -1, -2, -3, -4])
def test_get_agenda_periscolaire_endpoint_wrong_code(app, resource, family_data, activities, code):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = (
        '''<PORTAIL>
    <GETAGENDA>
        <CODE>%s</CODE>
    </GETAGENDA>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda_periscolaire?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err_desc'] == "Wrong agenda status"
    assert resp.json['err'] == 'agenda-code-error-%s' % code


def test_get_agenda_full_endpoint_axel_error(app, resource, family_data):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get(
            '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get(
                '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.get(
                    '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_get_agenda_full_endpoint_bad_date_format(app, resource, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    resp = app.get(
        '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=%s&end_date=2021-08-31'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'
    resp = app.get(
        '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=%s'
        % value,
        status=400,
    )
    assert resp.json['err_desc'] == "bad date format, should be YYYY-MM-DD"
    assert resp.json['err'] == 'bad-request'


def test_get_agenda_full_endpoint_no_result(app, resource):
    resp = app.get(
        '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=zzz&start_date=2020-09-01&end_date=2021-08-31'
        )
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'


def test_get_agenda_full_endpoint_date_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.get(
            '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2021-05-31&end_date=2021-05-30',
            status=400,
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        resp = app.get(
            '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2021-09-01&end_date=2022-09-01',
            status=400,
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_get_agenda_full_endpoint(app, resource, family_data, activities_full):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>7</CODE>
        <JOUR>
          <JOURDATE>26/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>27/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>28/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>29/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>31/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
        <JOUR>
          <JOURDATE>01/11/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities_full,
            ):
                resp = app.get(
                    '/caluire-axel/test/get_agenda_full?NameID=yyy&idpersonne=50632&start_date=2020-09-01&end_date=2021-08-31'
                )
    assert len(resp.json['data']) == 40
    assert resp.json['data'][0]['id'] == '50632:NAV MATIN:2020-10-26'
    assert resp.json['data'][1]['id'] == '50632:ACCMAT:2020-10-26'
    assert resp.json['data'][2]['id'] == '50632:ECOLELEM:2020-10-26'
    assert resp.json['data'][3]['id'] == '50632:ETUDES:2020-10-26'
    assert resp.json['data'][4]['id'] == '50632:GARDERIES:2020-10-26'
    assert resp.json['data'][5]['id'] == '50632:NAV SOIR:2020-10-26'
    assert resp.json['data'][6]['id'] == '50632:CJ MER:2020-10-26'
    assert resp.json['data'][7]['id'] == '50632:CJ1:2020-10-26'
    assert resp.json['data'][8]['id'] == '50632:NAV MATIN:2020-10-27'
    assert resp.json['data'][9]['id'] == '50632:ACCMAT:2020-10-27'
    assert resp.json['data'][10]['id'] == '50632:ECOLELEM:2020-10-27'
    assert resp.json['data'][11]['id'] == '50632:ETUDES:2020-10-27'
    assert resp.json['data'][12]['id'] == '50632:GARDERIES:2020-10-27'
    assert resp.json['data'][13]['id'] == '50632:NAV SOIR:2020-10-27'
    assert resp.json['data'][14]['id'] == '50632:CJ MER:2020-10-27'
    assert resp.json['data'][15]['id'] == '50632:CJ1:2020-10-27'
    assert resp.json['data'][16]['id'] == '50632:NAV MATIN:2020-10-28'
    assert resp.json['data'][17]['id'] == '50632:ACCMAT:2020-10-28'
    assert resp.json['data'][18]['id'] == '50632:ECOLELEM:2020-10-28'
    assert resp.json['data'][19]['id'] == '50632:ETUDES:2020-10-28'
    assert resp.json['data'][20]['id'] == '50632:GARDERIES:2020-10-28'
    assert resp.json['data'][21]['id'] == '50632:NAV SOIR:2020-10-28'
    assert resp.json['data'][22]['id'] == '50632:CJ MER:2020-10-28'
    assert resp.json['data'][23]['id'] == '50632:CJ1:2020-10-28'
    assert resp.json['data'][24]['id'] == '50632:NAV MATIN:2020-10-29'
    assert resp.json['data'][25]['id'] == '50632:ACCMAT:2020-10-29'
    assert resp.json['data'][26]['id'] == '50632:ECOLELEM:2020-10-29'
    assert resp.json['data'][27]['id'] == '50632:ETUDES:2020-10-29'
    assert resp.json['data'][28]['id'] == '50632:GARDERIES:2020-10-29'
    assert resp.json['data'][29]['id'] == '50632:NAV SOIR:2020-10-29'
    assert resp.json['data'][30]['id'] == '50632:CJ MER:2020-10-29'
    assert resp.json['data'][31]['id'] == '50632:CJ1:2020-10-29'
    assert resp.json['data'][32]['id'] == '50632:NAV MATIN:2020-10-30'
    assert resp.json['data'][33]['id'] == '50632:ACCMAT:2020-10-30'
    assert resp.json['data'][34]['id'] == '50632:ECOLELEM:2020-10-30'
    assert resp.json['data'][35]['id'] == '50632:ETUDES:2020-10-30'
    assert resp.json['data'][36]['id'] == '50632:GARDERIES:2020-10-30'
    assert resp.json['data'][37]['id'] == '50632:NAV SOIR:2020-10-30'
    assert resp.json['data'][38]['id'] == '50632:CJ MER:2020-10-30'
    assert resp.json['data'][39]['id'] == '50632:CJ1:2020-10-30'


@freezegun.freeze_time('2020-09-01')
def test_set_agenda_endpoint_axel_error(app, resource, family_data, activities, booking_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    booking_params['booking_list'] = ['50632:ELEM:2020-10-30']
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.side_effect = AxelError('FooBar')
                    resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_set_agenda_endpoint_no_result(app, resource, booking_params):
    booking_params['child_id'] = 'zzz'
    resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params)
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'


def test_set_agenda_endpoint_date_error(app, resource, booking_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        booking_params['start_date'] = '2021-09-01'
        booking_params['end_date'] = '2021-08-31'
        resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params, status=400)
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        booking_params['end_date'] = '2022-09-01'
        resp = app.post_json('/caluire-axel/test/set_agenda?NameID=yyy', params=booking_params, status=400)
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_set_agenda_endpoint(app, resource, family_data, activities, booking_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    booking_params['end_date'] = '2020-09-01'
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value=activities,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=[],
            ):
                resp = app.post_json(
                    '/caluire-axel/test/set_agenda?NameID=yyy',
                    params=booking_params,
                )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 0


@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_multi(app, resource, family_data, booking_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ECOLELEM',
            'LIBELLEACTIVITE': 'Cantine',
        },
    ]
    booking_params['end_date'] = '2020-09-11'
    booking_params['booking_list'] = [
        '50632:ACCMAT:2020-09-07',
        '50632:ACCMAT:2020-09-08',
        '50632:ECOLELEM:2020-09-07',
        '50632:ECOLELEM:2020-09-10',
    ]
    bookings = []
    for activity_id in ['ACCMAT', 'ECOLELEM']:
        for day in ['2020-09-07', '2020-09-08']:
            bookings.append(
                {
                    'id': '50632:%s:%s' % (activity_id, day),
                    'disabled': False,
                    'prefill': False,
                }
            )
        for day in ['2020-09-10', '2020-09-11']:
            bookings.append(
                {
                    'id': '50632:%s:%s' % (activity_id, day),
                    'disabled': False,
                    'prefill': True,
                }
            )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda?NameID=yyy',
                        params=booking_params,
                    )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 6
    assert resp.json['changes'] == [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-07', 'booked': True},
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-08', 'booked': True},
        {'activity_id': 'ECOLELEM', 'activity_label': 'Cantine', 'day': '2020-09-07', 'booked': True},
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-10', 'booked': False},
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-11', 'booked': False},
        {'activity_id': 'ECOLELEM', 'activity_label': 'Cantine', 'day': '2020-09-11', 'booked': False},
    ]

    assert len(operation.call_args_list) == 2
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'ACCMAT'
    assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 4
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
        == '2020-09-07'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['JOURDATE']
        == '2020-09-08'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['MATIN'] == 'X'
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][2]['JOURDATE']
        == '2020-09-10'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][2]['MATIN'] == 'D'
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][3]['JOURDATE']
        == '2020-09-11'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][3]['MATIN'] == 'D'

    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'ECOLELEM'
    )
    assert len(operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 2
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
        == '2020-09-07'
    )
    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['JOURDATE']
        == '2020-09-11'
    )
    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['MATIN'] == 'D'


@pytest.mark.parametrize(
    'booked, ok',
    [
        ([], True),
        (['50632:ACCMAT:2020-09-07', '50632:CANTINE:2020-09-07'], True),  # cantine & accmat are not exlusive
        (['50632:ACCMAT:2020-09-07', '50632:ACCMAT:2020-09-07'], True),  # same day sent twice
        (['50642:ACCMAT:2020-09-07', '50632:NAV MATIN:2020-09-07'], True),  # not the same child
        (['50632:ACCMAT:2020-09-07', '50632:NAV MATIN:2020-09-07'], False),
    ],
)
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_multi_matin(app, resource, family_data, booking_params, booked, ok):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'CANTINE',
            'LIBELLEACTIVITE': 'Cantine',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'NAV MATIN',
            'LIBELLEACTIVITE': 'Navette du matin',
        },
    ]
    booking_params['end_date'] = '2020-09-07'
    booking_params['booking_list'] = booked
    bookings = []
    for activity_id in ['ACCMAT', 'CANTINE', 'NAV MATIN']:
        bookings.append(
            {
                'id': '50632:%s:2020-09-07' % activity_id,
                'disabled': False,
                'prefill': False,
            }
        )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    if ok:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
                        assert resp.json['err'] == 0
                    else:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                            status=400,
                        )
                        assert resp.json['err_desc'] == "not possible to book %s the same day" % ' and '.join(
                            booked
                        )
                        assert resp.json['err'] == 'bad-request'


@pytest.mark.parametrize('prefill', [True, False])
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_multi_matin_no_changes(app, resource, family_data, booking_params, prefill):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'NAV MATIN',
            'LIBELLEACTIVITE': 'Navette du matin',
        },
    ]
    booking_params['end_date'] = '2020-09-07'
    booking_params['booking_list'] = ['50632:ACCMAT:2020-09-07', '50632:NAV MATIN:2020-09-07']
    bookings = []
    for activity_id in ['ACCMAT', 'NAV MATIN']:
        bookings.append(
            {
                'id': '50632:%s:2020-09-07' % activity_id,
                'disabled': False,
                'prefill': prefill,
            }
        )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    if prefill:
                        # was already booked, no changes => no error
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
                        assert resp.json['err'] == 0
                    else:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                            status=400,
                        )
                        assert resp.json['err_desc'] == "not possible to book %s the same day" % ' and '.join(
                            booking_params['booking_list']
                        )
                        assert resp.json['err'] == 'bad-request'


@pytest.mark.parametrize(
    'booked, ok',
    [
        ([], True),
        (['50632:ETUDES:2020-09-07', '50632:CANTINE:2020-09-07'], True),  # cantine & etudes are not exlusive
        (['50632:GARDERIES:2020-09-07', '50632:GARDERIES:2020-09-07'], True),  # same day sent twice
        (['50632:ETUDES:2020-09-07', '50642:GARDERIES:2020-09-07'], True),  # not the same child
        (['50632:ETUDES:2020-09-07', '50632:GARDERIES:2020-09-07'], False),
        (['50632:ETUDES:2020-09-07', '50632:NAV SOIR:2020-09-07'], False),
        (['50632:GARDERIES:2020-09-07', '50632:NAV SOIR:2020-09-07'], False),
        (['50632:ETUDES:2020-09-07', '50632:GARDERIES:2020-09-07', '50632:NAV SOIR:2020-09-07'], False),
    ],
)
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_multi_soir(app, resource, family_data, booking_params, booked, ok):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'CANTINE',
            'LIBELLEACTIVITE': 'Cantine',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'GARDERIES',
            'LIBELLEACTIVITE': 'Garderie',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ETUDES',
            'LIBELLEACTIVITE': 'Etudes',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'NAV SOIR',
            'LIBELLEACTIVITE': 'Navette du soir',
        },
    ]
    booking_params['end_date'] = '2020-09-07'
    booking_params['booking_list'] = booked
    bookings = []
    for activity_id in ['GARDERIES', 'ETUDES', 'CANTINE', 'NAV SOIR']:
        bookings.append(
            {
                'id': '50632:%s:2020-09-07' % activity_id,
                'disabled': False,
                'prefill': False,
            }
        )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    if ok:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
                        assert resp.json['err'] == 0
                    else:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                            status=400,
                        )
                        assert resp.json['err_desc'] == "not possible to book %s the same day" % ' and '.join(
                            booked
                        )
                        assert resp.json['err'] == 'bad-request'


@pytest.mark.parametrize('prefill', [True, False])
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_multi_soir_no_changes(app, resource, family_data, booking_params, prefill):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'GARDERIES',
            'LIBELLEACTIVITE': 'Garderie',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ETUDES',
            'LIBELLEACTIVITE': 'Etudes',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'NAV SOIR',
            'LIBELLEACTIVITE': 'Navette du soir',
        },
    ]
    booking_params['end_date'] = '2020-09-07'
    booking_params['booking_list'] = [
        '50632:ETUDES:2020-09-07',
        '50632:GARDERIES:2020-09-07',
        '50632:NAV SOIR:2020-09-07',
    ]
    bookings = []
    for activity_id in ['GARDERIES', 'ETUDES', 'NAV SOIR']:
        bookings.append(
            {
                'id': '50632:%s:2020-09-07' % activity_id,
                'disabled': False,
                'prefill': prefill,
            }
        )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    if prefill:
                        # was already booked, no changes => no error
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
                        assert resp.json['err'] == 0
                    else:
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                            status=400,
                        )
                        assert resp.json['err_desc'] == "not possible to book %s the same day" % ' and '.join(
                            booking_params['booking_list']
                        )
                        assert resp.json['err'] == 'bad-request'


@pytest.mark.parametrize(
    'prefill, wanted, expected',
    [
        (True, True, None),  # no changes
        (True, False, False),
        (False, True, True),
        (False, False, None),  # no changes
    ],
)
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_prefill_periscolaire(
    app, resource, family_data, booking_params, prefill, wanted, expected
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    booking_params['end_date'] = '2020-09-01'
    for activity_id in ['ACCMAT', 'GARDERIES', 'ETUDES', 'CANTINE', 'FOOBAR', 'NAV MATIN', 'NAV SOIR']:
        activity = {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': activity_id,
            'LIBELLEACTIVITE': 'FOOBAR',
        }
        if wanted:
            booking_params['booking_list'] = ['50632:%s:2020-09-01' % activity_id]
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value={'ACTIVITE': [activity]},
            ):
                bookings = [
                    {
                        'id': '50632:%s:2020-09-01' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                ]
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                        operation.return_value = OperationResult(
                            json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                            xml_request='',
                            xml_response='',
                        )
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
        assert resp.json['err'] == 0
        assert resp.json['updated'] is True
        if expected is not None:
            assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
            assert (
                operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE']
                == activity_id
            )
            assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
            assert (
                operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
                == '2020-09-01'
            )
            assert (
                operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN']
                == 'X'
                if expected
                else 'D'
            )
        else:
            assert len(operation.call_args_list) == 0


@pytest.mark.parametrize('prefill', [True, False])
@pytest.mark.parametrize('wanted', [True, False])
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_prefill_extrascolaire(
    app, resource, family_data, booking_params, prefill, wanted
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    booking_params['end_date'] = '2020-09-01'
    for activity_id in ['CJ MER', 'CJVACANCES']:
        activity = {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': activity_id,
            'LIBELLEACTIVITE': 'FOOBAR',
        }
        if wanted:
            booking_params['booking_list'] = ['50632:%s:2020-09-01' % activity_id]
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value={'ACTIVITE': [activity]},
            ):
                bookings = [
                    {
                        'id': '50632:%s:2020-09-01' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                ]
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                        operation.return_value = OperationResult(
                            json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                            xml_request='',
                            xml_response='',
                        )
                        resp = app.post_json(
                            '/caluire-axel/test/set_agenda?NameID=yyy',
                            params=booking_params,
                        )
        assert resp.json['err'] == 0
        assert resp.json['updated'] is True
        assert len(operation.call_args_list) == 0  # not bookable


@pytest.mark.parametrize('disabled', [True, False, None])
@freezegun.freeze_time('2020-08-01')
def test_set_agenda_endpoint_disabled(app, resource, family_data, booking_params, disabled):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activity = {
        'ENTREE': '2020-09-02',
        'SORTIE': '2021-08-31',
        'IDENTACTIVITE': 'FOOBAR',
        'LIBELLEACTIVITE': 'FOOBAR',
    }
    booking_params['end_date'] = '2020-09-01'
    booking_params['booking_list'] = ['50632:FOOBAR:2020-09-01']
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': [activity]},
        ):
            bookings = []
            if disabled is not None:
                bookings = [
                    {
                        'id': '50632:FOOBAR:2020-09-01',
                        'disabled': disabled,
                        'prefill': False,
                    },
                ]
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda?NameID=yyy',
                        params=booking_params,
                    )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    if disabled is False:
        assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'FOOBAR'
        )
        assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
            == '2020-09-01'
        )
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'
        )
    else:
        assert len(operation.call_args_list) == 0


@pytest.mark.parametrize('code', [-1, -2, -3, -4])
def test_set_agenda_endpoint_wrong_code(app, resource, family_data, activities, booking_params, code):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    booking_params['end_date'] = '2020-09-01'
    bookings = [
        {
            'id': '50632:ELEM:2020-09-01',
            'disabled': False,
            'prefill': True,
        },
    ]
    content = (
        '''<PORTAIL>
    <SETAGENDA>
        <CODE>%s</CODE>
    </SETAGENDA>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'SetAgenda', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda?NameID=yyy',
                        params=booking_params,
                    )
    assert resp.json['err_desc'] == "Wrong agenda status"
    assert resp.json['err'] == 'agenda-code-error-%s' % code


@freezegun.freeze_time('2020-09-01')
def test_set_agenda_apply_changes_endpoint_axel_error(app, resource, family_data, changes_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    changes_params['changes'] = [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-10-30', 'booked': True},
    ]
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json('/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json(
                '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.post_json(
                    '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params
                )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
    ]
    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>30/10/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value={'ACTIVITE': activities},
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.side_effect = AxelError('FooBar')
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params
                    )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_set_agenda_apply_changes_endpoint_no_result(app, resource, changes_params):
    changes_params['child_id'] = 'zzz'
    resp = app.post_json('/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.post_json('/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params)
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'


def test_set_agenda_apply_changes_endpoint_date_error(app, resource, changes_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        changes_params['start_date'] = '2021-09-01'
        changes_params['end_date'] = '2021-08-31'
        resp = app.post_json(
            '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params, status=400
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        changes_params['end_date'] = '2022-09-01'
        resp = app.post_json(
            '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy', params=changes_params, status=400
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_set_agenda_apply_changes_endpoint(app, resource, family_data, activities, changes_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    changes_params['end_date'] = '2020-09-01'
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value=activities,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=[],
            ):
                resp = app.post_json(
                    '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                    params=changes_params,
                )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 0


@freezegun.freeze_time('2020-08-01')
def test_set_agenda_apply_changes_endpoint_multi(app, resource, family_data, changes_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ECOLELEM',
            'LIBELLEACTIVITE': 'Cantine',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'CJ MER',
            'LIBELLEACTIVITE': 'FOOBAR',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'CJVACANCES',
            'LIBELLEACTIVITE': 'FOOBAR',
        },
    ]
    changes_params['end_date'] = '2020-09-11'
    changes_params['changes'] = [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-07', 'booked': False},
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-08', 'booked': True},
        {
            'activity_id': 'ECOLELEM2',
            'activity_label': 'Cantine',
            'day': '2020-09-07',
            'booked': True,
        },  # cantine, not the same id
        {
            'activity_id': 'ECOLELEM2',
            'activity_label': 'Cantine',
            'day': '2020-09-10',
            'booked': False,
        },  # cantine, not the same id
        {'activity_id': 'CJ MER', 'activity_label': 'FOOBAR', 'day': '2020-09-08', 'booked': True},  # ignored
        {
            'activity_id': 'CJVACANCES',
            'activity_label': 'FOOBAR',
            'day': '2020-09-08',
            'booked': True,
        },  # ignored
    ]
    bookings = []
    for activity_id in ['ACCMAT', 'ECOLELEM']:
        for day in ['2020-09-07', '2020-09-08']:
            bookings.append(
                {
                    'id': '50632:%s:%s' % (activity_id, day),
                    'disabled': False,
                    'prefill': False,
                }
            )
        for day in ['2020-09-10', '2020-09-11']:
            bookings.append(
                {
                    'id': '50632:%s:%s' % (activity_id, day),
                    'disabled': False,
                    'prefill': True,
                }
            )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                        params=changes_params,
                    )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 3
    assert resp.json['changes'] == [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-08', 'booked': True},
        {'activity_id': 'ECOLELEM', 'activity_label': 'Cantine', 'day': '2020-09-07', 'booked': True},
        {'activity_id': 'ECOLELEM', 'activity_label': 'Cantine', 'day': '2020-09-10', 'booked': False},
    ]

    assert len(operation.call_args_list) == 2
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'ACCMAT'
    assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
        == '2020-09-08'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'

    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'ECOLELEM'
    )
    assert len(operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 2
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
        == '2020-09-07'
    )
    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'
    assert (
        operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['JOURDATE']
        == '2020-09-10'
    )
    assert operation.call_args_list[1][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][1]['MATIN'] == 'D'


@freezegun.freeze_time('2020-08-01')
def test_set_agenda_apply_changes_endpoint_multi_too_many_cantine_activities(
    app, resource, family_data, changes_params
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    # more than one activity "midi"
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ECOLELEM',
            'LIBELLEACTIVITE': 'Cantine',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ECOLELEM2',
            'LIBELLEACTIVITE': 'Cantine',
        },
    ]
    changes_params['end_date'] = '2020-09-11'
    changes_params['changes'] = [
        {
            'activity_id': 'ECOLELEM2',
            'activity_label': 'Cantine',
            'day': '2020-09-07',
            'booked': True,
        },
    ]
    bookings = [
        {
            'id': '50632:MIDI:2020-09-07',
            'disabled': False,
            'prefill': False,
        },
    ]
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                        params=changes_params,
                        status=400,
                    )
                    assert (
                        resp.json['err_desc']
                        == "more than one activity cantine found for this child (ECOLELEM, ECOLELEM2)"
                    )
                    assert resp.json['err'] == 'bad-request'


@freezegun.freeze_time('2020-08-01')
def test_set_agenda_apply_changes_endpoint_multi_unkown_activity(app, resource, family_data, changes_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ACCMAT',
            'LIBELLEACTIVITE': 'Matin',
        },
    ]
    changes_params['end_date'] = '2020-09-11'
    changes_params['changes'] = [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-07', 'booked': False},
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-08', 'booked': True},
        {
            'activity_id': 'ECOLELEM2',
            'activity_label': 'Cantine',
            'day': '2020-09-07',
            'booked': True,
        },  # cantine, child is not registered
        {
            'activity_id': 'ECOLELEM2',
            'activity_label': 'Cantine',
            'day': '2020-09-10',
            'booked': False,
        },  # cantine, child is not registered
    ]
    bookings = []
    for day in ['2020-09-07', '2020-09-08']:
        bookings.append(
            {
                'id': '50632:ACCMAT:%s' % day,
                'disabled': False,
                'prefill': False,
            }
        )
    for day in ['2020-09-10', '2020-09-11']:
        bookings.append(
            {
                'id': '50632:ACCMAT:%s' % day,
                'disabled': False,
                'prefill': True,
            }
        )
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                        params=changes_params,
                    )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 1
    assert resp.json['changes'] == [
        {'activity_id': 'ACCMAT', 'activity_label': 'Matin', 'day': '2020-09-08', 'booked': True},
    ]

    assert len(operation.call_args_list) == 1
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'ACCMAT'
    assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
    assert (
        operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
        == '2020-09-08'
    )
    assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'


@freezegun.freeze_time('2020-08-01')
def test_set_agenda_apply_changes_endpoint_multi_soir(app, resource, family_data, changes_params):
    # just a little check, booking exclusivity is handled by _set_agenda method,
    # already tested for set_agenda endpoint
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activities = [
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'GARDERIES',
            'LIBELLEACTIVITE': 'Garderie',
        },
        {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': 'ETUDES',
            'LIBELLEACTIVITE': 'Etudes',
        },
    ]
    changes_params['end_date'] = '2020-09-11'
    changes_params['changes'] = [
        {'activity_id': 'GARDERIES', 'activity_label': 'Garderie', 'day': '2020-09-07', 'booked': True},
    ]
    bookings = [
        {
            'id': '50632:GARDERIES:2020-09-07',
            'disabled': False,
            'prefill': False,
        },
        {
            'id': '50632:ETUDES:2020-09-07',
            'disabled': False,
            'prefill': True,
        },
    ]
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                        params=changes_params,
                        status=400,
                    )
                    assert (
                        resp.json['err_desc']
                        == "not possible to book 50632:ETUDES:2020-09-07 and 50632:GARDERIES:2020-09-07 the same day"
                    )
                    assert resp.json['err'] == 'bad-request'

    # already booked, no error
    bookings = [
        {
            'id': '50632:GARDERIES:2020-09-07',
            'disabled': False,
            'prefill': True,
        },
        {
            'id': '50632:ETUDES:2020-09-07',
            'disabled': False,
            'prefill': True,
        },
    ]
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': activities},
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_agenda_apply_changes?NameID=yyy',
                        params=changes_params,
                    )
                    assert resp.json['err'] == 0


@freezegun.freeze_time('2020-08-01')
def test_set_activity_agenda_typical_week_endpoint_axel_error(
    app, resource, family_data, activities, week_booking_params
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    week_booking_params['booking_list'] = ['monday']
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json(
            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy', params=week_booking_params
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_activites') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json(
                '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy', params=week_booking_params
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/activities_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetListActivites'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch('passerelle.contrib.caluire_axel.schemas.get_agenda') as operation:
                operation.side_effect = AxelError('FooBar')
                resp = app.post_json(
                    '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                    params=week_booking_params,
                )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    content = '''<PORTAIL>
    <GETAGENDA>
        <CODE>1</CODE>
        <JOUR>
          <JOURDATE>07/09/2020</JOURDATE>
          <MATIN>.</MATIN>
          <MIDI></MIDI>
          <APRESMIDI></APRESMIDI>
          <FERME>N</FERME>
        </JOUR>
    </GETAGENDA>
</PORTAIL>'''
    with mock_data(content, 'GetAgenda'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.side_effect = AxelError('FooBar')
                    resp = app.post_json(
                        '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                        params=week_booking_params,
                    )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_set_activity_agenda_typical_week_endpoint_no_result(app, resource, week_booking_params):
    week_booking_params['child_id'] = 'zzz'
    resp = app.post_json(
        '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy', params=week_booking_params
    )
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        resp = app.post_json(
            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy', params=week_booking_params
        )
        assert resp.json['err_desc'] == "Child not found"
        assert resp.json['err'] == 'not-found'


def test_set_activity_agenda_typical_week_endpoint_date_error(app, resource, week_booking_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/family_info.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'GetFamilleIndividus'):
        week_booking_params['start_date'] = '2021-09-01'
        week_booking_params['end_date'] = '2021-08-31'
        resp = app.post_json(
            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
            params=week_booking_params,
            status=400,
        )
        assert resp.json['err_desc'] == "start_date should be before end_date"
        assert resp.json['err'] == 'bad-request'

        week_booking_params['end_date'] = '2022-09-01'
        resp = app.post_json(
            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
            params=week_booking_params,
            status=400,
        )
        assert (
            resp.json['err_desc'] == "start_date and end_date are in different reference year (2021 != 2022)"
        )
        assert resp.json['err'] == 'bad-request'


def test_set_activity_agenda_typical_week_endpoint(
    app, resource, family_data, activities, week_booking_params
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value=activities,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=[],
            ):
                resp = app.post_json(
                    '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                    params=week_booking_params,
                )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    assert resp.json['count'] == 0


@pytest.mark.parametrize('prefill', [True, False])
@freezegun.freeze_time('2020-08-01')
def test_set_activity_agenda_typical_week_endpoint_prefill_periscolaire(
    app, resource, family_data, week_booking_params, prefill
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    for activity_id in ['ACCMAT', 'GARDERIES', 'ETUDES', 'CANTINE', 'FOOBAR', 'NAV MATIN', 'NAV SOIR']:
        activity = {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': activity_id,
            'LIBELLEACTIVITE': 'FOOBAR',
        }
        week_booking_params['booking_list'] = ['monday']
        week_booking_params['activity_id'] = activity_id
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value={'ACTIVITE': [activity]},
            ):
                bookings = [
                    {
                        'id': '50632:%s:2020-09-07' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                    {
                        'id': '50632:%s:2020-09-08' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                    {
                        'id': '50632:%s:2020-09-10' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                    {
                        'id': '50632:%s:2020-09-11' % activity_id,
                        'disabled': False,
                        'prefill': prefill,
                    },
                ]
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                        operation.return_value = OperationResult(
                            json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                            xml_request='',
                            xml_response='',
                        )
                        resp = app.post_json(
                            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                            params=week_booking_params,
                        )
        assert resp.json['err'] == 0
        assert resp.json['updated'] is True
        assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE']
            == activity_id
        )
        if prefill is True:
            assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 3
            for i, day in enumerate(['2020-09-08', '2020-09-10', '2020-09-11']):
                assert (
                    operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][i][
                        'JOURDATE'
                    ]
                    == day
                )
                assert (
                    operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][i]['MATIN']
                    == 'D'
                )
        else:
            assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
            assert (
                operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
                == '2020-09-07'
            )
            assert (
                operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN']
                == 'X'
            )


@freezegun.freeze_time('2020-08-01')
def test_set_activity_agenda_typical_week_endpoint_extrascolaire(
    app,
    resource,
    family_data,
    week_booking_params,
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    for activity_id in ['CJ MER', 'CJVACANCES']:
        activity = {
            'ENTREE': '2020-09-02',
            'SORTIE': '2021-08-31',
            'IDENTACTIVITE': activity_id,
            'LIBELLEACTIVITE': 'FOOBAR',
        }
        week_booking_params['booking_list'] = ['monday']
        week_booking_params['activity_id'] = activity_id
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value={'ACTIVITE': [activity]},
            ):
                bookings = [
                    {
                        'id': '50632:%s:2020-09-07' % activity_id,
                        'disabled': False,
                        'prefill': False,
                    },
                ]
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                        operation.return_value = OperationResult(
                            json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                            xml_request='',
                            xml_response='',
                        )
                        resp = app.post_json(
                            '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                            params=week_booking_params,
                            status=400,
                        )
        assert resp.json['err_desc'] == "Not available for this activity"
        assert resp.json['err'] == 'bad-request'


@pytest.mark.parametrize('disabled', [True, False, None])
@freezegun.freeze_time('2020-08-01')
def test_set_activity_agenda_typical_week_endpoint_disabled(
    app, resource, family_data, week_booking_params, disabled
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    activity = {
        'ENTREE': '2020-09-02',
        'SORTIE': '2021-08-31',
        'IDENTACTIVITE': 'FOOBAR',
        'LIBELLEACTIVITE': 'FOOBAR',
    }
    week_booking_params['booking_list'] = ['monday']
    week_booking_params['activity_id'] = 'FOOBAR'
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
            return_value={'ACTIVITE': [activity]},
        ):
            bookings = []
            if disabled is not None:
                bookings = [
                    {
                        'id': '50632:FOOBAR:2020-09-07',
                        'disabled': disabled,
                        'prefill': False,
                    },
                ]
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                return_value=bookings,
            ):
                with mock.patch('passerelle.contrib.caluire_axel.schemas.set_agenda') as operation:
                    operation.return_value = OperationResult(
                        json_response={'DATA': {'PORTAIL': {'SETAGENDA': {'CODE': 0}}}},
                        xml_request='',
                        xml_response='',
                    )
                    resp = app.post_json(
                        '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                        params=week_booking_params,
                    )
    assert resp.json['err'] == 0
    assert resp.json['updated'] is True
    if disabled is False:
        assert operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['IDENTINDIVIDU'] == '50632'
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['IDENTACTIVITE'] == 'FOOBAR'
        )
        assert len(operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR']) == 1
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['JOURDATE']
            == '2020-09-07'
        )
        assert (
            operation.call_args_list[0][0][1]['PORTAIL']['SETAGENDA']['ACTIVITE']['JOUR'][0]['MATIN'] == 'X'
        )
    else:
        assert len(operation.call_args_list) == 0


@pytest.mark.parametrize('code', [-1, -2, -3, -4])
def test_set_activity_agenda_typical_week_endpoint_wrong_code(
    app, resource, family_data, activities, week_booking_params, code
):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    bookings = [
        {
            'id': '50632:ELEM:2020-09-07',
            'disabled': False,
            'prefill': True,
        },
    ]
    content = (
        '''<PORTAIL>
    <SETAGENDA>
        <CODE>%s</CODE>
    </SETAGENDA>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'SetAgenda', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            with mock.patch(
                'passerelle.contrib.caluire_axel.models.CaluireAxel.get_child_activities',
                return_value=activities,
            ):
                with mock.patch(
                    'passerelle.contrib.caluire_axel.models.CaluireAxel.get_bookings',
                    return_value=bookings,
                ):
                    resp = app.post_json(
                        '/caluire-axel/test/set_activity_agenda_typical_week?NameID=yyy',
                        params=week_booking_params,
                    )
    assert resp.json['err_desc'] == "Wrong agenda status"
    assert resp.json['err'] == 'agenda-code-error-%s' % code


def test_invoices_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_factures_a_payer') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices?NameID=yyy')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    content = '''<PORTAIL>
    <GETFACTURESAPAYER>
        <CODE>-3</CODE>
    </GETFACTURESAPAYER>
</PORTAIL>'''
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices?NameID=yyy')
    assert resp.json['err_desc'] == "Wrong get-invoices status"
    assert resp.json['err'] == 'get-invoices-code-error--3'


def test_invoices_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices?NameID=yyy')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_invoices_endpoint_no_invoice(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETFACTURESAPAYER>
        <CODE>0</CODE>
    </GETFACTURESAPAYER>
</PORTAIL>'''
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == []


@freezegun.freeze_time('2019-12-12')
def test_invoices_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''
<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {
            'id': 'XXX-42',
            'display_id': '42',
            'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
            'amount': '4.94',
            'total_amount': '44.94',
            'amount_paid': '40.00',
            'online_payment': False,
            'created': '2019-11-12',
            'pay_limit_date': '2019-12-04',
            'has_pdf': True,
            'paid': False,
            'vendor': {
                'caluire-axel': {
                    'IDFACTURE': 42,
                    'MONTANT': '44.94',
                    'ENCAISSE': '40.00',
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                    'ECHEANCE': '2019-12-04',
                    'EMISSION': '2019-11-12',
                    'EXISTEPDF': True,
                }
            },
        },
        {
            'id': 'XXX-43',
            'display_id': '43',
            'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
            'amount': '44.94',
            'total_amount': '44.94',
            'amount_paid': '0.00',
            'online_payment': True,
            'created': '2019-12-12',
            'pay_limit_date': '2020-01-04',
            'has_pdf': False,
            'paid': False,
            'vendor': {
                'caluire-axel': {
                    'IDFACTURE': 43,
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
                    'MONTANT': '44.94',
                    'ENCAISSE': '0.00',
                    'ECHEANCE': '2020-01-04',
                    'EMISSION': '2019-12-12',
                    'EXISTEPDF': False,
                }
            },
        },
    ]


def test_invoices_history_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_factures') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    content = '''<PORTAIL>
    <GETLISTFACTURES>
        <CODE>-3</CODE>
    </GETLISTFACTURES>
</PORTAIL>'''
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
    assert resp.json['err_desc'] == "Wrong get-historical-invoices status"
    assert resp.json['err'] == 'get-historical-invoices-code-error--3'


def test_invoices_history_endpoint_bad_request(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock_data(None, 'GetListFactures'):
        resp = app.get(
            '/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy&nb_mounts_limit=not_a_number',
            status=400,
        )
    assert resp.json['err_desc'] == "nb_mounts_limit must be an integer"
    assert resp.json['err'] == 'bad-request'


def test_invoices_history_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'


def test_invoices_history_endpoint_no_invoice(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    content = '''<PORTAIL>
    <GETLISTFACTURES>
        <CODE>0</CODE>
    </GETLISTFACTURES>
</PORTAIL>'''
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == []


@freezegun.freeze_time('2019-12-12')
def test_invoices_history_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''<PORTAIL>
    <GETLISTFACTURES>
        %s
    </GETLISTFACTURES>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == [
        {
            'id': 'historical-XXX-42',
            'display_id': '42',
            'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
            'amount': 0,
            'created': '2019-11-12',
            'total_amount': '44.94',
            'online_payment': False,
            'pay_limit_date': '',
            'has_pdf': True,
            'paid': False,
            'vendor': {
                'caluire-axel': {
                    'IDFACTURE': 42,
                    'MONTANT': '44.94',
                    'ENCAISSE': '40.00',
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                    'ECHEANCE': '2019-12-04',
                    'EMISSION': '2019-11-12',
                    'EXISTEPDF': True,
                }
            },
        },
        {
            'id': 'historical-XXX-43',
            'display_id': '43',
            'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
            'amount': 0,
            'created': '2019-12-12',
            'total_amount': '44.94',
            'online_payment': False,
            'pay_limit_date': '',
            'has_pdf': False,
            'paid': False,
            'vendor': {
                'caluire-axel': {
                    'IDFACTURE': 43,
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
                    'MONTANT': '44.94',
                    'ENCAISSE': '0.00',
                    'ECHEANCE': '2020-01-04',
                    'EMISSION': '2019-12-12',
                    'EXISTEPDF': False,
                }
            },
        },
    ]


def test_invoice_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_factures_a_payer') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_invoice_endpoint_bad_request(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock_data(None, 'GetListFactures'):
        resp = app.get(
            '/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42?NameID=yyy&nb_mounts_limit=not_a_number',
            status=400,
        )
    assert resp.json['err_desc'] == "nb_mounts_limit must be an integer"
    assert resp.json['err'] == 'bad-request'

    content = '''<PORTAIL>
    <GETFACTURESAPAYER>
        <CODE>-3</CODE>
    </GETFACTURESAPAYER>
</PORTAIL>'''
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
    assert resp.json['err_desc'] == "Wrong get-invoices status"
    assert resp.json['err'] == 'get-invoices-code-error--3'

    content = '''<PORTAIL>
    <GETLISTFACTURES>
        <CODE>-3</CODE>
    </GETLISTFACTURES>
</PORTAIL>'''
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42?NameID=yyy')
    assert resp.json['err_desc'] == "Wrong get-historical-invoices status"
    assert resp.json['err'] == 'get-historical-invoices-code-error--3'


@freezegun.freeze_time('2019-12-12')
def test_invoice_endpoint_no_result(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        invoices = xml.read()
    content = (
        '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-35?NameID=yyy')
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-44?NameID=yyy')
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    content = (
        '''<PORTAIL>
    <GETLISTFACTURES>
        %s
    </GETLISTFACTURES>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-35?NameID=yyy')
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-44?NameID=yyy')
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'


@freezegun.freeze_time('2019-12-04')
def test_invoice_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        invoices = xml.read()
    content = (
        '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'id': 'XXX-42',
        'display_id': '42',
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
        'amount': '4.94',
        'total_amount': '44.94',
        'amount_paid': '40.00',
        'online_payment': True,
        'created': '2019-11-12',
        'pay_limit_date': '2019-12-04',
        'has_pdf': True,
        'paid': False,
        'vendor': {
            'caluire-axel': {
                'IDFACTURE': 42,
                'MONTANT': '44.94',
                'ENCAISSE': '40.00',
                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                'ECHEANCE': '2019-12-04',
                'EMISSION': '2019-11-12',
                'EXISTEPDF': True,
            }
        },
    }

    content = (
        '''<PORTAIL>
    <GETLISTFACTURES>
        %s
    </GETLISTFACTURES>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42?NameID=yyy')
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'id': 'historical-XXX-42',
        'display_id': '42',
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
        'amount': 0,
        'total_amount': '44.94',
        'online_payment': False,
        'created': '2019-11-12',
        'pay_limit_date': '',
        'has_pdf': True,
        'paid': False,
        'vendor': {
            'caluire-axel': {
                'IDFACTURE': 42,
                'MONTANT': '44.94',
                'ENCAISSE': '40.00',
                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                'ECHEANCE': '2019-12-04',
                'EMISSION': '2019-11-12',
                'EXISTEPDF': True,
            },
        },
    }


@freezegun.freeze_time('2019-12-04')
def test_invoice_endpoint_anonymously(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        invoices = xml.read()
    content = (
        '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42')
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'id': 'XXX-42',
        'display_id': '42',
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
        'amount': '4.94',
        'total_amount': '44.94',
        'amount_paid': '40.00',
        'online_payment': True,
        'created': '2019-11-12',
        'pay_limit_date': '2019-12-04',
        'has_pdf': True,
        'paid': False,
        'vendor': {
            'caluire-axel': {
                'IDFACTURE': 42,
                'MONTANT': '44.94',
                'ENCAISSE': '40.00',
                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                'ECHEANCE': '2019-12-04',
                'EMISSION': '2019-11-12',
                'EXISTEPDF': True,
            }
        },
    }

    content = (
        '''<PORTAIL>
    <GETLISTFACTURES>
        %s
    </GETLISTFACTURES>
</PORTAIL>'''
        % invoices
    )
    with mock_data(content, 'GetListFactures'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42')
    assert resp.json['err'] == 0
    assert resp.json['data'] == {
        'id': 'historical-XXX-42',
        'display_id': '42',
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
        'amount': 0,
        'total_amount': '44.94',
        'online_payment': False,
        'created': '2019-11-12',
        'pay_limit_date': '',
        'has_pdf': True,
        'paid': False,
        'vendor': {
            'caluire-axel': {
                'IDFACTURE': 42,
                'MONTANT': '44.94',
                'ENCAISSE': '40.00',
                'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
                'ECHEANCE': '2019-12-04',
                'EMISSION': '2019-11-12',
                'EXISTEPDF': True,
            },
        },
    }


def test_invoice_pdf_endpoint_axel_error(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_factures_a_payer') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetFacturesaPayer'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.get_pdf_facture') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


def test_invoice_pdf_endpoint_bad_request(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock_data(None, 'GetListFactures'):
        resp = app.get(
            '/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42/pdf?NameID=yyy&nb_mounts_limit=not_a_number',
            status=404,
        )
    assert resp.json['err_desc'] == "nb_mounts_limit must be an integer"
    assert resp.json['err'] == 'bad-request'


@freezegun.freeze_time('2019-12-13')
def test_invoice_pdf_endpoint_no_result(app, resource):
    resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-35/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-44/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-43/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "PDF not available"
    assert resp.json['err'] == 'not-available'

    pdf_content = '''<PORTAIL>
    <GETPDFFACTURE>
        <CODE>1</CODE>
        <FACTUREPDF></FACTUREPDF>
    </GETPDFFACTURE>
</PORTAIL>'''
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice') as invoice:
        invoice.return_value = {'has_pdf': True, 'display_id': '42'}
        with mock_data(pdf_content, 'GetPdfFacture'):
            resp = app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
    assert resp.json['err_desc'] == "PDF error"
    assert resp.json['err'] == 'error'


def test_invoice_pdf_endpoint(app, resource):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    pdf_content = '''<PORTAIL>
    <GETPDFFACTURE>
        <CODE>1</CODE>
        <FACTUREPDF>aGVsbG8gd29ybGQ=</FACTUREPDF>
    </GETPDFFACTURE>
</PORTAIL>'''
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice') as invoice:
        invoice.return_value = {'has_pdf': True, 'display_id': '42'}
        with mock_data(pdf_content, 'GetPdfFacture'):
            app.get('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy')
    assert invoice.call_args_list[0][1]['historical'] is False

    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice') as invoice:
        invoice.return_value = {'has_pdf': True, 'display_id': '42'}
        with mock_data(pdf_content, 'GetPdfFacture'):
            app.get('/caluire-axel/test/regie/MAREGIE/invoice/historical-XXX-42/pdf?NameID=yyy')
    assert invoice.call_args_list[0][1]['historical'] is True


def test_pay_invoice_endpoint_axel_error(app, resource):
    payload = {
        'transaction_date': '2021-06-15T12:00:00',
        'transaction_id': 'foo',
    }
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_factures_a_payer') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetFacturesaPayer'):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json(
                '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'
    for key in ('xml_request', 'xml_response', 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs'):
        assert key in resp.json['data'].keys()

    content2 = '''
<PORTAIL>
  <SETPAIEMENT>
    <CODE>-3</CODE>
  </SETPAIEMENT>
</PORTAIL>'''
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        client.return_value.service.getData.return_value = XML_RESPONSE_TEMPLATE % (
            'GetFacturesaPayer',
            content,
        )
        client.return_value.service.setData.return_value = XML_RESPONSE_TEMPLATE % ('SetPaiement', content2)
        resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
    assert resp.json['err_desc'] == "Wrong pay-invoice status"
    assert resp.json['err'] == 'pay-invoice-code-error--3'


def test_pay_invoice_endpoint_bad_request(app, resource):
    resp = app.post_json(
        '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params={}, status=400
    )
    assert resp.json['err_desc'] == "'transaction_date' is a required property"


@freezegun.freeze_time('2019-12-04')
def test_pay_invoice_endpoint_no_result(app, resource):
    payload = {
        'transaction_date': '2021-06-15T12:00:00',
        'transaction_id': 'foo',
    }
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-35/pay?NameID=yyy', params=payload)
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'

    with mock_data(content, 'GetFacturesaPayer'):
        resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-44/pay?NameID=yyy', params=payload)
    assert resp.json['err_desc'] == "Invoice not found"
    assert resp.json['err'] == 'not-found'


def test_pay_invoice_endpoint_wrong_response(app, resource):
    payload = {
        'transaction_date': '2021-06-15T12:00:00',
        'transaction_id': 'foo',
    }
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice',
        return_value={'amount': '44.9'},
    ):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
            operation.return_value = OperationResult(
                json_response={'DATA': {'PORTAIL': {}}},
                xml_request='',
                xml_response='',
            )
            resp = app.post_json(
                '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy',
                params=payload,
                status=500,
            )
        assert resp.json['err'] == 'pay-invoice-code-response-error'
        assert resp.json['err_desc'] == 'Wrong pay-invoice response'
        for key in 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs', 'result':
            assert key in resp.json['data'].keys()

        with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
            operation.return_value = OperationResult(
                json_response={'DATA': {'PORTAIL': {'SETPAIEMENT': {'CODE': 'oups'}}}},
                xml_request='',
                xml_response='',
            )
            resp = app.post_json(
                '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy',
                params=payload,
                status=500,
            )
        assert resp.json['err'] == 'pay-invoice-code-response-error'
        assert resp.json['err_desc'] == 'Wrong pay-invoice response'
        for key in 'regie_id', 'family_id', 'invoice', 'post_data', 'kwargs', 'result':
            assert key in resp.json['data'].keys()


def test_pay_invoice_endpoint(app, resource):
    payload = {
        'transaction_date': '2021-06-15T12:00:00',
        'transaction_id': 'foo',
    }
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
    with open(filepath) as xml:
        content = (
            '''
<PORTAIL>
  <GETFACTURESAPAYER>
    %s
  </GETFACTURESAPAYER>
</PORTAIL>'''
            % xml.read()
        )
    content2 = '''
<PORTAIL>
  <SETPAIEMENT>
    <CODE>0</CODE>
  </SETPAIEMENT>
</PORTAIL>'''
    with mock.patch('passerelle.contrib.caluire_axel.models.CaluireAxel.soap_client') as client:
        client.return_value.service.getData.return_value = XML_RESPONSE_TEMPLATE % (
            'GetFacturesaPayer',
            content,
        )
        client.return_value.service.setData.return_value = XML_RESPONSE_TEMPLATE % ('SetPaiement', content2)
        resp = app.post_json('/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
    assert resp.json['err'] == 0
    assert resp.json['created'] is True


def test_pay_invoice_providing_mode_reglement(app, resource):
    payload = {
        'transaction_date': '2021-06-15T12:00:00',
        'transaction_id': 'foo',
    }
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_invoice',
        return_value={'amount': '44.9'},
    ):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.set_paiement') as operation:
            operation.return_value = OperationResult(
                json_response={'DATA': {'PORTAIL': {'SETPAIEMENT': {'CODE': 0}}}},
                xml_request='',
                xml_response='',
            )
            resp = app.post_json(
                '/caluire-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload
            )
    assert operation.call_args[0][1]['PORTAIL']['SETPAIEMENT']['IDENTMODEREGLEMENT'] == 'INCB'
    assert resp.json['err'] == 0
    assert resp.json['created'] is True


def test_upload_attachments_endpoint_axel_error(app, resource, family_data, upload_attachments_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_famille_individus') as operation:
        operation.side_effect = AxelError('FooBar')
        resp = app.post_json(
            '/caluire-axel/test/upload_attachments?NameID=yyy', params=upload_attachments_params
        )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'

    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        with mock.patch('passerelle.contrib.caluire_axel.schemas.set_pieces') as operation:
            operation.side_effect = AxelError('FooBar')
            resp = app.post_json(
                '/caluire-axel/test/upload_attachments?NameID=yyy', params=upload_attachments_params
            )
    assert resp.json['err_desc'] == "Axel error: FooBar"
    assert resp.json['err'] == 'error'


@pytest.mark.parametrize('value', ['foo', '20/01/2020', '2020'])
def test_upload_attachments_endpoint_bad_date_format(app, resource, upload_attachments_params, value):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    upload_attachments_params['reference_date'] = value
    resp = app.post_json(
        '/caluire-axel/test/upload_attachments?NameID=yyy',
        params=upload_attachments_params,
        status=400,
    )
    assert resp.json['err_desc'] == "reference_date: '%s' does not match '[0-9]{4}-[0-9]{2}-[0-9]{2}'" % value
    assert resp.json['err'] == 1


def test_upload_attachments_endpoint_no_result(app, resource, family_data, upload_attachments_params):
    resp = app.post_json('/caluire-axel/test/upload_attachments?NameID=yyy', params=upload_attachments_params)
    assert resp.json['err_desc'] == "Person not found"
    assert resp.json['err'] == 'not-found'

    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    with mock.patch(
        'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
        return_value=family_data,
    ):
        upload_attachments_params['child_id'] = 'zzz'
        resp = app.post_json(
            '/caluire-axel/test/upload_attachments?NameID=yyy',
            params=upload_attachments_params,
        )
    assert resp.json['err_desc'] == "Child not found"
    assert resp.json['err'] == 'not-found'


def test_upload_attachments(app, resource, family_data, upload_attachments_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/upload_attachments.xml')
    with open(filepath) as xml:
        content = xml.read()
    with mock_data(content, 'SetPieces', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.post_json(
                '/caluire-axel/test/upload_attachments?NameID=yyy',
                params=upload_attachments_params,
            )
    assert resp.json['err'] == 0
    assert resp.json['created']


def test_upload_attachments_wrong_code(app, resource, family_data, upload_attachments_params):
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
    code = -1
    content = (
        '''
<PORTAIL>
  <SETPIECES>
    <PIECE>
      <CODE>0</CODE>
      <LIBELLE>ID card</LIBELLE>
    </PIECE>
    <PIECE>
      <CODE>%s</CODE>
      <LIBELLE>Passport</LIBELLE>
    </PIECE>
  </SETPIECES>
</PORTAIL>'''
        % code
    )
    with mock_data(content, 'SetPieces', data_method='setData'):
        with mock.patch(
            'passerelle.contrib.caluire_axel.models.CaluireAxel.get_family_data',
            return_value=family_data,
        ):
            resp = app.post_json(
                '/caluire-axel/test/upload_attachments?NameID=yyy',
                params=upload_attachments_params,
            )

    assert resp.json['err_desc'] == "Wrong upload-attachments status"
    assert resp.json['err'] == 'upload-attachments-code-error-%s' % code
