0003-toulouse-maelis-provide-add-supplied-document-endpoi.patch
functests/toulouse_maelis/conftest.py | ||
---|---|---|
408 | 408 |
create_result = resp.json() |
409 | 409 |
assert create_result['err'] == 0 |
410 | 410 |
print('\ncreate DUI: %s' % str(create_result['data']['number'])) |
411 | 411 |
data = diff_family(conn, name_id, 'test_create_family.json') |
412 | 412 | |
413 | 413 |
return { |
414 | 414 |
'name_id': name_id, # linked |
415 | 415 |
'family_id': str(create_result['data']['number']), |
416 |
'family_payload': create_family_payload, |
|
416 | 417 |
'lastname': lastname, |
417 | 418 |
'rl1_num': data['RL1']['num'], |
418 |
'family_payload': create_family_payload,
|
|
419 |
'bart_num': data['childList'][0]['num'],
|
|
419 | 420 |
'data': data, |
420 | 421 |
} |
421 | 422 | |
422 | 423 | |
423 | 424 |
@pytest.fixture(scope='session') |
424 | 425 |
def update_data(request, conn): |
425 | 426 |
name_id = request.config.getoption('--nameid') |
426 | 427 |
lastname = request.config.getoption('--lastname') |
functests/toulouse_maelis/test_family.py | ||
---|---|---|
1 |
import base64 |
|
1 | 2 |
import copy |
2 | 3 | |
3 | 4 |
import pytest |
4 | 5 |
import requests |
6 |
from django.utils.encoding import force_str |
|
5 | 7 | |
6 | 8 |
from .conftest import diff, diff_child, diff_family, diff_rlg, link, read_family, unlink |
7 | 9 | |
8 | 10 |
FAMILY_RESET_PAYLOAD = { |
9 | 11 |
'category': 'AUTR', |
10 | 12 |
'situation': 'AUTR', |
11 | 13 |
'rl1': { |
12 | 14 |
'civility': 'MR', # no effect |
... | ... | |
871 | 873 |
child_id, |
872 | 874 |
person_id, |
873 | 875 |
) |
874 | 876 |
resp = requests.get(url) |
875 | 877 |
resp.raise_for_status() |
876 | 878 |
res = resp.json() |
877 | 879 |
assert res['err'] == 0 |
878 | 880 |
assert res['data']['personInfo']['firstname'] == 'ABRAHAM JEBEDIAH' |
881 | ||
882 | ||
883 |
def test_add_supplied_document(conn, create_data): |
|
884 |
unlink(conn, create_data['name_id']) |
|
885 |
link(conn, create_data) |
|
886 | ||
887 |
# push on family |
|
888 |
payload = { |
|
889 |
'documentList/0/code': '46', |
|
890 |
'documentList/0/depositDate': '2022-12-20', |
|
891 |
'documentList/0/file': { # w.c.s. file field |
|
892 |
'filename': '201x201.jpg', |
|
893 |
'content_type': 'image/jpeg', |
|
894 |
'content': force_str(base64.b64encode(open('data/201x201.jpg', 'rb').read())), |
|
895 |
}, |
|
896 |
} |
|
897 |
url = conn + '/add-supplied-document?NameID=%s' % create_data['name_id'] |
|
898 |
resp = requests.post(url, json=payload) |
|
899 |
resp.raise_for_status() |
|
900 |
res = resp.json() |
|
901 |
assert res['err'] == 0 |
|
902 | ||
903 |
# push on RL |
|
904 |
payload['numPerson'] = create_data['rl1_num'] |
|
905 |
url = conn + '/add-supplied-document?NameID=%s' % create_data['name_id'] |
|
906 |
resp = requests.post(url, json=payload) |
|
907 |
resp.raise_for_status() |
|
908 |
res = resp.json() |
|
909 |
assert res['err'] == 0 |
|
910 | ||
911 |
# push on childe |
|
912 |
payload['numPerson'] = create_data['bart_num'] |
|
913 |
url = conn + '/add-supplied-document?NameID=%s' % create_data['name_id'] |
|
914 |
resp = requests.post(url, json=payload) |
|
915 |
resp.raise_for_status() |
|
916 |
res = resp.json() |
|
917 |
assert res['err'] == 0 |
passerelle/contrib/toulouse_maelis/family_schemas.py | ||
---|---|---|
712 | 712 |
'cdquo': { |
713 | 713 |
'description': 'Code du quotient (depuis référentiel)', |
714 | 714 |
'type': 'string', |
715 | 715 |
'pattern': '.+', |
716 | 716 |
}, |
717 | 717 |
}, |
718 | 718 |
'additionalProperties': False, |
719 | 719 |
} |
720 | ||
721 |
WCS_FILE_SCHEMA = { |
|
722 |
'$schema': 'http://json-schema.org/draft-04/schema#', |
|
723 |
'title': 'WCS File', |
|
724 |
'description': 'Champ W.C.S. de type ficher', |
|
725 |
'type': 'object', |
|
726 |
'required': ['filename', 'content_type', 'content'], |
|
727 |
'properties': { |
|
728 |
'filename': { |
|
729 |
'description': "Nom du ficher", |
|
730 |
'type': 'string', |
|
731 |
}, |
|
732 |
'content_type': { |
|
733 |
'description': "Type MIME", |
|
734 |
'type': 'string', |
|
735 |
}, |
|
736 |
'content': { |
|
737 |
'description': "Contenu", |
|
738 |
'type': 'string', |
|
739 |
}, |
|
740 |
}, |
|
741 |
} |
|
742 | ||
743 |
SUPPLIED_DOCUMENT_SCHEMA = { |
|
744 |
'$schema': 'http://json-schema.org/draft-04/schema#', |
|
745 |
'title': 'Supplied document', |
|
746 |
'description': 'Ajoute un document pour une famille, un responsable légal ou un enfant', |
|
747 |
'type': 'object', |
|
748 |
'required': ['code', 'file'], |
|
749 |
'properties': { |
|
750 |
'code': { |
|
751 |
'description': 'Code de la pièce (depuis référentiel)', |
|
752 |
'type': 'string', |
|
753 |
'pattern': '.+', |
|
754 |
}, |
|
755 |
'depositDate': { |
|
756 |
'description': 'Date de dépôt (date du jour si non transmise) ', |
|
757 |
'type': 'string', |
|
758 |
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2}){0,1}$', |
|
759 |
}, |
|
760 |
'file': WCS_FILE_SCHEMA, |
|
761 |
}, |
|
762 |
} |
|
763 | ||
764 |
SUPPLIED_DOCUMENTS_SCHEMA = { |
|
765 |
'$schema': 'http://json-schema.org/draft-04/schema#', |
|
766 |
'title': 'Supplied documents', |
|
767 |
'description': 'Ajoute des documents pour une famille, un responsable légal ou un enfant', |
|
768 |
'type': 'object', |
|
769 |
'required': ['documentList'], |
|
770 |
'properties': { |
|
771 |
'numPerson': { |
|
772 |
'description': "Numéro du responsable légal de l'enfant", |
|
773 |
'type': 'string', |
|
774 |
}, |
|
775 |
'documentList': {'type': 'array', 'items': SUPPLIED_DOCUMENT_SCHEMA}, |
|
776 |
}, |
|
777 |
'unflatten': True, |
|
778 |
'additionalProperties': False, |
|
779 |
} |
passerelle/contrib/toulouse_maelis/models.py | ||
---|---|---|
8 | 8 |
# This program is distributed in the hope that it will be useful, |
9 | 9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | 10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | 11 |
# GNU Affero General Public License for more details. |
12 | 12 |
# |
13 | 13 |
# You should have received a copy of the GNU Affero General Public License |
14 | 14 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | 15 | |
16 |
import base64 |
|
16 | 17 |
from urllib.parse import urljoin |
17 | 18 | |
18 | 19 |
import zeep |
19 | 20 |
from django.contrib.postgres.fields import JSONField |
20 | 21 |
from django.db import models |
21 | 22 |
from django.utils.timezone import now |
22 | 23 |
from zeep.helpers import serialize_object |
23 | 24 |
from zeep.wsse.username import UsernameToken |
... | ... | |
1557 | 1558 |
) |
1558 | 1559 |
def update_child_indicator(self, request, NameID, child_id, post_data): |
1559 | 1560 |
self.get_link(NameID) |
1560 | 1561 |
self.assert_update_indicator_payload_in_referential('ChildIndicator', post_data) |
1561 | 1562 | |
1562 | 1563 |
self.call('Family', 'updatePersonIndicatorList', numPerson=child_id, **post_data) |
1563 | 1564 |
return {'data': 'ok'} |
1564 | 1565 | |
1566 |
@endpoint( |
|
1567 |
display_category='Famille', |
|
1568 |
description='Ajoute un document pour une famille, un responsable légal ou un enfant', |
|
1569 |
name='add-supplied-document', |
|
1570 |
perm='can_access', |
|
1571 |
parameters={ |
|
1572 |
'NameID': {'description': 'Publik NameID'}, |
|
1573 |
}, |
|
1574 |
post={'request_body': {'schema': {'application/json': family_schemas.SUPPLIED_DOCUMENTS_SCHEMA}}}, |
|
1575 |
) |
|
1576 |
def add_supplied_document(self, request, NameID, post_data): |
|
1577 |
family_id = self.get_link(NameID).family_id |
|
1578 |
for i in range(0, len(post_data.get('documentList', []))): |
|
1579 |
self.assert_post_data_in_referential('Document', post_data, ['documentList', i, 'code']) |
|
1580 | ||
1581 |
for item in post_data['documentList']: |
|
1582 |
file = item.pop('file') |
|
1583 |
item['filename'] = file['filename'] |
|
1584 |
item['fileSupplied'] = { |
|
1585 |
'dataHandler': base64.b64decode(file['content']), |
|
1586 |
'fileType': file['content_type'], |
|
1587 |
'name': file['filename'], |
|
1588 |
} |
|
1589 |
payload = {'addSuppliedDocumentRequestBean': post_data} |
|
1590 |
payload['addSuppliedDocumentRequestBean']['numDossier'] = family_id |
|
1591 |
response = self.call('Family', 'addSuppliedDocument', **payload) |
|
1592 |
data = serialize_object(response) |
|
1593 |
if data != 'OK': |
|
1594 |
raise APIError('maelis fails to add the supplied document') |
|
1595 |
return {'data': 'ok'} |
|
1596 | ||
1565 | 1597 |
@endpoint( |
1566 | 1598 |
display_category='Facture', |
1567 | 1599 |
description="Ajout d'autorisation de prélèvement", |
1568 | 1600 |
name='add-direct-debit-order', |
1569 | 1601 |
perm='can_access', |
1570 | 1602 |
parameters={'NameID': {'description': 'Publik NameID'}}, |
1571 | 1603 |
post={ |
1572 | 1604 |
'request_body': {'schema': {'application/json': invoice_schemas.ADD_DIRECT_DEBIT_ORDER_SCHEMA}} |
tests/data/toulouse_maelis/R_add_supplied_document.xml | ||
---|---|---|
1 |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> |
|
2 |
<soap:Body> |
|
3 |
<ns2:addSuppliedDocumentResponse xmlns:ns2="family.ws.maelis.sigec.com"> |
|
4 |
<addSuppliedDocumentResultBean>%s</addSuppliedDocumentResultBean> |
|
5 |
</ns2:addSuppliedDocumentResponse> |
|
6 |
</soap:Body> |
|
7 |
</soap:Envelope> |
tests/test_toulouse_maelis.py | ||
---|---|---|
8 | 8 |
# This program is distributed in the hope that it will be useful, |
9 | 9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | 10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | 11 |
# GNU Affero General Public License for more details. |
12 | 12 |
# |
13 | 13 |
# You should have received a copy of the GNU Affero General Public License |
14 | 14 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | 15 | |
16 |
import base64 |
|
16 | 17 |
import logging |
17 | 18 |
import os |
18 | 19 |
from unittest import mock |
19 | 20 | |
20 | 21 |
import pytest |
21 | 22 |
import responses |
23 |
from django.utils.encoding import force_str |
|
22 | 24 |
from requests.exceptions import ConnectionError |
23 | 25 |
from zeep import Settings |
24 | 26 | |
25 | 27 |
from passerelle.contrib.toulouse_maelis.models import Link, Referential, ToulouseMaelis |
26 | 28 |
from passerelle.utils.jsonresponse import APIError |
27 | 29 |
from passerelle.utils.soap import SOAPError |
28 | 30 |
from tests.utils import FakedResponse, ResponsesSoap, generic_endpoint_url, setup_access_rights |
29 | 31 | |
30 | 32 |
TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'toulouse_maelis') |
31 | 33 | |
32 | 34 | |
33 | 35 |
def get_xml_file(filename): |
34 | 36 |
with open(os.path.join(TEST_BASE_DIR, filename), 'rb') as desc: |
35 | 37 |
return desc.read() |
36 | 38 | |
37 | 39 | |
40 |
def get_media_file(filename): |
|
41 |
with open(os.path.join(TEST_BASE_DIR, "%s" % filename), 'rb') as desc: |
|
42 |
return desc.read() |
|
43 | ||
44 | ||
38 | 45 |
CONNECTION_ERROR = ConnectionError('No address associated with hostname') |
39 | 46 |
FAMILY_SERVICE_WSDL = FakedResponse(content=get_xml_file('FamilyService.wsdl'), status_code=200) |
40 | 47 |
ACTIVITY_SERVICE_WSDL = FakedResponse(content=get_xml_file('ActivityService.wsdl'), status_code=200) |
41 | 48 |
INVOICE_SERVICE_WSDL = FakedResponse(content=get_xml_file('InvoiceService.wsdl'), status_code=200) |
42 | 49 |
FAILED_AUTH = FakedResponse(content=get_xml_file('R_failed_authentication.xml'), status_code=500) |
43 | 50 |
ISWSRUNNING_TRUE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'true', status_code=200) |
44 | 51 |
ISWSRUNNING_FALSE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'false', status_code=200) |
45 | 52 | |
... | ... | |
3302 | 3309 |
resp = app.post_json(url + '?NameID=local&child_id=613880', params=params) |
3303 | 3310 |
assert resp.json['err'] == 'wrong-key' |
3304 | 3311 |
assert ( |
3305 | 3312 |
resp.json['err_desc'] |
3306 | 3313 |
== "indicatorList/0/code key value 'plop' do not belong to 'ChildIndicator' required referential" |
3307 | 3314 |
) |
3308 | 3315 | |
3309 | 3316 | |
3317 |
def test_add_supplied_document(family_service, con, app): |
|
3318 |
def request_check(request): |
|
3319 |
assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg') |
|
3320 | ||
3321 |
family_service.add_soap_response( |
|
3322 |
'addSuppliedDocument', |
|
3323 |
get_xml_file('R_add_supplied_document.xml') % b'OK', |
|
3324 |
request_check=request_check, |
|
3325 |
) |
|
3326 |
url = get_endpoint('add-supplied-document') |
|
3327 |
params = { |
|
3328 |
'numPerson': '613880', |
|
3329 |
'documentList/0/code': '46', |
|
3330 |
'documentList/0/depositDate': '2022-12-20', |
|
3331 |
'documentList/0/file': { # w.c.s. file field |
|
3332 |
'filename': '201x201.jpg', |
|
3333 |
'content_type': 'image/jpeg', |
|
3334 |
'content': force_str(base64.b64encode(get_media_file('201x201.jpg'))), |
|
3335 |
}, |
|
3336 |
} |
|
3337 | ||
3338 |
Link.objects.create(resource=con, family_id='1312', name_id='local') |
|
3339 |
resp = app.post_json(url + '?NameID=local', params=params) |
|
3340 |
assert resp.json['err'] == 0 |
|
3341 |
assert resp.json['data'] == 'ok' |
|
3342 | ||
3343 | ||
3344 |
def test_add_supplied_document_not_linked_error(con, app): |
|
3345 |
url = get_endpoint('add-supplied-document') |
|
3346 |
params = { |
|
3347 |
'documentList': [], |
|
3348 |
} |
|
3349 | ||
3350 |
resp = app.post_json(url + '?NameID=local', params=params) |
|
3351 |
assert resp.json['err'] == 'not-linked' |
|
3352 |
assert resp.json['err_desc'] == 'User not linked to family' |
|
3353 | ||
3354 | ||
3355 |
def test_add_supplied_document_empty_referential_key_error(con, app): |
|
3356 |
url = get_endpoint('add-supplied-document') |
|
3357 |
params = { |
|
3358 |
'documentList/0/code': '', |
|
3359 |
'documentList/0/depositDate': '2022-12-20', |
|
3360 |
'documentList/0/file': { # w.c.s. file field |
|
3361 |
'filename': '201x201.jpg', |
|
3362 |
'content_type': 'image/jpeg', |
|
3363 |
'content': force_str(base64.b64encode(get_media_file('201x201.jpg'))), |
|
3364 |
}, |
|
3365 |
} |
|
3366 | ||
3367 |
Link.objects.create(resource=con, family_id='1312', name_id='local') |
|
3368 |
resp = app.post_json(url + '?NameID=local', params=params, status=400) |
|
3369 |
assert resp.json['err'] == 1 |
|
3370 |
assert resp.json['err_desc'] == "documentList/0/code: '' does not match '.+'" |
|
3371 | ||
3372 | ||
3373 |
def test_add_supplied_document_wrong_referential_key_error(con, app): |
|
3374 |
url = get_endpoint('add-supplied-document') |
|
3375 |
params = { |
|
3376 |
'documentList/0/code': 'plop', |
|
3377 |
'documentList/0/depositDate': '2022-12-20', |
|
3378 |
'documentList/0/file': { # w.c.s. file field |
|
3379 |
'filename': '201x201.jpg', |
|
3380 |
'content_type': 'image/jpeg', |
|
3381 |
'content': force_str(base64.b64encode(get_media_file('201x201.jpg'))), |
|
3382 |
}, |
|
3383 |
} |
|
3384 | ||
3385 |
Link.objects.create(resource=con, family_id='1312', name_id='local') |
|
3386 |
resp = app.post_json(url + '?NameID=local', params=params) |
|
3387 |
assert resp.json['err'] == 'wrong-key' |
|
3388 |
assert ( |
|
3389 |
resp.json['err_desc'] |
|
3390 |
== "documentList/0/code key value 'plop' do not belong to 'Document' required referential" |
|
3391 |
) |
|
3392 | ||
3393 | ||
3394 |
def test_add_supplied_document_maelis_error(family_service, con, app): |
|
3395 |
def request_check(request): |
|
3396 |
assert request.documentList[0]['fileSupplied']['dataHandler'] == get_media_file('201x201.jpg') |
|
3397 | ||
3398 |
family_service.add_soap_response( |
|
3399 |
'addSuppliedDocument', |
|
3400 |
get_xml_file('R_add_supplied_document.xml') % b'KO', |
|
3401 |
request_check=request_check, |
|
3402 |
) |
|
3403 |
url = get_endpoint('add-supplied-document') |
|
3404 |
params = { |
|
3405 |
'documentList/0/code': '46', |
|
3406 |
'documentList/0/depositDate': '2022-12-20', |
|
3407 |
'documentList/0/file': { # w.c.s. file field |
|
3408 |
'filename': '201x201.jpg', |
|
3409 |
'content_type': 'image/jpeg', |
|
3410 |
'content': force_str(base64.b64encode(get_media_file('201x201.jpg'))), |
|
3411 |
}, |
|
3412 |
} |
|
3413 | ||
3414 |
Link.objects.create(resource=con, family_id='1312', name_id='local') |
|
3415 |
resp = app.post_json(url + '?NameID=local', params=params) |
|
3416 |
assert resp.json['err'] == 1 |
|
3417 |
assert resp.json['err_desc'] == 'maelis fails to add the supplied document' |
|
3418 | ||
3419 | ||
3310 | 3420 |
def test_add_direct_debit_order(invoice_service, con, app): |
3311 | 3421 |
def request_check(request): |
3312 | 3422 |
assert request.dossierNumber == 1312 |
3313 | 3423 | |
3314 | 3424 |
invoice_service.add_soap_response( |
3315 | 3425 |
'addDirectDebitOrder', get_xml_file('R_add_direct_debit_order.xml'), request_check=request_check |
3316 | 3426 |
) |
3317 | 3427 |
url = get_endpoint('add-direct-debit-order') |
3318 |
- |