Projet

Général

Profil

0003-toulouse-maelis-manage-indicators-71964.patch

Nicolas Roche, 02 décembre 2022 12:40

Télécharger (56 ko)

Voir les différences:

Subject: [PATCH 3/3] toulouse-maelis: manage indicators (#71964)

 functests/toulouse_maelis/conftest.py         |  22 ++
 .../data/test_child_indicator.json            |   1 +
 .../data/test_create_family.json              |  17 +-
 .../data/test_rl_indicator.json               |   1 +
 .../data/test_update_child.json               |  17 +-
 .../data/test_update_family.json              |  34 ++-
 .../toulouse_maelis/data/test_update_rl2.json |  17 +-
 functests/toulouse_maelis/test_family.py      |  83 ++++++-
 passerelle/contrib/toulouse_maelis/models.py  |  67 +++++
 passerelle/contrib/toulouse_maelis/schemas.py |  61 +++++
 .../Q_update_child_indicator.xml              |  24 ++
 .../toulouse_maelis/Q_update_rl_indicator.xml |  24 ++
 tests/data/toulouse_maelis/R_read_family.xml  |  18 ++
 .../toulouse_maelis/R_read_family_relax.xml   |  18 ++
 .../R_read_family_reordered.xml               |  18 ++
 .../toulouse_maelis/R_update_indicator.xml    |   6 +
 tests/test_toulouse_maelis.py                 | 231 +++++++++++++++++-
 17 files changed, 642 insertions(+), 17 deletions(-)
 create mode 100644 functests/toulouse_maelis/data/test_child_indicator.json
 create mode 100644 functests/toulouse_maelis/data/test_rl_indicator.json
 create mode 100644 tests/data/toulouse_maelis/Q_update_child_indicator.xml
 create mode 100644 tests/data/toulouse_maelis/Q_update_rl_indicator.xml
 create mode 100644 tests/data/toulouse_maelis/R_update_indicator.xml
functests/toulouse_maelis/conftest.py
56 56
            'employerName': 'Burns',
57 57
            'phone': '0133333333',
58 58
            'profession': 'Inspecteur de sécurité',
59 59
        },
60 60
        'CAFInfo': {
61 61
            'number': '123',
62 62
            'organ': 'A10007752822',
63 63
        },
64
        'indicatorList': [
65
            {
66
                'code': 'AVL',
67
                'isActive': True,
68
            },
69
            {
70
                'code': 'ETABSPEC',
71
                'note': 'SNPP',
72
                'isActive': True,
73
            },
74
        ],
64 75
    },
65 76
    'childList': [
66 77
        {
67 78
            'sexe': 'M',
68 79
            'firstname': 'Bart',
69 80
            'lastname': 'Simpson',
70 81
            'birth': {'dateBirth': '1978-04-01'},
71 82
            'bPhoto': True,
......
101 112
                        'vaccinationDate': '2011-01-11',
102 113
                    },
103 114
                    {
104 115
                        'code': 'ROR',
105 116
                        'vaccinationDate': '2022-02-22',
106 117
                    },
107 118
                ],
108 119
            },
120
            'indicatorList': [
121
                {
122
                    'code': 'LUNETTE',
123
                    'isActive': True,
124
                },
125
                {
126
                    'code': 'AUTRE',
127
                    'note': 'rebellious',
128
                    'isActive': True,
129
                },
130
            ],
109 131
            'authorizedPersonList': [
110 132
                {
111 133
                    'personInfo': {
112 134
                        'civility': 'M.',
113 135
                        'firstname': 'Abraham Jebediah',
114 136
                        'lastname': 'Simpson',
115 137
                        'dateBirth': '1927-05-24',
116 138
                        'sexe': 'M',
functests/toulouse_maelis/data/test_child_indicator.json
1
[]
functests/toulouse_maelis/data/test_create_family.json
102 102
          },
103 103
          "personQuality": {
104 104
            "code": "GMP",
105 105
            "libelle": "GRAND-MERE PATERNELLE",
106 106
            "code_text": "GRAND-MERE PATERNELLE"
107 107
          }
108 108
        }
109 109
      ],
110
      "indicatorList": [],
110
      "indicatorList": [
111
        {
112
          "code": "AUTRE",
113
          "label": "Autre",
114
          "note": "rebellious",
115
          "choice": null,
116
          "code_text": "Autre"
117
        },
118
        {
119
          "code": "LUNETTE",
120
          "label": "Port de lunettes",
121
          "note": null,
122
          "choice": null,
123
          "code_text": "Port de lunettes"
124
        }
125
      ],
111 126
      "medicalRecord": {
112 127
        "familyDoctor": {
113 128
          "name": "MONROE",
114 129
          "phone": "0612341234",
115 130
          "address": {
116 131
            "street1": "Alameda",
117 132
            "zipcode": "90701",
118 133
            "town": "Springfield"
functests/toulouse_maelis/data/test_rl_indicator.json
1
[]
functests/toulouse_maelis/data/test_update_child.json
53 53
      },
54 54
      "personQuality": {
55 55
        "code": "GMP",
56 56
        "libelle": "GRAND-MERE PATERNELLE",
57 57
        "code_text": "GRAND-MERE PATERNELLE"
58 58
      }
59 59
    }
60 60
  ],
61
  "indicatorList": [],
61
  "indicatorList": [
62
    {
63
      "code": "AUTRE",
64
      "label": "Autre",
65
      "note": "rebellious",
66
      "choice": null,
67
      "code_text": "Autre"
68
    },
69
    {
70
      "code": "LUNETTE",
71
      "label": "Port de lunettes",
72
      "note": null,
73
      "choice": null,
74
      "code_text": "Port de lunettes"
75
    }
76
  ],
62 77
  "medicalRecord": {
63 78
    "familyDoctor": {
64 79
      "name": "MONROE",
65 80
      "phone": "0612341234",
66 81
      "address": {
67 82
        "street1": "Alameda",
68 83
        "zipcode": "90701",
69 84
        "town": "Springfield"
functests/toulouse_maelis/data/test_update_family.json
87 87
      },
88 88
      "codeCSP_text": "CADRE SUPERIEUR"
89 89
    },
90 90
    "CAFInfo": {
91 91
      "number": "123",
92 92
      "organ": "A10007752822",
93 93
      "organ_text": "LA COLLE SUR LOUP"
94 94
    },
95
    "indicatorList": [],
95
    "indicatorList": [
96
      {
97
        "code": "AVL",
98
        "label": "Auxiliaire de Vie loisirs",
99
        "note": null,
100
        "choice": null,
101
        "code_text": "Auxiliaire de Vie loisirs"
102
      },
103
      {
104
        "code": "ETABSPEC",
105
        "label": "Etablissement sp\u00e9cialis\u00e9",
106
        "note": "SNPP",
107
        "choice": null,
108
        "code_text": "Etablissement sp\u00e9cialis\u00e9"
109
      }
110
    ],
96 111
    "quotientList": [],
97 112
    "subscribeActivityList": [],
98 113
    "civility_text": "Monsieur",
99 114
    "quality_text": "PERE"
100 115
  },
101 116
  "quotientList": [],
102 117
  "childList": [
103 118
    {
......
155 170
          },
156 171
          "personQuality": {
157 172
            "code": "GMP",
158 173
            "libelle": "GRAND-MERE PATERNELLE",
159 174
            "code_text": "GRAND-MERE PATERNELLE"
160 175
          }
161 176
        }
162 177
      ],
163
      "indicatorList": [],
178
      "indicatorList": [
179
        {
180
          "code": "AUTRE",
181
          "label": "Autre",
182
          "note": "rebellious",
183
          "choice": null,
184
          "code_text": "Autre"
185
        },
186
        {
187
          "code": "LUNETTE",
188
          "label": "Port de lunettes",
189
          "note": null,
190
          "choice": null,
191
          "code_text": "Port de lunettes"
192
        }
193
      ],
164 194
      "medicalRecord": {
165 195
        "familyDoctor": {
166 196
          "name": "MONROE",
167 197
          "phone": "0612341234",
168 198
          "address": {
169 199
            "street1": "Alameda",
170 200
            "zipcode": "90701",
171 201
            "town": "Springfield"
functests/toulouse_maelis/data/test_update_rl2.json
41 41
    },
42 42
    "codeCSP_text": "CADRE SUPERIEUR"
43 43
  },
44 44
  "CAFInfo": {
45 45
    "number": "123",
46 46
    "organ": "A10007752822",
47 47
    "organ_text": "LA COLLE SUR LOUP"
48 48
  },
49
  "indicatorList": [],
49
  "indicatorList": [
50
    {
51
      "code": "AVL",
52
      "label": "Auxiliaire de Vie loisirs",
53
      "note": null,
54
      "choice": null,
55
      "code_text": "Auxiliaire de Vie loisirs"
56
    },
57
    {
58
      "code": "ETABSPEC",
59
      "label": "Etablissement sp\u00e9cialis\u00e9",
60
      "note": "SNPP",
61
      "choice": null,
62
      "code_text": "Etablissement sp\u00e9cialis\u00e9"
63
    }
64
  ],
50 65
  "quotientList": [],
51 66
  "subscribeActivityList": [],
52 67
  "civility_text": "Monsieur",
53 68
  "quality_text": "AUTRE"
54 69
}
functests/toulouse_maelis/test_family.py
45 45
            'employerName': '',
46 46
            'phone': '',
47 47
            'profession': '',
48 48
        },
49 49
        'CAFInfo': {
50 50
            'number': 'reset',  # cannot be removed
51 51
            'organ': '',
52 52
        },
53
        'indicatorList': [
54
            {
55
                'code': 'AVL',
56
                'isActive': False,
57
            },
58
            {
59
                'code': 'ETABSPEC',
60
                'isActive': False,
61
            },
62
        ],
53 63
    },
54 64
    'childList': [
55 65
        {
56 66
            'num': 'place holder',  # required for update
57 67
            'sexe': 'F',
58 68
            'firstname': 'Bartolome',  # some side effects, cf test_update_child
59 69
            'lastname': 'Simps',
60 70
            'birth': {'dateBirth': '1970-01-01'},
......
82 92
                'comment1': '',
83 93
                'comment2': '',
84 94
                'observ1': '',
85 95
                'observ2': '',
86 96
                'isAuthHospital': False,
87 97
                'hospital': '',
88 98
                'vaccinList': [],
89 99
            },
100
            'indicatorList': [
101
                {
102
                    'code': 'LUNETTE',
103
                    'isActive': False,
104
                },
105
                {
106
                    'code': 'AUTRE',
107
                    'note': 'rebellious',
108
                    'isActive': False,
109
                },
110
            ],
90 111
            # setting authorizedPersonList to None will remove the list
91 112
            'authorizedPersonList': [
92 113
                {
93 114
                    'personInfo': {
94 115
                        'civility': None,
95 116
                        'firstname': 'reset',  # E704 : Le prénom de la personne est obligatoire
96 117
                        'lastname': 'reset',  # E705 : Le nom de la personne est obligatoire
97 118
                        'dateBirth': '1970-01-01',
......
279 300
    link(conn, create_data)
280 301

  
281 302
    data = read_family(conn, create_data['name_id'])
282 303
    assert data['RL2'] is None
283 304

  
284 305
    # no unicity restriction on RL2 (duplicate RL2 from update_data)
285 306
    url = conn + '/create-rl2?NameID=%s' % create_data['name_id']
286 307
    payload = copy.deepcopy(update_data['family_payload']['rl2'])
287
    for key in 'contact', 'profession', 'CAFInfo':
308
    for key in 'contact', 'profession', 'CAFInfo', 'indicatorList':
288 309
        del payload[key]
289 310
    resp = requests.post(url, json=payload)
290 311
    resp.raise_for_status()
291 312
    assert resp.json()['err'] == 0
292 313
    assert diff_rlg(conn, create_data['name_id'], 2, 'test_create_rl2.json')
293 314

  
294 315

  
295 316
@pytest.mark.parametrize("rl", ['1', '2'])
......
297 318
    rlg = 'rl' + rl
298 319
    RLG = 'RL' + rl
299 320
    unlink(conn, update_data['name_id'])
300 321
    link(conn, update_data)
301 322
    url = conn + '/update-rl%s?NameID=%s' % (rl, update_data['name_id'])
302 323

  
303 324
    # reset responsable legal
304 325
    payload = copy.deepcopy(FAMILY_RESET_PAYLOAD[rlg])
305
    for key in 'adresse', 'contact', 'profession', 'CAFInfo':
326
    for key in 'adresse', 'contact', 'profession', 'CAFInfo', 'indicatorList':
306 327
        if key in payload:
307 328
            del payload[key]
308 329
    resp = requests.post(url, json=payload)
309 330
    resp.raise_for_status()
310 331
    assert resp.json()['err'] == 0
311 332
    data = diff_rlg(conn, update_data['name_id'], rl, 'test_update_rl%s.json' % rl)
312 333

  
313 334
    # unchanged values
......
351 372
            "Le Responsable légal %s transmis n'est pas celui qui existe pour la famille" % rl
352 373
            in res['err_desc']
353 374
        )
354 375
    else:
355 376
        assert "La date de naissance ne peut pas être modifiée" in res['err_desc']
356 377

  
357 378
    # restore RL1
358 379
    payload = copy.deepcopy(update_data['family_payload'][rlg])
359
    for key in 'adresse', 'contact', 'profession', 'CAFInfo':
380
    for key in 'adresse', 'contact', 'profession', 'CAFInfo', 'indicatorList':
360 381
        if payload.get(key):
361 382
            del payload[key]
362 383
    resp = requests.post(url, json=payload)
363 384
    resp.raise_for_status()
364 385
    assert resp.json()['err'] == 0
365 386
    data = diff_family(conn, update_data['name_id'], 'test_update_family.json')
366 387

  
367 388

  
......
463 484
def test_update_child(conn, update_data, create_data):
464 485
    unlink(conn, update_data['name_id'])
465 486
    link(conn, update_data)
466 487

  
467 488
    # renaming using existing child names on same family will in fact target the existing child
468 489
    # side effect: the authorized person list is copied by the connector (from Lisa to Maggie)
469 490
    url = conn + '/update-child?NameID=%s&child_id=%s' % (update_data['name_id'], update_data['lisa_num'])
470 491
    payload = copy.deepcopy(update_data['family_payload']['childList'][2])  # Maggie content
471
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList':
492
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList', 'indicatorList':
472 493
        if key in payload:
473 494
            del payload[key]
474 495
    assert payload['firstname'] == 'Maggie'
475 496
    payload['sexe'] = 'M'
476 497
    resp = requests.post(url, json=payload)  # use Lisa id in url
477 498
    resp.raise_for_status()
478 499
    assert resp.json()['err'] == 0
479 500
    data = read_family(conn, update_data['name_id'])
480 501
    assert data['childList'][1]['num'] == update_data['lisa_num']
481 502
    assert data['childList'][1]['firstname'] == 'LISA'  # Lisa unchanged
482 503
    assert data['childList'][2]['sexe'] == 'M'  # Maggie updated
483 504

  
484 505
    # restore Maggie
485 506
    url = conn + '/update-child?NameID=%s&child_id=%s' % (update_data['name_id'], update_data['maggie_num'])
486 507
    payload = copy.deepcopy(update_data['family_payload']['childList'][2])
487
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList':
508
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList', 'indicatorList':
488 509
        if key in payload:
489 510
            del payload[key]
490 511
    resp = requests.post(url, json=payload)
491 512
    resp.raise_for_status()
492 513
    assert resp.json()['err'] == 0
493 514
    assert diff_family(conn, update_data['name_id'], 'test_update_family.json')
494 515

  
495 516
    # rename to an existing child on other family
496 517
    url = conn + '/update-child?NameID=%s&child_id=%s' % (update_data['name_id'], update_data['bart_num'])
497 518
    payload = copy.deepcopy(create_data['family_payload']['childList'][1])
498
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList':
519
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList', 'indicatorList':
499 520
        if key in payload:
500 521
            del payload[key]
501 522
    resp = requests.post(url, json=payload)
502 523
    resp.raise_for_status()
503 524
    assert resp.json()['err'] == 0
504 525
    data = read_family(conn, update_data['name_id'])
505 526
    assert data['childList'][0]['num'] == update_data['bart_num']
506 527
    assert data['childList'][0]['firstname'] == 'MAGGIE'
507 528

  
508 529
    # reset Bart
509 530
    payload = copy.deepcopy(FAMILY_RESET_PAYLOAD['childList'][0])
510
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList':
531
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList', 'indicatorList':
511 532
        if key in payload:
512 533
            del payload[key]
513 534
    resp = requests.post(url, json=payload)
514 535
    resp.raise_for_status()
515 536
    assert resp.json()['err'] == 0
516 537
    assert diff_child(conn, update_data['name_id'], 0, 'test_update_child.json')
517 538

  
518 539
    # restore Bart
519 540
    payload = copy.deepcopy(update_data['family_payload']['childList'][0])
520
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList':
541
    for key in 'dietcode', 'paiInfoBean', 'medicalRecord', 'authorizedPersonList', 'indicatorList':
521 542
        if key in payload:
522 543
            del payload[key]
523 544
    resp = requests.post(url, json=payload)
524 545
    resp.raise_for_status()
525 546
    assert resp.json()['err'] == 0
526 547
    assert diff_family(conn, update_data['name_id'], 'test_update_family.json')
527 548

  
528 549

  
......
680 701
        update_data['bart_num'],
681 702
        abi_num,
682 703
    )
683 704
    payload = update_data['family_payload']['childList'][0]['authorizedPersonList'][0]
684 705
    resp = requests.post(url, json=payload)
685 706
    resp.raise_for_status()
686 707
    assert resp.json()['err'] == 0
687 708
    assert diff_family(conn, update_data['name_id'], 'test_update_family.json')
709

  
710

  
711
def test_update_rl_indicator(conn, update_data):
712
    unlink(conn, update_data['name_id'])
713
    link(conn, update_data)
714
    url = conn + '/update-rl-indicator?NameID=%s&rl_id=%s' % (
715
        update_data['name_id'],
716
        update_data['rl2_num'],
717
    )
718

  
719
    # reset RL indicators
720
    payload = {'indicatorList': FAMILY_RESET_PAYLOAD['rl2']['indicatorList']}
721
    resp = requests.post(url, json=payload)
722
    resp.raise_for_status()
723
    assert resp.json()['err'] == 0
724
    assert diff_rlg(conn, update_data['name_id'], 1, 'test_rl_indicator.json', key='indicatorList')
725

  
726
    # restore RL indicators
727
    payload = {'indicatorList': update_data['family_payload']['rl2']['indicatorList']}
728
    resp = requests.post(url, json=payload)
729
    resp.raise_for_status()
730
    assert resp.json()['err'] == 0
731
    assert diff_family(conn, update_data['name_id'], 'test_update_family.json')
732

  
733

  
734
def test_update_child_indicator(conn, update_data):
735
    unlink(conn, update_data['name_id'])
736
    link(conn, update_data)
737
    url = conn + '/update-child-indicator?NameID=%s&child_id=%s' % (
738
        update_data['name_id'],
739
        update_data['bart_num'],
740
    )
741

  
742
    # reset Bart indicators
743
    payload = {'indicatorList': FAMILY_RESET_PAYLOAD['childList'][0]['indicatorList']}
744
    resp = requests.post(url, json=payload)
745
    resp.raise_for_status()
746
    assert resp.json()['err'] == 0
747
    assert diff_child(conn, update_data['name_id'], 0, 'test_child_indicator.json', key='indicatorList')
748

  
749
    # restore Bart indicators
750
    payload = {'indicatorList': update_data['family_payload']['childList'][0]['indicatorList']}
751
    resp = requests.post(url, json=payload)
752
    resp.raise_for_status()
753
    assert resp.json()['err'] == 0
754
    assert diff_family(conn, update_data['name_id'], 'test_update_family.json')
passerelle/contrib/toulouse_maelis/models.py
180 180
        last_key = keys.pop()
181 181
        for key in keys:
182 182
            if not isinstance(data, dict) or not key in data:
183 183
                return
184 184
            data = data[key]
185 185
        if isinstance(data, dict) and last_key in data and data[last_key] is not None:
186 186
            data[last_key + '_text'] = self.get_referential_value(referential_name, data[last_key])
187 187

  
188
    def add_text_value_to_rl_indicator(self, data):
189
        self.add_text_value('RLIndicator', data, ['code'])
190

  
191
    def add_text_value_to_child_indicator(self, data):
192
        self.add_text_value('ChildIndicator', data, ['code'])
193

  
188 194
    def add_text_value_to_child_person(self, data):
189 195
        self.add_text_value('Civility', data, ['personInfo', 'civility'])
190 196
        self.add_text_value('Quality', data, ['personQuality', 'code'])
191 197
        self.add_text_value('Sex', data, ['personInfo', 'sexe'])
192 198
        return data
193 199

  
194 200
    def add_text_value_to_child(self, data):
195 201
        self.add_text_value('Sex', data, ['sexe'])
196 202
        self.add_text_value('DietCode', data, ['dietcode'])
197 203
        self.add_text_value('PAI', data, ['paiInfoBean', 'code'])
198 204
        for person in data['authorizedPersonList']:
199 205
            self.add_text_value_to_child_person(person)
206
        for indicator in data['indicatorList']:
207
            self.add_text_value_to_child_indicator(indicator)
208

  
209
        # sort indicators
210
        if data['indicatorList']:
211
            data['indicatorList'].sort(key=lambda x: x['code'])
200 212
        return data
201 213

  
202 214
    def add_text_value_to_person(self, data):
203 215
        self.add_text_value('Civility', data, ['civility'])
204 216
        self.add_text_value('Quality', data, ['quality'])
205 217
        self.add_text_value('Sex', data, ['sexe'])
206 218

  
207 219
    def add_text_value_to_rl(self, data):
208 220
        self.add_text_value('Civility', data, ['civility'])
209 221
        self.add_text_value('Quality', data, ['quality'])
210 222
        self.add_text_value('Complement', data, ['adresse', 'numComp'])
211 223
        self.add_text_value('CSP', data, ['profession', 'codeCSP'])
212 224
        self.add_text_value('Organ', data, ['CAFInfo', 'organ'])
225
        for indicator in data['indicatorList']:
226
            self.add_text_value_to_rl_indicator(indicator)
227

  
228
        # sort indicators
229
        if data['indicatorList']:
230
            data['indicatorList'].sort(key=lambda x: x['code'])
213 231

  
214 232
    def add_text_value_to_family(self, data):
215 233
        self.add_text_value('Category', data, ['category'])
216 234
        self.add_text_value('Situation', data, ['situation'])
217 235
        for rlg in 'RL1', 'RL2':
218 236
            if data.get(rlg):
219 237
                self.add_text_value_to_rl(data[rlg])
220 238
        for child in data['childList']:
......
269 287
                isinstance(data, dict) and key in data
270 288
            ):
271 289
                break
272 290
            data = data[key]
273 291
        else:
274 292
            key_value = data
275 293
        self.assert_key_in_referential(referential_name, key_value, '/'.join(str(x) for x in keys), required)
276 294

  
295
    def assert_update_indicator_payload_in_referential(self, referential, post_data, parent_keys=None):
296
        keys = parent_keys or []
297
        data = post_data
298
        for key in keys:
299
            data = data[key]
300

  
301
        for i in range(0, len(data.get('indicatorList', []))):
302
            self.assert_post_data_in_referential(
303
                referential, post_data, keys + ['indicatorList', i, 'code'], required=True
304
            )
305

  
277 306
    def assert_child_medical_record_payload_in_referential(self, post_data, parent_keys=None):
278 307
        keys = parent_keys or []
279 308
        data = post_data
280 309
        for key in keys:
281 310
            data = data[key]
282 311

  
283 312
        for i in range(0, len(data.get('vaccinList', []))):
284 313
            self.assert_post_data_in_referential(
......
307 336

  
308 337
        if 'dietcode' in data:
309 338
            self.assert_post_data_in_referential('DietCode', post_data, keys + ['dietcode'], required=False)
310 339
        if 'paiInfoBean' in data:
311 340
            self.assert_child_pai_payoad_in_referential(post_data, keys + ['paiInfoBean'])
312 341
        if 'medicalRecord' in data:
313 342
            # dead code as updateFamily seems not to modify medicalRecord
314 343
            self.assert_child_medical_record_payload_in_referential(post_data, keys + ['medicalRecord'])
344
        self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data, keys)
315 345

  
316 346
    def assert_person_payload_in_referential(self, post_data, parent_keys=None):
317 347
        keys = parent_keys or []
318 348
        self.assert_post_data_in_referential('Civility', post_data, keys + ['civility'], required=False)
319 349
        self.assert_post_data_in_referential('Sex', post_data, keys + ['sexe'], required=False)
320 350
        self.assert_post_data_in_referential('Quality', post_data, keys + ['quality'])
321 351

  
322 352
    def assert_update_coordinate_payload_in_referential(self, post_data, parent_keys=None):
......
329 359
        )
330 360
        self.assert_post_data_in_referential('Organ', post_data, keys + ['CAFInfo', 'organ'], required=False)
331 361

  
332 362
    def assert_rl_payload_in_referential(self, post_data, parent_keys=None):
333 363
        keys = parent_keys or []
334 364
        self.assert_post_data_in_referential('Civility', post_data, keys + ['civility'])
335 365
        self.assert_post_data_in_referential('Quality', post_data, keys + ['quality'])
336 366
        self.assert_update_coordinate_payload_in_referential(post_data, keys)
367
        self.assert_update_indicator_payload_in_referential('RLIndicator', post_data, keys)
337 368

  
338 369
    def assert_create_rl1_payload_in_referential(self, post_data):
339 370
        self.assert_post_data_in_referential('Category', post_data, ['category'])
340 371
        self.assert_post_data_in_referential('Situation', post_data, ['situation'])
341 372
        self.assert_rl_payload_in_referential(post_data, ['rl1'])
342 373

  
343 374
    def assert_family_payload_in_referential(self, post_data):
344 375
        self.assert_post_data_in_referential('Category', post_data, ['category'])
......
880 911
    def update_coordinate(self, request, NameID, rl_id, post_data):
881 912
        family_id = self.get_link(NameID).family_id
882 913
        self.assert_update_coordinate_payload_in_referential(post_data)
883 914
        self.replace_null_values(post_data)
884 915

  
885 916
        self.call('Family', 'updateCoordinate', numDossier=family_id, numPerson=rl_id, **post_data)
886 917
        return {'data': 'ok'}
887 918

  
919
    @endpoint(
920
        display_category='Famille',
921
        description="Mise à jour des indicateurs d'un responsable légal",
922
        name='update-rl-indicator',
923
        perm='can_access',
924
        parameters={
925
            'NameID': {'description': 'Publik NameID'},
926
            'rl_id': {'description': 'Numéro du représentant légal'},
927
        },
928
        post={'request_body': {'schema': {'application/json': schemas.UPDATE_INDICATOR_SCHEMA}}},
929
    )
930
    def update_rl_indicator(self, request, NameID, rl_id, post_data):
931
        self.get_link(NameID)
932
        self.assert_update_indicator_payload_in_referential('RLIndicator', post_data)
933

  
934
        self.call('Family', 'updatePersonIndicatorList', numPerson=rl_id, **post_data)
935
        return {'data': 'ok'}
936

  
888 937
    @endpoint(
889 938
        display_category='Famille',
890 939
        description="Création d'une personne à prévenir en cas d'urgence",
891 940
        name='create-person',
892 941
        perm='can_access',
893 942
        parameters={
894 943
            'NameID': {'description': 'Publik NameID'},
895 944
        },
......
1151 1200

  
1152 1201
        payload = {
1153 1202
            'numPerson': child_id,
1154 1203
            'medicalRecord': post_data,
1155 1204
        }
1156 1205
        self.call('Family', 'updateChildMedicalRecord', updateChildMedicalRecordRequest=payload)
1157 1206
        return {'data': 'ok'}
1158 1207

  
1208
    @endpoint(
1209
        display_category='Famille',
1210
        description="Mise à jour des indicateurs d'un enfant",
1211
        name='update-child-indicator',
1212
        perm='can_access',
1213
        parameters={
1214
            'NameID': {'description': 'Publik NameID'},
1215
            'child_id': {'description': "Numéro de l'enfant"},
1216
        },
1217
        post={'request_body': {'schema': {'application/json': schemas.UPDATE_INDICATOR_SCHEMA}}},
1218
    )
1219
    def update_child_indicator(self, request, NameID, child_id, post_data):
1220
        self.get_link(NameID)
1221
        self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data)
1222

  
1223
        self.call('Family', 'updatePersonIndicatorList', numPerson=child_id, **post_data)
1224
        return {'data': 'ok'}
1225

  
1159 1226

  
1160 1227
class Link(models.Model):
1161 1228
    resource = models.ForeignKey(ToulouseMaelis, on_delete=models.CASCADE)
1162 1229
    name_id = models.CharField(blank=False, max_length=256)
1163 1230
    family_id = models.CharField(blank=False, max_length=128)
1164 1231
    created = models.DateTimeField(auto_now_add=True)
1165 1232
    updated = models.DateTimeField(auto_now=True)
1166 1233

  
passerelle/contrib/toulouse_maelis/schemas.py
173 173
        },
174 174
        'countryCode': {
175 175
            'description': 'Pays de naissance (depuis référentiel)',
176 176
            'oneOf': [{'type': 'string'}, {'type': 'null'}],
177 177
        },
178 178
    },
179 179
}
180 180

  
181
INDICATOR_SCHEMA = {
182
    '$schema': 'http://json-schema.org/draft-04/schema#',
183
    'title': 'Address',
184
    'description': 'Indicateurs',
185
    'type': 'object',
186
    'required': ['code', 'isActive'],
187
    'properties': {
188
        'code': {
189
            'description': "Code de l'indicateur (depuis référentiel)",
190
            'type': 'string',
191
            'pattern': '.+',
192
        },
193
        'note': {
194
            'description': "Commentaire pour les indicateurs de type NOTE",
195
            'oneOf': [{'type': 'string'}, {'type': 'null'}],
196
        },
197
        'isActive': {
198
            'description': "True pour ajouter/modifier l'indicateur (défault) ou False pour le retirer",
199
            'oneOf': BOOLEAN_TYPES,
200
        },
201
    },
202
}
203

  
181 204
ID_PROPERTIES = {
182 205
    'firstname': {
183 206
        'description': 'Prénom',
184 207
        'type': 'string',
185 208
    },
186 209
    'lastname': {
187 210
        'description': 'Nom',
188 211
        'type': 'string',
......
345 368
            'description': 'Qualité (depuis référentiel)',
346 369
            'type': 'string',
347 370
            'pattern': '.+',
348 371
        },
349 372
        'adresse': ADDRESS_SCHEMA,
350 373
        'contact': {'oneOf': [CONTACT_SCHEMA, {'type': 'null'}]},
351 374
        'profession': {'oneOf': [PROFESSION_SCHEMA, {'type': 'null'}]},
352 375
        'CAFInfo': {'oneOf': [CAFINFO_SCHEMA, {'type': 'null'}]},
376
        'indicatorList': {
377
            'oneOf': [
378
                {
379
                    'type': 'array',
380
                    'items': INDICATOR_SCHEMA,
381
                },
382
                {'type': 'null'},
383
            ],
384
        },
353 385
    },
354 386
    'unflatten': True,
355 387
    'additionalProperties': False,
356 388
}
357 389
RLINFO_SCHEMA['properties'].update(ID_PROPERTIES)
358 390

  
359 391
DOCTORADDRESS_SCHEMA = {
360 392
    '$schema': 'http://json-schema.org/draft-04/schema#',
......
537 569
            'oneOf': [
538 570
                {
539 571
                    'type': 'array',
540 572
                    'items': AUTHORIZED_PERSON_SCHEMA,
541 573
                },
542 574
                {'type': 'null'},
543 575
            ],
544 576
        },
577
        'indicatorList': {
578
            'oneOf': [
579
                {
580
                    'type': 'array',
581
                    'items': INDICATOR_SCHEMA,
582
                },
583
                {'type': 'null'},
584
            ],
585
        },
545 586
    },
546 587
    'additionalProperties': False,
547 588
}
548 589
CHILD_SCHEMA['properties'].update(ID_PROPERTIES)
549 590

  
550 591
UPDATE_FAMILY_SCHEMA = {
551 592
    '$schema': 'http://json-schema.org/draft-04/schema#',
552 593
    'title': 'Family',
......
617 658
del CREATE_RL1_SCHEMA['properties']['rl1']['properties']['CAFInfo']
618 659

  
619 660
UPDATE_RL1_SCHEMA = copy.deepcopy(RLINFO_SCHEMA)
620 661
UPDATE_RL1_SCHEMA['required'] = ['firstname', 'lastname', 'civility', 'quality', 'birth']
621 662
del UPDATE_RL1_SCHEMA['properties']['adresse']
622 663
del UPDATE_RL1_SCHEMA['properties']['contact']
623 664
del UPDATE_RL1_SCHEMA['properties']['profession']
624 665
del UPDATE_RL1_SCHEMA['properties']['CAFInfo']
666
del UPDATE_RL1_SCHEMA['properties']['indicatorList']
625 667

  
626 668
CREATE_RL2_SCHEMA = copy.deepcopy(RLINFO_SCHEMA)
627 669
CREATE_RL2_SCHEMA['unflatten'] = True
628 670
del CREATE_RL2_SCHEMA['properties']['contact']
629 671
del CREATE_RL2_SCHEMA['properties']['profession']
630 672
del CREATE_RL2_SCHEMA['properties']['CAFInfo']
673
del CREATE_RL2_SCHEMA['properties']['indicatorList']
631 674

  
632 675
UPDATE_RL2_SCHEMA = copy.deepcopy(UPDATE_RL1_SCHEMA)
633 676

  
634 677
CREATE_CHILD_SCHEMA = copy.deepcopy(CHILD_SCHEMA)
635 678
CREATE_CHILD_SCHEMA['unflatten'] = True
636 679
del CREATE_CHILD_SCHEMA['properties']['dietcode']
637 680
del CREATE_CHILD_SCHEMA['properties']['medicalRecord']
638 681
del CREATE_CHILD_SCHEMA['properties']['paiInfoBean']
639 682
del CREATE_CHILD_SCHEMA['properties']['authorizedPersonList']
683
del CREATE_CHILD_SCHEMA['properties']['indicatorList']
640 684

  
641 685
UPDATE_CHILD_SCHEMA = copy.deepcopy(CREATE_CHILD_SCHEMA)
642 686

  
643 687
UPDATE_COORDINATE_SCHEMA = {
644 688
    '$schema': 'http://json-schema.org/draft-04/schema#',
645 689
    'title': 'Update coordinate',
646 690
    'description': "Mise à jour des coordonnées d'un responsable légal",
647 691
    'type': 'object',
......
650 694
        'adresse': ADDRESS_SCHEMA,
651 695
        'contact': {'oneOf': [CONTACT_SCHEMA, {'type': 'null'}]},
652 696
        'profession': {'oneOf': [PROFESSION_SCHEMA, {'type': 'null'}]},
653 697
        'CAFInfo': {'oneOf': [CAFINFO_SCHEMA, {'type': 'null'}]},
654 698
    },
655 699
    'unflatten': True,
656 700
    'additionalProperties': False,
657 701
}
702

  
703
UPDATE_INDICATOR_SCHEMA = {
704
    '$schema': 'http://json-schema.org/draft-04/schema#',
705
    'title': 'Update indicators',
706
    'description': 'Mise à jour des indicateurs',
707
    'type': 'object',
708
    'required': ['indicatorList'],
709
    'properties': {
710
        'indicatorList': {
711
            'type': 'array',
712
            'items': INDICATOR_SCHEMA,
713
            'minItems': 1,
714
        }
715
    },
716
    'additionalProperties': False,
717
    'unflatten': True,
718
}
tests/data/toulouse_maelis/Q_update_child_indicator.xml
1
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
2
  <soap-env:Header>
3
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
4
      <wsse:UsernameToken>
5
        <wsse:Username>maelis-webservice</wsse:Username>
6
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">maelis-password</wsse:Password>
7
      </wsse:UsernameToken>
8
    </wsse:Security>
9
  </soap-env:Header>
10
  <soap-env:Body>
11
    <ns0:updatePersonIndicatorList xmlns:ns0="family.ws.maelis.sigec.com">
12
      <numPerson>613880</numPerson>
13
      <indicatorList>
14
        <code>LUNETTE</code>
15
        <isActive>true</isActive>
16
      </indicatorList>
17
      <indicatorList>
18
        <code>AUTRE</code>
19
        <note>rebellious</note>
20
        <isActive>true</isActive>
21
      </indicatorList>
22
    </ns0:updatePersonIndicatorList>
23
  </soap-env:Body>
24
</soap-env:Envelope>
tests/data/toulouse_maelis/Q_update_rl_indicator.xml
1
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
2
  <soap-env:Header>
3
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
4
      <wsse:UsernameToken>
5
        <wsse:Username>maelis-webservice</wsse:Username>
6
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">maelis-password</wsse:Password>
7
      </wsse:UsernameToken>
8
    </wsse:Security>
9
  </soap-env:Header>
10
  <soap-env:Body>
11
    <ns0:updatePersonIndicatorList xmlns:ns0="family.ws.maelis.sigec.com">
12
      <numPerson>613878</numPerson>
13
      <indicatorList>
14
        <code>AVL</code>
15
        <isActive>true</isActive>
16
      </indicatorList>
17
      <indicatorList>
18
        <code>ETABSPEC</code>
19
        <note>SNPP</note>
20
        <isActive>true</isActive>
21
      </indicatorList>
22
    </ns0:updatePersonIndicatorList>
23
  </soap-env:Body>
24
</soap-env:Envelope>
tests/data/toulouse_maelis/R_read_family.xml
31 31
            <mail>djhon@example.org</mail>
32 32
            <isContactMail>true</isContactMail>
33 33
            <isContactSms>true</isContactSms>
34 34
            <isInvoicePdf>true</isInvoicePdf>
35 35
          </contact>
36 36
          <profession>
37 37
            <addressPro/>
38 38
          </profession>
39
          <indicatorList>
40
            <code>ETABSPEC</code>
41
            <label>Etablissement sp&#233;cialis&#233;</label>
42
            <note>SNPP</note>
43
          </indicatorList>
44
          <indicatorList>
45
            <code>AVL</code>
46
            <label>Auxiliaire de Vie loisirs</label>
47
          </indicatorList>
39 48
        </RL1>
40 49
        <RL2>
41 50
          <num>613879</num>
42 51
          <lastname>DOE</lastname>
43 52
          <firstname>JANE</firstname>
44 53
          <maidenName>SMITH</maidenName>
45 54
          <quality>MERE</quality>
46 55
          <civility>MME</civility>
......
115 124
                <mail>abent@example.org</mail>
116 125
              </contact>
117 126
            </personInfo>
118 127
            <personQuality>
119 128
              <code>T</code>
120 129
              <libelle>TANTE</libelle>
121 130
            </personQuality>
122 131
          </authorizedPersonList>
132
          <indicatorList>
133
            <code>LUNETTE</code>
134
            <label>Port de lunettes</label>
135
          </indicatorList>
136
          <indicatorList>
137
            <code>AUTRE</code>
138
            <label>Autre</label>
139
            <note>rebellious</note>
140
          </indicatorList>
123 141
          <medicalRecord>
124 142
            <familyDoctor>
125 143
              <name>DRE</name>
126 144
              <phone>0612341234</phone>
127 145
              <address>
128 146
                <street1>Alameda</street1>
129 147
                <zipcode>90220</zipcode>
130 148
                <town>Compton</town>
tests/data/toulouse_maelis/R_read_family_relax.xml
31 31
            <mail>djhon@example.org</mail>
32 32
            <isContactMail>true</isContactMail>
33 33
            <isContactSms>true</isContactSms>
34 34
            <isInvoicePdf>true</isInvoicePdf>
35 35
          </contact>
36 36
          <profession>
37 37
            <addressPro/>
38 38
          </profession>
39
          <indicatorList>
40
            <code>ETABSPEC</code>
41
            <label>Etablissement sp&#233;cialis&#233;</label>
42
            <note>SNPP</note>
43
          </indicatorList>
44
          <indicatorList>
45
            <code>AVL</code>
46
            <label>Auxiliaire de Vie loisirs</label>
47
          </indicatorList>
39 48
        </RL1>
40 49
        <RL2>
41 50
          <num>613879</num>
42 51
          <lastname>DOE</lastname>
43 52
          <firstname>JANE</firstname>
44 53
          <maidenName>SMITH</maidenName>
45 54
          <quality>MERE</quality>
46 55
          <civility>MME</civility>
......
115 124
                <mail>abent@example.org</mail>
116 125
              </contact>
117 126
            </personInfo>
118 127
            <personQuality>
119 128
              <code>T</code>
120 129
              <libelle>TANTE</libelle>
121 130
            </personQuality>
122 131
          </authorizedPersonList>
132
          <indicatorList>
133
            <code>LUNETTE</code>
134
            <label>Port de lunettes</label>
135
          </indicatorList>
136
          <indicatorList>
137
            <code>AUTRE</code>
138
            <label>Autre</label>
139
            <note>rebellious</note>
140
          </indicatorList>
123 141
          <medicalRecord>
124 142
            <familyDoctor>
125 143
              <name>DRE</name>
126 144
              <phone>0612341234</phone>
127 145
              <address>
128 146
                <street1>Alameda</street1>
129 147
                <zipcode>90220</zipcode>
130 148
                <town>Compton</town>
tests/data/toulouse_maelis/R_read_family_reordered.xml
31 31
            <mail>djhon@example.org</mail>
32 32
            <isContactMail>true</isContactMail>
33 33
            <isContactSms>true</isContactSms>
34 34
            <isInvoicePdf>true</isInvoicePdf>
35 35
          </contact>
36 36
          <profession>
37 37
            <addressPro/>
38 38
          </profession>
39
          <indicatorList>
40
            <code>ETABSPEC</code>
41
            <label>Etablissement sp&#233;cialis&#233;</label>
42
            <note>SNPP</note>
43
          </indicatorList>
44
          <indicatorList>
45
            <code>AVL</code>
46
            <label>Auxiliaire de Vie loisirs</label>
47
          </indicatorList>
39 48
        </RL1>
40 49
        <RL2>
41 50
          <num>613879</num>
42 51
          <lastname>DOE</lastname>
43 52
          <firstname>JANE</firstname>
44 53
          <maidenName>SMITH</maidenName>
45 54
          <quality>MERE</quality>
46 55
          <civility>MME</civility>
......
115 124
                <mail>abent@example.org</mail>
116 125
              </contact>
117 126
            </personInfo>
118 127
            <personQuality>
119 128
              <code>T</code>
120 129
              <libelle>TANTE</libelle>
121 130
            </personQuality>
122 131
          </authorizedPersonList>
132
          <indicatorList>
133
            <code>LUNETTE</code>
134
            <label>Port de lunettes</label>
135
          </indicatorList>
136
          <indicatorList>
137
            <code>AUTRE</code>
138
            <label>Autre</label>
139
            <note>rebellious</note>
140
          </indicatorList>
123 141
          <medicalRecord>
124 142
            <familyDoctor>
125 143
              <name>DRE</name>
126 144
              <phone>0612341234</phone>
127 145
              <address>
128 146
                <street1>Alameda</street1>
129 147
                <zipcode>90220</zipcode>
130 148
                <town>Compton</town>
tests/data/toulouse_maelis/R_update_indicator.xml
1
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
  <soap:Body>
3
    <ns2:updatePersonIndicatorListResponse
4
        xmlns:ns2="family.ws.maelis.sigec.com"/>
5
  </soap:Body>
6
</soap:Envelope>
tests/test_toulouse_maelis.py
75 75
UPDATE_DIETCODE = FakedResponse(content=get_xml_file('R_update_child_dietcode.xml'), status_code=200)
76 76
UPDATE_PAI = FakedResponse(content=get_xml_file('R_update_child_pai.xml'), status_code=200)
77 77
UPDATE_PAI_500 = FakedResponse(content=get_xml_file('R_update_child_pai_soap_error.xml'), status_code=500)
78 78
UPDATE_MEDICAL = FakedResponse(content=get_xml_file('R_update_child_medical_record.xml'), status_code=200)
79 79
UPDATE_MEDICAL_500 = FakedResponse(
80 80
    content=get_xml_file('R_update_child_medical_record_soap_error.xml'), status_code=500
81 81
)
82 82
UPDATE_CHILD_AUTO = FakedResponse(content=get_xml_file('R_update_child_authorization.xml'), status_code=200)
83
UPDATE_INDICATOR = FakedResponse(content=get_xml_file('R_update_indicator.xml'), status_code=200)
83 84

  
84 85

  
85 86
def assert_sent_payload(mocked_post, query_file):
86 87
    soap_sent = etree.tostring(etree.fromstring(mocked_post.call_args.kwargs['data']), pretty_print=True)
87 88
    expected = etree.tostring(etree.fromstring(get_xml_file(query_file)), pretty_print=True)
88 89
    assert soap_sent.decode() == expected.decode()
89 90

  
90 91

  
......
636 637
    ]
637 638

  
638 639

  
639 640
@pytest.mark.parametrize("read_family", [READ_FAMILY, READ_FAMILY_LAX, READ_FAMILY_ORD])
640 641
@mock.patch('passerelle.utils.Request.get')
641 642
@mock.patch('passerelle.utils.Request.post')
642 643
def test_read_family(mocked_post, mocked_get, read_family, con, app):
643 644
    mocked_get.return_value = FAMILY_SERVICE_WSDL
644
    mocked_post.side_effect = [
645
    side_effect = [
645 646
        read_family,
646 647
        READ_CATEGORIES,
647 648
        READ_SITUATIONS,
648 649
        READ_CIVILITIES,
649 650
        READ_QUALITIES,
651
        READ_RL_INDICATOR,
650 652
        READ_CSP,
651 653
        READ_ORGAN,
652 654
        READ_DIETCODE,
653
        READ_PAI,
654 655
    ]
656
    if read_family == READ_FAMILY_LAX:
657
        side_effect.append(READ_CHILD_INDICATOR)
658
    else:
659
        side_effect.append(READ_PAI)
660
        side_effect.append(READ_CHILD_INDICATOR)
661
    mocked_post.side_effect = side_effect
662

  
655 663
    url = get_endpoint('read-family')
656 664
    Link.objects.create(resource=con, family_id='1312', name_id='local')
657 665

  
658 666
    resp = app.get(url + '?NameID=local')
659 667
    assert resp.json['err'] == 0
660 668
    data = resp.json['data']
661 669
    del data['RL1']
662 670
    del data['RL2']
......
707 715
            'isContactMail': True,
708 716
            'isContactSms': True,
709 717
            'isInvoicePdf': True,
710 718
        },
711 719
        'CAFInfo': None,
712 720
        'civility_text': 'Monsieur',
713 721
        'quality_text': 'PERE',
714 722
        'quotientList': [],
715
        'indicatorList': [],
723
        'indicatorList': [
724
            {
725
                'choice': None,
726
                'code': 'AVL',
727
                'code_text': 'Auxiliaire de Vie loisirs',
728
                'label': 'Auxiliaire de Vie loisirs',
729
                'note': None,
730
            },
731
            {
732
                'choice': None,
733
                'code': 'ETABSPEC',
734
                'code_text': 'Etablissement spécialisé',
735
                'label': 'Etablissement spécialisé',
736
                'note': 'SNPP',
737
            },
738
        ],
716 739
        'subscribeActivityList': [],
717 740
    }
718 741
    data = resp.json['data']['childList'][0]
719 742
    del data['medicalRecord']
720 743
    del data['authorizedPersonList']
721 744
    del data['paiInfoBean']
745
    del data['indicatorList']
722 746
    assert data == {
723 747
        'num': '613880',
724 748
        'lastname': 'DOE',
725 749
        'firstname': 'JANNIS',
726 750
        'sexe': 'F',
727 751
        'sexe_text': 'Féminin',
728 752
        'birth': {
729 753
            'dateBirth': '1943-01-19T00:00:00+01:00',
......
731 755
            'communeCode': '91122',
732 756
            'countryCode': '99100',
733 757
        },
734 758
        'dietcode': 'RSV',
735 759
        'dietcode_text': '3- RÉGIME SANS VIANDE',
736 760
        'bPhoto': True,
737 761
        'bLeaveAlone': False,
738 762
        'insurance': None,
739
        'indicatorList': [],
740 763
        'subscribeSchoolList': [],
741 764
        'mother': {'num': 613963, 'civility': 'MME', 'firstname': 'JANE', 'lastname': 'DOE'},
742 765
        'father': {'num': 613878, 'civility': 'M.', 'firstname': 'JHON', 'lastname': 'DOE'},
743 766
        'rl': None,
744 767
        'subscribeActivityList': [],
745 768
    }
746 769
    if read_family != READ_FAMILY_LAX:
747 770
        assert resp.json['data']['childList'][0]['paiInfoBean'] == {
......
815 838
            'contact': {'phone': '0123456789', 'mobile': '0623456789', 'mail': 'abent@example.org'},
816 839
        },
817 840
        'personQuality': {
818 841
            'code': 'T',
819 842
            'code_text': 'TANTE',
820 843
            'libelle': 'TANTE',
821 844
        },
822 845
    }
846
    assert resp.json['data']['childList'][0]['indicatorList'] == [
847
        {'choice': None, 'code': 'AUTRE', 'code_text': 'Autre', 'label': 'Autre', 'note': 'rebellious'},
848
        {
849
            'choice': None,
850
            'code': 'LUNETTE',
851
            'code_text': 'Port de lunettes',
852
            'label': 'Port de lunettes',
853
            'note': None,
854
        },
855
    ]
823 856

  
824 857

  
825 858
def test_read_family_not_linked_error(con, app):
826 859
    url = get_endpoint('read-family')
827 860

  
828 861
    resp = app.get(url + '?NameID=')
829 862
    assert resp.json['err'] == 'not-linked'
830 863
    assert resp.json['err_desc'] == 'User not linked to family'
......
833 866
@mock.patch('passerelle.utils.Request.get')
834 867
@mock.patch('passerelle.utils.Request.post')
835 868
def test_read_rl1(mocked_post, mocked_get, con, app):
836 869
    mocked_get.return_value = FAMILY_SERVICE_WSDL
837 870
    mocked_post.side_effect = [
838 871
        READ_FAMILY,
839 872
        READ_CIVILITIES,
840 873
        READ_QUALITIES,
874
        READ_RL_INDICATOR,
841 875
        READ_CSP,
842 876
    ]
843 877
    url = get_endpoint('read-rl')
844 878
    Link.objects.create(resource=con, family_id='1312', name_id='local')
845 879

  
846 880
    resp = app.get(url + '?NameID=local&rl_id=613878')
847 881
    assert resp.json['err'] == 0
848 882
    assert resp.json['data']['firstname'] == 'JHON'
......
979 1013
def test_read_child(mocked_post, mocked_get, con, app):
980 1014
    mocked_get.return_value = FAMILY_SERVICE_WSDL
981 1015
    mocked_post.side_effect = [
982 1016
        READ_FAMILY,
983 1017
        READ_DIETCODE,
984 1018
        READ_PAI,
985 1019
        READ_CIVILITIES,
986 1020
        READ_QUALITIES,
1021
        READ_CHILD_INDICATOR,
987 1022
    ]
988 1023
    url = get_endpoint('read-child')
989 1024
    Link.objects.create(resource=con, family_id='1312', name_id='local')
990 1025

  
991 1026
    resp = app.get(url + '?NameID=local&child_id=613880')
992 1027
    assert resp.json['err'] == 0
993 1028
    assert resp.json['data']['firstname'] == 'JANNIS'
994 1029

  
......
2922 2957
        'vaccinList/1/code': 'plop',
2923 2958
        'vaccinList/1/vaccinationDate': '2022-02-22',
2924 2959
    }
2925 2960

  
2926 2961
    Link.objects.create(resource=con, family_id='1312', name_id='local')
2927 2962
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
2928 2963
    assert resp.json['err'] == 'wrong-key'
2929 2964
    assert resp.json['err_desc'] == "vaccinList/1/code key value 'plop' do not belong to 'Vaccin' referential"
2965

  
2966

  
2967
@mock.patch('passerelle.utils.Request.get')
2968
@mock.patch('passerelle.utils.Request.post')
2969
def test_update_rl_indicator(mocked_post, mocked_get, con, app):
2970
    mocked_get.return_value = FAMILY_SERVICE_WSDL
2971
    mocked_post.side_effect = [READ_RL_INDICATOR, UPDATE_INDICATOR]
2972
    url = get_endpoint('update-rl-indicator')
2973
    params = {
2974
        'indicatorList': [
2975
            {
2976
                'code': 'AVL',
2977
                'isActive': True,
2978
            },
2979
            {
2980
                'code': 'ETABSPEC',
2981
                'note': 'SNPP',
2982
                'isActive': True,
2983
            },
2984
        ],
2985
    }
2986

  
2987
    Link.objects.create(resource=con, family_id='1312', name_id='local')
2988
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
2989
    assert_sent_payload(mocked_post, 'Q_update_rl_indicator.xml')
2990
    assert resp.json['err'] == 0
2991
    assert resp.json['data'] == 'ok'
2992

  
2993

  
2994
def test_update_rl_indicator_not_linked_error(con, app):
2995
    url = get_endpoint('update-rl-indicator')
2996
    params = {
2997
        'indicatorList': [
2998
            {
2999
                'code': 'AVL',
3000
                'isActive': True,
3001
            },
3002
        ],
3003
    }
3004

  
3005
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
3006
    assert resp.json['err'] == 'not-linked'
3007
    assert resp.json['err_desc'] == 'User not linked to family'
3008

  
3009

  
3010
def test_update_rl_indicator_no_indicator_error(con, app):
3011
    url = get_endpoint('update-rl-indicator')
3012
    params = {'indicatorList': []}
3013

  
3014
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3015
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
3016
    assert resp.json['err'] == 1
3017
    assert resp.json['err_desc'] == 'indicatorList: [] is too short'
3018

  
3019

  
3020
def test_update_rl_indicator_empty_referential_key_error(con, app):
3021
    url = get_endpoint('update-rl-indicator')
3022
    params = {
3023
        'indicatorList': [
3024
            {
3025
                'code': '',
3026
                'isActive': True,
3027
            },
3028
        ],
3029
    }
3030

  
3031
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3032
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params, status=400)
3033
    assert resp.json['err'] == 1
3034
    assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'"
3035

  
3036

  
3037
@mock.patch('passerelle.utils.Request.get')
3038
@mock.patch('passerelle.utils.Request.post')
3039
def test_update_rl_indicator_wrong_referential_key_error(mocked_post, mocked_get, con, app):
3040
    mocked_get.return_value = FAMILY_SERVICE_WSDL
3041
    mocked_post.side_effect = [READ_RL_INDICATOR]
3042
    url = get_endpoint('update-rl-indicator')
3043
    params = {
3044
        'indicatorList': [
3045
            {
3046
                'code': 'plop',
3047
                'isActive': True,
3048
            },
3049
        ],
3050
    }
3051

  
3052
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3053
    resp = app.post_json(url + '?NameID=local&rl_id=613878', params=params)
3054
    assert resp.json['err'] == 'wrong-key'
3055
    assert (
3056
        resp.json['err_desc']
3057
        == "indicatorList/0/code key value 'plop' do not belong to 'RLIndicator' required referential"
3058
    )
3059

  
3060

  
3061
@mock.patch('passerelle.utils.Request.get')
3062
@mock.patch('passerelle.utils.Request.post')
3063
def test_update_child_indicator(mocked_post, mocked_get, con, app):
3064
    mocked_get.return_value = FAMILY_SERVICE_WSDL
3065
    mocked_post.side_effect = [READ_CHILD_INDICATOR, UPDATE_INDICATOR]
3066
    url = get_endpoint('update-child-indicator')
3067
    params = {
3068
        'indicatorList': [
3069
            {
3070
                'code': 'LUNETTE',
3071
                'isActive': True,
3072
            },
3073
            {
3074
                'code': 'AUTRE',
3075
                'note': 'rebellious',
3076
                'isActive': True,
3077
            },
3078
        ],
3079
    }
3080

  
3081
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3082
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
3083
    assert_sent_payload(mocked_post, 'Q_update_child_indicator.xml')
3084
    assert resp.json['err'] == 0
3085
    assert resp.json['data'] == 'ok'
3086

  
3087

  
3088
def test_update_child_indicator_not_linked_error(con, app):
3089
    url = get_endpoint('update-child-indicator')
3090
    params = {
3091
        'indicatorList': [
3092
            {
3093
                'code': 'LUNETTE',
3094
                'isActive': True,
3095
            },
3096
        ],
3097
    }
3098

  
3099
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
3100
    assert resp.json['err'] == 'not-linked'
3101
    assert resp.json['err_desc'] == 'User not linked to family'
3102

  
3103

  
3104
def test_update_child_indicator_no_indicator_error(con, app):
3105
    url = get_endpoint('update-child-indicator')
3106
    params = {'indicatorList': []}
3107

  
3108
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3109
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400)
3110
    assert resp.json['err'] == 1
3111
    assert resp.json['err_desc'] == 'indicatorList: [] is too short'
3112

  
3113

  
3114
def test_update_child_indicator_empty_referential_key_error(con, app):
3115
    url = get_endpoint('update-child-indicator')
3116
    params = {
3117
        'indicatorList': [
3118
            {
3119
                'code': '',
3120
                'isActive': True,
3121
            },
3122
        ],
3123
    }
3124

  
3125
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3126
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params, status=400)
3127
    assert resp.json['err'] == 1
3128
    assert resp.json['err_desc'] == "indicatorList/0/code: '' does not match '.+'"
3129

  
3130

  
3131
@mock.patch('passerelle.utils.Request.get')
3132
@mock.patch('passerelle.utils.Request.post')
3133
def test_update_child_indicator_wrong_referential_key_error(mocked_post, mocked_get, con, app):
3134
    mocked_get.return_value = FAMILY_SERVICE_WSDL
3135
    mocked_post.side_effect = [READ_CHILD_INDICATOR]
3136
    url = get_endpoint('update-child-indicator')
3137
    params = {
3138
        'indicatorList': [
3139
            {
3140
                'code': 'plop',
3141
                'isActive': True,
3142
            },
3143
        ],
3144
    }
3145

  
3146
    Link.objects.create(resource=con, family_id='1312', name_id='local')
3147
    resp = app.post_json(url + '?NameID=local&child_id=613880', params=params)
3148
    assert resp.json['err'] == 'wrong-key'
3149
    assert (
3150
        resp.json['err_desc']
3151
        == "indicatorList/0/code key value 'plop' do not belong to 'ChildIndicator' required referential"
3152
    )
2930
-