Projet

Général

Profil

0001-start-support-for-PayFiP-Regie-web-service-38405.patch

Benjamin Dauvergne, 26 décembre 2019 16:52

Télécharger (43,4 ko)

Voir les différences:

Subject: [PATCH 1/2] start support for PayFiP Regie web-service (#38405)

 README.txt                                    |  31 +++
 eopayment/payfip_ws.py                        | 184 ++++++++++++++++++
 setup.py                                      |   2 +
 tests/data/PaiementSecuriseService.wsdl       | 140 +++++++++++++
 tests/data/PaiementSecuriseService1.xsd       | 116 +++++++++++
 tests/data/PaiementSecuriseService2.xsd       |  16 ++
 tests/data/PaiementSecuriseService3.xsd       |  47 +++++
 tests/data/payfip-test_get_client_info.json   |   1 +
 ...p-test_get_idop_adresse_mel_incorrect.json |   1 +
 tests/data/payfip-test_get_idop_ok.json       |   1 +
 .../payfip-test_get_idop_refdet_error.json    |   1 +
 .../payfip-test_get_info_paiement_P1.json     |   1 +
 .../payfip-test_get_info_paiement_P5.json     |   1 +
 .../payfip-test_get_info_paiement_ok.json     |   1 +
 tests/test_payfip_ws.py                       | 167 ++++++++++++++++
 tox.ini                                       |   8 +
 16 files changed, 718 insertions(+)
 create mode 100644 eopayment/payfip_ws.py
 create mode 100644 tests/data/PaiementSecuriseService.wsdl
 create mode 100644 tests/data/PaiementSecuriseService1.xsd
 create mode 100644 tests/data/PaiementSecuriseService2.xsd
 create mode 100644 tests/data/PaiementSecuriseService3.xsd
 create mode 100644 tests/data/payfip-test_get_client_info.json
 create mode 100644 tests/data/payfip-test_get_idop_adresse_mel_incorrect.json
 create mode 100644 tests/data/payfip-test_get_idop_ok.json
 create mode 100644 tests/data/payfip-test_get_idop_refdet_error.json
 create mode 100644 tests/data/payfip-test_get_info_paiement_P1.json
 create mode 100644 tests/data/payfip-test_get_info_paiement_P5.json
 create mode 100644 tests/data/payfip-test_get_info_paiement_ok.json
 create mode 100644 tests/test_payfip_ws.py
README.txt
37 37

  
38 38
For other backends, the order and transaction ids, separated by '!' are sent in
39 39
order id field, so they can be matched in backoffice.
40

  
41
PayFiP
42
======
43

  
44
You can test your PayFiP regie web-service connection with an integrated CLI utility:
45

  
46
    $ python3 -m eopayment.payfip_ws info-client --help
47
    Usage: payfip_ws.py info-client [OPTIONS] NUMCLI
48

  
49
    Options:
50
      --help  Show this message and exit.
51

  
52
    $ python3 -m eopayment.payfip_ws get-idop --help
53
    Usage: payfip_ws.py get-idop [OPTIONS] NUMCLI
54

  
55
    Options:
56
      --saisie [T|X|W]         [required]
57
      --exer TEXT              [required]
58
      --montant INTEGER        [required]
59
      --refdet TEXT            [required]
60
      --mel TEXT               [required]
61
      --url-notification TEXT  [required]
62
      --url-redirect TEXT      [required]
63
      --objet TEXT
64
      --help                   Show this message and exit.
65

  
66
    $ python3 -m eopayment.payfip_ws info-paiement --help
67
    Usage: payfip_ws.py info-paiement [OPTIONS] IDOP
68

  
69
    Options:
70
      --help  Show this message and exit.
eopayment/payfip_ws.py
1
# eopayment - online payment library
2
# Copyright (C) 2011-2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from __future__ import print_function, unicode_literals
18

  
19
import copy
20
import functools
21
import xml.etree.ElementTree as ET
22

  
23
import six
24

  
25
import zeep
26
import zeep.exceptions
27

  
28

  
29
WSDL_URL = 'https://www.tipi.budget.gouv.fr/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService?wsdl'  # noqa: E501
30

  
31
SERVICE_URL = 'https://www.tipi.budget.gouv.fr/tpa/services/securite'  # noqa: E501
32

  
33

  
34
def clear_namespace(element):
35
    def helper(element):
36
        if element.tag.startswith('{'):
37
            element.tag = element.tag[element.tag.index('}') + 1:]
38
        for subelement in element:
39
            helper(subelement)
40

  
41
    element = copy.deepcopy(element)
42
    helper(element)
43
    return element
44

  
45

  
46
class PayFiPError(Exception):
47
    def __init__(self, code, message, origin=None):
48
        self.code = code
49
        self.message = message
50
        self.origin = origin
51
        args = [code, message]
52
        if origin:
53
            args.append(origin)
54
        super(PayFiPError, self).__init__(*args)
55

  
56

  
57
class PayFiP(object):
58
    '''Encapsulate SOAP web-services of PayFiP'''
59

  
60
    def __init__(self, wsdl_url=None, service_url=None, zeep_client_kwargs=None):
61
        self.client = zeep.Client(wsdl_url or WSDL_URL, **(zeep_client_kwargs or {}))
62
        # distribued WSDL is wrong :/
63
        self.client.service._binding_options['address'] = service_url or SERVICE_URL
64

  
65
    def fault_to_exception(self, fault):
66
        if fault.message != 'fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur' or fault.detail is None:
67
            return
68
        detail = clear_namespace(fault.detail)
69
        code = detail.find('FonctionnelleErreur/code')
70
        if code is None or not code.text:
71
            return PayFiPError('inconnu', ET.tostring(detail))
72
        descriptif = detail.find('FonctionnelleErreur/descriptif')
73
        libelle = detail.find('FonctionnelleErreur/libelle')
74
        return PayFiPError(
75
            code=code.text,
76
            message=(descriptif is not None and descriptif.text)
77
            or (libelle is not None and libelle.text)
78
            or '')
79

  
80
    def _perform(self, request_qname, operation, **kwargs):
81
        RequestType = self.client.get_type(request_qname)  # noqa: E501
82
        try:
83
            return getattr(self.client.service, operation)(RequestType(**kwargs))
84
        except zeep.exceptions.Fault as fault:
85
            raise self.fault_to_exception(fault) or PayFiPError('unknown', fault.message, fault)
86
        except zeep.exceptions.Error as zeep_error:
87
            raise PayFiPError('erreur-soap', str(zeep_error), zeep_error)
88

  
89
    def get_info_client(self, numcli):
90
        return self._perform(
91
            '{http://securite.service.tpa.cp.finances.gouv.fr/reponse}RecupererDetailClientRequest',
92
            'recupererDetailClient',
93
            numCli=numcli)
94

  
95
    def get_idop(self, numcli, saisie, exer, refdet, montant, mel, url_notification, url_redirect, objet=None):
96
        return self._perform(
97
            '{http://securite.service.tpa.cp.finances.gouv.fr/requete}CreerPaiementSecuriseRequest',
98
            'creerPaiementSecurise',
99
            numcli=numcli,
100
            saisie=saisie,
101
            exer=exer,
102
            montant=montant,
103
            refdet=refdet,
104
            mel=mel,
105
            urlnotif=url_notification,
106
            urlredirect=url_redirect,
107
            objet=objet)
108

  
109
    def get_info_paiement(self, idop):
110
        return self._perform(
111
            '{http://securite.service.tpa.cp.finances.gouv.fr/reponse}RecupererDetailPaiementSecuriseRequest',
112
            'recupererDetailPaiementSecurise',
113
            idOp=idop)
114

  
115

  
116
if __name__ == '__main__':
117
    import click
118

  
119
    def show_payfip_error(func):
120
        @functools.wraps(func)
121
        def f(*args, **kwargs):
122
            try:
123
                return func(*args, **kwargs)
124
            except PayFiPError as e:
125
                click.echo(click.style('PayFiP ERROR : %s "%s"' % (e.code, e.message), fg='red'))
126
        return f
127

  
128
    @click.group()
129
    @click.option('--wsdl-url', default=None)
130
    @click.option('--service-url', default=None)
131
    @click.pass_context
132
    def main(ctx, wsdl_url, service_url):
133
        import logging
134
        logging.basicConfig(level=logging.INFO)
135
        # hide warning from zeep
136
        logging.getLogger('zeep.wsdl.bindings.soap').level = logging.ERROR
137

  
138
        ctx.obj = PayFiP(wsdl_url=wsdl_url, service_url=service_url)
139

  
140
    def numcli(ctx, param, value):
141
        if not isinstance(value, six.string_types) or len(value) != 6 or not value.isdigit():
142
            raise click.BadParameter('numcli must a 6 digits number')
143
        return value
144

  
145
    @main.command()
146
    @click.argument('numcli', callback=numcli, type=str)
147
    @click.pass_obj
148
    @show_payfip_error
149
    def info_client(payfip, numcli):
150
        response = payfip.get_info_client(numcli)
151
        for key in response:
152
            print('%15s:' % key, response[key])
153

  
154
    @main.command()
155
    @click.argument('numcli', callback=numcli, type=str)
156
    @click.option('--saisie', type=click.Choice(['T', 'X', 'W']), required=True)
157
    @click.option('--exer', type=str, required=True)
158
    @click.option('--montant', type=int, required=True)
159
    @click.option('--refdet', type=str, required=True)
160
    @click.option('--mel', type=str, required=True)
161
    @click.option('--url-notification', type=str, required=True)
162
    @click.option('--url-redirect', type=str, required=True)
163
    @click.option('--objet', default=None, type=str)
164
    @click.pass_obj
165
    @show_payfip_error
166
    def get_idop(payfip, numcli, saisie, exer, montant, refdet, mel, objet, url_notification, url_redirect):
167
        idop = payfip.get_idop(numcli=numcli, saisie=saisie, exer=exer,
168
                               montant=montant, refdet=refdet, mel=mel,
169
                               objet=objet, url_notification=url_notification,
170
                               url_redirect=url_redirect)
171
        print('idOp:', idop)
172
        print('https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=%s' % idop)
173

  
174
    @main.command()
175
    @click.argument('idop', type=str)
176
    @click.pass_obj
177
    @show_payfip_error
178
    def info_paiement(payfip, idop):
179
        print(payfip.get_info_paiement(idop))
180

  
181
    main()
182

  
183

  
184

  
setup.py
123 123
        'pytz',
124 124
        'requests',
125 125
        'six',
126
        'click',
127
        'zeep',
126 128
    ],
127 129
    cmdclass={
128 130
        'sdist': eo_sdist,
tests/data/PaiementSecuriseService.wsdl
1
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.7-b01-. --><definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService" name="PaiementSecuriseService">
2
  <types>
3
    <xsd:schema>
4
      <xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService" schemaLocation="PaiementSecuriseService1.xsd"/>
5
    </xsd:schema>
6
    <xsd:schema>
7
      <xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/requete" schemaLocation="PaiementSecuriseService2.xsd"/>
8
    </xsd:schema>
9
    <xsd:schema>
10
      <xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse" schemaLocation="PaiementSecuriseService3.xsd"/>
11
    </xsd:schema>
12
  </types>
13
  <message name="creerPaiementSecurise">
14
    <part name="parameters" element="tns:creerPaiementSecurise"/>
15
  </message>
16
  <message name="creerPaiementSecuriseResponse">
17
    <part name="parameters" element="tns:creerPaiementSecuriseResponse"/>
18
  </message>
19
  <message name="FonctionnelleErreur">
20
    <part name="fault" element="tns:FonctionnelleErreur"/>
21
  </message>
22
  <message name="TechDysfonctionnementErreur">
23
    <part name="fault" element="tns:TechDysfonctionnementErreur"/>
24
  </message>
25
  <message name="TechIndisponibiliteErreur">
26
    <part name="fault" element="tns:TechIndisponibiliteErreur"/>
27
  </message>
28
  <message name="TechProtocolaireErreur">
29
    <part name="fault" element="tns:TechProtocolaireErreur"/>
30
  </message>
31
  <message name="recupererDetailClient">
32
    <part name="parameters" element="tns:recupererDetailClient"/>
33
  </message>
34
  <message name="recupererDetailClientResponse">
35
    <part name="parameters" element="tns:recupererDetailClientResponse"/>
36
  </message>
37
  <message name="recupererDetailPaiementSecurise">
38
    <part name="parameters" element="tns:recupererDetailPaiementSecurise"/>
39
  </message>
40
  <message name="recupererDetailPaiementSecuriseResponse">
41
    <part name="parameters" element="tns:recupererDetailPaiementSecuriseResponse"/>
42
  </message>
43
  <portType name="PaiementSecuriseService">
44
    <operation name="creerPaiementSecurise">
45
      <input message="tns:creerPaiementSecurise"/>
46
      <output message="tns:creerPaiementSecuriseResponse"/>
47
      <fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
48
      <fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
49
      <fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
50
      <fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
51
    </operation>
52
    <operation name="recupererDetailClient">
53
      <input message="tns:recupererDetailClient"/>
54
      <output message="tns:recupererDetailClientResponse"/>
55
      <fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
56
      <fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
57
      <fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
58
      <fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
59
    </operation>
60
    <operation name="recupererDetailPaiementSecurise">
61
      <input message="tns:recupererDetailPaiementSecurise"/>
62
      <output message="tns:recupererDetailPaiementSecuriseResponse"/>
63
      <fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
64
      <fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
65
      <fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
66
      <fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
67
    </operation>
68
  </portType>
69
  <binding name="PaiementSecuriseServicePortBinding" type="tns:PaiementSecuriseService">
70
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
71
    <operation name="creerPaiementSecurise">
72
      <soap:operation soapAction=""/>
73
      <input>
74
        <soap:body use="literal"/>
75
      </input>
76
      <output>
77
        <soap:body use="literal"/>
78
      </output>
79
      <fault name="FonctionnelleErreur">
80
        <soap:fault name="FonctionnelleErreur" use="literal"/>
81
      </fault>
82
      <fault name="TechDysfonctionnementErreur">
83
        <soap:fault name="TechDysfonctionnementErreur" use="literal"/>
84
      </fault>
85
      <fault name="TechIndisponibiliteErreur">
86
        <soap:fault name="TechIndisponibiliteErreur" use="literal"/>
87
      </fault>
88
      <fault name="TechProtocolaireErreur">
89
        <soap:fault name="TechProtocolaireErreur" use="literal"/>
90
      </fault>
91
    </operation>
92
    <operation name="recupererDetailClient">
93
      <soap:operation soapAction=""/>
94
      <input>
95
        <soap:body use="literal"/>
96
      </input>
97
      <output>
98
        <soap:body use="literal"/>
99
      </output>
100
      <fault name="FonctionnelleErreur">
101
        <soap:fault name="FonctionnelleErreur" use="literal"/>
102
      </fault>
103
      <fault name="TechDysfonctionnementErreur">
104
        <soap:fault name="TechDysfonctionnementErreur" use="literal"/>
105
      </fault>
106
      <fault name="TechIndisponibiliteErreur">
107
        <soap:fault name="TechIndisponibiliteErreur" use="literal"/>
108
      </fault>
109
      <fault name="TechProtocolaireErreur">
110
        <soap:fault name="TechProtocolaireErreur" use="literal"/>
111
      </fault>
112
    </operation>
113
    <operation name="recupererDetailPaiementSecurise">
114
      <soap:operation soapAction=""/>
115
      <input>
116
        <soap:body use="literal"/>
117
      </input>
118
      <output>
119
        <soap:body use="literal"/>
120
      </output>
121
      <fault name="FonctionnelleErreur">
122
        <soap:fault name="FonctionnelleErreur" use="literal"/>
123
      </fault>
124
      <fault name="TechDysfonctionnementErreur">
125
        <soap:fault name="TechDysfonctionnementErreur" use="literal"/>
126
      </fault>
127
      <fault name="TechIndisponibiliteErreur">
128
        <soap:fault name="TechIndisponibiliteErreur" use="literal"/>
129
      </fault>
130
      <fault name="TechProtocolaireErreur">
131
        <soap:fault name="TechProtocolaireErreur" use="literal"/>
132
      </fault>
133
    </operation>
134
  </binding>
135
  <service name="PaiementSecuriseService">
136
    <port name="PaiementSecuriseServicePort" binding="tns:PaiementSecuriseServicePortBinding">
137
      <soap:address location="http://www.tipi.budget.gouv.fr:80/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService"/>
138
    </port>
139
  </service>
140
</definitions>
tests/data/PaiementSecuriseService1.xsd
1
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><xs:schema xmlns:ns2="http://securite.service.tpa.cp.finances.gouv.fr/reponse" xmlns:ns1="http://securite.service.tpa.cp.finances.gouv.fr/requete" xmlns:tns="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService">
2

  
3
  <xs:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/requete" schemaLocation="PaiementSecuriseService2.xsd"/>
4

  
5
  <xs:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse" schemaLocation="PaiementSecuriseService3.xsd"/>
6

  
7
  <xs:element name="FonctionnelleErreur" type="tns:FonctionnelleErreur"/>
8

  
9
  <xs:element name="TechDysfonctionnementErreur" type="tns:TechDysfonctionnementErreur"/>
10

  
11
  <xs:element name="TechIndisponibiliteErreur" type="tns:TechIndisponibiliteErreur"/>
12

  
13
  <xs:element name="TechProtocolaireErreur" type="tns:TechProtocolaireErreur"/>
14

  
15
  <xs:element name="creerPaiementSecurise" type="tns:creerPaiementSecurise"/>
16

  
17
  <xs:element name="creerPaiementSecuriseResponse" type="tns:creerPaiementSecuriseResponse"/>
18

  
19
  <xs:element name="recupererDetailClient" type="tns:recupererDetailClient"/>
20

  
21
  <xs:element name="recupererDetailClientResponse" type="tns:recupererDetailClientResponse"/>
22

  
23
  <xs:element name="recupererDetailPaiementSecurise" type="tns:recupererDetailPaiementSecurise"/>
24

  
25
  <xs:element name="recupererDetailPaiementSecuriseResponse" type="tns:recupererDetailPaiementSecuriseResponse"/>
26

  
27
  <xs:complexType name="creerPaiementSecurise">
28
    <xs:sequence>
29
      <xs:element name="arg0" type="ns1:CreerPaiementSecuriseRequest" minOccurs="0"/>
30
    </xs:sequence>
31
  </xs:complexType>
32

  
33
  <xs:complexType name="creerPaiementSecuriseResponse">
34
    <xs:sequence>
35
      <xs:element name="return" type="ns2:CreerPaiementSecuriseResponse" minOccurs="0"/>
36
    </xs:sequence>
37
  </xs:complexType>
38

  
39
  <xs:complexType name="FonctionnelleErreur">
40
    <xs:sequence>
41
      <xs:element name="code" type="xs:string" minOccurs="0"/>
42
      <xs:element name="descriptif" type="xs:string" minOccurs="0"/>
43
      <xs:element name="libelle" type="xs:string" minOccurs="0"/>
44
      <xs:element name="message" type="xs:string" minOccurs="0"/>
45
      <xs:element name="severite" type="xs:int"/>
46
      <xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
47
    </xs:sequence>
48
  </xs:complexType>
49

  
50
  <xs:complexType name="throwable">
51
    <xs:sequence>
52
      <xs:element name="stackTrace" type="tns:stackTraceElement" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
53
    </xs:sequence>
54
  </xs:complexType>
55

  
56
  <xs:complexType name="stackTraceElement" final="extension restriction">
57
    <xs:sequence/>
58
  </xs:complexType>
59

  
60
  <xs:complexType name="TechDysfonctionnementErreur">
61
    <xs:sequence>
62
      <xs:element name="code" type="xs:string" minOccurs="0"/>
63
      <xs:element name="descriptif" type="xs:string" minOccurs="0"/>
64
      <xs:element name="libelle" type="xs:string" minOccurs="0"/>
65
      <xs:element name="message" type="xs:string" minOccurs="0"/>
66
      <xs:element name="severite" type="xs:int"/>
67
      <xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
68
    </xs:sequence>
69
  </xs:complexType>
70

  
71
  <xs:complexType name="TechIndisponibiliteErreur">
72
    <xs:sequence>
73
      <xs:element name="code" type="xs:string" minOccurs="0"/>
74
      <xs:element name="descriptif" type="xs:string" minOccurs="0"/>
75
      <xs:element name="libelle" type="xs:string" minOccurs="0"/>
76
      <xs:element name="message" type="xs:string" minOccurs="0"/>
77
      <xs:element name="severite" type="xs:int"/>
78
      <xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
79
    </xs:sequence>
80
  </xs:complexType>
81

  
82
  <xs:complexType name="TechProtocolaireErreur">
83
    <xs:sequence>
84
      <xs:element name="code" type="xs:string" minOccurs="0"/>
85
      <xs:element name="descriptif" type="xs:string" minOccurs="0"/>
86
      <xs:element name="libelle" type="xs:string" minOccurs="0"/>
87
      <xs:element name="message" type="xs:string" minOccurs="0"/>
88
      <xs:element name="severite" type="xs:int"/>
89
      <xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
90
    </xs:sequence>
91
  </xs:complexType>
92

  
93
  <xs:complexType name="recupererDetailClient">
94
    <xs:sequence>
95
      <xs:element name="arg0" type="ns2:RecupererDetailClientRequest" minOccurs="0"/>
96
    </xs:sequence>
97
  </xs:complexType>
98

  
99
  <xs:complexType name="recupererDetailClientResponse">
100
    <xs:sequence>
101
      <xs:element name="return" type="ns2:RecupererDetailClientResponse" minOccurs="0"/>
102
    </xs:sequence>
103
  </xs:complexType>
104

  
105
  <xs:complexType name="recupererDetailPaiementSecurise">
106
    <xs:sequence>
107
      <xs:element name="arg0" type="ns2:RecupererDetailPaiementSecuriseRequest" minOccurs="0"/>
108
    </xs:sequence>
109
  </xs:complexType>
110

  
111
  <xs:complexType name="recupererDetailPaiementSecuriseResponse">
112
    <xs:sequence>
113
      <xs:element name="return" type="ns2:RecupererDetailPaiementSecuriseResponse" minOccurs="0"/>
114
    </xs:sequence>
115
  </xs:complexType>
116
</xs:schema>
tests/data/PaiementSecuriseService2.xsd
1
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://securite.service.tpa.cp.finances.gouv.fr/requete">
2

  
3
  <xs:complexType name="CreerPaiementSecuriseRequest">
4
    <xs:sequence>
5
      <xs:element name="exer" type="xs:string" minOccurs="0"/>
6
      <xs:element name="mel" type="xs:string" minOccurs="0"/>
7
      <xs:element name="montant" type="xs:string" minOccurs="0"/>
8
      <xs:element name="numcli" type="xs:string" minOccurs="0"/>
9
      <xs:element name="objet" type="xs:string" minOccurs="0"/>
10
      <xs:element name="refdet" type="xs:string" minOccurs="0"/>
11
      <xs:element name="saisie" type="xs:string" minOccurs="0"/>
12
      <xs:element name="urlnotif" type="xs:string" minOccurs="0"/>
13
      <xs:element name="urlredirect" type="xs:string" minOccurs="0"/>
14
    </xs:sequence>
15
  </xs:complexType>
16
</xs:schema>
tests/data/PaiementSecuriseService3.xsd
1
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse">
2

  
3
  <xs:complexType name="CreerPaiementSecuriseResponse">
4
    <xs:sequence>
5
      <xs:element name="idOp" type="xs:string" minOccurs="0"/>
6
    </xs:sequence>
7
  </xs:complexType>
8

  
9
  <xs:complexType name="RecupererDetailClientRequest">
10
    <xs:sequence>
11
      <xs:element name="numCli" type="xs:string" minOccurs="0"/>
12
    </xs:sequence>
13
  </xs:complexType>
14

  
15
  <xs:complexType name="RecupererDetailClientResponse">
16
    <xs:sequence>
17
      <xs:element name="libelleN1" type="xs:string" minOccurs="0"/>
18
      <xs:element name="libelleN2" type="xs:string" minOccurs="0"/>
19
      <xs:element name="libelleN3" type="xs:string" minOccurs="0"/>
20
      <xs:element name="numcli" type="xs:string" minOccurs="0"/>
21
      <xs:element name="IdentifiantGen" type="xs:string" minOccurs="0"/>
22
    </xs:sequence>
23
  </xs:complexType>
24

  
25
  <xs:complexType name="RecupererDetailPaiementSecuriseRequest">
26
    <xs:sequence>
27
      <xs:element name="idOp" type="xs:string" minOccurs="0"/>
28
    </xs:sequence>
29
  </xs:complexType>
30

  
31
  <xs:complexType name="RecupererDetailPaiementSecuriseResponse">
32
    <xs:sequence>
33
      <xs:element name="dattrans" type="xs:string" minOccurs="0"/>
34
      <xs:element name="exer" type="xs:string" minOccurs="0"/>
35
      <xs:element name="heurtrans" type="xs:string" minOccurs="0"/>
36
      <xs:element name="idOp" type="xs:string" minOccurs="0"/>
37
      <xs:element name="mel" type="xs:string" minOccurs="0"/>
38
      <xs:element name="montant" type="xs:string" minOccurs="0"/>
39
      <xs:element name="numauto" type="xs:string" minOccurs="0"/>
40
      <xs:element name="numcli" type="xs:string" minOccurs="0"/>
41
      <xs:element name="objet" type="xs:string" minOccurs="0"/>
42
      <xs:element name="refdet" type="xs:string" minOccurs="0"/>
43
      <xs:element name="resultrans" type="xs:string" minOccurs="0"/>
44
      <xs:element name="saisie" type="xs:string" minOccurs="0"/>
45
    </xs:sequence>
46
  </xs:complexType>
47
</xs:schema>
tests/data/payfip-test_get_client_info.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:recupererDetailClient xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <numCli>090909</numCli>\n      </arg0>\n    </ns0:recupererDetailClient>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <ns2:recupererDetailClientResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <return>\n        <libelleN1>RR COMPOSTEURS INDIVIDUELS</libelleN1>\n        <libelleN2>POUETPOUET</libelleN2>\n        <libelleN3>COLLECTE VALORISATION DECHETS</libelleN3>\n        <numcli>090909</numcli>\n      </return>\n    </ns2:recupererDetailClientResponse>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_idop_adresse_mel_incorrect.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <exer>2019</exer>\n        <mel>john.doeexample.com</mel>\n        <montant>9990000001</montant>\n        <numcli>090909</numcli>\n        <objet>coucou</objet>\n        <refdet>ABCDEF</refdet>\n        <saisie>T</saisie>\n        <urlnotif>https://notif.payfip.example.com/</urlnotif>\n        <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n      </arg0>\n    </ns0:creerPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n      <faultcode>S:Server</faultcode>\n      <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n      <detail>\n        <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n          <code>A2</code>\n          <descriptif/>\n          <libelle>Adresse m&#233;l incorrecte. </libelle>\n          <severite>2</severite>\n        </ns2:FonctionnelleErreur>\n      </detail>\n    </S:Fault>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_idop_ok.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <exer>2019</exer>\n        <mel>john.doe@example.com</mel>\n        <montant>1000</montant>\n        <numcli>090909</numcli>\n        <objet>coucou</objet>\n        <refdet>ABCDEFGH</refdet>\n        <saisie>T</saisie>\n        <urlnotif>https://notif.payfip.example.com/</urlnotif>\n        <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n      </arg0>\n    </ns0:creerPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <ns2:creerPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <return>\n        <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n      </return>\n    </ns2:creerPaiementSecuriseResponse>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_idop_refdet_error.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <exer>2019</exer>\n        <mel>john.doe@example.com</mel>\n        <montant>1000</montant>\n        <numcli>090909</numcli>\n        <objet>coucou</objet>\n        <refdet>ABCD</refdet>\n        <saisie>T</saisie>\n        <urlnotif>https://notif.payfip.example.com/</urlnotif>\n        <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n      </arg0>\n    </ns0:creerPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n      <faultcode>S:Server</faultcode>\n      <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n      <detail>\n        <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n          <code>R3</code>\n          <descriptif/>\n          <libelle>Le format du param&#232;tre REFDET n'est pas conforme</libelle>\n          <severite>2</severite>\n        </ns2:FonctionnelleErreur>\n      </detail>\n    </S:Fault>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_P1.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n      </arg0>\n    </ns0:recupererDetailPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n      <faultcode>S:Server</faultcode>\n      <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n      <detail>\n        <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n          <code>P1</code>\n          <descriptif/>\n          <libelle>IdOp incorrect.</libelle>\n          <severite>2</severite>\n        </ns2:FonctionnelleErreur>\n      </detail>\n    </S:Fault>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_P5.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n      </arg0>\n    </ns0:recupererDetailPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n      <faultcode>S:Server</faultcode>\n      <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n      <detail>\n        <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n          <code>P5</code><descriptif />\n                    <libelle>R&#233;sultat de la transaction non connu.</libelle><severite>2</severite>\n        </ns2:FonctionnelleErreur>\n      </detail>\n    </S:Fault>\n  </S:Body>\n</S:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_ok.json
1
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <arg0>\n        <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n      </arg0>\n    </ns0:recupererDetailPaiementSecurise>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <S:Body>\n    <ns2:recupererDetailPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n      <return>\n                        <dattrans>12122019</dattrans><exer>20</exer><heurtrans>1311</heurtrans><idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp><mel>john.doe@example.com</mel><montant>1000</montant><numauto>112233445566-tip</numauto><numcli>090909</numcli><objet>coucou</objet><refdet>EFEFAEFG</refdet><resultrans>V</resultrans><saisie>T</saisie>\n            </return>\n    </ns2:recupererDetailPaiementSecuriseResponse>\n  </S:Body>\n</S:Envelope>\n"]]
tests/test_payfip_ws.py
1
# coding: utf-8
2
#
3
# eopayment - online payment library
4
# Copyright (C) 2011-2019 Entr'ouvert
5
#
6
# This program is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU Affero General Public License as published
8
# by the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU Affero General Public License for more details.
15
#
16
# You should have received a copy of the GNU Affero General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18

  
19
from __future__ import print_function, unicode_literals
20

  
21
import json
22
import lxml.etree as ET
23

  
24
import httmock
25
import pytest
26

  
27
from zeep.plugins import HistoryPlugin
28

  
29
from eopayment.payfip_ws import PayFiP, PayFiPError
30

  
31

  
32
def xmlindent(content):
33
    if hasattr(content, 'encode') or hasattr(content, 'decode'):
34
        content = ET.fromstring(content)
35
    return ET.tostring(content, pretty_print=True).decode('utf-8', 'ignore')
36

  
37
NUMCLI = '090909'
38

  
39

  
40
class PayFiPHTTMock(object):
41
    def __init__(self, request):
42
        history_path = 'tests/data/payfip-%s.json' % request.function.__name__
43
        with open(history_path) as fd:
44
            self.history = json.load(fd)
45
        self.counter = 0
46

  
47
    @httmock.urlmatch()
48
    def mock(self, url, request):
49
        request_content, response_content = self.history[self.counter]
50
        self.counter += 1
51
        assert xmlindent(request.body) == request_content
52
        return response_content
53

  
54

  
55
@pytest.fixture
56
def payfip(request):
57
    history = HistoryPlugin()
58

  
59
    @httmock.urlmatch()
60
    def raise_on_request(url, request):
61
        # ensure we do not access network
62
        from requests.exceptions import RequestException
63
        raise RequestException('huhu')
64

  
65
    with httmock.HTTMock(raise_on_request):
66
        payfip = PayFiP(wsdl_url='file://tests/data/PaiementSecuriseService.wsdl',
67
                        zeep_client_kwargs={'plugins': [history]})
68
    try:
69
        if 'update_data' not in request.keywords:
70
            with httmock.HTTMock(PayFiPHTTMock(request).mock):
71
                yield payfip
72
        else:
73
            yield payfip
74
    finally:
75
        # add @pytest.mark.update_data to test to update fixtures data
76
        if 'update_data' in request.keywords:
77
            history_path = 'tests/data/payfip-%s.json' % request.function.__name__
78
            d = [
79
                (xmlindent(exchange['sent']['envelope']),
80
                 xmlindent(exchange['received']['envelope']))
81
                for exchange in history._buffer
82
            ]
83
            content = json.dumps(d)
84
            with open(history_path, 'wb') as fd:
85
                fd.write(content)
86

  
87
# pytestmark = pytest.mark.update_data
88

  
89

  
90
def test_get_client_info(payfip):
91
    result = payfip.get_info_client(NUMCLI)
92
    assert result.numcli == NUMCLI
93
    assert result.libelleN2 == 'POUETPOUET'
94

  
95

  
96
def test_get_idop_ok(payfip):
97
    result = payfip.get_idop(
98
        numcli=NUMCLI,
99
        exer='2019',
100
        refdet='ABCDEFGH',
101
        montant='1000',
102
        mel='john.doe@example.com',
103
        objet='coucou',
104
        url_notification='https://notif.payfip.example.com/',
105
        url_redirect='https://redirect.payfip.example.com/',
106
        saisie='T')
107
    assert result == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
108

  
109

  
110
def test_get_idop_refdet_error(payfip):
111
    with pytest.raises(PayFiPError, match='.*R3.*Le format.*REFDET.*conforme'):
112
        payfip.get_idop(
113
            numcli=NUMCLI,
114
            exer='2019',
115
            refdet='ABCD',
116
            montant='1000',
117
            mel='john.doe@example.com',
118
            objet='coucou',
119
            url_notification='https://notif.payfip.example.com/',
120
            url_redirect='https://redirect.payfip.example.com/',
121
            saisie='T')
122

  
123

  
124
def test_get_idop_adresse_mel_incorrect(payfip):
125
    with pytest.raises(PayFiPError, match='.*A2.*Adresse.*incorrecte'):
126
        payfip.get_idop(
127
            numcli=NUMCLI,
128
            exer='2019',
129
            refdet='ABCDEF',
130
            montant='9990000001',
131
            mel='john.doeexample.com',
132
            objet='coucou',
133
            url_notification='https://notif.payfip.example.com/',
134
            url_redirect='https://redirect.payfip.example.com/',
135
            saisie='T')
136

  
137

  
138
def test_get_info_paiement_ok(payfip):
139
    result = payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
140
    assert {k: result[k] for k in result} == {
141
        'dattrans': '12122019',
142
        'exer': '20',
143
        'heurtrans': '1311',
144
        'idOp': 'cc0cb210-1cd4-11ea-8cca-0213ad91a103',
145
        'mel': 'john.doe@example.com',
146
        'montant': '1000',
147
        'numauto': '112233445566-tip',
148
        'numcli': NUMCLI,
149
        'objet': 'coucou',
150
        'refdet': 'EFEFAEFG',
151
        'resultrans': 'V',
152
        'saisie': 'T'
153
    }
154

  
155

  
156
def test_get_info_paiement_P1(payfip):
157
    # idop par pas encore reçu par la plate-forme ou déjà nettoyé (la nuit)
158
    with pytest.raises(PayFiPError, match='.*P1.*IdOp incorrect.*'):
159
        payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
160

  
161

  
162
def test_get_info_paiement_P5(payfip):
163
    # idop reçu par la plate-forme mais transaction en cours
164
    with pytest.raises(PayFiPError, match='.*P5.*sultat de la transaction non connu.*'):
165
        payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
166

  
167

  
tox.ini
18 18
  pytest-freezegun
19 19
  py2: pytest-cov
20 20
  mock
21
  httmock
22
  lxml
23

  
24
[pytest]
25
filterwarnings =
26
  ignore:defusedxml.lxml is no longer supported.*
27
markers =
28
  update_data
21
-