Projet

Général

Profil

0004-toulouse_maelis-add-FSL-webservice-69045.patch

Nicolas Roche, 13 septembre 2022 19:43

Télécharger (16,2 ko)

Voir les différences:

Subject: [PATCH 4/5] toulouse_maelis: add FSL webservice (#69045)

 passerelle/contrib/toulouse_maelis/models.py  | 47 ++++++++++
 passerelle/contrib/toulouse_maelis/schemas.py | 16 ++--
 .../toulouse_maelis/Q_update_child_fsl.xml    | 38 +++++++++
 .../toulouse_maelis/R_update_child_fsl.xml    |  5 ++
 .../R_update_child_fsl_soap_error.xml         | 15 ++++
 tests/test_toulouse_maelis.py                 | 85 +++++++++++++++++--
 6 files changed, 191 insertions(+), 15 deletions(-)
 create mode 100644 tests/data/toulouse_maelis/Q_update_child_fsl.xml
 create mode 100644 tests/data/toulouse_maelis/R_update_child_fsl.xml
 create mode 100644 tests/data/toulouse_maelis/R_update_child_fsl_soap_error.xml
passerelle/contrib/toulouse_maelis/models.py
153 153
        for child in data['childList']:
154 154
            add_text_value('Sex', child, ['sexe'])
155 155
            add_text_value('DietCode', child, ['dietcode'])
156 156
            add_text_value('PAI', child, ['paiInfoBean', 'code'])
157 157
        for kind in ('authorized', 'emergency'):
158 158
            for person in data[kind + 'PersonList']:
159 159
                add_text_value('Civility', person, ['civility'])
160 160
                add_text_value('Quality', person, ['quality'])
161

  
162
        # convert O/N string into boolean
163
        for child in data['childList']:
164
            if child.get('fsl'):
165
                for key in (
166
                    'allergieAlimentaire',
167
                    'allergieRespiratoire',
168
                    'allergieAutre',
169
                    'allergieMedicament',
170
                    'asthme',
171
                    'flPAI',
172
                    'flImage',
173
                ):
174
                    child['fsl'][key] = bool(child['fsl'][key] == 'O')
161 175
        return data
162 176

  
163 177
    def replace_null_values(self, dico):
164 178
        '''send null fields as empty SOAP tag to tell maelis to empty the value'''
165 179
        for key, value in dico.items():
166 180
            if isinstance(value, dict):
167 181
                self.replace_null_values(value)
168 182
            if value is None:
......
619 633
        # use None to empty date passed as an empty string by date filter
620 634
        for key in 'dateDeb', 'dateFin':
621 635
            if post_data[key] == '':
622 636
                post_data[key] = None
623 637

  
624 638
        self.call('Family', 'updateChildPAI', personNumber=child_id, **post_data)
625 639
        return {'data': 'ok'}
626 640

  
641
    @endpoint(
642
        display_category='Famille',
643
        description="Créer ou mettre à jour la fiche sanitaire d'un enfant",
644
        name='update-child-fsl',
645
        perm='can_access',
646
        parameters={
647
            'NameID': {'description': 'Publik NameID'},
648
            'child_id': {'description': "Numéro de l'enfant"},
649
        },
650
        post={'request_body': {'schema': {'application/json': schemas.FSL_SCHEMA}}},
651
    )
652
    def update_child_fsl(self, request, NameID, child_id, post_data):
653
        self.get_link(NameID)
654

  
655
        # maelis expect strings O/N
656
        for key in (
657
            'allergieAlimentaire',
658
            'allergieRespiratoire',
659
            'allergieAutre',
660
            'allergieMedicament',
661
            'asthme',
662
            'flPAI',
663
            'flImage',
664
        ):
665
            post_data[key] = 'O' if post_data.get(key) else 'N'
666

  
667
        # use None to empty optional date passed as an empty string by date filter
668
        if post_data.get('dtcPrap1') == '':
669
            post_data['dtcPrap1'] = None
670

  
671
        self.call('Family', 'createOrUpdateFSL', arg0=child_id, arg1=post_data)
672
        return {'data': 'ok'}
673

  
627 674

  
628 675
class Link(models.Model):
629 676
    resource = models.ForeignKey(ToulouseMaelis, on_delete=models.CASCADE)
630 677
    name_id = models.CharField(blank=False, max_length=256)
631 678
    family_id = models.CharField(blank=False, max_length=128)
632 679
    created = models.DateTimeField(auto_now_add=True)
633 680
    updated = models.DateTimeField(auto_now=True)
634 681

  
passerelle/contrib/toulouse_maelis/schemas.py
281 281
                },
282 282
                'dateFin': {
283 283
                    'description': 'Date de fin',
284 284
                    'type': 'string',
285 285
                    'pattern': '^[0-9]{4}-[0-9]{2}-[0-9]{2}$',
286 286
                },
287 287
                'allergieAlimentaire': {
288 288
                    'description': 'Allergie alimentaire',
289
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
289
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
290 290
                },
291 291
                'allergieRespiratoire': {
292 292
                    'description': 'Allergie respiratoire',
293
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
293
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
294 294
                },
295 295
                'allergieAutre': {
296 296
                    'description': 'Allergie autre',
297
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
297
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
298 298
                },
299 299
                'allergieMedicament': {
300 300
                    'description': 'Allergie médicament',
301
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
301
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
302 302
                },
303 303
                'asthme': {
304 304
                    'description': 'Asthmatique',
305
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
305
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
306 306
                },
307 307
                'flPAI': {
308 308
                    'description': 'PAI',
309
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
309
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
310 310
                },
311 311
                'flImage': {
312 312
                    'description': 'Autorisation photo',
313
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
313
                    'oneOf': [{'type': 'null'}] + BOOLEAN_TYPES,
314 314
                },
315 315
                'dtcPrap1': {
316 316
                    'description': 'Date du dernier rappel DT Polio',
317 317
                    'type': 'string',
318
                    'pattern': '^[0-9]{4}-[0-9]{2}-[0-9]{2}$',
318
                    'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2}){0,1}$',
319 319
                },
320 320
                'obsMed1': {
321 321
                    'description': 'Observation médecin 1',
322 322
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
323 323
                },
324 324
                'obsMed2': {
325 325
                    'description': 'Observation médecin 2',
326 326
                    'oneOf': [{'type': 'null'}, {'type': 'string'}],
tests/data/toulouse_maelis/Q_update_child_fsl.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:createOrUpdateFSL xmlns:ns0="family.ws.maelis.sigec.com">
12
      <arg0>613878</arg0>
13
      <arg1>
14
        <dateDeb>2022-01-01</dateDeb>
15
        <dateFin>2022-12-31</dateFin>
16
        <allergieAlimentaire>O</allergieAlimentaire>
17
        <allergieRespiratoire>O</allergieRespiratoire>
18
        <allergieAutre>O</allergieAutre>
19
        <allergieMedicament>O</allergieMedicament>
20
        <asthme>N</asthme>
21
        <flPAI>N</flPAI>
22
        <flImage>N</flImage>
23
        <dtcPrap1>2022-02-22</dtcPrap1>
24
        <obsMed1>some obsMed1 text</obsMed1>
25
        <obsMed2>some obsMed2 text</obsMed2>
26
        <obsMed3>some obsMed3 text</obsMed3>
27
        <obsDir1>some obsDir1 text</obsDir1>
28
        <obsDir2>some obsDir2 text</obsDir2>
29
        <obsDir3>some obsDir3 text</obsDir3>
30
        <obsAssist1>some obsAssist1 text</obsAssist1>
31
        <obsAssist2>some obsAssist2 text</obsAssist2>
32
        <obsAssist3>some obsAssist3 text</obsAssist3>
33
        <cons1Med>some cons1Med text</cons1Med>
34
        <cons2Med>some cons2Med text</cons2Med>
35
      </arg1>
36
    </ns0:createOrUpdateFSL>
37
  </soap-env:Body>
38
</soap-env:Envelope>
tests/data/toulouse_maelis/R_update_child_fsl.xml
1
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
  <soap:Body>
3
    <ns2:createOrUpdateFSLResponse xmlns:ns2="family.ws.maelis.sigec.com"/>
4
  </soap:Body>
5
</soap:Envelope>
tests/data/toulouse_maelis/R_update_child_fsl_soap_error.xml
1
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
  <soap:Body>
3
    <soap:Fault>
4
      <faultcode>soap:Server</faultcode>
5
      <faultstring>Une erreur est survenue : java.sql.SQLException: ORA-12899: valeur trop grande pour la colonne "MAELIS"."H_FICHESAN"."FS_OBSMED1" (réelle : 71, maximum : 70)
6
</faultstring>
7
      <detail>
8
        <ns1:MaelisFamilyException xmlns:ns1="family.ws.maelis.sigec.com">
9
          <message xmlns:ns2="family.ws.maelis.sigec.com">Une erreur est survenue : java.sql.SQLException: ORA-12899: valeur trop grande pour la colonne "MAELIS"."H_FICHESAN"."FS_OBSMED1" (réelle : 71, maximum : 70)
10
</message>
11
        </ns1:MaelisFamilyException>
12
      </detail>
13
    </soap:Fault>
14
  </soap:Body>
15
</soap:Envelope>
tests/test_toulouse_maelis.py
62 62
CREATE_FAMILY = FakedResponse(content=get_xml_file('R_create_family.xml'), status_code=200)
63 63
CREATE_FAMILY_ERR = FakedResponse(content=get_xml_file('R_create_family_error.xml'), status_code=200)
64 64
UPDATE_FAMILY = FakedResponse(content=get_xml_file('R_update_family.xml'), status_code=200)
65 65
UPDATE_FAMILY_ERR = FakedResponse(content=get_xml_file('R_update_family_error.xml'), status_code=200)
66 66
UPDATE_FAMILY_500 = FakedResponse(content=get_xml_file('R_update_family_soap_error.xml'), status_code=500)
67 67
UPDATE_DIETCODE = FakedResponse(content=get_xml_file('R_update_child_dietcode.xml'), status_code=200)
68 68
UPDATE_PAI = FakedResponse(content=get_xml_file('R_update_child_pai.xml'), status_code=200)
69 69
UPDATE_PAI_500 = FakedResponse(content=get_xml_file('R_update_child_pai_soap_error.xml'), status_code=500)
70
UPDATE_FSL = FakedResponse(content=get_xml_file('R_update_child_fsl.xml'), status_code=200)
71
UPDATE_FSL_500 = FakedResponse(content=get_xml_file('R_update_child_fsl_soap_error.xml'), status_code=500)
70 72

  
71 73

  
72 74
def assert_sent_payload(mocked_post, query_file):
73 75
    soap_sent = etree.tostring(etree.fromstring(mocked_post.call_args.kwargs['data']), pretty_print=True)
74 76
    expected = etree.tostring(etree.fromstring(get_xml_file(query_file)), pretty_print=True)
75 77
    assert soap_sent.decode() == expected.decode()
76 78

  
77 79

  
......
610 612
            'dateDeb': '2022-01-01T00:00:00+01:00',
611 613
            'dateFin': '2022-12-31T00:00:00+01:00',
612 614
            'description': 'bla bla PAI',
613 615
        },
614 616
    }
615 617
    assert resp.json['data']['childList'][0]['fsl'] == {
616 618
        'dateDeb': '2022-01-01T00:00:00+01:00',
617 619
        'dateFin': '2022-12-31T00:00:00+01:00',
618
        'allergieAlimentaire': 'O',
619
        'allergieRespiratoire': 'O',
620
        'allergieAutre': 'O',
621
        'allergieMedicament': 'O',
622
        'asthme': 'N',
623
        'flPAI': 'N',
624
        'flImage': 'N',
620
        'allergieAlimentaire': True,
621
        'allergieRespiratoire': True,
622
        'allergieAutre': True,
623
        'allergieMedicament': True,
624
        'asthme': False,
625
        'flPAI': False,
626
        'flImage': False,
625 627
        'dtcPrap1': '2022-02-22T00:00:00+01:00',
626 628
        'obsMed1': 'some obsMed1 text',
627 629
        'obsMed2': 'some obsMed2 text',
628 630
        'obsMed3': 'some obsMed3 text',
629 631
        'obsDir1': 'some obsDir1 text',
630 632
        'obsDir2': 'some obsDir2 text',
631 633
        'obsDir3': 'some obsDir3 text',
632 634
        'obsAssist1': 'some obsAssist1 text',
......
1456 1458
    }
1457 1459

  
1458 1460
    Link.objects.create(resource=con, family_id='1312', name_id='local')
1459 1461
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
1460 1462
    assert resp.json['err'] == 'Family-updateChildPAI-soap:Server'
1461 1463
    assert 'Une erreur est survenue' in resp.json['err_desc']
1462 1464
    assert 'valeur trop grande' in resp.json['err_desc']
1463 1465
    assert 'maximum : 500' in resp.json['err_desc']
1466

  
1467

  
1468
@mock.patch('passerelle.utils.Request.get')
1469
@mock.patch('passerelle.utils.Request.post')
1470
def test_update_child_fsl(mocked_post, mocked_get, con, app):
1471
    mocked_get.return_value = FAMILY_SERVICE_WSDL
1472
    mocked_post.return_value = UPDATE_FSL
1473
    url = get_endpoint('update-child-fsl')
1474
    params = {
1475
        'dateDeb': '2022-01-01',
1476
        'dateFin': '2022-12-31',
1477
        'allergieAlimentaire': True,
1478
        'allergieRespiratoire': True,
1479
        'allergieAutre': True,
1480
        'allergieMedicament': True,
1481
        'asthme': False,
1482
        'flPAI': False,
1483
        'flImage': False,
1484
        'dtcPrap1': '2022-02-22',
1485
        'obsMed1': 'some obsMed1 text',
1486
        'obsMed2': 'some obsMed2 text',
1487
        'obsMed3': 'some obsMed3 text',
1488
        'obsDir1': 'some obsDir1 text',
1489
        'obsDir2': 'some obsDir2 text',
1490
        'obsDir3': 'some obsDir3 text',
1491
        'obsAssist1': 'some obsAssist1 text',
1492
        'obsAssist2': 'some obsAssist2 text',
1493
        'obsAssist3': 'some obsAssist3 text',
1494
        'cons1Med': 'some cons1Med text',
1495
        'cons2Med': 'some cons2Med text',
1496
    }
1497

  
1498
    Link.objects.create(resource=con, family_id='1312', name_id='local')
1499
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
1500
    assert_sent_payload(mocked_post, 'Q_update_child_fsl.xml')
1501
    assert resp.json['err'] == 0
1502
    assert resp.json['data'] == 'ok'
1503

  
1504

  
1505
def test_update_child_fsl_not_linked_error(con, app):
1506
    url = get_endpoint('update-child-fsl')
1507
    params = {
1508
        'dateDeb': '2022-01-01',
1509
        'dateFin': '2022-12-31',
1510
    }
1511

  
1512
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
1513
    assert resp.json['err'] == 'not-linked'
1514
    assert resp.json['err_desc'] == 'User not linked to family'
1515

  
1516

  
1517
@mock.patch('passerelle.utils.Request.get')
1518
@mock.patch('passerelle.utils.Request.post')
1519
def test_update_child_fsl_soap_error(mocked_post, mocked_get, con, app):
1520
    mocked_get.return_value = FAMILY_SERVICE_WSDL
1521
    mocked_post.return_value = UPDATE_FSL_500
1522
    url = get_endpoint('update-child-fsl')
1523
    params = {
1524
        'dateDeb': '2022-01-01',
1525
        'dateFin': '2022-12-31',
1526
        'obsMed1': 'a' * 71,
1527
    }
1528

  
1529
    Link.objects.create(resource=con, family_id='1312', name_id='local')
1530
    resp = app.post_json(url + '?NameID=local&child_id=613878', params=params)
1531
    assert resp.json['err'] == 'Family-createOrUpdateFSL-soap:Server'
1532
    assert 'Une erreur est survenue' in resp.json['err_desc']
1533
    assert 'valeur trop grande' in resp.json['err_desc']
1534
    assert 'maximum : 70' in resp.json['err_desc']
1464
-