0001-add-Saga-payment-method-46502.patch
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éservation concert XYZ numé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\"><?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><erreur>Méthode Transaction_WS_Ministere - Impossible de déterminer le paramétrage de la solution du paiement en ligne de régie correspondante.</erreur></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éservation concert XYZ numé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\"><?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><url>https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=347b2060-1a37-11eb-af92-0213ad91a103</url></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\"><?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><ok email=\"john.doe@entrouvert.com\" etat=\"paye\" id_tiers=\"-1\" montant=\"10.00\" num_service=\"868\" numcp=\"70688\" numcpt_lib_ecriture=\"COUCOU\" /></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 |
- |