From 91465044ab3be5ff7dd4eeb96e0f04d70229e8e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Mon, 27 Jan 2020 15:39:31 +0100
Subject: [PATCH] toulouse_axel: add labels to explain some values (#39291)

---
 functests/toulouse_axel/test_toulouse_axel.py |  8 ++-
 passerelle/contrib/toulouse_axel/models.py    | 46 +++++++++++--
 passerelle/contrib/toulouse_axel/utils.py     | 66 +++++++++++++++++++
 tests/data/toulouse_axel/family_info.xml      |  4 +-
 tests/test_toulouse_axel.py                   | 44 +++++++++++++
 5 files changed, 158 insertions(+), 10 deletions(-)
 create mode 100644 passerelle/contrib/toulouse_axel/utils.py

diff --git a/functests/toulouse_axel/test_toulouse_axel.py b/functests/toulouse_axel/test_toulouse_axel.py
index b6214603..47c465ff 100644
--- a/functests/toulouse_axel/test_toulouse_axel.py
+++ b/functests/toulouse_axel/test_toulouse_axel.py
@@ -45,19 +45,21 @@ def test_link(conn, user):
     payload['DROITALIMAGE'] = 'NON'
     payload['REVENUS']['CHOIXREVENU'] = ''
     # remove non editable fields
-    for key in ['SITUATIONFAMILIALE', 'NBENFANTACTIF', 'NBRLACTIF', 'IDDUI', 'CODEMISEAJOUR']:
+    for key in ['SITUATIONFAMILIALE', 'SITUATIONFAMILIALE_label', 'NBENFANTACTIF', 'NBRLACTIF', 'IDDUI', 'CODEMISEAJOUR']:
         payload.pop(key)
-    for key in ['IDPERSONNE', 'NOM', 'PRENOM', 'NOMJEUNEFILLE', 'DATENAISSANCE', 'CIVILITE', 'INDICATEURRL']:
+    for key in ['IDPERSONNE', 'NOM', 'PRENOM', 'NOMJEUNEFILLE', 'DATENAISSANCE', 'CIVILITE', 'INDICATEURRL', 'CSP_label']:
         if 'RL1' in payload:
             payload['RL1'].pop(key)
         if 'RL2' in payload:
             payload['RL2'].pop(key)
-    for key in ['MONTANTTOTAL', 'DATEVALIDITE', 'SFI', 'IREVENUS', 'RNF', 'NBENFANTSACHARGE']:
+    for key in ['MONTANTTOTAL', 'DATEVALIDITE', 'SFI', 'IREVENUS', 'RNF', 'NBENFANTSACHARGE', 'TYPEREGIME_label']:
         payload['REVENUS'].pop(key, None)
     for enfant in payload['ENFANT']:
         for key in ['NOM', 'DATENAISSANCE', 'SEXE', 'PRENOMPERE', 'PRENOMMERE', 'NOMPERE', 'NOMMERE', 'RATTACHEAUTREDUI', 'PRENOM']:
             enfant.pop(key)
         enfant['AUTORISATIONURGENCEMEDICALE'] = 'OUI'
+        for contact in enfant.get('CONTACT', []):
+            contact.pop('LIENPARENTE_label')
         if 'SANITAIRE' not in enfant:
             continue
         # manage handicap data (not the same schema)
diff --git a/passerelle/contrib/toulouse_axel/models.py b/passerelle/contrib/toulouse_axel/models.py
index 25e31fd1..775869ce 100644
--- a/passerelle/contrib/toulouse_axel/models.py
+++ b/passerelle/contrib/toulouse_axel/models.py
@@ -36,6 +36,7 @@ from passerelle.compat import json_loads
 from passerelle.utils.api import endpoint
 from passerelle.utils.jsonresponse import APIError
 from passerelle.utils.xml import JSONSchemaFromXMLSchema
+from . import utils
 
 logger = logging.getLogger('passerelle.contrib.toulouse_axel')
 
@@ -520,6 +521,22 @@ class ToulouseAxel(BaseResource):
         link.delete()
         return {'link': link_id, 'deleted': True, 'dui': link.dui}
 
+    @endpoint(
+        description=_("Get a referential"),
+        perm='can_access',
+        pattern=r'^(?P<code>[\w-]+)/?$',
+        example_pattern='csp',
+        parameters={
+            'code': {'description': _('Referential code. Possible values: situation_familiale, csp, lien_parente, type_regime')},
+        })
+    def referential(self, request, code):
+        if code not in ['situation_familiale', 'csp', 'lien_parente', 'type_regime']:
+            raise APIError('Referential not found', err_code='not-found')
+        references = getattr(utils, '{}_mapping'.format(code))
+        if references is None:
+            raise APIError('Referential not found', err_code='not-found', http_status=404)
+        return {'data': [{'id': key, 'text': val} for key, val in references.items()]}
+
     def get_family_data(self, name_id):
         link = self.get_link(name_id)
         try:
@@ -540,8 +557,28 @@ class ToulouseAxel(BaseResource):
         })
     def family_info(self, request, NameID):
         family_data = self.get_family_data(NameID)
+        family_data['SITUATIONFAMILIALE_label'] = utils.get_label(utils.situation_familiale_mapping, family_data['SITUATIONFAMILIALE'])
+        for key in ['RL1', 'RL2']:
+            if key not in family_data:
+                continue
+            rl = family_data[key]
+            rl['CSP_label'] = utils.get_label(utils.csp_mapping, rl['CSP'])
+        for child in family_data.get('ENFANT', []):
+            for contact in child.get('CONTACT', []):
+                contact['LIENPARENTE_label'] = utils.get_label(utils.lien_parente_mapping, contact['LIENPARENTE'])
+        if 'REVENUS' in family_data:
+            family_data['REVENUS']['TYPEREGIME_label'] = utils.get_label(utils.type_regime_mapping, family_data['REVENUS']['TYPEREGIME'])
         return {'data': family_data}
 
+    def get_child_data(self, name_id, child_id):
+        family_data = self.get_family_data(name_id)
+
+        for child in family_data['ENFANT']:
+            if child['IDPERSONNE'] == child_id:
+                return child
+
+        raise APIError('Child not found', err_code='not-found')
+
     @endpoint(
         description=_("Get information about a child"),
         perm='can_access',
@@ -550,13 +587,12 @@ class ToulouseAxel(BaseResource):
             'idpersonne': {'description': _('Child ID')},
         })
     def child_info(self, request, idpersonne, NameID):
-        family_data = self.get_family_data(NameID)
+        child_data = self.get_child_data(NameID, idpersonne)
 
-        for child in family_data['ENFANT']:
-            if child['IDPERSONNE'] == idpersonne:
-                return {'data': child}
+        for contact in child_data.get('CONTACT', []):
+            contact['LIENPARENTE_label'] = utils.get_label(utils.lien_parente_mapping, contact['LIENPARENTE'])
 
-        raise APIError('Child not found', err_code='not-found')
+        return {'data': child_data}
 
     def pre_sanitize_update_family_data(self, post_data):
         # before json payload validation, check maj fields and remove empty blocks
diff --git a/passerelle/contrib/toulouse_axel/utils.py b/passerelle/contrib/toulouse_axel/utils.py
new file mode 100644
index 00000000..fb434a96
--- /dev/null
+++ b/passerelle/contrib/toulouse_axel/utils.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# passerelle - uniform access to multiple data sources and services
+# Copyright (C) 2020  Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import unicode_literals
+
+from collections import OrderedDict
+
+
+situation_familiale_mapping = OrderedDict([
+    ('C', 'Célibataire'),
+    ('D', 'Divorcé (e)'),
+    ('M', 'Marié (e)'),
+    ('S', 'Séparé (e)'),
+    ('V', 'Veuf (ve)'),
+    ('VM', 'Vie Maritale'),
+    ('P', 'Pacs'),
+])
+
+csp_mapping = OrderedDict([
+    ('OUV', 'Ouvriers'),
+    ('EMP', 'Employés'),
+    ('ETU', 'Etudiants'),
+    ('RET', 'Retraités'),
+    ('STA', 'Personnes en stage'),
+    ('AGEX', 'Agriculteurs exploitants'),
+    ('ARCO', 'Artisans commercants chefs entreprise'),
+    ('CADP', 'Cadres professions intellectuelles supérieures'),
+    ('PRIN', 'Professions intermediaires'),
+    ('SACT', 'Autres personnes sans activité professionnelle'),
+    ('REC', 'Recherche emploi'),
+])
+
+lien_parente_mapping = OrderedDict([
+    ('GRP1', 'Grands-parents paternels'),
+    ('GRP2', 'Grands-parents maternels'),
+    ('VOI', 'Voisin'),
+    ('FRE', "Frère de l'enfant"),
+    ('SOE', "Soeur de l'enfant"),
+    ('AMI', 'Ami (e)'),
+    ('FAMI', 'Membre de la famille'),
+    ('BABY', 'Baby sitter'),
+])
+
+type_regime_mapping = OrderedDict([
+    ('GENE', 'Régime général'),
+    ('ZAU', 'Autre'),
+    ('MSA', 'MSA'),
+])
+
+
+def get_label(mapping, code):
+    return mapping.get(code, code)
diff --git a/tests/data/toulouse_axel/family_info.xml b/tests/data/toulouse_axel/family_info.xml
index 2e42f007..efbe4c07 100644
--- a/tests/data/toulouse_axel/family_info.xml
+++ b/tests/data/toulouse_axel/family_info.xml
@@ -4,7 +4,7 @@
     <CODEMISEAJOUR>19</CODEMISEAJOUR>
     <NBRLACTIF>2</NBRLACTIF>
     <NBENFANTACTIF>2</NBENFANTACTIF>
-    <SITUATIONFAMILIALE>P</SITUATIONFAMILIALE>
+    <SITUATIONFAMILIALE>S</SITUATIONFAMILIALE>
     <REACTUALISATIONENLIGNE>NON</REACTUALISATIONENLIGNE>
     <DEMATFACTURES>NON</DEMATFACTURES>
     <ADRESSE>
@@ -131,7 +131,7 @@
       <CONTACT>
         <NOM>foo</NOM>
         <PRENOM>foo</PRENOM>
-        <LIENPARENTE/>
+        <LIENPARENTE>GRP1</LIENPARENTE>
         <ENCASURGENCE>OUI</ENCASURGENCE>
         <CHERCHERLENFANT>OUI</CHERCHERLENFANT>
         <TELFIXE>0505050505</TELFIXE>
diff --git a/tests/test_toulouse_axel.py b/tests/test_toulouse_axel.py
index 933fb70f..a38553c2 100644
--- a/tests/test_toulouse_axel.py
+++ b/tests/test_toulouse_axel.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # passerelle - uniform access to multiple data sources and services
 # Copyright (C) 2019 Entr'ouvert
 #
@@ -14,6 +15,8 @@
 # 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/>.
 
+from __future__ import unicode_literals
+
 from contextlib import contextmanager
 import copy
 import datetime
@@ -41,6 +44,12 @@ from passerelle.contrib.toulouse_axel.models import (
     ref_facture_pdf,
     ref_verif_dui,
 )
+from passerelle.contrib.toulouse_axel.utils import (
+    situation_familiale_mapping,
+    csp_mapping,
+    lien_parente_mapping,
+    type_regime_mapping,
+)
 from passerelle.utils.jsonresponse import APIError
 import utils
 
@@ -568,6 +577,24 @@ def test_unlink_endpoint(app, resource):
     assert resp.json['deleted'] is True
 
 
+def test_refetential_endpoint_no_result(app, resource):
+    resp = app.get('/toulouse-axel/test/referential/foo/')
+    assert resp.json['err_desc'] == "Referential not found"
+    assert resp.json['err'] == 'not-found'
+
+
+@pytest.mark.parametrize('code, mapping', [
+    ('situation_familiale', situation_familiale_mapping),
+    ('csp', csp_mapping),
+    ('lien_parente', lien_parente_mapping),
+    ('type_regime', type_regime_mapping),
+])
+def test_refetential_endpoint(app, resource, code, mapping):
+    resp = app.get('/toulouse-axel/test/referential/%s/' % code)
+    expected = [{'id': k, 'text': v} for k, v in mapping.items()]
+    assert dict(resp.json['data']) == dict(expected)
+
+
 def test_family_info_endpoint_axel_error(app, resource):
     Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
     with mock.patch('passerelle.contrib.toulouse_axel.models.ref_famille_dui') as operation:
@@ -604,8 +631,21 @@ def test_family_info_endpoint(app, resource):
         'RL1',
         'RL2',
         'SITUATIONFAMILIALE',
+        'SITUATIONFAMILIALE_label',
         'TELFIXE',
     ])
+    assert resp.json['data']['SITUATIONFAMILIALE'] == 'S'
+    assert resp.json['data']['SITUATIONFAMILIALE_label'] == 'Séparé (e)'
+    assert resp.json['data']['RL1']['CSP'] == 'ETU'
+    assert resp.json['data']['RL1']['CSP_label'] == 'Etudiants'
+    assert resp.json['data']['RL2']['CSP'] == 'EMP'
+    assert resp.json['data']['RL2']['CSP_label'] == 'Employés'
+    assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['LIENPARENTE'] == 'GRP1'
+    assert resp.json['data']['ENFANT'][0]['CONTACT'][0]['LIENPARENTE_label'] == 'Grands-parents paternels'
+    assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['LIENPARENTE'] is None
+    assert resp.json['data']['ENFANT'][0]['CONTACT'][1]['LIENPARENTE_label'] is None
+    assert resp.json['data']['REVENUS']['TYPEREGIME'] == 'GENE'
+    assert resp.json['data']['REVENUS']['TYPEREGIME_label'] == 'Régime général'
 
 
 def test_child_info_endpoint_axel_error(app, resource):
@@ -655,6 +695,10 @@ def test_child_info_endpoint(app, resource):
         'SANITAIRE',
         'SEXE',
     ])
+    assert resp.json['data']['CONTACT'][0]['LIENPARENTE'] == 'GRP1'
+    assert resp.json['data']['CONTACT'][0]['LIENPARENTE_label'] == 'Grands-parents paternels'
+    assert resp.json['data']['CONTACT'][1]['LIENPARENTE'] is None
+    assert resp.json['data']['CONTACT'][1]['LIENPARENTE_label'] is None
 
 
 def test_update_family_info_endpoint_axel_error(app, resource, update_params, family_data):
-- 
2.20.1

