From 4e0d8c3222f020bc219a84a68b9c528b8341227f Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 15 Dec 2022 22:32:07 +0100
Subject: [PATCH 1/4] toulouse-maelis: correct bool input on indicators
 (#72523)

---
 passerelle/contrib/toulouse_maelis/models.py  |  9 +-
 passerelle/contrib/toulouse_maelis/schemas.py |  5 +
 tests/test_toulouse_maelis.py                 | 96 ++++++++++++++-----
 3 files changed, 85 insertions(+), 25 deletions(-)

diff --git a/passerelle/contrib/toulouse_maelis/models.py b/passerelle/contrib/toulouse_maelis/models.py
index ff13351c..ce4d7e9c 100644
--- a/passerelle/contrib/toulouse_maelis/models.py
+++ b/passerelle/contrib/toulouse_maelis/models.py
@@ -343,26 +343,33 @@ class ToulouseMaelis(BaseResource, HTTPResource):
                 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 in range(0, len(data.get('indicatorList', []))):
+        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]
 
         for i in range(0, len(data.get('vaccinList', []))):
diff --git a/passerelle/contrib/toulouse_maelis/schemas.py b/passerelle/contrib/toulouse_maelis/schemas.py
index 452c5366..17625ebc 100644
--- a/passerelle/contrib/toulouse_maelis/schemas.py
+++ b/passerelle/contrib/toulouse_maelis/schemas.py
@@ -16,16 +16,21 @@
 
 BOOLEAN_TYPES = [
     {'type': 'boolean'},
     {
         'type': 'string',
         'pattern': '^([Oo][Uu][Ii]|[Nn][Oo][Nn]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|1|0)$',
         'pattern_description': 'Les valeurs "0", "1", "true", "false", "oui" ou "non" sont autorisées (insensibles à la casse).',
     },
+    {
+        'type': 'integer',
+        'minimum': 0,
+        'maximum': 1,
+    },
 ]
 
 BASIC_ID_PROPERTIES = {
     'firstname': {
         'description': 'Prénom',
         'type': 'string',
     },
     'lastname': {
diff --git a/tests/test_toulouse_maelis.py b/tests/test_toulouse_maelis.py
index e32bb589..8595e577 100644
--- a/tests/test_toulouse_maelis.py
+++ b/tests/test_toulouse_maelis.py
@@ -2971,30 +2971,40 @@ def test_update_child_medical_record_wrong_referential_key_error(con, app):
 
     Link.objects.create(resource=con, family_id='1312', name_id='local')
     resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
     assert resp.json['err'] == 'wrong-key'
     assert resp.json['err_desc'] == "vaccinList/1/code key value 'plop' do not belong to 'Vaccin' referential"
 
 
 def test_update_rl_indicator(family_service, con, app):
-    family_service.add_soap_response('updatePersonIndicatorList', get_xml_file('R_update_indicator.xml'))
+    def request_check(request):
+        assert [(x['code'], x['isActive']) for x in request.indicatorList] == [
+            ('AVL', True),
+            ('AVS', False),
+            ('ETABSPEC', True),
+            ('MDPH', False),
+        ]
+
+    family_service.add_soap_response(
+        'updatePersonIndicatorList',
+        get_xml_file('R_update_indicator.xml'),
+        request_check=request_check,
+    )
     url = get_endpoint('update-rl-indicator')
     params = {
-        'indicatorList': [
-            {
-                'code': 'AVL',
-                'isActive': True,
-            },
-            {
-                'code': 'ETABSPEC',
-                'note': 'SNPP',
-                'isActive': True,
-            },
-        ],
+        'indicatorList/0/code': 'AVL',
+        'indicatorList/0/isActive': True,
+        'indicatorList/1/code': 'AVS',
+        'indicatorList/1/isActive': False,
+        'indicatorList/2/code': 'ETABSPEC',
+        'indicatorList/2/note': 'SNPP',
+        'indicatorList/2/isActive': 'True',
+        'indicatorList/3/code': 'MDPH',
+        'indicatorList/3/isActive': 'False',
     }
 
     Link.objects.create(resource=con, family_id='1312', name_id='local')
     resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
     assert resp.json['err'] == 0
     assert resp.json['data'] == 'ok'
 
 
@@ -3009,16 +3019,31 @@ def test_update_rl_indicator_not_linked_error(con, app):
         ],
     }
 
     resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
     assert resp.json['err'] == 'not-linked'
     assert resp.json['err_desc'] == 'User not linked to family'
 
 
+@pytest.mark.parametrize('value', ['plop', '', 2, 0.5, 'N'])
+def test_update_rl_indicator_schema_error(value, con, app):
+    url = get_endpoint('update-rl-indicator')
+    params = {
+        'indicatorList/0/code': 'AVL',
+        'indicatorList/0/isActive': value,
+    }
+
+    Link.objects.create(resource=con, family_id='1312', name_id='local')
+    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
+    assert resp.json['err'] == 1
+    assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
+    assert "is not of type 'boolean'" in resp.json['err_desc']
+
+
 def test_update_rl_indicator_no_indicator_error(con, app):
     url = get_endpoint('update-rl-indicator')
     params = {'indicatorList': []}
 
     Link.objects.create(resource=con, family_id='1312', name_id='local')
     resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
     assert resp.json['err'] == 1
     assert resp.json['err_desc'] == 'indicatorList: [] is too short'
@@ -3057,30 +3082,53 @@ def test_update_rl_indicator_wrong_referential_key_error(con, app):
     assert resp.json['err'] == 'wrong-key'
     assert (
         resp.json['err_desc']
         == "indicatorList/0/code key value 'plop' do not belong to 'RLIndicator' required referential"
     )
 
 
 def test_update_child_indicator(family_service, con, app):
-    family_service.add_soap_response('updatePersonIndicatorList', get_xml_file('R_update_indicator.xml'))
+    def request_check(request):
+        assert [(x['code'], x['isActive']) for x in request.indicatorList] == [
+            ('APPDENTAIRE', True),
+            ('AUTRE', False),
+            ('AVL', True),
+            ('AVS', False),
+            ('ETABSPEC', True),
+            ('LENTILLE', False),
+            ('LUNETTE', True),
+            ('MDPH', False),
+        ]
+
+    family_service.add_soap_response(
+        'updatePersonIndicatorList',
+        get_xml_file('R_update_indicator.xml'),
+        request_check=request_check,
+    )
     url = get_endpoint('update-child-indicator')
     params = {
-        'indicatorList': [
-            {
-                'code': 'LUNETTE',
-                'isActive': True,
-            },
-            {
-                'code': 'AUTRE',
-                'note': 'rebellious',
-                'isActive': True,
-            },
-        ],
+        'indicatorList/0/code': 'APPDENTAIRE',
+        'indicatorList/0/isActive': 1,
+        'indicatorList/1/code': 'AUTRE',
+        'indicatorList/1/note': 'rebellious',
+        'indicatorList/1/isActive': 0,
+        'indicatorList/2/code': 'AVL',
+        'indicatorList/2/isActive': '1',
+        'indicatorList/3/code': 'AVS',
+        'indicatorList/3/isActive': '0',
+        'indicatorList/4/code': 'ETABSPEC',
+        'indicatorList/4/note': 'xxx',
+        'indicatorList/4/isActive': 'Oui',
+        'indicatorList/5/code': 'LENTILLE',
+        'indicatorList/5/isActive': 'Non',
+        'indicatorList/6/code': 'LUNETTE',
+        'indicatorList/6/isActive': 'TRUE',
+        'indicatorList/7/code': 'MDPH',
+        'indicatorList/7/isActive': 'FALSE',
     }
 
     Link.objects.create(resource=con, family_id='1312', name_id='local')
     resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
     assert resp.json['err'] == 0
     assert resp.json['data'] == 'ok'
 
 
-- 
2.30.2

