0001-dpark-add-support-for-methods-PLS_ENREG2-and-PLS_NOT.patch
passerelle/contrib/dpark/models.py | ||
---|---|---|
31 | 31 | |
32 | 32 |
from passerelle.base.models import BaseResource |
33 | 33 |
from passerelle.utils.api import endpoint |
34 |
from passerelle.utils.conversion import to_pdf |
|
34 |
from passerelle.utils.conversion import any2bool, to_pdf
|
|
35 | 35 |
from passerelle.utils.jsonresponse import APIError |
36 | 36 |
from passerelle.views import WrongParameter |
37 | 37 | |
... | ... | |
290 | 290 |
@endpoint(perm='can_access', methods=['post'], description=_('Register a subscription application')) |
291 | 291 |
def register(self, request, *args, **kwargs): |
292 | 292 |
data = json.loads(request.body) |
293 |
is_erroneous( |
|
294 |
data, |
|
295 |
( |
|
296 |
'application_id', |
|
297 |
'applicant_title', |
|
298 |
'applicant_lastname', |
|
299 |
'applicant_firstnames', |
|
300 |
'applicant_email', |
|
301 |
'address_sticode', |
|
302 |
'address_zipcode', |
|
303 |
'address_locality', |
|
304 |
'address_district', |
|
305 |
), |
|
306 |
) |
|
293 |
double_plaque = any2bool(data.get('double_plaque')) |
|
294 |
required_fields = [ |
|
295 |
'application_id', |
|
296 |
'applicant_title', |
|
297 |
'applicant_lastname', |
|
298 |
'applicant_firstnames', |
|
299 |
'applicant_email', |
|
300 |
'address_sticode', |
|
301 |
'address_zipcode', |
|
302 |
'address_locality', |
|
303 |
'address_district', |
|
304 |
] |
|
305 |
if double_plaque: |
|
306 |
required_fields.extend(['id_contexte', 'id_produit']) |
|
307 |
is_erroneous(data, required_fields) |
|
307 | 308 |
application_id = data['application_id'] |
308 | 309 |
applicant = { |
309 | 310 |
'Demandeur_Civilite': data['applicant_title'], |
... | ... | |
339 | 340 |
'Demande_IBAN': data.get('application_bank_iban', ''), |
340 | 341 |
'Demande_BIC': data.get('application_bank_bic', ''), |
341 | 342 |
} |
342 |
reply = self.call('PLS_ENREG', application_id, applicant, address, application) |
|
343 |
if double_plaque: |
|
344 |
reply = self.call( |
|
345 |
'PLS_ENREG2', |
|
346 |
application_id, |
|
347 |
applicant, |
|
348 |
address, |
|
349 |
application, |
|
350 |
data['id_produit'], |
|
351 |
data['id_contexte'], |
|
352 |
) |
|
353 |
else: |
|
354 |
reply = self.call('PLS_ENREG', application_id, applicant, address, application) |
|
343 | 355 |
if filenumber: |
344 | 356 |
for pairing in Pairing.objects.filter(filenumber=filenumber): |
345 | 357 |
pairing.clear_cache() |
... | ... | |
499 | 511 |
total_amount = int(data['total_amount']) * 100 # in cents |
500 | 512 |
if not pairings: |
501 | 513 |
raise APIError(_('No pairing exists')) |
514 |
double_plaque = any2bool(data.get('double_plaque')) |
|
502 | 515 |
self.call( |
503 |
'PLS_NOTIFCB', |
|
516 |
'PLS_NOTIFCB2' if double_plaque else 'PLS_NOTIFCB',
|
|
504 | 517 |
data['application_external_id'], |
505 | 518 |
data['filenumber'], |
506 | 519 |
data['application_id'], |
tests/data/dpark.awws.wsdl | ||
---|---|---|
360 | 360 |
</xsd:sequence> |
361 | 361 |
</xsd:complexType> |
362 | 362 |
<xsd:element name="FPS_Rech_ImmatResponse" type="s0:tFPS_Rech_ImmatResponse"/> |
363 |
<xsd:complexType name="tPLS_ENREG2"> |
|
364 |
<xsd:sequence> |
|
365 |
<xsd:element name="NumeroTeledossier" type="xsd:string"/> |
|
366 |
<xsd:element name="Entree_Demandeur" type="s0:tEntree_Demandeur_PLS_ENREG"/> |
|
367 |
<xsd:element name="Entree_Adresse" type="s0:tEntree_Adresse"/> |
|
368 |
<xsd:element name="Entree_Demande" type="s0:tEntree_Demande_PLS_ENREG"/> |
|
369 |
<xsd:element name="ID_PRODUIT" type="xsd:int"/> |
|
370 |
<xsd:element name="ID_CONTEXTE" type="xsd:int"/> |
|
371 |
</xsd:sequence> |
|
372 |
</xsd:complexType> |
|
373 |
<xsd:element name="PLS_ENREG2" type="s0:tPLS_ENREG2"/> |
|
374 |
<xsd:complexType name="tPLS_ENREG2Response"> |
|
375 |
<xsd:sequence> |
|
376 |
<xsd:element name="PLS_ENREG2Result" type="s0:tRetour_PLS_ENREG"/> |
|
377 |
</xsd:sequence> |
|
378 |
</xsd:complexType> |
|
379 |
<xsd:element name="PLS_ENREG2Response" type="s0:tPLS_ENREG2Response"/> |
|
380 |
<xsd:complexType name="tPLS_NOTIFCB2"> |
|
381 |
<xsd:sequence> |
|
382 |
<xsd:element name="NumeroTeledossierPhase1" type="xsd:string"/> |
|
383 |
<xsd:element name="NumeroDossier" type="xsd:int"/> |
|
384 |
<xsd:element name="NumeroDemande" type="xsd:int"/> |
|
385 |
<xsd:element name="TypePaiement" type="xsd:int"/> |
|
386 |
<xsd:element name="MontantPaye" type="xsd:int"/> |
|
387 |
<xsd:element name="DatePaiement" type="xsd:string"/> |
|
388 |
<xsd:element name="RefTransaction" type="xsd:string"/> |
|
389 |
</xsd:sequence> |
|
390 |
</xsd:complexType> |
|
391 |
<xsd:element name="PLS_NOTIFCB2" type="s0:tPLS_NOTIFCB2"/> |
|
392 |
<xsd:complexType name="tPLS_NOTIFCB2Response"> |
|
393 |
<xsd:sequence> |
|
394 |
<xsd:element name="PLS_NOTIFCB2Result" type="s0:tRetour_PLS"/> |
|
395 |
</xsd:sequence> |
|
396 |
</xsd:complexType> |
|
397 |
<xsd:element name="PLS_NOTIFCB2Response" type="s0:tPLS_NOTIFCB2Response"/> |
|
363 | 398 |
</xsd:schema> |
364 | 399 |
</types> |
365 | 400 |
<message name="Webservice_Residants_PLS_EXIST_MessageIn"> |
... | ... | |
434 | 469 |
<message name="Webservice_Residants_FPS_Rech_Immat_MessageOut"> |
435 | 470 |
<part name="parameters" element="s0:FPS_Rech_ImmatResponse"/> |
436 | 471 |
</message> |
472 |
<message name="Webservice_Residants_PLS_ENREG2_MessageIn"> |
|
473 |
<part name="parameters" element="s0:PLS_ENREG2"/> |
|
474 |
</message> |
|
475 |
<message name="Webservice_Residants_PLS_ENREG2_MessageOut"> |
|
476 |
<part name="parameters" element="s0:PLS_ENREG2Response"/> |
|
477 |
</message> |
|
478 |
<message name="Webservice_Residants_PLS_NOTIFCB2_MessageIn"> |
|
479 |
<part name="parameters" element="s0:PLS_NOTIFCB2"/> |
|
480 |
</message> |
|
481 |
<message name="Webservice_Residants_PLS_NOTIFCB2_MessageOut"> |
|
482 |
<part name="parameters" element="s0:PLS_NOTIFCB2Response"/> |
|
483 |
</message> |
|
437 | 484 |
<portType name="Webservice_ResidantsSOAPPortType"> |
438 | 485 |
<operation name="PLS_EXIST"> |
439 | 486 |
<input message="s0:Webservice_Residants_PLS_EXIST_MessageIn"/> |
... | ... | |
484 | 531 |
<input message="s0:Webservice_Residants_FPS_Rech_Immat_MessageIn"/> |
485 | 532 |
<output message="s0:Webservice_Residants_FPS_Rech_Immat_MessageOut"/> |
486 | 533 |
</operation> |
534 |
<operation name="PLS_ENREG2"> |
|
535 |
<input message="s0:Webservice_Residants_PLS_ENREG2_MessageIn"/> |
|
536 |
<output message="s0:Webservice_Residants_PLS_ENREG2_MessageOut"/> |
|
537 |
</operation> |
|
538 |
<operation name="PLS_NOTIFCB2"> |
|
539 |
<input message="s0:Webservice_Residants_PLS_NOTIFCB2_MessageIn"/> |
|
540 |
<output message="s0:Webservice_Residants_PLS_NOTIFCB2_MessageOut"/> |
|
541 |
</operation> |
|
487 | 542 |
</portType> |
488 | 543 |
<binding name="Webservice_ResidantsSOAPBinding" type="s0:Webservice_ResidantsSOAPPortType"> |
489 | 544 |
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> |
... | ... | |
595 | 650 |
<soap:body use="literal"/> |
596 | 651 |
</output> |
597 | 652 |
</operation> |
653 |
<operation name="PLS_ENREG2"> |
|
654 |
<soap:operation soapAction="urn:Webservice_Residants/PLS_ENREG2" style="document"/> |
|
655 |
<input> |
|
656 |
<soap:body use="literal"/> |
|
657 |
</input> |
|
658 |
<output> |
|
659 |
<soap:body use="literal"/> |
|
660 |
</output> |
|
661 |
</operation> |
|
662 |
<operation name="PLS_NOTIFCB2"> |
|
663 |
<soap:operation soapAction="urn:Webservice_Residants/PLS_NOTIFCB2" style="document"/> |
|
664 |
<input> |
|
665 |
<soap:body use="literal"/> |
|
666 |
</input> |
|
667 |
<output> |
|
668 |
<soap:body use="literal"/> |
|
669 |
</output> |
|
670 |
</operation> |
|
598 | 671 |
</binding> |
599 | 672 |
<service name="Webservice_Residants"> |
600 | 673 |
<port name="Webservice_ResidantsSOAPPort" binding="s0:Webservice_ResidantsSOAPBinding"> |
601 |
<soap:address location="http://W01DPA001T/WEBSERVICE_RESIDANTS_WEB/awws/Webservice_Residants.awws"/>
|
|
674 |
<soap:address location="http://w01dpa001i/WEBSERVICE_RESIDANTS_WEB/awws/Webservice_Residants.awws"/>
|
|
602 | 675 |
</port> |
603 | 676 |
</service> |
604 | 677 |
</definitions> |
tests/test_dpark.py | ||
---|---|---|
629 | 629 |
'<Demande_AbonnementTiers>%s</Demande_AbonnementTiers>' |
630 | 630 |
% repr(application_thirdparty_subscription).lower() |
631 | 631 |
) |
632 |
assert demande_abonnementtiers in force_text(dpark.mock_requests[0].body) |
|
632 |
body = dpark.mock_requests[0].body.decode() |
|
633 |
assert ':PLS_ENREG ' in body |
|
634 |
assert demande_abonnementtiers in body |
|
633 | 635 |
assert resp.json['err'] == 1 |
634 | 636 |
assert resp.json['err_desc'] == 'Dossier incomplet' |
635 | 637 |
# with complete application |
... | ... | |
766 | 768 |
base64.b64encode(to_pdf(JPEG_CONTENT)) |
767 | 769 |
) |
768 | 770 |
assert base64.b64decode(pj_node.findall('Bloc_Fichiers')[3].find('Fichier').text).startswith(b'%PDF') |
771 | ||
772 | ||
773 |
@pytest.mark.parametrize('application_thirdparty_subscription', [True, False]) |
|
774 |
def test_registration_double_plaque(dpark, app, application_thirdparty_subscription): |
|
775 |
url = '/dpark/test/register/' |
|
776 |
params = { |
|
777 |
"address_complement1": "", |
|
778 |
"address_complement2": "", |
|
779 |
"address_district": "PERI", |
|
780 |
"address_locality": "Toulouse", |
|
781 |
"address_sticode": "315553609651", |
|
782 |
"address_streetext": "1", |
|
783 |
"address_streetname": "", |
|
784 |
"address_streetno": "16", |
|
785 |
"address_zipcode": "31000", |
|
786 |
"applicant_email": "sh@eggs.org", |
|
787 |
"applicant_firstnames": "Spam Ham", |
|
788 |
"applicant_lastname": "EGGS", |
|
789 |
"applicant_mobilephone": "0655443322", |
|
790 |
"applicant_phone": "", |
|
791 |
"applicant_title": "1", |
|
792 |
"application_car1_brand": "Peugeot", |
|
793 |
"application_car1_exemption": "8", |
|
794 |
"application_car1_model": "206", |
|
795 |
"application_car1_plate": "AA777ZZ", |
|
796 |
"application_id": "12-4", |
|
797 |
"application_payment_type": "10", |
|
798 |
"application_thirdparty_subscription": application_thirdparty_subscription, |
|
799 |
"application_type": 1, |
|
800 |
'double_plaque': '1', |
|
801 |
} |
|
802 |
# with missing parameter |
|
803 |
app.post_json(url, params=params, status=400) |
|
804 |
params.update( |
|
805 |
{ |
|
806 |
'id_contexte': '1', |
|
807 |
'id_produit': '2', |
|
808 |
} |
|
809 |
) |
|
810 |
# with an imcplete application |
|
811 |
dpark.mock_responses.append( |
|
812 |
"""<?xml version="1.0" encoding="utf-8"?> |
|
813 |
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
|
814 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
815 |
<SOAP-ENV:Header/> |
|
816 |
<SOAP-ENV:Body> |
|
817 |
<ns1:PLS_ENREGResponse xmlns:ns1="urn:Webservice_Residants"> |
|
818 |
<PLS_ENREG2Result> |
|
819 |
<CodeRetour>02</CodeRetour> |
|
820 |
<MessageRetour>Dossier incomplet</MessageRetour> |
|
821 |
</PLS_ENREG2Result> |
|
822 |
</ns1:PLS_ENREGResponse> |
|
823 |
</SOAP-ENV:Body> |
|
824 |
</SOAP-ENV:Envelope>""" |
|
825 |
) |
|
826 |
resp = app.post_json(url, params=params) |
|
827 |
demande_abonnementtiers = ( |
|
828 |
'<Demande_AbonnementTiers>%s</Demande_AbonnementTiers>' |
|
829 |
% repr(application_thirdparty_subscription).lower() |
|
830 |
) |
|
831 |
body = dpark.mock_requests[0].body.decode() |
|
832 |
assert demande_abonnementtiers in body |
|
833 |
assert ':PLS_ENREG2 ' in body |
|
834 |
assert '<ID_CONTEXTE>1<' in body |
|
835 |
assert '<ID_PRODUIT>2<' in body |
|
836 |
assert resp.json['err'] == 1 |
|
837 |
assert resp.json['err_desc'] == 'Dossier incomplet' |
|
838 |
# with complete application |
|
839 |
dpark.mock_responses.append( |
|
840 |
"""<?xml version="1.0" encoding="utf-8"?> |
|
841 |
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
|
842 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
843 |
<SOAP-ENV:Header/> |
|
844 |
<SOAP-ENV:Body> |
|
845 |
<ns1:PLS_ENREGResponse xmlns:ns1="urn:Webservice_Residants"> |
|
846 |
<PLS_ENREG2Result> |
|
847 |
<CodeRetour>01</CodeRetour> |
|
848 |
<MessageRetour/> |
|
849 |
<NumeroDossier>22334</NumeroDossier> |
|
850 |
<NumeroDemande>59492</NumeroDemande> |
|
851 |
</PLS_ENREG2Result> |
|
852 |
</ns1:PLS_ENREGResponse> |
|
853 |
</SOAP-ENV:Body> |
|
854 |
</SOAP-ENV:Envelope>""" |
|
855 |
) |
|
856 |
resp = app.post_json(url, params=params) |
|
857 |
body = dpark.mock_requests[1].body.decode() |
|
858 |
assert demande_abonnementtiers in body |
|
859 |
assert resp.json['data']['numerodossier'] == 22334 |
|
860 |
assert resp.json['data']['numerodemande'] == 59492 |
|
861 | ||
862 | ||
863 |
@pytest.mark.parametrize( |
|
864 |
'transaction_datetime,expected_date', |
|
865 |
[ |
|
866 |
('20180611', '20180611'), |
|
867 |
# UTC datetime should be converted to Europe/Paris date |
|
868 |
('2018-06-11T23:59:00', '20180612'), |
|
869 |
], |
|
870 |
) |
|
871 |
def test_payment_notification_double_plaque(dpark, app, transaction_datetime, expected_date): |
|
872 |
operation = mock.Mock(name='PLS_NOTIFCB2') |
|
873 |
service = mock.Mock(spec=['PLS_NOTIFCB2'], PLS_NOTIFCB2=operation) |
|
874 |
create_service = mock.Mock(spec=[], return_value=service) |
|
875 |
client = mock.NonCallableMock(spec=['create_service'], create_service=create_service) |
|
876 |
with mock.patch('passerelle.contrib.dpark.models.get_client', return_value=client): |
|
877 |
nameid = 'abcd' * 8 |
|
878 |
filenumber = '1' * 9 |
|
879 |
params = { |
|
880 |
'nameid': nameid, |
|
881 |
'filenumber': filenumber, |
|
882 |
'transaction_id': 'I123456789', |
|
883 |
'transaction_datetime': transaction_datetime, |
|
884 |
'total_amount': '125', |
|
885 |
'application_id': '61718', |
|
886 |
'application_external_id': 'E-8-N5UTAK6P', |
|
887 |
'double_plaque': '1', |
|
888 |
} |
|
889 |
url = '/dpark/test/notify-payment/' |
|
890 |
resp = app.post_json(url, params=params) |
|
891 |
assert resp.json['err'] == 1 |
|
892 |
assert resp.json['err_desc'] == 'No pairing exists' |
|
893 |
Pairing.objects.create( |
|
894 |
resource=dpark, |
|
895 |
**{ |
|
896 |
'nameid': nameid, |
|
897 |
'firstnames': 'spam eggs', |
|
898 |
'lastname': 'bar', |
|
899 |
'filenumber': filenumber, |
|
900 |
'badgenumber': '2' * 9, |
|
901 |
}, |
|
902 |
) |
|
903 |
operation.return_value = mock.Mock(CodeRetour='02', MessageRetour='Dossier inconnu') |
|
904 |
resp = app.post_json(url, params=params) |
|
905 |
assert operation.call_args_list[-1].args[5] == expected_date |
|
906 |
assert resp.json['err'] == 1 |
|
907 |
assert resp.json['err_desc'] == 'Dossier inconnu' |
|
908 |
operation.return_value = mock.Mock(CodeRetour='01') |
|
909 |
resp = app.post_json(url, params=params) |
|
910 |
assert resp.json['data'] is True |
|
769 |
- |