Projet

Général

Profil

0001-add-Saga-payment-method-46502.patch

Benjamin Dauvergne, 30 octobre 2020 19:07

Télécharger (39,9 ko)

Voir les différences:

Subject: [PATCH] add Saga payment method (#46502)

 eopayment/__init__.py                       |   5 +-
 eopayment/saga.py                           | 250 ++++++++++++++++++++
 tests/conftest.py                           | 112 +++++++++
 tests/data/saga-test_error_parametrage.json |   1 +
 tests/data/saga-test_request.json           |   1 +
 tests/data/saga-test_response.json          |   1 +
 tests/test_saga.py                          |  95 ++++++++
 7 files changed, 463 insertions(+), 2 deletions(-)
 create mode 100644 eopayment/saga.py
 create mode 100644 tests/conftest.py
 create mode 100644 tests/data/saga-test_error_parametrage.json
 create mode 100644 tests/data/saga-test_request.json
 create mode 100644 tests/data/saga-test_response.json
 create mode 100644 tests/test_saga.py
eopayment/__init__.py
31 31
__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS', 'SYSTEMPAY',
32 32
           'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED', 'PAID',
33 33
           'DENIED', 'CANCELED', 'CANCELLED', 'ERROR', 'WAITING',
34
           'get_backends', 'PAYFIP_WS']
34
           'get_backends', 'PAYFIP_WS', 'SAGA']
35 35

  
36 36
if six.PY3:
37 37
    __all__.extend(['KEYWARE', 'MOLLIE'])
......
47 47
PAYFIP_WS = 'payfip_ws'
48 48
KEYWARE = 'keyware'
49 49
MOLLIE = 'mollie'
50
SAGA = 'saga'
50 51

  
51 52
logger = logging.getLogger(__name__)
52 53

  
......
57 58
    return module.Payment
58 59

  
59 60
__BACKENDS = [DUMMY, SIPS, SIPS2, SYSTEMPAY, OGONE, PAYBOX, PAYZEN,
60
              TIPI, PAYFIP_WS, KEYWARE, MOLLIE]
61
              TIPI, PAYFIP_WS, KEYWARE, MOLLIE, SAGA]
61 62

  
62 63

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

  
18
from __future__ import unicode_literals, print_function
19

  
20
import functools
21

  
22
from six.moves.urllib.parse import urljoin, parse_qs
23

  
24
import lxml.etree as ET
25
import zeep
26
import zeep.exceptions
27

  
28
from .common import (PaymentException, PaymentCommon, ResponseError, URL, PAID,
29
                     DENIED, CANCELLED, ERROR, PaymentResponse)
30

  
31
_zeep_transport = None
32

  
33

  
34
class SagaError(PaymentException):
35
    pass
36

  
37

  
38
class Saga(object):
39
    def __init__(self, wsdl_url, service_url=None, zeep_client_kwargs=None):
40
        self.wsdl_url = wsdl_url
41
        kwargs = (zeep_client_kwargs or {}).copy()
42
        if _zeep_transport and 'transport' not in kwargs:
43
            kwargs['transport'] = _zeep_transport
44
        self.client = zeep.Client(wsdl_url, **kwargs)
45
        # distribued WSDL is wrong :/
46
        if service_url:
47
            self.client.service._binding_options['address'] = service_url
48

  
49
    def soap_call(self, operation, content_tag, **kwargs):
50
        content = getattr(self.client.service, operation)(**kwargs)
51
        if 'ISO-8859-1' in content:
52
            encoded_content = content.encode('latin1')
53
        else:
54
            encoded_content = content.encode('utf-8')
55
        try:
56
            tree = ET.fromstring(encoded_content)
57
        except Exception:
58
            raise SagaError('Invalid SAGA response "%s"' % content[:1024])
59
        if tree.tag == 'erreur':
60
            raise SagaError(tree.text)
61
        if tree.tag != content_tag:
62
            raise SagaError('Invalid SAGA response "%s"' % content[:1024])
63
        return tree
64

  
65
    def transaction(self, num_service, id_tiers, compte, lib_ecriture, montant,
66
                    urlretour_asynchrone, email, urlretour_synchrone):
67
        tree = self.soap_call(
68
            'Transaction',
69
            'url',
70
            num_service=num_service,
71
            id_tiers=id_tiers,
72
            compte=compte,
73
            lib_ecriture=lib_ecriture,
74
            montant=montant,
75
            urlretour_asynchrone=urlretour_asynchrone,
76
            email=email,
77
            urlretour_synchrone=urlretour_synchrone)
78
        # tree == <url>...</url>
79
        return tree.text
80

  
81
    def page_retour(self, operation, idop):
82
        tree = self.soap_call(
83
            operation,
84
            'ok',
85
            idop=idop)
86
        # tree == <ok id_tiers="A1"
87
        # etat="paye" email="albert,dupond@monsite.com" num_service="222222"
88
        # montant="100.00" compte="708"
89
        # lib_ecriture="Paiement pour M. Albert Dupondréservationsejourxxxx" />
90
        return tree.attrib
91

  
92
    def page_retour_synchrone(self, idop):
93
        return self.page_retour('PageRetourSynchrone', idop)
94

  
95
    def page_retour_asynchrone(self, idop):
96
        return self.page_retour('PageRetourAsynchrone', idop)
97

  
98

  
99
class Payment(PaymentCommon):
100
    description = {
101
        'caption': 'Système de paiement Saga / SAGA',
102
        'parameters': [
103
            {
104
                'name': 'base_url',
105
                'caption': 'URL de base du WSDL',
106
                'help_text': 'Sans la partie /paiement_internet_ws_ministere?wsdl',
107
                'required': True,
108
            },
109
            {
110
                'name': 'num_service',
111
                'caption': 'Numéro du service',
112
                'required': True,
113
            },
114
            {
115
                'name': 'compte',
116
                'caption': 'Compte de recettes',
117
                'required': True,
118
            },
119
            {
120
                'name': 'normal_return_url',
121
                'caption': 'Normal return URL',
122
                'default': '',
123
                'required': True,
124
            },
125
            {
126
                'name': 'automatic_return_url',
127
                'caption': 'Automatic return URL (ignored, must be set in Ogone backoffice)',
128
                'required': False,
129
            },
130
        ]
131
    }
132

  
133
    @property
134
    def saga(self):
135
        return Saga(
136
            wsdl_url=urljoin(self.base_url, 'paiement_internet_ws_ministere?wsdl'))
137

  
138
    def request(self, amount, email, subject, orderid=None, **kwargs):
139
        num_service = self.num_service
140
        id_tiers = '-1'
141
        compte = self.compte
142
        lib_ecriture = subject
143
        montant = self.clean_amount(amount, max_amount=100000, cents=False)
144
        urlretour_synchrone = self.normal_return_url
145
        urlretour_asynchrone = self.automatic_return_url
146

  
147
        url = self.saga.transaction(
148
            num_service=num_service,
149
            id_tiers=id_tiers,
150
            compte=compte,
151
            lib_ecriture=lib_ecriture,
152
            montant=montant,
153
            urlretour_asynchrone=urlretour_asynchrone,
154
            email=email,
155
            urlretour_synchrone=urlretour_synchrone)
156

  
157
        try:
158
            idop = parse_qs(url.split('?', 1)[-1])['idop'][0]
159
        except Exception:
160
            raise SagaError('Invalid payment URL, no idop: %s' % url)
161

  
162
        return str(idop), URL, url
163

  
164
    def response(self, query_string, **kwargs):
165
        fields = parse_qs(query_string, True)
166
        idop = (fields.get('idop') or [None])[0]
167

  
168
        if not idop:
169
            raise ResponseError('missing idop parameter in query')
170

  
171
        redirect = kwargs.get('redirect', False)
172

  
173
        if redirect:
174
            response = self.saga.page_retour_synchrone(idop=idop)
175
        else:
176
            response = self.saga.page_retour_asynchrone(idop=idop)
177

  
178
        etat = response['etat']
179
        if etat == 'paye':
180
            result = PAID
181
            bank_status = 'paid'
182
        elif etat == 'refus':
183
            result = DENIED
184
            bank_status = 'refused'
185
        elif etat == 'abandon':
186
            result = CANCELLED
187
            bank_status = 'cancelled'
188
        else:
189
            result = ERROR
190
            bank_status = 'unknown result code: etat=%r' % etat
191

  
192
        return PaymentResponse(
193
            result=result,
194
            bank_status=bank_status,
195
            signed=True,
196
            bank_data=response,
197
            order_id=idop,
198
            transaction_id=idop,
199
            test=False)
200

  
201

  
202
if __name__ == '__main__':
203
    import click
204

  
205
    def show_payfip_error(func):
206
        @functools.wraps(func)
207
        def f(*args, **kwargs):
208
            try:
209
                return func(*args, **kwargs)
210
            except SagaError as e:
211
                click.echo(click.style('SAGA ERROR : %s' % e, fg='red'))
212
        return f
213

  
214
    @click.group()
215
    @click.option('--wsdl-url')
216
    @click.option('--service-url', default=None)
217
    @click.pass_context
218
    def main(ctx, wsdl_url, service_url):
219
        import logging
220
        logging.basicConfig(level=logging.INFO)
221
        # hide warning from zeep
222
        logging.getLogger('zeep.wsdl.bindings.soap').level = logging.ERROR
223

  
224
        ctx.obj = Saga(wsdl_url=wsdl_url, service_url=service_url)
225

  
226
    @main.command()
227
    @click.option('--num-service', type=str, required=True)
228
    @click.option('--id-tiers', type=str, required=True)
229
    @click.option('--compte', type=str, required=True)
230
    @click.option('--lib-ecriture', type=str, required=True)
231
    @click.option('--montant', type=str, required=True)
232
    @click.option('--urlretour-asynchrone', type=str, required=True)
233
    @click.option('--email', type=str, required=True)
234
    @click.option('--urlretour-synchrone', type=str, required=True)
235
    @click.pass_obj
236
    @show_payfip_error
237
    def transaction(saga, num_service, id_tiers, compte, lib_ecriture, montant,
238
                    urlretour_asynchrone, email, urlretour_synchrone):
239
        url = saga.transaction(
240
            num_service=num_service,
241
            id_tiers=id_tiers,
242
            compte=compte,
243
            lib_ecriture=lib_ecriture,
244
            montant=montant,
245
            urlretour_asynchrone=urlretour_asynchrone,
246
            email=email,
247
            urlretour_synchrone=urlretour_synchrone)
248
        print('url:', url)
249

  
250
    main()
tests/conftest.py
1
# eopayment - online payment library
2
# Copyright (C) 2011-2020 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
import json
18

  
19
import pytest
20

  
21
import httmock
22
import lxml.etree as ET
23

  
24
from requests.adapters import HTTPAdapter
25
from requests import Session
26

  
27

  
28
def pytest_addoption(parser):
29
    parser.addoption("--save-http-session", action="store_true", help="save HTTP session")
30
    parser.addoption("--target-url", help="target URL")
31

  
32

  
33
class LoggingAdapter(HTTPAdapter):
34
    def __init__(self, *args, **kwargs):
35
        self.history = []
36
        super(LoggingAdapter, self).__init__(*args, **kwargs)
37

  
38
    def send(self, request, *args, **kwargs):
39
        response = super(LoggingAdapter, self).send(request, *args, **kwargs)
40
        self.history.append((request, response))
41
        return response
42

  
43

  
44
def xmlindent(content):
45
    if hasattr(content, 'encode') or hasattr(content, 'decode'):
46
        content = ET.fromstring(content)
47
    return ET.tostring(content, pretty_print=True).decode('utf-8', 'ignore')
48

  
49

  
50
@pytest.fixture
51
def record_http_session(request):
52
    module_name = request.module.__name__.split('test_', 1)[-1]
53
    function_name = request.function.__name__
54
    save = request.config.getoption('--save-http-session')
55
    filename = 'tests/data/%s-%s.json' % (module_name, function_name)
56

  
57
    def is_xml_content_type(r):
58
        headers = r.headers
59
        content_type = headers.get('content-type')
60
        return content_type and content_type.startswith(('text/xml', 'application/xml'))
61

  
62
    if save:
63
        session = Session()
64
        adapter = LoggingAdapter()
65
        session.mount('http://', adapter)
66
        session.mount('https://', adapter)
67
        try:
68
            yield session
69
        finally:
70
            with open(filename, 'w') as fd:
71
                history = []
72

  
73
                for request, response in adapter.history:
74
                    request_content = (request.body or b'')
75
                    response_content = (response.content or b'')
76

  
77
                    if is_xml_content_type(request):
78
                        request_content = xmlindent(request_content)
79
                    else:
80
                        request_content = request_content.decode('utf-8')
81
                    if is_xml_content_type(response):
82
                        response_content = xmlindent(response_content)
83
                    else:
84
                        response_content = response_content.decode('utf-8')
85
                    history.append((request_content, response_content))
86
                json.dump(history, fd)
87
    else:
88
        with open(filename) as fd:
89
            history = json.load(fd)
90

  
91
        class Mocker:
92
            counter = 0
93

  
94
            @httmock.urlmatch()
95
            def mock(self, url, request):
96
                expected_request_content, response_content = history[self.counter]
97
                self.counter += 1
98
                if expected_request_content:
99
                    request_content = request.body or b''
100
                    if is_xml_content_type(request):
101
                        request_content = xmlindent(request_content)
102
                    else:
103
                        request_content = request_content.decode('utf-8')
104
                    assert request_content == expected_request_content
105
                return response_content
106
        with httmock.HTTMock(Mocker().mock):
107
            yield None
108

  
109

  
110
@pytest.fixture
111
def target_url(request):
112
    return request.config.getoption('--target-url') or 'https://target.url/'
tests/data/saga-test_error_parametrage.json
1
[["", "<wsdl:definitions xmlns:apachesoap=\"http://xml.apache.org/xml-soap\" xmlns:impl=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:intf=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:wsdlsoap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n<!--WSDL created by Apache Axis version: 1.4\nBuilt on Apr 22, 2006 (06:55:48 PDT)-->\n\n   <wsdl:message name=\"PageRetourAsynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionResponse\">\n\n      <wsdl:part name=\"TransactionReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourAsynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourAsynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourSynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionRequest\">\n\n      <wsdl:part name=\"num_service\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"id_tiers\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"compte\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"lib_ecriture\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"montant\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_asynchrone\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"email\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_synchrone\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:portType name=\"PaiementLigneWebServiceWSMinistere\">\n\n      <wsdl:operation name=\"PageRetourAsynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourAsynchroneRequest\" name=\"PageRetourAsynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourAsynchroneResponse\" name=\"PageRetourAsynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourSynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourSynchroneRequest\" name=\"PageRetourSynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourSynchroneResponse\" name=\"PageRetourSynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\" parameterOrder=\"num_service id_tiers compte lib_ecriture montant urlretour_asynchrone email urlretour_synchrone\">\n\n         <wsdl:input message=\"impl:TransactionRequest\" name=\"TransactionRequest\"/>\n\n         <wsdl:output message=\"impl:TransactionResponse\" name=\"TransactionResponse\"/>\n\n      </wsdl:operation>\n\n   </wsdl:portType>\n\n   <wsdl:binding name=\"paiement_internet_ws_ministereSoapBinding\" type=\"impl:PaiementLigneWebServiceWSMinistere\">\n\n      <wsdlsoap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n\n      <wsdl:operation name=\"PageRetourAsynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourAsynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourAsynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourSynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourSynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourSynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"TransactionRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"TransactionResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n   </wsdl:binding>\n\n   <wsdl:service name=\"PaiementLigneWebServiceWSMinistereService\">\n\n      <wsdl:port binding=\"impl:paiement_internet_ws_ministereSoapBinding\" name=\"paiement_internet_ws_ministere\">\n\n         <wsdlsoap:address location=\"https://saga.example.com/saga/paiement_internet_ws_ministere\"/>\n\n      </wsdl:port>\n\n   </wsdl:service>\n\n</wsdl:definitions>\n"], ["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:Transaction xmlns:ns0=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n      <num_service>1</num_service>\n      <id_tiers>-1</id_tiers>\n      <compte>1</compte>\n      <lib_ecriture>R&#233;servation concert XYZ num&#233;ro 1234</lib_ecriture>\n      <montant>10.00</montant>\n      <urlretour_asynchrone>https://automatic.notif.url/automatic/</urlretour_asynchrone>\n      <email>john.doe@example.com</email>\n      <urlretour_synchrone>https://normal.notif.url/normal/</urlretour_synchrone>\n    </ns0:Transaction>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <soapenv:Body>\n    <ns1:TransactionResponse xmlns:ns1=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n      <TransactionReturn xsi:type=\"xsd:string\">&lt;?xml version=\"1.0\" encoding=\"ISO-8859-1\"?&gt;&lt;erreur&gt;M&#233;thode Transaction_WS_Ministere - Impossible de d&#233;terminer le param&#233;trage de la solution du paiement en ligne de r&#233;gie correspondante.&lt;/erreur&gt;</TransactionReturn>\n    </ns1:TransactionResponse>\n  </soapenv:Body>\n</soapenv:Envelope>\n"]]
tests/data/saga-test_request.json
1
[["", "<wsdl:definitions xmlns:apachesoap=\"http://xml.apache.org/xml-soap\" xmlns:impl=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:intf=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:wsdlsoap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n<!--WSDL created by Apache Axis version: 1.4\nBuilt on Apr 22, 2006 (06:55:48 PDT)-->\n\n   <wsdl:message name=\"PageRetourAsynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionResponse\">\n\n      <wsdl:part name=\"TransactionReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourSynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourAsynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourAsynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionRequest\">\n\n      <wsdl:part name=\"num_service\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"id_tiers\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"compte\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"lib_ecriture\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"montant\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_asynchrone\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"email\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_synchrone\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:portType name=\"PaiementLigneWebServiceWSMinistere\">\n\n      <wsdl:operation name=\"PageRetourSynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourSynchroneRequest\" name=\"PageRetourSynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourSynchroneResponse\" name=\"PageRetourSynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourAsynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourAsynchroneRequest\" name=\"PageRetourAsynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourAsynchroneResponse\" name=\"PageRetourAsynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\" parameterOrder=\"num_service id_tiers compte lib_ecriture montant urlretour_asynchrone email urlretour_synchrone\">\n\n         <wsdl:input message=\"impl:TransactionRequest\" name=\"TransactionRequest\"/>\n\n         <wsdl:output message=\"impl:TransactionResponse\" name=\"TransactionResponse\"/>\n\n      </wsdl:operation>\n\n   </wsdl:portType>\n\n   <wsdl:binding name=\"paiement_internet_ws_ministereSoapBinding\" type=\"impl:PaiementLigneWebServiceWSMinistere\">\n\n      <wsdlsoap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n\n      <wsdl:operation name=\"PageRetourSynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourSynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourSynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourAsynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourAsynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourAsynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"TransactionRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"TransactionResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n   </wsdl:binding>\n\n   <wsdl:service name=\"PaiementLigneWebServiceWSMinistereService\">\n\n      <wsdl:port binding=\"impl:paiement_internet_ws_ministereSoapBinding\" name=\"paiement_internet_ws_ministere\">\n\n         <wsdlsoap:address location=\"https://saga.example.com/saga/paiement_internet_ws_ministere\"/>\n\n      </wsdl:port>\n\n   </wsdl:service>\n\n</wsdl:definitions>\n"], ["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:Transaction xmlns:ns0=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n      <num_service>868</num_service>\n      <id_tiers>-1</id_tiers>\n      <compte>70688</compte>\n      <lib_ecriture>R&#233;servation concert XYZ num&#233;ro 1234</lib_ecriture>\n      <montant>10.00</montant>\n      <urlretour_asynchrone>https://automatic.notif.url/automatic/</urlretour_asynchrone>\n      <email>john.doe@example.com</email>\n      <urlretour_synchrone>https://normal.notif.url/normal/</urlretour_synchrone>\n    </ns0:Transaction>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <soapenv:Body>\n    <ns1:TransactionResponse xmlns:ns1=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n      <TransactionReturn xsi:type=\"xsd:string\">&lt;?xml version=\"1.0\" encoding=\"ISO-8859-1\"?&gt;&lt;url&gt;https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=347b2060-1a37-11eb-af92-0213ad91a103&lt;/url&gt;</TransactionReturn>\n    </ns1:TransactionResponse>\n  </soapenv:Body>\n</soapenv:Envelope>\n"]]
tests/data/saga-test_response.json
1
[["", "<wsdl:definitions xmlns:apachesoap=\"http://xml.apache.org/xml-soap\" xmlns:impl=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:intf=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:wsdlsoap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n<!--WSDL created by Apache Axis version: 1.4\nBuilt on Apr 22, 2006 (06:55:48 PDT)-->\n\n   <wsdl:message name=\"PageRetourAsynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionResponse\">\n\n      <wsdl:part name=\"TransactionReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourSynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourAsynchroneResponse\">\n\n      <wsdl:part name=\"PageRetourAsynchroneReturn\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"PageRetourSynchroneRequest\">\n\n      <wsdl:part name=\"idop\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:message name=\"TransactionRequest\">\n\n      <wsdl:part name=\"num_service\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"id_tiers\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"compte\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"lib_ecriture\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"montant\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_asynchrone\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"email\" type=\"xsd:string\"/>\n\n      <wsdl:part name=\"urlretour_synchrone\" type=\"xsd:string\"/>\n\n   </wsdl:message>\n\n   <wsdl:portType name=\"PaiementLigneWebServiceWSMinistere\">\n\n      <wsdl:operation name=\"PageRetourSynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourSynchroneRequest\" name=\"PageRetourSynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourSynchroneResponse\" name=\"PageRetourSynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourAsynchrone\" parameterOrder=\"idop\">\n\n         <wsdl:input message=\"impl:PageRetourAsynchroneRequest\" name=\"PageRetourAsynchroneRequest\"/>\n\n         <wsdl:output message=\"impl:PageRetourAsynchroneResponse\" name=\"PageRetourAsynchroneResponse\"/>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\" parameterOrder=\"num_service id_tiers compte lib_ecriture montant urlretour_asynchrone email urlretour_synchrone\">\n\n         <wsdl:input message=\"impl:TransactionRequest\" name=\"TransactionRequest\"/>\n\n         <wsdl:output message=\"impl:TransactionResponse\" name=\"TransactionResponse\"/>\n\n      </wsdl:operation>\n\n   </wsdl:portType>\n\n   <wsdl:binding name=\"paiement_internet_ws_ministereSoapBinding\" type=\"impl:PaiementLigneWebServiceWSMinistere\">\n\n      <wsdlsoap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n\n      <wsdl:operation name=\"PageRetourSynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourSynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourSynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"PageRetourAsynchrone\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"PageRetourAsynchroneRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"PageRetourAsynchroneResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n      <wsdl:operation name=\"Transaction\">\n\n         <wsdlsoap:operation soapAction=\"\"/>\n\n         <wsdl:input name=\"TransactionRequest\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:input>\n\n         <wsdl:output name=\"TransactionResponse\">\n\n            <wsdlsoap:body encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" namespace=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" use=\"encoded\"/>\n\n         </wsdl:output>\n\n      </wsdl:operation>\n\n   </wsdl:binding>\n\n   <wsdl:service name=\"PaiementLigneWebServiceWSMinistereService\">\n\n      <wsdl:port binding=\"impl:paiement_internet_ws_ministereSoapBinding\" name=\"paiement_internet_ws_ministere\">\n\n         <wsdlsoap:address location=\"https://saga.example.com/saga/paiement_internet_ws_ministere\"/>\n\n      </wsdl:port>\n\n   </wsdl:service>\n\n</wsdl:definitions>\n"], ["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap-env:Body>\n    <ns0:PageRetourAsynchrone xmlns:ns0=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\">\n      <idop>28b52f40-1ace-11eb-8ce3-0213ad91a104</idop>\n    </ns0:PageRetourAsynchrone>\n  </soap-env:Body>\n</soap-env:Envelope>\n", "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <soapenv:Body>\n    <ns1:PageRetourAsynchroneResponse xmlns:ns1=\"http://web_service.saga.futursystem.com/namespace/paiement_internet_ws_ministere\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n      <PageRetourAsynchroneReturn xsi:type=\"xsd:string\">&lt;?xml version=\"1.0\" encoding=\"ISO-8859-1\"?&gt;&lt;ok email=\"john.doe@entrouvert.com\" etat=\"paye\" id_tiers=\"-1\" montant=\"10.00\" num_service=\"868\" numcp=\"70688\" numcpt_lib_ecriture=\"COUCOU\" /&gt;</PageRetourAsynchroneReturn>\n    </ns1:PageRetourAsynchroneResponse>\n  </soapenv:Body>\n</soapenv:Envelope>\n"]]
tests/test_saga.py
1
# coding: utf-8
2
#
3
# eopayment - online payment library
4
# Copyright (C) 2011-2020 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 pytest
22

  
23
import zeep.transports
24

  
25
import eopayment
26

  
27

  
28
@pytest.fixture
29
def saga(record_http_session):
30
    if record_http_session:
31
        from eopayment import saga
32

  
33
        saga._zeep_transport = zeep.transports.Transport(session=record_http_session)
34
        try:
35
            yield None
36
        finally:
37
            saga._zeep_transport = None
38
    else:
39
        yield
40

  
41

  
42
@pytest.fixture
43
def backend_factory(saga, target_url):
44
    def factory(**kwargs):
45
        return eopayment.Payment('saga', dict({
46
            'base_url': target_url,
47
            'num_service': '868',
48
            'compte': '70688',
49
            'automatic_return_url': 'https://automatic.notif.url/automatic/',
50
            'normal_return_url': 'https://normal.notif.url/normal/',
51
        }, **kwargs))
52
    return factory
53

  
54

  
55
def test_error_parametrage(backend_factory):
56
    payment = backend_factory(num_service='1', compte='1')
57
    with pytest.raises(eopayment.PaymentException, match='Impossible de déterminer le paramétrage'):
58
        transaction_id, kind, url = payment.request(
59
            amount='10.00',
60
            email='john.doe@example.com',
61
            subject='Réservation concert XYZ numéro 1234')
62

  
63

  
64
def test_request(backend_factory):
65
    transaction_id, kind, url = backend_factory().request(
66
        amount='10.00',
67
        email='john.doe@example.com',
68
        subject='Réservation concert XYZ numéro 1234')
69
    assert transaction_id == '347b2060-1a37-11eb-af92-0213ad91a103'
70
    assert kind == eopayment.URL
71
    assert url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=347b2060-1a37-11eb-af92-0213ad91a103'
72

  
73

  
74
def test_response(backend_factory):
75
    response = backend_factory().response('idop=28b52f40-1ace-11eb-8ce3-0213ad91a104', redirect=False)
76
    assert response.__dict__ == {
77
        'bank_data': {
78
            'email': 'john.doe@entrouvert.com',
79
            'etat': 'paye',
80
            'id_tiers': '-1',
81
            'montant': '10.00',
82
            'num_service': '868',
83
            'numcp': '70688',
84
            'numcpt_lib_ecriture': 'COUCOU'
85
        },
86
        'bank_status': 'paid',
87
        'order_id': '28b52f40-1ace-11eb-8ce3-0213ad91a104',
88
        'result': 3,
89
        'return_content': None,
90
        'signed': True,
91
        'test': False,
92
        'transaction_date': None,
93
        'transaction_id': '28b52f40-1ace-11eb-8ce3-0213ad91a104',
94
    }
95

  
0
-