From 51bf6fd125994201fa2798ee61311637f096a337 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Fri, 4 Nov 2022 11:37:35 +0100
Subject: [PATCH 2/5] toulouse-maelis: add id and q parameters on referentiels
 (#70982)

---
 passerelle/contrib/toulouse_maelis/models.py | 115 +++++++++++++++----
 tests/test_toulouse_maelis.py                |  18 +++
 2 files changed, 109 insertions(+), 24 deletions(-)

diff --git a/passerelle/contrib/toulouse_maelis/models.py b/passerelle/contrib/toulouse_maelis/models.py
index d19de757..ea46d949 100644
--- a/passerelle/contrib/toulouse_maelis/models.py
+++ b/passerelle/contrib/toulouse_maelis/models.py
@@ -18,16 +18,17 @@ from urllib.parse import urljoin
 import zeep
 from django.core.cache import cache
 from django.db import models
 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 to_ascii
 from passerelle.utils.jsonresponse import APIError
 
 from . import schemas
 
 
 class ToulouseMaelis(BaseResource, HTTPResource):
     # noqa pylint: disable=too-many-public-methods
 
@@ -97,29 +98,47 @@ class ToulouseMaelis(BaseResource, HTTPResource):
                     'list': [{'id': x.id, 'text': x.code} for x in response],
                     'dict': {x.id: x.code for x in response},
                 }
             else:
                 data = {
                     'list': [{'id': x.code, 'text': x.libelle} for x in response],
                     'dict': {x.code: x.libelle for x in response},
                 }
+            data['search'] = {to_ascii(x['text']).lower(): x for x in data['list']}
+
             # put in cache for two hours
             cache.set(cache_key, data, 3600 * 2)
         return data
 
     def get_referential_value(self, referential_name, key, log_warning=False):
         try:
             return self.get_referential(referential_name)['dict'][key]
         except KeyError:
             if log_warning:
                 # Maelis DB not properly configurated
                 self.logger.warning("No '%s' key into Maelis '%s' referential", key, referential_name)
             return None
 
+    def get_referential_list(self, referential_name, id=None, q=None):
+        data = []
+
+        if id:
+            text = self.get_referential_value(referential_name, id)
+            if text:
+                data.append({'id': id, 'text': text})
+        elif q is not None:
+            key = to_ascii(q.strip()).lower()
+            if key:
+                items = self.get_referential(referential_name)['search'].items()
+                data = [v for k, v in items if key in k]
+        else:
+            data = self.get_referential(referential_name)['list']
+        return data
+
     def get_link(self, NameID):
         try:
             return self.link_set.get(name_id=NameID)
         except Link.DoesNotExist:
             raise APIError('User not linked to family', err_code='not-linked')
 
     def get_family_raw(self, family_id):
         response = self.call('Family', 'readFamily', dossierNumber=family_id)
@@ -361,128 +380,176 @@ class ToulouseMaelis(BaseResource, HTTPResource):
             if value is None:
                 dico[key] = ''
 
     @endpoint(
         display_category='Famille',
         description='Liste des catégories',
         name='read-category-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_category_list(self, request):
-        return {'data': self.get_referential('Category')['list']}
+    def read_category_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Category', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des civilités',
         name='read-civility-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_civility_list(self, request):
-        return {'data': self.get_referential('Civility')['list']}
+    def read_civility_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Civility', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des compléments du numéro de voie',
         name='read-complement-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_complement_list(self, request):
-        return {'data': self.get_referential('Complement')['list']}
+    def read_complement_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Complement', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='liste des catégories socio-professionnelles',
         name='read-csp-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_csp_list(self, request):
-        data = self.get_referential('CSP')['list']
+    def read_csp_list(self, request, id=None, q=None):
+        data = self.get_referential_list('CSP', id, q)
 
         # remove redundant codes
         uniq_text = set()
         uniq_data = []
         for item in data:
             item['text'] = item['text'].strip()
             if item['text'] not in uniq_text:
                 uniq_data.append(item)
                 uniq_text.add(item['text'])
         return {'data': uniq_data}
 
     @endpoint(
         display_category='Famille',
         description='Liste des régimes alimentaires',
         name='read-dietcode-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_dietcode_list(self, request):
-        return {'data': self.get_referential('DietCode')['list']}
+    def read_dietcode_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('DietCode', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des organismes (CAF)',
         name='read-organ-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_organ_list(self, request):
-        return {'data': self.get_referential('Organ')['list']}
+    def read_organ_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Organ', id, q)}
 
     @endpoint(
         display_category='Famille',
         description="Liste des projet d'accueil individualisés",
         name='read-pai-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_pai_list(self, request):
-        return {'data': self.get_referential('PAI')['list']}
+    def read_pai_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('PAI', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='liste des qualités du référenciel',
         name='read-quality-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_quality_list(self, request):
-        return {'data': self.get_referential('Quality')['list']}
+    def read_quality_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Quality', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des quotients',
         name='read-quotient-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_quotient_list(self, request):
-        return {'data': self.get_referential('Quotient')['list']}
+    def read_quotient_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Quotient', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des sexes',
         name='read-sex-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_sex_list(self, request):
-        return {'data': self.get_referential('Sex')['list']}
+    def read_sex_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Sex', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='liste des situations',
         name='read-situation-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_situation_list(self, request):
-        return {'data': self.get_referential('Situation')['list']}
+    def read_situation_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Situation', id, q)}
 
     @endpoint(
         display_category='Famille',
         description='Liste des vaccins',
         name='read-vaccin-list',
         perm='can_access',
+        parameters={
+            'id': {'description': 'Identifiant de l’enregistrement'},
+            'q': {'description': 'Recherche en texte intégral'},
+        },
     )
-    def read_vaccin_list(self, request):
-        return {'data': self.get_referential('Vaccin')['list']}
+    def read_vaccin_list(self, request, id=None, q=None):
+        return {'data': self.get_referential_list('Vaccin', id, q)}
 
     @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}}},
     )
diff --git a/tests/test_toulouse_maelis.py b/tests/test_toulouse_maelis.py
index 96160c35..0e2aa236 100644
--- a/tests/test_toulouse_maelis.py
+++ b/tests/test_toulouse_maelis.py
@@ -518,16 +518,34 @@ def test_read_situation_list(mocked_post, mocked_get, con, app):
         {'id': 'M', 'text': 'Marié (e)'},
         {'id': 'P', 'text': 'Pacsé (e)'},
         {'id': 'S', 'text': 'Séparé (e)'},
         {'id': 'UL', 'text': 'UNION LIBRE'},
         {'id': 'V', 'text': 'Veuf (ve)'},
         {'id': 'VM', 'text': 'Vivant maritalement'},
     ]
 
+    resp = app.get(url + '?id=V')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {'id': 'V', 'text': 'Veuf (ve)'},
+    ]
+
+    resp = app.get(url + '?q= sÉ ')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {'id': 'CS', 'text': 'EN COURS DE SEPARATION'},
+        {'id': 'P', 'text': 'Pacsé (e)'},
+        {'id': 'S', 'text': 'Séparé (e)'},
+    ]
+
+    resp = app.get(url + '?q= ')
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == []
+
 
 @mock.patch('passerelle.utils.Request.get')
 @mock.patch('passerelle.utils.Request.post')
 def test_read_vaccin_list(mocked_post, mocked_get, con, app):
     mocked_get.return_value = FAMILY_SERVICE_WSDL
     mocked_post.return_value = READ_VACCIN
     url = get_endpoint('read-vaccin-list')
 
-- 
2.30.2

