Projet

Général

Profil

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

Benjamin Dauvergne, 12 décembre 2019 15:18

Télécharger (41,8 ko)

Voir les différences:

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

 eopayment/payfip_ws.py                        | 186 ++++++++++++++++++
 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                       | 154 +++++++++++++++
 tox.ini                                       |   5 +
 15 files changed, 673 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
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
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
        except Exception as e:
89
            raise PayFiPError('erreur-inconnue', str(e), e)
90

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

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

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

  
117

  
118
if __name__ == '__main__':
119
    import click
120

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

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

  
140
        ctx.obj = PayFiP(wsdl_url=wsdl_url, service_url=service_url)
141

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

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

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

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

  
183
    main()
184

  
185

  
186

  
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="http://www.tipi.budget.gouv.fr:80/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService?xsd=2"/>
4

  
5
  <xs:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse" schemaLocation="http://www.tipi.budget.gouv.fr:80/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService?xsd=3"/>
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
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailClient>\n            <arg0>\n                <numCli>090909</numCli>\n            </arg0>\n        </ns1:recupererDetailClient>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailClientResponse>\n            <return>\n                <libelleN1>RR COMPOSTEURS INDIVIDUELS</libelleN1><libelleN2>POUETPOUET</libelleN2><libelleN3>COLLECTE VALORISATION DECHETS</libelleN3><numcli>090909</numcli>\n            </return>\n        </ns1:recupererDetailClientResponse>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_idop_adresse_mel_incorrect.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:creerPaiementSecurise>\n            <arg0>\n                <exer>2019</exer><mel>john.doeexample.com</mel><montant>9990000001</montant><numcli>090909</numcli><objet>coucou</objet><refdet>ABCDEF</refdet><saisie>T</saisie><urlnotif>https://notif.payfip.example.com/</urlnotif><urlredirect>https://redirect.payfip.example.com/</urlredirect>\n            </arg0>\n        </ns1:creerPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns0:Fault>\n            <faultcode>S:Server</faultcode><faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n            <detail>\n                <ns1:FonctionnelleErreur>\n                    <code>A2</code><descriptif />\n                    <libelle>Adresse m&#233;l incorrecte. </libelle><severite>2</severite>\n                </ns1:FonctionnelleErreur>\n            </detail>\n        </ns0:Fault>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_idop_ok.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:creerPaiementSecurise>\n            <arg0>\n                <exer>2019</exer><mel>john.doe@example.com</mel><montant>1000</montant><numcli>090909</numcli><objet>coucou</objet><refdet>ABCDEFGH</refdet><saisie>T</saisie><urlnotif>https://notif.payfip.example.com/</urlnotif><urlredirect>https://redirect.payfip.example.com/</urlredirect>\n            </arg0>\n        </ns1:creerPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:creerPaiementSecuriseResponse>\n            <return>\n                <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n            </return>\n        </ns1:creerPaiementSecuriseResponse>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_idop_refdet_error.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:creerPaiementSecurise>\n            <arg0>\n                <exer>2019</exer><mel>john.doe@example.com</mel><montant>1000</montant><numcli>090909</numcli><objet>coucou</objet><refdet>ABCD</refdet><saisie>T</saisie><urlnotif>https://notif.payfip.example.com/</urlnotif><urlredirect>https://redirect.payfip.example.com/</urlredirect>\n            </arg0>\n        </ns1:creerPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns0:Fault>\n            <faultcode>S:Server</faultcode><faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n            <detail>\n                <ns1:FonctionnelleErreur>\n                    <code>R3</code><descriptif />\n                    <libelle>Le format du param&#232;tre REFDET n'est pas conforme</libelle><severite>2</severite>\n                </ns1:FonctionnelleErreur>\n            </detail>\n        </ns0:Fault>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_P1.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailPaiementSecurise>\n            <arg0>\n                <idOp>ac0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n            </arg0>\n        </ns1:recupererDetailPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns0:Fault>\n            <faultcode>S:Server</faultcode><faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n            <detail>\n                <ns1:FonctionnelleErreur>\n                    <code>P1</code><descriptif />\n                    <libelle>IdOp incorrect.</libelle><severite>2</severite>\n                </ns1:FonctionnelleErreur>\n            </detail>\n        </ns0:Fault>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_P5.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailPaiementSecurise>\n            <arg0>\n                <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n            </arg0>\n        </ns1:recupererDetailPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns0:Fault>\n            <faultcode>S:Server</faultcode><faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n            <detail>\n                <ns1:FonctionnelleErreur>\n                    <code>P5</code><descriptif />\n                    <libelle>R&#233;sultat de la transaction non connu.</libelle><severite>2</severite>\n                </ns1:FonctionnelleErreur>\n            </detail>\n        </ns0:Fault>\n    </ns0:Body>\n</ns0:Envelope>\n"]]
tests/data/payfip-test_get_info_paiement_ok.json
1
[["<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailPaiementSecurise>\n            <arg0>\n                <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n            </arg0>\n        </ns1:recupererDetailPaiementSecurise>\n    </ns0:Body>\n</ns0:Envelope>\n", "<ns0:Envelope xmlns:ns0=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n    <ns0:Body>\n        <ns1:recupererDetailPaiementSecuriseResponse>\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        </ns1:recupererDetailPaiementSecuriseResponse>\n    </ns0:Body>\n</ns0: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
import json
20
import subprocess
21
import xml.etree.ElementTree as ET
22

  
23
import httmock
24
import pytest
25

  
26
from zeep.plugins import HistoryPlugin
27

  
28
from eopayment.payfip_ws import PayFiP, PayFiPError
29

  
30

  
31
def xmlindent(content):
32
    process = subprocess.Popen(['xmlindent'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
33
    stdout, stderr = process.communicate(content)
34
    return stdout
35

  
36

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

  
44
    @httmock.urlmatch()
45
    def mock(self, url, request):
46
        request_content, response_content = self.history[self.counter]
47
        self.counter += 1
48
        assert xmlindent(ET.tostring(ET.fromstring(request.body))) == request_content
49
        return response_content
50

  
51

  
52
@pytest.fixture
53
def payfip(request):
54
    history = HistoryPlugin()
55
    payfip = PayFiP(wsdl_url='file://tests/data/PaiementSecuriseService.wsdl',
56
                    zeep_client_kwargs={'plugins': [history]})
57
    try:
58
        if 'update_data' not in request.keywords:
59
            with httmock.HTTMock(PayFiPHTTMock(request).mock):
60
                yield payfip
61
        else:
62
            yield payfip
63
    finally:
64
        # add @pytest.mark.update_data to test to update fixtures data
65
        if 'update_data' in request.keywords:
66
            history_path = 'tests/data/payfip-%s.json' % request.function.__name__
67
            d = [
68
                (xmlindent(ET.tostring(exchange['sent']['envelope'])),
69
                 xmlindent(ET.tostring(exchange['received']['envelope'])))
70
                for exchange in history._buffer
71
            ]
72
            content = json.dumps(d)
73
            with open(history_path, 'wb') as fd:
74
                fd.write(content)
75

  
76

  
77
def test_get_client_info(payfip):
78
    result = payfip.get_info_client('090909')
79
    assert result.numcli == '090909'
80
    assert result.libelleN2 == 'POUETPOUET'
81

  
82

  
83
def test_get_idop_ok(payfip):
84
    result = payfip.get_idop(
85
        numcli='090909',
86
        exer='2019',
87
        refdet='ABCDEFGH',
88
        montant='1000',
89
        mel='john.doe@example.com',
90
        objet='coucou',
91
        url_notification='https://notif.payfip.example.com/',
92
        url_redirect='https://redirect.payfip.example.com/',
93
        saisie='T')
94
    assert result == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
95

  
96

  
97
def test_get_idop_refdet_error(payfip):
98
    with pytest.raises(PayFiPError, match="(\'R3\', u\"Le format du param\\\\xe8tre REFDET n\\'est pas conforme\")"):
99
        payfip.get_idop(
100
            numcli='090909',
101
            exer='2019',
102
            refdet='ABCD',
103
            montant='1000',
104
            mel='john.doe@example.com',
105
            objet='coucou',
106
            url_notification='https://notif.payfip.example.com/',
107
            url_redirect='https://redirect.payfip.example.com/',
108
            saisie='T')
109

  
110

  
111
def test_get_idop_adresse_mel_incorrect(payfip):
112
    with pytest.raises(PayFiPError, match="('A2', u'Adresse m\\\\xe9l incorrecte. ')"):
113
        payfip.get_idop(
114
            numcli='090909',
115
            exer='2019',
116
            refdet='ABCDEF',
117
            montant='9990000001',
118
            mel='john.doeexample.com',
119
            objet='coucou',
120
            url_notification='https://notif.payfip.example.com/',
121
            url_redirect='https://redirect.payfip.example.com/',
122
            saisie='T')
123

  
124

  
125
def test_get_info_paiement_ok(payfip):
126
    result = payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
127
    assert {k: result[k] for k in result} == {
128
        'dattrans': '12122019',
129
        'exer': '20',
130
        'heurtrans': '1311',
131
        'idOp': 'cc0cb210-1cd4-11ea-8cca-0213ad91a103',
132
        'mel': 'john.doe@example.com',
133
        'montant': '1000',
134
        'numauto': '112233445566-tip',
135
        'numcli': '090909',
136
        'objet': 'coucou',
137
        'refdet': 'EFEFAEFG',
138
        'resultrans': 'V',
139
        'saisie': 'T'
140
    }
141

  
142

  
143
def test_get_info_paiement_P1(payfip):
144
    # idop par pas encore reçu par la plate-forme ou déjà nettoyé (la nuit)
145
    with pytest.raises(PayFiPError, match="('P1', 'IdOp incorrect.')"):
146
        payfip.get_info_paiement('ac0cb210-1cd4-11ea-8cca-0213ad91a103')
147

  
148

  
149
def test_get_info_paiement_P5(payfip):
150
    # idop reçu par la plate-forme mais transaction en cours
151
    with pytest.raises(PayFiPError, match="('P5', u'R\\\\xe9sultat de la transaction non connu.')"):
152
        payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
153

  
154

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

  
23
[pytest]
24
markers =
25
  update_data
21
-