passerelle/passerelle/contrib/toulouse_maelis/models.py

2787 lines
113 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (C) 2022 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import copy
import datetime
from operator import itemgetter
from urllib.parse import urljoin
import zeep
from dateutil import rrule
from django.contrib.postgres.fields import JSONField
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.utils import dateformat
from django.utils.dateparse import parse_date
from django.utils.timezone import now
from zeep.helpers import serialize_object
from zeep.wsse.username import UsernameToken
from passerelle.base.models import BaseResource, HTTPResource
from passerelle.utils.api import endpoint
from passerelle.utils.conversion import simplify
from passerelle.utils.jsonresponse import APIError
from passerelle.utils.templates import render_to_string
from . import activity_schemas, family_schemas, invoice_schemas, schemas, utils
class UpdateError(Exception):
pass
class ToulouseMaelis(BaseResource, HTTPResource):
# noqa pylint: disable=too-many-public-methods
base_wsdl_url = models.CharField(
max_length=128,
blank=False,
verbose_name='URL de base des WSDL',
default='https://demo-toulouse.sigec.fr/maelisws-toulouse/services/',
)
zeep_wsse_username = models.CharField(
max_length=64, blank=True, default='', verbose_name='Identifiant utilisateur WSSE'
)
zeep_wsse_password = models.CharField(
max_length=64, blank=True, default='', verbose_name='Mot de passe WSSE'
)
category = 'Connecteurs métiers'
_category_ordering = ['Famille', 'Activités']
class Meta:
verbose_name = 'Toulouse Maelis'
def get_client(self, wsdl_short_name):
wsse = UsernameToken(self.zeep_wsse_username, self.zeep_wsse_password)
wsdl_name = wsdl_short_name + 'Service?wsdl'
wsdl_url = urljoin(self.base_wsdl_url, wsdl_name)
settings = zeep.Settings(strict=False, xsd_ignore_sequence_order=True)
return self.soap_client(wsdl_url=wsdl_url, wsse=wsse, settings=settings)
def call(self, wsdl_short_name, service, **kwargs):
client = self.get_client(wsdl_short_name)
method = getattr(client.service, service)
try:
return method(**kwargs)
except zeep.exceptions.Fault as e:
raise APIError(e.message)
def check_status(self):
assert self.call('Family', 'isWSRunning')
assert self.call('Activity', 'isWSRunning')
assert self.call('Invoice', 'isWSRunning')
assert self.call('Site', 'isWSRunning')
assert self.call('Ape', 'isWSRunning')
def update_referential(self, referential_name, data, id_key, text_key):
last_update = now()
for item in data or []:
text = item[text_key] or ''
if isinstance(text, int):
text = str(text)
text = text.strip()
self.referential.update_or_create(
resource_id=self.id,
referential_name=referential_name,
item_id=item[id_key],
defaults={
'item_text': text,
'item_unaccent_text': simplify(text),
'item_data': dict({'id': item[id_key], 'text': text}, **item),
'updated': last_update,
},
)
self.referential.filter(referential_name=referential_name, updated__lt=last_update).delete()
def get_referential_data(self, service_name, referential_name):
try:
response = self.call(service_name, 'read' + referential_name + 'List')
return serialize_object(response)
except Exception as e:
raise UpdateError('Service indisponible : %s' % str(e))
def update_family_referentials(self):
# local referentials
complement_data = [
{'id': 'B', 'text': 'bis'},
{'id': 'Q', 'text': 'quater'},
{'id': 'T', 'text': 'ter'},
]
sex_data = [
{'id': 'F', 'text': 'Féminin'},
{'id': 'M', 'text': 'Masculin'},
]
self.update_referential('Complement', complement_data, 'id', 'text')
self.update_referential('Sex', sex_data, 'id', 'text')
# remote referentials
for referential_name in (
'Category',
'ChildIndicator',
'Civility',
'Country',
'CSP',
'DietCode',
'Document',
'Organ',
'PAI',
'Quality',
'Quotient',
'RLIndicator',
'Situation',
'Street',
'Vaccin',
):
id_key, text_key = 'code', 'libelle'
data = self.get_referential_data('Family', referential_name)
if referential_name == 'Organ':
id_key, text_key = 'id', 'code'
elif referential_name == 'Street':
id_key, text_key = 'idStreet', 'libelleStreet'
self.update_referential(referential_name, data, id_key, text_key)
def update_site_referentials(self):
for referential_name in ('YearSchool', 'Level', 'DerogReason'):
id_key, text_key = 'code', 'libelle'
data = self.get_referential_data('Site', referential_name)
if referential_name == 'YearSchool':
id_key, text_key = 'schoolYear', 'schoolYear'
self.update_referential(referential_name, data, id_key, text_key)
def update_activity_referentials(self):
for referential_name in ('ActivityNatureType',):
id_key, text_key = 'code', 'libelle'
data = self.get_referential_data('Activity', referential_name)
self.update_referential(referential_name, data, id_key, text_key)
# put activity catalog per year as referential
data = []
reference_year = utils.get_reference_year_from_date(datetime.date.today())
for year in range(reference_year, reference_year + 1):
response = self.call(
'Activity',
'readActivityList',
schoolyear=year,
dateStartCalend='%s-09-01' % year,
dateEndCalend='%s-09-01' % (year + 1),
)
data.append(
{
'id': str(year),
'text': '%s-%s' % (year, year + 1),
'data': serialize_object(response),
}
)
self.update_referential('ActivityCatalog', data, 'id', 'text')
def update_ape_referentials(self):
for referential_name in ('ApeIndicator',):
id_key, text_key = 'level', 'level'
data = self.get_referential_data('Ape', referential_name)
self.update_referential(referential_name, data, id_key, text_key)
def daily(self):
try:
self.update_family_referentials()
self.update_site_referentials()
self.update_activity_referentials()
self.update_ape_referentials()
except UpdateError as e:
self.logger.warning('Erreur sur la mise à jour: %s' % e)
else:
self.logger.info('Réferentiels mis à jour.')
def get_referential(self, referential_name, id=None, q=None, limit=None, distinct=True):
if id is not None:
queryset = self.referential.filter(referential_name=referential_name, item_id=id)
else:
queryset = self.referential.filter(referential_name=referential_name).all()
if q:
queryset = queryset.filter(item_unaccent_text__icontains=simplify(q))
if distinct:
queryset = queryset.distinct('resource', 'referential_name', 'item_text')
if limit:
try:
limit = int(limit)
except ValueError:
pass
else:
queryset = queryset[:limit]
return [x.item_data for x in queryset]
def get_referential_value(self, referential_name, key):
try:
return self.referential.get(referential_name=referential_name, item_id=key).item_text
except Referential.DoesNotExist:
self.logger.warning("No '%s' key into Maelis '%s' referential", key, referential_name)
return key
def get_link(self, NameID):
try:
return self.link_set.get(name_id=NameID)
except Link.DoesNotExist:
raise APIError('User not linked to family')
def get_family_raw(self, family_id, **kwargs):
response = self.call('Family', 'readFamily', dossierNumber=family_id, **kwargs)
data = serialize_object(response)
return data
def get_rl_raw(self, family_id, rl_id, **kwargs):
data = self.get_family_raw(family_id, **kwargs)
if data['RL1']['num'] == rl_id:
return data['RL1']
elif data['RL2'] and data['RL2']['num'] == rl_id:
return data['RL2']
raise APIError("no '%s' RL on '%s' family" % (rl_id, family_id))
def get_person_raw(self, family_id, person_id):
data = self.get_family_raw(family_id)
for person in data['emergencyPersonList']:
if str(person['numPerson']) == person_id:
return person
raise APIError("no '%s' emergency person on '%s' family" % (person_id, family_id))
def get_child_raw(self, family_id, child_id):
data = self.get_family_raw(family_id)
for child in data['childList']:
if child['num'] == child_id:
return child
raise APIError("no '%s' child on '%s' family" % (child_id, family_id))
def get_child_person_raw(self, family_id, child_id, person_id):
data = self.get_child_raw(family_id, child_id)
for person in data['authorizedPersonList']:
if str(person['personInfo']['num']) == person_id:
return person
raise APIError("no '%s' authorized person on '%s' child" % (person_id, child_id))
def add_text_value(self, referential_name, data, keys):
'''add text from referentials'''
last_key = keys.pop()
for key in keys:
if not isinstance(data, dict) or not key in data:
return
data = data[key]
if isinstance(data, dict) and last_key in data and data[last_key] is not None:
data[last_key + '_text'] = self.get_referential_value(referential_name, data[last_key])
def add_indicators_field(self, referential_name, data):
active_indicators = {x['code']: x for x in data['indicatorList']}
indicators = self.get_referential(referential_name)
result = {}
for item in indicators:
active_indicator = active_indicators.get(item['id']) or {}
item['isActive'] = bool(active_indicator)
if item['typeDesc'] == 'NOTE':
item['note'] = active_indicator.get('note')
del item['choiceList'] # no list based indicator on parsifal project
result[item['id']] = item
data['indicators'] = result
def add_text_value_to_rl_indicator(self, data):
self.add_text_value('RLIndicator', data, ['code'])
def add_text_value_to_child_indicator(self, data):
self.add_text_value('ChildIndicator', data, ['code'])
def add_text_value_to_child_person(self, data):
self.add_text_value('Civility', data, ['personInfo', 'civility'])
self.add_text_value('Quality', data, ['personQuality', 'code'])
self.add_text_value('Sex', data, ['personInfo', 'sexe'])
def add_text_value_to_child(self, data):
self.add_text_value('Sex', data, ['sexe'])
self.add_text_value('DietCode', data, ['dietcode'])
self.add_text_value('PAI', data, ['paiInfoBean', 'code'])
for person in data['authorizedPersonList']:
self.add_text_value_to_child_person(person)
for indicator in data['indicatorList']:
self.add_text_value_to_child_indicator(indicator)
self.add_indicators_field('ChildIndicator', data)
def add_text_value_to_person(self, data):
self.add_text_value('Civility', data, ['civility'])
self.add_text_value('Quality', data, ['quality'])
self.add_text_value('Sex', data, ['sexe'])
def add_text_value_to_rl(self, data):
self.add_text_value('Civility', data, ['civility'])
self.add_text_value('Quality', data, ['quality'])
self.add_text_value('Complement', data, ['adresse', 'numComp'])
self.add_text_value('Street', data, ['adresse', 'idStreet'])
self.add_text_value('CSP', data, ['profession', 'codeCSP'])
self.add_text_value('Organ', data, ['CAFInfo', 'organ'])
for indicator in data['indicatorList']:
self.add_text_value_to_rl_indicator(indicator)
for quotient in data['quotientList']:
self.add_text_value('Quotient', quotient, ['cdquo'])
self.add_indicators_field('RLIndicator', data)
def add_text_value_to_family(self, data):
self.add_text_value('Category', data, ['category'])
self.add_text_value('Situation', data, ['situation'])
for rlg in 'RL1', 'RL2':
if data.get(rlg):
self.add_text_value_to_rl(data[rlg])
for child in data['childList']:
self.add_text_value_to_child(child)
for person in data['emergencyPersonList']:
self.add_text_value_to_person(person)
def get_child_person(self, family_id, child_id, person_id):
data = self.get_child_person_raw(family_id, child_id, person_id)
self.add_text_value_to_child_person(data)
return data
def get_child(self, family_id, child_id):
data = self.get_child_raw(family_id, child_id)
self.add_text_value_to_child(data)
return data
def get_person(self, family_id, person_id):
data = self.get_person_raw(family_id, person_id)
self.add_text_value_to_person(data)
return data
def get_rl(self, family_id, rl_id, **kwargs):
data = self.get_rl_raw(family_id, rl_id, **kwargs)
self.add_text_value_to_rl(data)
return data
def get_family(self, family_id, **kwargs):
data = self.get_family_raw(family_id, **kwargs)
self.add_text_value_to_family(data)
return data
def assert_key_in_referential(self, referential_name, key_value, keys_text, required=True):
if not key_value:
if required:
raise APIError("%s is required and could not be None" % keys_text)
return
try:
self.referential.get(referential_name=referential_name, item_id=key_value)
except Referential.DoesNotExist:
ref_text = "required " if required else ""
ref_text = ref_text + "referential"
raise APIError(
"%s key value '%s' do not belong to '%s' %s"
% (keys_text, key_value, referential_name, ref_text)
)
def assert_post_data_in_referential(self, referential_name, data, keys, required=True):
key_value = None
for key in keys:
if not (isinstance(data, list) and isinstance(key, int)) and not (
isinstance(data, dict) and key in data
):
break
data = data[key]
else:
key_value = data
self.assert_key_in_referential(referential_name, key_value, '/'.join(str(x) for x in keys), required)
def encode_bool(self, obj):
if obj is True or str(obj).lower() in ['true', 'oui', '1']:
return True
if obj is False or str(obj).lower() in ['false', 'non', '0']:
return False
def assert_update_indicator_payload_in_referential(self, referential, post_data, parent_keys=None):
keys = parent_keys or []
data = post_data
for key in keys:
data = data[key]
for i, item in enumerate(data.get('indicatorList', [])):
self.assert_post_data_in_referential(
referential, post_data, keys + ['indicatorList', i, 'code'], required=True
)
item['isActive'] = self.encode_bool(item['isActive'])
def assert_child_medical_record_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
data = post_data
for key in keys:
data = data[key]
if 'isAuthHospital' in data:
data['isAuthHospital'] = self.encode_bool(data['isAuthHospital'])
for i in range(0, len(data.get('vaccinList', []))):
self.assert_post_data_in_referential(
'Vaccin', post_data, keys + ['vaccinList', i, 'code'], required=False
)
def assert_child_pai_payoad_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential('PAI', post_data, keys + ['code'])
def assert_child_person_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential(
'Civility', post_data, keys + ['personInfo', 'civility'], required=False
)
self.assert_post_data_in_referential('Sex', post_data, keys + ['personInfo', 'sexe'], required=False)
self.assert_post_data_in_referential('Quality', post_data, keys + ['personQuality', 'code'])
def assert_child_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential('Sex', post_data, keys + ['sexe'])
data = post_data
for key in keys:
data = data[key]
for key in ('bPhoto', 'bLeaveAlone'):
if key in data:
data[key] = self.encode_bool(data[key])
if 'dietcode' in data:
self.assert_post_data_in_referential('DietCode', post_data, keys + ['dietcode'], required=False)
if 'paiInfoBean' in data:
self.assert_child_pai_payoad_in_referential(post_data, keys + ['paiInfoBean'])
if 'medicalRecord' in data:
# dead code as updateFamily seems not to modify medicalRecord
self.assert_child_medical_record_payload_in_referential(post_data, keys + ['medicalRecord'])
self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data, keys)
def assert_person_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential('Civility', post_data, keys + ['civility'], required=False)
self.assert_post_data_in_referential('Sex', post_data, keys + ['sexe'], required=False)
self.assert_post_data_in_referential('Quality', post_data, keys + ['quality'])
def assert_update_coordinate_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential(
'Street', post_data, keys + ['adresse', 'idStreet'], required=False
)
self.assert_post_data_in_referential(
'Complement', post_data, keys + ['adresse', 'numComp'], required=False
)
self.assert_post_data_in_referential(
'CSP', post_data, keys + ['profession', 'codeCSP'], required=False
)
self.assert_post_data_in_referential('Organ', post_data, keys + ['CAFInfo', 'organ'], required=False)
data = post_data
for key in keys:
data = data[key]
if 'contact' in data:
data = data['contact']
for key in ('isContactMail', 'isContactSms', 'isInvoicePdf'):
if key in data:
data[key] = self.encode_bool(data[key])
def assert_rl_payload_in_referential(self, post_data, parent_keys=None):
keys = parent_keys or []
self.assert_post_data_in_referential('Civility', post_data, keys + ['civility'])
self.assert_post_data_in_referential('Quality', post_data, keys + ['quality'])
self.assert_update_coordinate_payload_in_referential(post_data, keys)
self.assert_update_indicator_payload_in_referential('RLIndicator', post_data, keys)
def assert_create_rl1_payload_in_referential(self, post_data):
self.assert_post_data_in_referential('Category', post_data, ['category'])
self.assert_post_data_in_referential('Situation', post_data, ['situation'])
self.assert_rl_payload_in_referential(post_data, ['rl1'])
def assert_family_payload_in_referential(self, post_data):
self.assert_post_data_in_referential('Category', post_data, ['category'])
self.assert_post_data_in_referential('Situation', post_data, ['situation'])
for rlg in 'rl1', 'rl2':
if rlg in post_data:
self.assert_rl_payload_in_referential(post_data, [rlg])
for i, person in enumerate(post_data.get('emergencyPersonList') or []):
for j in range(0, len(person.get('personList') or [])):
self.assert_person_payload_in_referential(
post_data, ['emergencyPersonList', i, 'personList', j]
)
for i in range(0, len(post_data.get('childList') or [])):
self.assert_child_payload_in_referential(post_data, ['childList', i])
if 'flagCom' in post_data:
post_data['flagCom'] = self.encode_bool(post_data['flagCom'])
def replace_null_values(self, dico):
'''send null fields as empty SOAP tag to tell maelis to empty the value'''
for key, value in dico.items():
if isinstance(value, dict):
self.replace_null_values(value)
if value is None:
dico[key] = ''
def get_person_activity_list_raw(
self, family_id, person_id, nature_id=None, reference_year=None, start_date=None, end_date=None
):
params = {
'numDossier': family_id,
'numPerson': person_id,
'codeNatureActivity': nature_id,
'yearSchool': reference_year,
'dateStartActivity': start_date,
'dateEndActivity': end_date,
}
response = self.call(
'Activity', 'getPersonCatalogueActivity', getPersonCatalogueActivityRequestBean=params
)
data = serialize_object(response)
return data
def get_basket_raw(self, family_id):
response = self.call(
'Activity',
'getFamilyBasket',
getFamilyBasketRequestBean={
'numFamily': family_id,
},
)
data = serialize_object(response)
return data
@endpoint(
display_category='Famille',
description='Liste les catégories',
name='read-category-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_category_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Category', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les indicateurs sur le enfants',
name='read-child-indicator-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_child_indicator_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('ChildIndicator', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les civilités',
name='read-civility-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_civility_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Civility', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les compléments du numéro de voie',
name='read-complement-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_complement_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Complement', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les pays',
name='read-country-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_country_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Country', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='liste les catégories socio-professionnelles',
name='read-csp-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_csp_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('CSP', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les régimes alimentaires',
name='read-dietcode-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_dietcode_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('DietCode', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les pièces jointes',
name='read-document-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_document_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Document', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les organismes (CAF)',
name='read-organ-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_organ_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Organ')}
@endpoint(
display_category='Famille',
description="Liste les Projets d'Accueils Individualisés (PAI)",
name='read-pai-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_pai_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('PAI', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='liste les qualités du référenciel',
name='read-quality-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_quality_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Quality', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les quotients',
name='read-quotient-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_quotient_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Quotient', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les indicateurs sur les responsables légaux',
name='read-rl-indicator-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_rl_indicator_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('RLIndicator')}
@endpoint(
display_category='Famille',
description='Liste les sexes',
name='read-sex-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_sex_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Sex', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='liste les situations',
name='read-situation-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_situation_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Situation', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='liste les voies',
name='read-street-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_street_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Street', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Liste les vaccins',
name='read-vaccin-list',
perm='can_access',
parameters={
'id': {'description': 'Identifiant de lenregistrement'},
'q': {'description': 'Recherche en texte intégral'},
'limit': {'description': 'Nombre maximal de résultats; doit être inférieur à 20.'},
'distinct': {'description': 'Supression des doublons'},
},
)
def read_vaccin_list(self, request, id=None, q=None, limit=None, distinct=True):
return {'data': self.get_referential('Vaccin', id, q, limit, distinct)}
@endpoint(
display_category='Famille',
description='Lier un compte usager à une famille',
perm='can_access',
parameters={'NameID': {'description': 'Publik NameID'}},
post={'request_body': {'schema': {'application/json': schemas.LINK_SCHEMA}}},
)
def link(self, request, NameID, post_data):
family_id = post_data['family_id']
response = self.call('Family', 'readFamily', dossierNumber=family_id)
if not (
response['RL1']['firstname'] == post_data['firstname'].upper()
and response['RL1']['lastname'] == post_data['lastname'].upper()
and response['RL1']['birth']['dateBirth'].strftime('%Y-%m-%d') == post_data['dateBirth']
):
raise APIError("RL1 does not match '%s' family" % family_id)
Link.objects.update_or_create(resource=self, name_id=NameID, defaults={'family_id': family_id})
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description='Supprimer une liaison entre un compte usager et une famille',
methods=['post'],
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
},
)
def unlink(self, request, NameID):
link = self.get_link(NameID)
link.delete()
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description='Informations sur la famille',
perm='can_access',
name='read-family',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'income_year': {'description': 'Année de revenu pour filtrer les quotients'},
},
)
def read_family(self, request, NameID=None, family_id=None, income_year=None):
family_id = family_id or self.get_link(NameID).family_id
data = self.get_family(family_id, incomeYear=income_year)
data['family_id'] = family_id
return {'data': data}
@endpoint(
display_category='Famille',
description="Liste les responsables légaux",
perm='can_access',
name='read-rl-list',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'text_template': {
'description': 'template utilisée pour la valeur text',
'example_value': '{{ lastname }} {{ firstname }}',
},
'income_year': {'description': 'Année de revenu pour filtrer les quotients'},
},
)
def read_rl_list(self, request, NameID=None, family_id=None, text_template=None, income_year=None):
family_id = family_id or self.get_link(NameID).family_id
result = self.get_family_raw(family_id, incomeYear=income_year)
if not text_template:
text_template = '{{ lastname }} {{ firstname }}'
data = []
for rlg in 'RL1', 'RL2':
item = result.get(rlg)
self.add_text_value_to_rl(item)
if not item:
break
item['id'] = item['num']
item['text'] = render_to_string(text_template, item).strip()
item['family_id'] = family_id
data.append(item)
return {'data': data}
@endpoint(
display_category='Famille',
description="Liste les personnes à prévenir en cas d'urgence",
perm='can_access',
name='read-person-list',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'text_template': {
'description': 'template utilisée pour la valeur text',
'example_value': '{{ lastname }} {{ firstname }}',
},
},
)
def read_person_list(self, request, NameID=None, family_id=None, text_template=None):
family_id = family_id or self.get_link(NameID).family_id
result = self.get_family_raw(family_id)
if not text_template:
text_template = '{{ lastname }} {{ firstname }}'
data = []
for item in result['emergencyPersonList']:
self.add_text_value_to_person(item)
item['id'] = item['numPerson']
item['text'] = render_to_string(text_template, item).strip()
item['family_id'] = family_id
data.append(item)
return {'data': data}
@endpoint(
display_category='Famille',
description="Liste les enfants",
perm='can_access',
name='read-child-list',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'text_template': {
'description': 'template utilisée pour la valeur text',
'example_value': '{{ lastname }} {{ firstname }}',
},
},
)
def read_child_list(self, request, NameID=None, family_id=None, text_template=None):
family_id = family_id or self.get_link(NameID).family_id
result = self.get_family_raw(family_id)
if not text_template:
text_template = '{{ lastname }} {{ firstname }}'
data = []
for item in result['childList']:
self.add_text_value_to_child(item)
item['id'] = item['num']
item['text'] = render_to_string(text_template, item).strip()
item['family_id'] = family_id
data.append(item)
return {'data': data}
@endpoint(
display_category='Famille',
description="Liste les personnes autorisées à récupérer l'enfant",
perm='can_access',
name='read-child-person-list',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'text_template': {
'description': 'template utilisée pour la valeur text',
'example_value': '{{ personInfo.lastname }} {{ personInfo.firstname }}',
},
},
)
def read_child_person_list(self, request, child_id, NameID=None, family_id=None, text_template=None):
family_id = family_id or self.get_link(NameID).family_id
result = self.get_child_raw(family_id, child_id)
if not text_template:
text_template = '{{ personInfo.lastname }} {{ personInfo.firstname }}'
data = []
for item in result['authorizedPersonList']:
self.add_text_value_to_child_person(item)
item['id'] = item['personInfo']['num']
item['text'] = render_to_string(text_template, item).strip()
item['family_id'] = family_id
data.append(item)
return {'data': data}
@endpoint(
display_category='Famille',
description="Informations sur un responsable légal",
perm='can_access',
name='read-rl',
parameters={
'rl_id': {'description': 'Numéro du représentant légal'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'income_year': {'description': 'Année de revenu pour filtrer les quotients'},
},
)
def read_rl(
self,
request,
rl_id,
NameID=None,
family_id=None,
income_year=None,
):
family_id = family_id or self.get_link(NameID).family_id
data = self.get_rl(family_id, rl_id, incomeYear=income_year)
data['family_id'] = family_id
return {'data': data}
@endpoint(
display_category='Famille',
description="Informations sur une personne autorisée à récupérer les enfants",
perm='can_access',
name='read-person',
parameters={
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def read_person(self, request, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
data = self.get_person(family_id, person_id)
data['family_id'] = family_id
return {'data': data}
@endpoint(
display_category='Famille',
description="Informations sur un enfant",
perm='can_access',
name='read-child',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def read_child(self, request, child_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
data = self.get_child(family_id, child_id)
data['family_id'] = family_id
return {'data': data}
@endpoint(
display_category='Famille',
description="Informations sur une personne autorisée à récupérer l'enfant",
perm='can_access',
name='read-child-person',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def read_child_person(self, request, child_id, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
data = self.get_child_person(family_id, child_id, person_id)
data['family_id'] = family_id
return {'data': data}
@endpoint(
display_category='Famille',
description="Vérifier qu'un responsable légal existe en base",
perm='can_access',
name='is-rl-exists',
post={'request_body': {'schema': {'application/json': family_schemas.ISEXISTS_SCHEMA}}},
)
def is_rl_exists(self, request, post_data):
response = self.call('Family', 'isRLExists', **post_data)
return {'data': response}
@endpoint(
display_category='Famille',
description="Vérifier qu'un responsable légal existe en base",
perm='can_access',
name='is-child-exists',
post={'request_body': {'schema': {'application/json': family_schemas.ISEXISTS_SCHEMA}}},
)
def is_child_exists(self, request, post_data):
response = self.call('Family', 'isChildExists', **post_data)
return {'data': response}
@endpoint(
display_category='Famille',
description='Création de la famille',
name='create-family',
perm='can_access',
parameters={'NameID': {'description': 'Publik NameID'}},
post={'request_body': {'schema': {'application/json': family_schemas.CREATE_FAMILY_SCHEMA}}},
)
def create_family(self, request, post_data, NameID=None):
if self.link_set.filter(name_id=NameID).exists():
raise APIError('User already linked to family')
self.assert_family_payload_in_referential(post_data)
response = self.call('Family', 'createFamily', **post_data)
data = serialize_object(response)
family_id = data.get('number')
if not family_id:
errors = data.get('rl1ErrorList') + data.get('childErrorList')
raise APIError(' ; '.join(errors))
if NameID:
Link.objects.create(resource=self, name_id=NameID, family_id=family_id)
return {'data': data}
@endpoint(
display_category='Famille',
description='Modification de la famille',
name='update-family',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_FAMILY_SCHEMA}}},
)
def update_family(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_family_payload_in_referential(post_data)
self.replace_null_values(post_data)
# adapt payload to use same input as create_family
if len(post_data.get('emergencyPersonList', [])):
persons = post_data.pop('emergencyPersonList')
post_data['emergencyPersonList'] = [{'personList': persons}]
response = self.call('Family', 'updateFamily', dossierNumber=family_id, **post_data)
data = serialize_object(response)
family_id = data.get('number')
errors = data.get('childErrorList')
if errors:
raise APIError(' ; '.join(errors))
return {'data': data}
@endpoint(
display_category='Famille',
description='Création du RL1',
name='create-rl1',
perm='can_access',
parameters={'NameID': {'description': 'Publik NameID'}},
post={'request_body': {'schema': {'application/json': family_schemas.CREATE_RL1_SCHEMA}}},
)
def create_rl1(self, request, post_data, NameID=None):
if self.link_set.filter(name_id=NameID).exists():
raise APIError('User already linked to family')
self.assert_create_rl1_payload_in_referential(post_data)
response = self.call('Family', 'createFamily', **post_data)
data = serialize_object(response)
family_id = data.get('number')
if not family_id:
errors = data.get('rl1ErrorList') or []
raise APIError(' ; '.join(errors))
if NameID:
Link.objects.create(resource=self, name_id=NameID, family_id=family_id)
return {'data': {'family_id': family_id}}
@endpoint(
display_category='Famille',
description='Modification du RL1',
name='update-rl1',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_RL1_SCHEMA}}},
)
def update_rl1(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_rl_payload_in_referential(post_data)
self.replace_null_values(post_data)
family = self.get_family_raw(family_id)
rl1 = post_data
rl1['adresse'] = family['RL1']['adresse']
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'rl1': rl1,
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description='Création du RL2',
name='create-rl2',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.CREATE_RL2_SCHEMA}}},
)
def create_rl2(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_rl_payload_in_referential(post_data)
family = self.get_family_raw(family_id)
if family['RL2']:
raise APIError('RL2 already defined on family')
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'rl2': post_data,
}
response = self.call('Family', 'updateFamily', **payload)
return {'data': {'id': response['RL2']['num']}}
@endpoint(
display_category='Famille',
description='Modification du RL2',
name='update-rl2',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_RL2_SCHEMA}}},
)
def update_rl2(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_rl_payload_in_referential(post_data)
self.replace_null_values(post_data)
family = self.get_family_raw(family_id)
if not family['RL2']:
raise APIError('No RL2 to update on family')
rl2 = post_data
rl2['adresse'] = family['RL2']['adresse']
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'rl2': rl2,
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Ajout d'un enfant",
name='create-child',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'force': {
'description': 'boolean to bypass doublon error',
'type': 'bool',
'example_value': 'false',
},
},
post={'request_body': {'schema': {'application/json': family_schemas.CREATE_CHILD_SCHEMA}}},
)
def create_child(self, request, post_data, NameID=None, family_id=None, force=False):
family_id = family_id or self.get_link(NameID).family_id
self.assert_child_payload_in_referential(post_data)
payload = {
'numDossier': family_id,
'isForceCreateChild': force,
'child': post_data,
}
response = self.call('Family', 'createChild', **payload)
data = serialize_object(response)
child_id = data.get('number')
if not child_id:
errors = data.get('childErrorList') or []
raise APIError(' ; '.join(errors))
return {'data': {'child_id': child_id}}
@endpoint(
display_category='Famille',
description="Modification d'un enfant",
name='update-child',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_CHILD_SCHEMA}}},
)
def update_child(self, request, post_data, child_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_child_payload_in_referential(post_data)
self.replace_null_values(post_data)
family = self.get_family_raw(family_id)
child = post_data
child['num'] = child_id
for known_child in family['childList']:
if str(known_child['num']) == child_id:
child['authorizedPersonList'] = known_child['authorizedPersonList']
break
else:
raise APIError('No child %s to update on family' % child_id)
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'childList': [child],
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Mise à jour des coordonnées d'un responsable légal",
name='update-coordinate',
perm='can_access',
parameters={
'rl_id': {'description': 'Numéro du représentant légal'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_COORDINATE_SCHEMA}}},
)
def update_coordinate(self, request, post_data, rl_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_update_coordinate_payload_in_referential(post_data)
self.replace_null_values(post_data)
self.call('Family', 'updateCoordinate', numDossier=family_id, numPerson=rl_id, **post_data)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Mise à jour des indicateurs d'un responsable légal",
name='update-rl-indicator',
perm='can_access',
parameters={
'rl_id': {'description': 'Numéro du représentant légal'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_INDICATOR_SCHEMA}}},
)
def update_rl_indicator(self, request, post_data, rl_id, NameID=None, family_id=None):
assert family_id or self.get_link(NameID)
self.assert_update_indicator_payload_in_referential('RLIndicator', post_data)
self.call('Family', 'updatePersonIndicatorList', numPerson=rl_id, **post_data)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Créer ou mettre à jour un quotient d'un responsable légal",
name='update-quotient',
perm='can_access',
parameters={
'rl_id': {'description': "Numéro du responsable légal"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_QUOTIENT_SCHEMA}}},
)
def update_quotient(self, request, post_data, rl_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_post_data_in_referential('Quotient', post_data, ['cdquo'])
payload = {
'dossierNumber': family_id,
'personNumber': rl_id,
'quotient': post_data,
}
self.call('Family', 'createUpdateQuotient', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Création d'une personne à prévenir en cas d'urgence",
name='create-person',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.EMERGENCY_PERSON_SCHEMA}}},
)
def create_person(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_person_payload_in_referential(post_data)
family = self.get_family_raw(family_id)
personList = family['emergencyPersonList']
personList.append(post_data)
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'emergencyPersonList': [{'personList': personList}],
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Mise à jour d'une personne à prévenir en cas d'urgence",
name='update-person',
perm='can_access',
parameters={
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.EMERGENCY_PERSON_SCHEMA}}},
)
def update_person(self, request, post_data, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_person_payload_in_referential(post_data)
family = self.get_family_raw(family_id)
personList = family['emergencyPersonList']
for i, person in enumerate(personList):
if str(person['numPerson']) == person_id:
personList[i] = post_data
personList[i]['numPerson'] = person_id
break
else:
raise APIError("no '%s' authorized person on '%s' family" % (person_id, family_id))
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'emergencyPersonList': [{'personList': personList}],
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Suppression d'une personne à prévenir en cas d'urgence",
name='delete-person',
perm='can_access',
parameters={
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def delete_person(self, request, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
family = self.get_family_raw(family_id)
personList = family['emergencyPersonList']
for i, person in enumerate(personList):
if str(person['numPerson']) == person_id:
del personList[i]
break
else:
raise APIError("no '%s' authorized person on '%s' family" % (person_id, family_id))
payload = {
'dossierNumber': family_id,
'category': family['category'],
'situation': family['situation'],
'flagCom': family['flagCom'],
'nbChild': family['nbChild'],
'nbTotalChild': family['nbTotalChild'],
'nbAES': family['nbAES'],
'emergencyPersonList': [{'personList': personList}],
}
self.call('Family', 'updateFamily', **payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Création d'une personne autorisée à récupérer l'enfant",
name='create-child-person',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.AUTHORIZED_PERSON_SCHEMA}}},
)
def create_child_person(self, request, post_data, child_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_child_person_payload_in_referential(post_data)
child = self.get_child_raw(family_id, child_id)
personList = child['authorizedPersonList']
personList.append(post_data)
req = {
'numFamily': family_id,
'numPerson': child_id,
'bLeaveAlone': child['bLeaveAlone'],
'bPhoto': child['bPhoto'],
'personList': personList,
}
self.call('Family', 'updateChildAutorization', updateChildAutorizationRequest=req)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Mise à jour d'une personne autorisée à récupérer l'enfant",
name='update-child-person',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.AUTHORIZED_PERSON_SCHEMA}}},
)
def update_child_person(self, request, post_data, child_id, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
self.assert_child_person_payload_in_referential(post_data)
child = self.get_child_raw(family_id, child_id)
personList = child['authorizedPersonList']
for i, person in enumerate(personList):
if str(person['personInfo']['num']) == person_id:
personList[i] = post_data
personList[i]['personInfo']['num'] = person_id
break
else:
raise APIError("No '%s' authorized person on '%s' child" % (person_id, child_id))
req = {
'numFamily': family_id,
'numPerson': child_id,
'bLeaveAlone': child['bLeaveAlone'],
'bPhoto': child['bPhoto'],
'personList': personList,
}
self.call('Family', 'updateChildAutorization', updateChildAutorizationRequest=req)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Suppression d'une personne autorisée à récupérer l'enfant",
name='delete-child-person',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'person_id': {'description': 'Numéro de la personne'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def delete_child_person(self, request, child_id, person_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
child = self.get_child_raw(family_id, child_id)
personList = child['authorizedPersonList']
for i, person in enumerate(personList):
if str(person['personInfo']['num']) == person_id:
del personList[i]
break
else:
raise APIError("No '%s' authorized person on '%s' child" % (person_id, child_id))
req = {
'numFamily': family_id,
'numPerson': child_id,
'bLeaveAlone': child['bLeaveAlone'],
'bPhoto': child['bPhoto'],
'personList': personList,
}
self.call('Family', 'updateChildAutorization', updateChildAutorizationRequest=req)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Créer ou mettre à jour le régime alimentaire d'un enfant",
name='update-child-dietcode',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'dietcode': {'description': 'code du régime alimentaire'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def update_child_dietcode(self, request, child_id, dietcode, NameID=None, family_id=None):
assert family_id or self.get_link(NameID)
self.assert_key_in_referential('DietCode', dietcode, 'dietcode parameter', required=False)
self.call('Family', 'createOrUpdateChildDiet', personNumber=child_id, code=dietcode)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Créer ou mettre à jour les informations relatives au PAI d'un enfant",
name='update-child-pai',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.PAIINFO_SCHEMA}}},
)
def update_child_pai(self, request, post_data, child_id, NameID=None, family_id=None):
assert family_id or self.get_link(NameID)
self.assert_child_pai_payoad_in_referential(post_data)
# use None to empty date passed as an empty string by date filter
for key in ('dateDeb', 'dateFin'):
if post_data[key] == '':
post_data[key] = None
self.call('Family', 'updateChildPAI', personNumber=child_id, **post_data)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Créer ou mettre à jour les données médicales d'un enfant",
name='update-child-medical-record',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.MEDICALRECORD_SCHEMA}}},
)
def update_child_medical_record(self, request, post_data, child_id, NameID=None, family_id=None):
assert family_id or self.get_link(NameID)
self.assert_child_medical_record_payload_in_referential(post_data)
self.replace_null_values(post_data)
payload = {
'numPerson': child_id,
'medicalRecord': post_data,
}
self.call('Family', 'updateChildMedicalRecord', updateChildMedicalRecordRequest=payload)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description="Mise à jour des indicateurs d'un enfant",
name='update-child-indicator',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.UPDATE_INDICATOR_SCHEMA}}},
)
def update_child_indicator(self, request, post_data, child_id, NameID=None, family_id=None):
assert family_id or self.get_link(NameID)
self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data)
self.call('Family', 'updatePersonIndicatorList', numPerson=child_id, **post_data)
return {'data': 'ok'}
@endpoint(
display_category='Famille',
description='Ajoute un document pour une famille, un responsable légal ou un enfant',
name='add-supplied-document',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={'request_body': {'schema': {'application/json': family_schemas.SUPPLIED_DOCUMENTS_SCHEMA}}},
)
def add_supplied_document(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
for i in range(0, len(post_data.get('documentList', []))):
self.assert_post_data_in_referential('Document', post_data, ['documentList', i, 'code'])
for item in post_data['documentList']:
file = item.pop('file')
item['filename'] = file['filename']
item['fileSupplied'] = {
'dataHandler': base64.b64decode(file['content']),
'fileType': file['content_type'],
'name': file['filename'],
}
payload = {'addSuppliedDocumentRequestBean': post_data}
payload['addSuppliedDocumentRequestBean']['numDossier'] = family_id
response = self.call('Family', 'addSuppliedDocument', **payload)
data = serialize_object(response)
if data != 'OK':
raise APIError('maelis fails to add the supplied document')
return {'data': 'ok'}
def get_start_and_end_dates(self, start_date, end_date):
try:
start_date = datetime.datetime.strptime(start_date, utils.json_date_format).date()
end_date = datetime.datetime.strptime(end_date, utils.json_date_format).date()
except ValueError:
raise APIError('bad date format, should be YYYY-MM-DD', http_status=400)
if start_date > end_date:
raise APIError('start_date should be before end_date', http_status=400)
reference_year = utils.get_reference_year_from_date(start_date)
end_reference_year = utils.get_reference_year_from_date(end_date)
if reference_year != end_reference_year:
raise APIError(
'start_date and end_date are in different reference year (%s != %s)'
% (reference_year, end_reference_year),
http_status=400,
)
return start_date, end_date, reference_year
def get_bookings(self, family_id, child_id, start_date, end_date):
bookings = []
for booking_date in rrule.rrule(rrule.MONTHLY, dtstart=start_date.replace(day=1), until=end_date):
payload = {
'requestBean': {
'numDossier': family_id,
'numPerson': child_id,
'year': booking_date.year,
'month': booking_date.month,
}
}
response = self.call('Activity', 'getPersonScheduleList', **payload)
result = serialize_object(response)
for result_data in result or []:
for schedule in result_data['activityScheduleList']:
activity = schedule['activity']
if not activity['activityType']['natureSpec']:
continue
if activity['activityType']['natureSpec']['code'] not in ['A', 'R']:
continue
activity_id = activity['idAct']
many_units = len(schedule['unitScheduleList']) > 1
for unit in schedule['unitScheduleList']:
days = unit['dayInfoList']
for day in days:
if day['status'] in ['NO_READ', 'NO_CUSTODY']:
continue
booking = {
'id': '%s:%s:%s'
% (child_id, activity_id, day['day'].strftime(utils.json_date_format)),
'text': dateformat.format(day['day'], 'l j F Y'),
'prefill': day['scheduledPresence'] > 0 or day['realPresence'] > 1,
'disabled': day['status'] != 'WRITABLE',
'details': day,
}
color = 'white'
if booking['prefill']:
color = 'green'
booking['details']['status_color'] = color
booking['details']['activity_id'] = activity_id
booking['details']['activity_type'] = activity['activityType']['code']
booking['details']['activity_label'] = activity['activityType']['libelle']
if many_units:
booking['details']['activity_label'] += ' (%s)' % unit['unit']['libelle']
booking['details']['child_id'] = child_id
booking['details']['day_str'] = day['day'].strftime(utils.json_date_format)
booking['details']['unit_id'] = unit['unit']['idUnit']
bookings.append(booking)
# sort bookings
activity_types = ['ACCMAT', 'RESTSCOL', 'ACCPERI', 'ACCSOIR']
bookings = [
(
b['details']['day'],
activity_types.index(b['details']['activity_type'])
if b['details']['activity_type'] in activity_types
else 0,
b['details']['activity_label'],
b,
)
for b in bookings
]
bookings = sorted(bookings, key=itemgetter(0, 1, 2))
bookings = [b for d, a, l, b in bookings]
return bookings
@endpoint(
display_category='Réservation',
description="Agenda d'un enfant",
name='read-child-agenda',
perm='can_access',
parameters={
'child_id': {'description': "Numéro de l'enfant"},
'start_date': {'description': 'Début de la période'},
'end_date': {'description': 'Fin de la période'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def read_child_agenda(self, request, child_id, start_date, end_date, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
start_date, end_date, reference_year = self.get_start_and_end_dates(start_date, end_date)
bookings = self.get_bookings(family_id, child_id, start_date, end_date)
return {
'data': bookings,
'extra_data': {
'start_date': start_date,
'end_date': end_date,
'school_year': '%s/%s' % (reference_year, reference_year + 1),
},
}
@endpoint(
display_category='Réservation',
description="Modifier l'agenda d'un enfant",
name='update-child-agenda',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={
'request_body': {
'schema': {
'application/json': activity_schemas.BOOKING_SCHEMA,
}
}
},
)
def update_child_agenda(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
child_id = post_data['child_id']
start_date, end_date, dummy = self.get_start_and_end_dates(
post_data['start_date'], post_data['end_date']
)
requested_bookings = post_data['booking_list']
# build list of existing booked days
bookings = self.get_bookings(family_id, child_id, start_date, end_date)
legacy_bookings = [b['id'] for b in bookings if b['prefill'] is True]
available_bookings = [b['id'] for b in bookings if b['disabled'] is False]
bookings_to_update = []
updated = []
for booking_info in bookings:
day_id = booking_info['id']
booked = None
action = booking_info['details']['action']
if day_id not in available_bookings:
# disabled or not available: not bookable
booked = None
elif (
day_id not in legacy_bookings
and day_id in requested_bookings
and action in ['ADD_PRES_PREVI', 'ADD_PRES_REAL', 'DEL_ABSENCE']
):
booked = action
elif (
day_id in legacy_bookings
and day_id not in requested_bookings
and action in ['DEL_PRES_PREVI', 'DEL_PRES_REAL', 'ADD_ABSENCE']
):
booked = action
if booked is not None:
# no changes, don't send the day
bookings_to_update.append(
{
'numPerson': child_id,
'idAct': booking_info['details']['activity_id'],
'idUni': booking_info['details']['unit_id'],
'date': booking_info['details']['day_str'],
'action': booked,
}
)
updated.append(
{
'activity_id': booking_info['details']['activity_id'],
'activity_type': booking_info['details']['activity_type'],
'activity_label': booking_info['details']['activity_label'],
'day': booking_info['details']['day_str'],
'booked': booked in ['ADD_PRES_PREVI', 'ADD_PRES_REAL', 'DEL_ABSENCE'],
}
)
if not bookings_to_update:
# don't call maelis if no changes
return updated
payload = {
'requestBean': {
'numDossier': family_id,
'unitPersonDayInfoList': bookings_to_update,
}
}
response = self.call('Activity', 'updatePersonSchedule', **payload)
errors = serialize_object(response)
if errors:
raise APIError(' ; '.join(errors))
# sort changes
activity_types = ['ACCMAT', 'RESTSCOL']
updated = [
(
not u['booked'],
activity_types.index(u['activity_type']) if u['activity_type'] in activity_types else 0,
u['activity_label'],
u['day'],
u,
)
for u in updated
]
updated = sorted(updated, key=itemgetter(0, 1, 2, 3))
updated = [u for b, a, l, d, u in updated]
updated = [
{
'booked': u['booked'],
'activity_id': u['activity_id'],
'activity_label': u['activity_label'],
'day': u['day'],
}
for u in updated
]
return {
'updated': True,
'count': len(updated),
'changes': updated,
}
@endpoint(
display_category='Facture',
description="Ajout d'autorisation de prélèvement",
name='add-rl1-direct-debit-order',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
post={
'request_body': {'schema': {'application/json': invoice_schemas.ADD_DIRECT_DEBIT_ORDER_SCHEMA}}
},
)
def add_rl1_direct_debit_order(self, request, post_data, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
family = self.get_family_raw(family_id)
post_data['numPerson'] = family['RL1']['num']
self.call('Invoice', 'addDirectDebitOrder', numDossier=family_id, **post_data)
return {'data': 'ok'}
@endpoint(
display_category='Facture',
description="Lecture des informations relatives à l'autorisation de prélèvement en cours à la date de référence",
name='get-rl1-direct-debit-order',
perm='can_access',
parameters={
'codeRegie': {'description': 'Code de la régie'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'dateRef': {
'description': 'Date de référence',
'type': 'date',
},
},
)
def get_rl1_direct_debit_order(self, request, codeRegie, dateRef, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
family = self.get_family_raw(family_id)
payload = {
'numDossier': family_id,
'numPerson': family['RL1']['num'],
'codeRegie': codeRegie,
'dateRef': dateRef,
}
response = self.call('Invoice', 'getDirectDebitOrder', **payload)
data = serialize_object(response)
return {'data': data}
@endpoint(
display_category='Inscriptions',
description="Liste les années scolaires",
name='read-school-years-list',
perm='can_access',
)
def read_school_years_list(self, request):
return {'data': self.get_referential('YearSchool')}
@endpoint(
display_category='Inscriptions',
description="Liste les niveaux scolaires",
name='read-school-levels-list',
perm='can_access',
parameters={
'age': {'description': 'Age de l\'enfant', 'example_value': '6'},
},
)
def read_school_levels_list(self, request, age=None):
data = self.get_referential('Level')
if age and age.isnumeric():
return {'data': [item for item in data if item.get('age') == int(age)]}
return {'data': data}
@endpoint(
display_category='Inscriptions',
description="Liste les motifs de dérogation",
name='read-exemption-reasons-list',
perm='can_access',
)
def read_exemption_reasons_list(self, request):
return {'data': self.get_referential('DerogReason')}
@endpoint(
display_category='Inscriptions',
description="Liste les écoles pour une adresse et niveau scolaire",
name='read-schools-for-address-and-level',
perm='can_access',
parameters={
'year': {'description': 'Année', 'example_value': '2022'},
'id_street': {'description': 'Identifiant de la voie', 'example_value': '2317'},
'num': {'description': 'Numero dans la voie', 'example_value': '4'},
'comp': {'description': 'Complément d\'adresse (bis, ...)'},
'level': {'description': 'Niveau scolaire'},
},
)
def read_schools_for_address_and_level(self, request, id_street, year, num, comp=None, level=None):
data = {'schoolYear': year, 'adresse': {'idStreet': id_street, 'num': num}}
if level:
data['levelCode'] = level
if comp:
data['adresse']['numComp'] = comp
response = self.call(
'Site', 'readSchoolForAdressAndLevel', readSchoolForAdressAndLevelRequestBean=data
)
data = []
for item in serialize_object(response):
item['id'] = item['idSchool']
item['text'] = item['schoolName']
data.append(item)
return {'data': serialize_object(data)}
@endpoint(
display_category='Inscriptions',
description="Liste les écoles pour un enfant et niveau scolaire",
name='read-schools-for-child-and-level',
perm='can_access',
parameters={
'year': {'description': 'Année', 'example_value': '2023'},
'child_id': {'description': 'Identifiant de l\'enfant', 'example_value': '190115'},
'level': {'description': 'Niveau scolaire'},
},
)
def read_schools_for_child_and_level(self, request, child_id, year, level=None):
data = {
'numPerson': child_id,
'schoolYear': year,
}
if level:
data['levelCode'] = level
response = self.call('Family', 'readSchoolForChildAndLevel', **data)
data = []
for item in serialize_object(response):
item['id'] = item['idSchool']
item['text'] = item['schoolName']
data.append(item)
return {'data': serialize_object(data)}
@endpoint(
display_category='Inscriptions',
description="Remonte les informations scolaires d'un enfant",
name='read-child-school-informations',
perm='can_access',
parameters={
'child_id': {'description': 'Identifiant de l\'enfant', 'example_value': '190115'},
'level': {'description': 'Niveau scolaire', 'example_value': 'CP'},
'year': {'description': 'Année scolaire', 'example_value': '2023'},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def read_child_school_informations(self, request, child_id, level, year, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
data = {'numDossier': family_id, 'numPerson': child_id, 'schoolYear': year, 'level': level}
response = self.call(
'Family', 'getChildSubscribeSchoolInformation', getFamilySubscribeSchoolInfoRequestBean=data
)
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Création d'une pré-inscription scolaire pour un enfant",
name='create-child-school-pre-registration',
perm='can_access',
post={
'request_body': {'schema': {'application/json': family_schemas.SCHOOL_PRE_REGISTRATION_SCHEMA}}
},
)
def create_child_school_pre_registration(self, request, post_data):
response = self.call('Family', 'preSubscribeSchoolPerim', **post_data)
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Création d'une pré-inscription scolaire avec demande de dérogation",
name='create-child-school-pre-registration-with-exemption',
perm='can_access',
post={
'request_body': {
'schema': {'application/json': family_schemas.SCHOOL_PRE_REGISTRATION_WITH_EXEMPTION_SCHEMA}
}
},
)
def create_child_school_pre_registration_with_exemption(self, request, post_data):
response = self.call('Family', 'presubscribeSchoolDerog', **post_data)
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Création d'une pré-inscription scolaire avec rapprochement de fratrie",
name='create-child-school-pre-registration-with-sibling',
perm='can_access',
post={
'request_body': {
'schema': {'application/json': family_schemas.SCHOOL_PRE_REGISTRATION_WITH_SIBLING_SCHEMA}
}
},
)
def create_child_school_pre_registration_with_sibling(self, request, post_data):
response = self.call('Family', 'presubscribeSchoolSibling', **post_data)
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Catalogue des activités loisir",
name='read-activity-list',
perm='can_access',
parameters={
'ref_date': {
'description': "Date de référence, utilisée pour déduire l'année scolaire",
'type': 'date',
},
},
)
def read_activity_list(self, request, ref_date):
reference_year = utils.get_reference_year_from_date(ref_date)
labels = {
'nature': "Nature de l'activité",
'type': "Type d'activité",
'public': 'Public',
'day': 'Jours',
}
day_names = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche']
all_criterias = {key: {'text': value, 'data': {}} for key, value in labels.items()}
criterias = {key: {'text': value, 'data': {}} for key, value in labels.items()}
catalogs = self.get_referential('ActivityCatalog', id=reference_year)
activities = catalogs[0]['data'] if catalogs else []
def add_criteria(label_key, criteria_key, criteria_value):
criterias[label_key]['data'][criteria_key] = criteria_value
if criteria_key not in all_criterias[label_key]['data']:
all_criterias[label_key]['data'][criteria_key] = criteria_value
def update_criterias_order_field(criterias_dict, label_keys=None):
if not label_keys:
label_keys = criterias_dict.keys()
for label_key in label_keys:
if label_key in ('public', 'day'):
criterias_dict[label_key]['order'] = sorted(x for x in criterias_dict[label_key]['data'])
else:
criterias_dict[label_key]['order'] = [
x[0]
for x in sorted(criterias_dict[label_key]['data'].items(), key=lambda x: x[1].lower())
]
data = []
for activity in activities:
if activity['activityPortail']['activityType']['natureSpec']['code'] not in ('P', 'L', 'S'):
continue
activity['id'] = activity['activityPortail']['idAct']
activity['text'] = activity['activityPortail']['libelle']
activity_type = activity['activityPortail']['activityType']
activity_nature = activity_type['natureSpec']
for label_key in criterias:
criterias[label_key]['data'] = {}
add_criteria('nature', activity_nature['code'], activity_nature['libelle'])
add_criteria('type', activity_type['code'], activity_type['libelle'])
if activity['activityPortail']['weeklyCalendarActivityList']:
for day in activity['activityPortail']['weeklyCalendarActivityList'][0]['dayWeekInfoList']:
if day['isOpen']:
add_criteria('day', str(day['dayNum']), day_names[day['dayNum'] - 1])
update_criterias_order_field(criterias, ['nature', 'type', 'day'])
for unit in activity.pop('unitPortailList'):
unit['id'] = unit['idUnit']
unit['text'] = unit['libelle']
criterias['public']['data'] = {}
for key, value in utils.get_public_criterias(
datetime.date.today(), unit['birthDateStart'], unit['birthDateEnd']
):
add_criteria('public', key, value)
update_criterias_order_field(criterias, ['public'])
for place in unit.pop('placeList'):
place['id'] = place['id']
place['text'] = place['lib2'] or place['lib']
data.append(
{
'id': '%s-%s-%s' % (activity['id'], unit['id'], place['id']),
'text': '%s, %s, %s' % (activity['text'], unit['text'], place['text']),
'activity': activity,
'unit': unit,
'place': place,
'criterias': copy.deepcopy(criterias),
}
)
update_criterias_order_field(all_criterias)
return {
'data': data,
'meta': {
'reference_year': reference_year,
'all_criterias': all_criterias,
'all_criterias_order': ['nature', 'type', 'public', 'day'],
},
}
@endpoint(
display_category='Inscriptions',
description="Catalogue des activités d'une personne",
name='get-person-activity-list',
perm='can_access',
parameters={
'person_id': {'description': "Numéro du responsale légal ou de l'enfant"},
'nature_id': {'description': "Numéro de la nature des activités"},
'start_date': {'description': 'Début de la période'},
'end_date': {'description': 'Fin de la période'},
'text_template': {
'description': "template utilisé pour la valeur text (URL encoding)",
'example_value': '{{ activity.libelle2 }}',
},
},
)
def get_person_activity_list(
self,
request,
person_id,
NameID=None,
family_id=None,
nature_id=None,
start_date=None,
end_date=None,
text_template=None,
):
family_id = family_id or self.get_link(NameID).family_id
reference_year = None
if start_date and end_date:
start_date, end_date, reference_year = self.get_start_and_end_dates(start_date, end_date)
if not text_template:
text_template = '{{ activity.libelle2|default:activity.libelle1 }}'
response = self.get_person_activity_list_raw(
family_id,
person_id,
nature_id=nature_id,
reference_year=reference_year,
start_date=start_date and start_date.strftime(utils.json_date_format),
end_date=start_date and end_date.strftime(utils.json_date_format),
)
for item in response['catalogueActivityList']:
item['id'] = item['activity']['idActivity']
item['text'] = render_to_string(text_template, item).strip()
return {'data': response['catalogueActivityList'], 'meta': {'person': response['person']}}
@endpoint(
display_category='Inscriptions',
description="Liste les unités d'une activité pour une personne",
name='get-person-unit-list',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'person_id': {'description': "Numéro du responsale légal ou de l'enfant"},
'activity_id': {'description': "Numéro de l'activités"},
'start_date': {'description': 'Début de la période'},
'end_date': {'description': 'Fin de la période'},
'text_template': {
'description': 'template utilisée pour la valeur text (URL encoding)',
'example_value': '{{ libelle }}',
},
},
)
def get_person_unit_list(
self,
request,
person_id,
activity_id,
NameID=None,
family_id=None,
start_date=None,
end_date=None,
text_template=None,
):
family_id = family_id or self.get_link(NameID).family_id
reference_year = None
if start_date and end_date:
start_date, end_date, reference_year = self.get_start_and_end_dates(start_date, end_date)
if not text_template:
text_template = '{{ libelle }}'
response = self.get_person_activity_list_raw(
family_id,
person_id,
reference_year=reference_year,
start_date=start_date and start_date.strftime(utils.json_date_format),
end_date=start_date and end_date.strftime(utils.json_date_format),
)
for activity in response['catalogueActivityList']:
if activity['activity']['idActivity'] == activity_id:
break
else:
raise APIError('No activity %s for person' % activity_id)
data = activity.pop('unitInfoList')
meta = {'person': response['person'], 'activity': activity}
for item in data:
item['id'] = item['idUnit']
context = dict(item)
context['meta'] = meta
item['text'] = render_to_string(text_template, context).strip()
return {'data': data, 'meta': meta}
@endpoint(
display_category='Inscriptions',
description="Liste les lieux d'une unité pour une personne",
name='get-person-place-list',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'person_id': {'description': "Numéro du responsale légal ou de l'enfant"},
'activity_id': {'description': "Numéro de l'activités"},
'unit_id': {'description': "Numéro de l'unité"},
'start_date': {'description': 'Début de la période'},
'end_date': {'description': 'Fin de la période'},
'text_template': {
'description': 'template utilisée pour la valeur text (URL encoding)',
'example_value': '{{ libelle }}',
},
},
)
def get_person_place_list(
self,
request,
person_id,
activity_id,
unit_id,
NameID=None,
family_id=None,
start_date=None,
end_date=None,
text_template=None,
):
family_id = family_id or self.get_link(NameID).family_id
reference_year = None
if start_date and end_date:
start_date, end_date, reference_year = self.get_start_and_end_dates(start_date, end_date)
if not text_template:
text_template = '{{ place.lib2|default:place.lib1 }}'
response = self.get_person_activity_list_raw(
family_id,
person_id,
reference_year=reference_year,
start_date=start_date and start_date.strftime(utils.json_date_format),
end_date=start_date and end_date.strftime(utils.json_date_format),
)
for activity in response['catalogueActivityList']:
if activity['activity']['idActivity'] == activity_id:
break
else:
raise APIError('No activity %s for person' % activity_id)
for unit in activity['unitInfoList']:
if unit['idUnit'] == unit_id:
break
else:
raise APIError('No unit %s for person' % unit_id)
data = unit.pop('placeInfoList')
del activity['unitInfoList']
meta = {'person': response['person'], 'activity': activity, 'unit': unit}
for item in data:
item['id'] = item['place']['idPlace']
context = dict(item)
context['meta'] = meta
item['text'] = render_to_string(text_template, context).strip()
return {'data': data, 'meta': meta}
@endpoint(
display_category='Inscriptions',
description="Catalog geojson pour une personne",
name='get-person-catalog-geojson',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'person_id': {'description': "Numéro du responsale légal ou de l'enfant"},
'nature_id': {'description': "Numéro de la nature des activités"},
'start_date': {'description': 'Début de la période'},
'end_date': {'description': 'Fin de la période'},
'activity_id': {'description': "Numéro de l'activités"},
'unit_id': {'description': "Numéro de l'unité"},
'place_id': {'description': "Numéro du lieu"},
},
)
def get_person_catalog_geojson(
self,
request,
person_id,
NameID=None,
family_id=None,
start_date=None,
end_date=None,
nature_id=None,
activity_id=None,
unit_id=None,
place_id=None,
):
family_id = family_id or self.get_link(NameID).family_id
reference_year = None
if start_date and end_date:
start_date, end_date, reference_year = self.get_start_and_end_dates(start_date, end_date)
response = self.get_person_activity_list_raw(
family_id,
person_id,
nature_id=nature_id,
reference_year=reference_year,
start_date=start_date and start_date.strftime(utils.json_date_format),
end_date=start_date and end_date.strftime(utils.json_date_format),
)
def places(properties, place_list, place_id=None):
for place in place_list:
properties['place'] = place
properties['place_id'] = place['place']['idPlace']
if not place['place']['longitude'] or not place['place']['latitude']:
continue
if place_id:
if properties['place_id'] == place_id:
yield properties
break
else:
yield properties
def units(properties, unit_list, unit_id=None, place_id=None):
for unit in unit_list:
place_list = unit.pop('placeInfoList')
properties['unit'] = unit
properties['unit_id'] = unit['idUnit']
if unit_id:
if properties['unit_id'] == unit_id:
yield from places(properties, place_list, place_id)
break
else:
yield from places(properties, place_list, place_id)
def activities(activity_id=None, unit_id=None, place_id=None):
for activity in response['catalogueActivityList']:
unit_list = activity.pop('unitInfoList')
properties = {
'person': response['person'],
'activity_id': activity['activity']['idActivity'],
'activity': activity,
}
if activity_id:
if properties['activity_id'] == activity_id:
yield from units(properties, unit_list, unit_id, place_id)
break
else:
yield from units(properties, unit_list, unit_id, place_id)
geojson = {
'type': 'FeatureCollection',
'features': [],
}
for item in activities(activity_id, unit_id, place_id):
geojson['features'].append(
{
'type': 'Feature',
'geometry': {
'coordinates': [
float(item['place']['place']['longitude']),
float(item['place']['place']['latitude']),
],
'type': 'Point',
},
'properties': {
'id': '%s:%s:%s' % (item['activity_id'], item['unit_id'], item['place_id']),
'text': '%s / %s / %s'
% (
item['activity']['activity']['libelle1'],
item['unit']['libelle'],
item['place']['place']['lib1'],
),
**item,
},
}
)
return geojson
@endpoint(
display_category='Inscriptions',
description="Liste les natures des activités",
name='read-activity-nature-list',
perm='can_access',
)
def read_activity_nature_list(self, request):
return {'data': self.get_referential('ActivityNatureType')}
@endpoint(
display_category='Inscriptions',
description="Liste les indicateurs pour les activités petite enfance",
name='read-ape-indicators-list',
perm='can_access',
)
def read_ape_indicators_list(self, request):
return {'data': self.get_referential('ApeIndicator')}
@endpoint(
display_category='Inscriptions',
description="Informations pour s'inscrire puis réserver sur l'extra-scolaire ou le loisir",
name='get-person-subscription-info',
perm='can_access',
parameters={
'person_id': {'description': "Numéro du responsale légal ou de l'enfant"},
'activity_id': {'description': "Numéro de l'activité"},
'unit_id': {'description': "Numéro de l'unité"},
'place_id': {'description': "Numéro du lieu"},
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'ref_date': {'description': 'Date du début du calcul'},
},
)
def get_person_subscription_info(
self,
request,
person_id,
activity_id,
unit_id,
place_id,
NameID=None,
family_id=None,
ref_date=None,
):
family_id = family_id or self.get_link(NameID).family_id
if ref_date:
try:
ref_date = parse_date(ref_date)
except ValueError:
raise APIError('%s is not a valid date' % ref_date, http_status=400)
if not ref_date:
raise APIError('bad date format, should be YYYY-MM-DD', http_status=400)
ref_date = ref_date.strftime(utils.json_date_format)
params = {
'numDossier': family_id,
'numPerson': person_id,
'activityUnitPlace': {
'idActivity': activity_id,
'idUnit': unit_id,
'idPlace': place_id,
},
'dateRef': ref_date,
}
response = self.call('Activity', 'getPersonUnitInfo', getPersonUnitInfoRequestBean=params)
data = serialize_object(response)
return {'data': data}
@endpoint(
display_category='Inscriptions',
description="Ajoute au panier une inscription extra-scolaire ou loisir",
name='add-person-basket-subscription',
post={
'request_body': {
'schema': {
'application/json': activity_schemas.SUBSCRIPTION_SCHEMA,
}
}
},
)
def add_person_basket_subscription(
self,
request,
post_data,
NameID=None,
family_id=None,
):
family_id = family_id or self.get_link(NameID).family_id
payload = {
'addPersonUnitBasketRequestBean': {
'numFamily': family_id,
'numPerson': post_data['person_id'],
'idAct': post_data['activity_id'],
'idUnit': post_data['unit_id'],
'idPlace': post_data['place_id'],
'dateStartSubscribe': post_data['start_date'],
'dateEndSubscribe': post_data['end_date'],
}
}
response = self.call('Activity', 'addPersonUnitBasket', **payload)
if not response['controlResult']['controlOK']:
raise APIError(response['controlResult']['message'])
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Lecture du panier de la famille",
name='get-basket',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
)
def get_basket(self, request, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
return {'data': self.get_basket_raw(family_id)}
@endpoint(
display_category='Inscriptions',
description="Prolonge la durée de vie du panier",
name='update-basket-time',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def update_basket_time(self, request, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
basket = self.get_basket_raw(family_id)
if not basket or not basket.get('id'):
raise APIError("no basket on '%s' family" % family_id)
self.call('Activity', 'updateBasketTime', idBasket=basket['id'])
return {'data': 'ok'}
@endpoint(
display_category='Inscriptions',
description="Suppression d'une ligne du panier",
name='delete-basket-line',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
'line_id': {'description': 'Numéro de ligne du panier'},
},
methods=['post'],
)
def delete_basket_line(self, request, line_id, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
basket = self.get_basket_raw(family_id)
if not basket or not basket.get('id'):
raise APIError("no basket on '%s' family" % family_id)
for line in basket['lignes']:
if line['id'] == line_id:
break
else:
raise APIError("no '%s' basket line on '%s' family" % (line_id, family_id))
response = self.call(
'Activity',
'deletePersonUnitBasket',
deletePersonUnitBasketRequestBean={
'idBasketLine': line_id,
},
)
return {'data': serialize_object(response)}
@endpoint(
display_category='Inscriptions',
description="Suppression du panier de la famille",
name='delete-basket',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def delete_basket(self, request, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
basket = self.get_basket_raw(family_id)
if not basket or not basket.get('id'):
raise APIError("no basket on '%s' family" % family_id)
self.call(
'Activity',
'deleteBasket',
deleteBasketRequestBean={
'idBasket': basket['id'],
'idUtilisat': NameID or 'Middle-office',
},
)
return {'data': 'ok'}
@endpoint(
display_category='Inscriptions',
description="Validation du panier de la famille",
name='validate-basket',
perm='can_access',
parameters={
'NameID': {'description': 'Publik NameID'},
'family_id': {'description': 'Numéro de DUI'},
},
methods=['post'],
)
def validate_basket(self, request, NameID=None, family_id=None):
family_id = family_id or self.get_link(NameID).family_id
basket = self.get_basket_raw(family_id)
if not basket or not basket.get('id'):
raise APIError("no basket on '%s' family" % family_id)
response = self.call(
'Activity',
'validateBasket',
validateBasketRequestBean={
'idBasket': basket['id'],
},
)
return {'data': serialize_object(response)}
class Link(models.Model):
resource = models.ForeignKey(ToulouseMaelis, on_delete=models.CASCADE)
name_id = models.CharField(blank=False, max_length=256)
family_id = models.CharField(blank=False, max_length=128)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('resource', 'name_id')
class Referential(models.Model):
resource = models.ForeignKey(
verbose_name='Resource',
to=ToulouseMaelis,
on_delete=models.CASCADE,
related_name='referential',
)
referential_name = models.TextField('Name')
item_id = models.TextField('Key')
item_text = models.TextField('Text')
item_unaccent_text = models.TextField('Text', null=True)
item_data = JSONField('Data', encoder=DjangoJSONEncoder)
created = models.DateTimeField('Created', auto_now_add=True)
updated = models.DateTimeField('Updated', auto_now=True)
def __repr__(self):
return '<Referential "%s/%s">' % (self.referential_name, self.item_id)
class Meta:
ordering = ('resource', 'referential_name', 'item_text', 'item_id')
unique_together = [['resource', 'referential_name', 'item_id']]