start support for PayFiP Regie web-service (#38405)

This commit is contained in:
Benjamin Dauvergne 2019-12-12 10:50:38 +01:00
parent 8ae9b712c4
commit edb97113d5
20 changed files with 980 additions and 0 deletions

View File

@ -5,3 +5,7 @@ include VERSION
include README.txt include README.txt
include eopayment/request include eopayment/request
include eopayment/response include eopayment/response
include eopayment/resource/PaiementSecuriseService.wsdl
include eopayment/resource/PaiementSecuriseService1.xsd
include eopayment/resource/PaiementSecuriseService2.xsd
include eopayment/resource/PaiementSecuriseService3.xsd

View File

@ -37,3 +37,34 @@ fields, in order to allow to match them in payment system backoffice. They are:
For other backends, the order and transaction ids, separated by '!' are sent in For other backends, the order and transaction ids, separated by '!' are sent in
order id field, so they can be matched in backoffice. order id field, so they can be matched in backoffice.
PayFiP
======
You can test your PayFiP regie web-service connection with an integrated CLI utility:
$ python3 -m eopayment.payfip_ws info-client --help
Usage: payfip_ws.py info-client [OPTIONS] NUMCLI
Options:
--help Show this message and exit.
$ python3 -m eopayment.payfip_ws get-idop --help
Usage: payfip_ws.py get-idop [OPTIONS] NUMCLI
Options:
--saisie [T|X|W] [required]
--exer TEXT [required]
--montant INTEGER [required]
--refdet TEXT [required]
--mel TEXT [required]
--url-notification TEXT [required]
--url-redirect TEXT [required]
--objet TEXT
--help Show this message and exit.
$ python3 -m eopayment.payfip_ws info-paiement --help
Usage: payfip_ws.py info-paiement [OPTIONS] IDOP
Options:
--help Show this message and exit.

346
eopayment/payfip_ws.py Normal file
View File

@ -0,0 +1,346 @@
# eopayment - online payment library
# Copyright (C) 2011-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function, unicode_literals
import copy
import datetime
from decimal import Decimal, ROUND_DOWN
import functools
import os
import random
import xml.etree.ElementTree as ET
from gettext import gettext as _
import six
from six.moves.urllib.parse import parse_qs
import zeep
import zeep.exceptions
from .systempayv2 import isonow
from .common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED,
CANCELLED, ERROR, ResponseError, PaymentException)
WSDL_URL = 'https://www.tipi.budget.gouv.fr/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService?wsdl' # noqa: E501
SERVICE_URL = 'https://www.tipi.budget.gouv.fr/tpa/services/securite' # noqa: E501
PAYMENT_URL = 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=%s'
def clear_namespace(element):
def helper(element):
if element.tag.startswith('{'):
element.tag = element.tag[element.tag.index('}') + 1:]
for subelement in element:
helper(subelement)
element = copy.deepcopy(element)
helper(element)
return element
class PayFiPError(PaymentException):
def __init__(self, code, message, origin=None):
self.code = code
self.message = message
self.origin = origin
args = [code, message]
if origin:
args.append(origin)
super(PayFiPError, self).__init__(*args)
class PayFiP(object):
'''Encapsulate SOAP web-services of PayFiP'''
def __init__(self, wsdl_url=None, service_url=None, zeep_client_kwargs=None):
self.client = zeep.Client(wsdl_url or WSDL_URL, **(zeep_client_kwargs or {}))
# distribued WSDL is wrong :/
self.client.service._binding_options['address'] = service_url or SERVICE_URL
def fault_to_exception(self, fault):
if fault.message != 'fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur' or fault.detail is None:
return
detail = clear_namespace(fault.detail)
code = detail.find('FonctionnelleErreur/code')
if code is None or not code.text:
return PayFiPError('inconnu', ET.tostring(detail))
descriptif = detail.find('FonctionnelleErreur/descriptif')
libelle = detail.find('FonctionnelleErreur/libelle')
return PayFiPError(
code=code.text,
message=(descriptif is not None and descriptif.text)
or (libelle is not None and libelle.text)
or '')
def _perform(self, request_qname, operation, **kwargs):
RequestType = self.client.get_type(request_qname) # noqa: E501
try:
return getattr(self.client.service, operation)(RequestType(**kwargs))
except zeep.exceptions.Fault as fault:
raise self.fault_to_exception(fault) or PayFiPError('unknown', fault.message, fault)
except zeep.exceptions.Error as zeep_error:
raise PayFiPError('erreur-soap', str(zeep_error), zeep_error)
def get_info_client(self, numcli):
return self._perform(
'{http://securite.service.tpa.cp.finances.gouv.fr/reponse}RecupererDetailClientRequest',
'recupererDetailClient',
numCli=numcli)
def get_idop(self, numcli, saisie, exer, refdet, montant, mel, url_notification, url_redirect, objet=None):
return self._perform(
'{http://securite.service.tpa.cp.finances.gouv.fr/requete}CreerPaiementSecuriseRequest',
'creerPaiementSecurise',
numcli=numcli,
saisie=saisie,
exer=exer,
montant=montant,
refdet=refdet,
mel=mel,
urlnotif=url_notification,
urlredirect=url_redirect,
objet=objet)
def get_info_paiement(self, idop):
return self._perform(
'{http://securite.service.tpa.cp.finances.gouv.fr/reponse}RecupererDetailPaiementSecuriseRequest',
'recupererDetailPaiementSecurise',
idOp=idop)
class Payment(PaymentCommon):
'''Produce requests for and verify response from the TIPI online payment
processor from the French Finance Ministry.
'''
description = {
'caption': 'TIPI, Titres Payables par Internet',
'parameters': [
{
'name': 'numcli',
'caption': _(u'Client number'),
'help_text': _(u'6 digits number provided by DGFIP'),
'validation': lambda s: str.isdigit(s) and len(s) == 6,
'required': True,
},
{
'name': 'service_url',
'default': SERVICE_URL,
'caption': _(u'PayFIP WS service URL'),
'help_text': _(u'do not modify if you do not know'),
'validation': lambda x: x.startswith('http'),
},
{
'name': 'wsdl_url',
'default': WSDL_URL,
'caption': _(u'PayFIP WS WSDL URL'),
'help_text': _(u'do not modify if you do not know'),
'validation': lambda x: x.startswith('http'),
},
{
'name': 'saisie',
'caption': _('Payment type'),
'default': 'T',
'choices': [
('T', _('test')),
('X', _('activation')),
('W', _('production')),
],
},
{
'name': 'normal_return_url',
'caption': _('User return URL'),
'required': True,
},
{
'name': 'automatic_return_url',
'caption': _('Asynchronous return URL'),
'required': True,
},
],
}
def __init__(self, *args, **kwargs):
super(Payment, self).__init__(*args, **kwargs)
wsdl_url = self.wsdl_url
# use cached WSDL
if wsdl_url == WSDL_URL:
base_path = os.path.join(os.path.dirname(__file__), 'resource', 'PaiementSecuriseService.wsdl')
wsdl_url = 'file://%s' % base_path
self.payfip = PayFiP(wsdl_url=wsdl_url, service_url=self.service_url)
def _generate_refdet(self):
return '%s%010d' % (isonow(), random.randint(1, 1000000000))
def request(self, amount, email, **kwargs):
try:
montant = Decimal(amount)
# MONTANT must be sent as centimes
montant = montant * Decimal('100')
montant = montant.to_integral_value(ROUND_DOWN)
if not (Decimal('0') < montant <= Decimal('10000000')):
raise ValueError('MONTANT > 100000 euros or < 0')
montant = str(montant)
except ValueError:
raise ValueError(
'MONTANT invalid format, must be '
'a decimal integer with less than 4 digits '
'before and 2 digits after the decimal point '
', here it is %s' % repr(amount))
numcli = self.numcli
urlnotif = self.automatic_return_url
urlredirect = self.normal_return_url
exer = str(datetime.date.today().year)
refdet = kwargs.get('refdet', self._generate_refdet())
mel = email
if hasattr(mel, 'decode'):
mel = email.decode('ascii')
try:
if '@' not in mel:
raise ValueError('no @ in MEL')
if not (6 <= len(mel) <= 80):
raise ValueError('len(MEL) is invalid, must be between 6 and 80')
except Exception as e:
raise ValueError('MEL is not a valid email, %r' % mel, e)
# check saisie
saisie = self.saisie
if saisie not in ('T', 'X', 'W'):
raise ValueError('SAISIE invalid format, %r, must be M, T, X or A' % saisie)
idop = self.payfip.get_idop(numcli=numcli, saisie=saisie, exer=exer,
refdet=refdet, montant=montant, mel=mel,
url_notification=urlnotif,
url_redirect=urlredirect)
return str(idop), URL, PAYMENT_URL % idop
def response(self, query_string, **kwargs):
fields = parse_qs(query_string, True)
idop = (fields.get('idop') or [None])[0]
if not idop:
raise ResponseError('missing idop parameter in query string')
try:
response = self.payfip.get_info_paiement(idop)
except PayFiPError as e:
raise ResponseError('invalid return from payfip', e)
if response.resultrans == 'P':
result = PAID
bank_status = ''
elif response.resultrans == 'R':
result = DENIED
bank_status = 'refused'
elif response.resultrans == 'A':
result = CANCELLED
bank_status = 'cancelled'
else:
result = ERROR
bank_status = 'unknown result code: %r' % response.resultrans
transaction_id = response.refdet
transaction_id += ' ' + idop
if response.numauto:
transaction_id += ' ' + response.numauto
return PaymentResponse(
result=result,
bank_status=bank_status,
signed=True,
bank_data={k: response[k] for k in response},
order_id=idop,
transaction_id=transaction_id,
test=response.saisie == 'T')
if __name__ == '__main__':
import click
def show_payfip_error(func):
@functools.wraps(func)
def f(*args, **kwargs):
try:
return func(*args, **kwargs)
except PayFiPError as e:
click.echo(click.style('PayFiP ERROR : %s "%s"' % (e.code, e.message), fg='red'))
return f
@click.group()
@click.option('--wsdl-url', default=None)
@click.option('--service-url', default=None)
@click.pass_context
def main(ctx, wsdl_url, service_url):
import logging
logging.basicConfig(level=logging.INFO)
# hide warning from zeep
logging.getLogger('zeep.wsdl.bindings.soap').level = logging.ERROR
ctx.obj = PayFiP(wsdl_url=wsdl_url, service_url=service_url)
def numcli(ctx, param, value):
if not isinstance(value, six.string_types) or len(value) != 6 or not value.isdigit():
raise click.BadParameter('numcli must a 6 digits number')
return value
@main.command()
@click.argument('numcli', callback=numcli, type=str)
@click.pass_obj
@show_payfip_error
def info_client(payfip, numcli):
response = payfip.get_info_client(numcli)
for key in response:
print('%15s:' % key, response[key])
@main.command()
@click.argument('numcli', callback=numcli, type=str)
@click.option('--saisie', type=click.Choice(['T', 'X', 'W']), required=True)
@click.option('--exer', type=str, required=True)
@click.option('--montant', type=int, required=True)
@click.option('--refdet', type=str, required=True)
@click.option('--mel', type=str, required=True)
@click.option('--url-notification', type=str, required=True)
@click.option('--url-redirect', type=str, required=True)
@click.option('--objet', default=None, type=str)
@click.pass_obj
@show_payfip_error
def get_idop(payfip, numcli, saisie, exer, montant, refdet, mel, objet, url_notification, url_redirect):
idop = payfip.get_idop(numcli=numcli, saisie=saisie, exer=exer,
montant=montant, refdet=refdet, mel=mel,
objet=objet, url_notification=url_notification,
url_redirect=url_redirect)
print('idOp:', idop)
print(PAYMENT_URL % idop)
@main.command()
@click.argument('idop', type=str)
@click.pass_obj
@show_payfip_error
def info_paiement(payfip, idop):
print(payfip.get_info_paiement(idop))
main()

View File

@ -0,0 +1,140 @@
<?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">
<types>
<xsd:schema>
<xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService" schemaLocation="PaiementSecuriseService1.xsd"/>
</xsd:schema>
<xsd:schema>
<xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/requete" schemaLocation="PaiementSecuriseService2.xsd"/>
</xsd:schema>
<xsd:schema>
<xsd:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse" schemaLocation="PaiementSecuriseService3.xsd"/>
</xsd:schema>
</types>
<message name="creerPaiementSecurise">
<part name="parameters" element="tns:creerPaiementSecurise"/>
</message>
<message name="creerPaiementSecuriseResponse">
<part name="parameters" element="tns:creerPaiementSecuriseResponse"/>
</message>
<message name="FonctionnelleErreur">
<part name="fault" element="tns:FonctionnelleErreur"/>
</message>
<message name="TechDysfonctionnementErreur">
<part name="fault" element="tns:TechDysfonctionnementErreur"/>
</message>
<message name="TechIndisponibiliteErreur">
<part name="fault" element="tns:TechIndisponibiliteErreur"/>
</message>
<message name="TechProtocolaireErreur">
<part name="fault" element="tns:TechProtocolaireErreur"/>
</message>
<message name="recupererDetailClient">
<part name="parameters" element="tns:recupererDetailClient"/>
</message>
<message name="recupererDetailClientResponse">
<part name="parameters" element="tns:recupererDetailClientResponse"/>
</message>
<message name="recupererDetailPaiementSecurise">
<part name="parameters" element="tns:recupererDetailPaiementSecurise"/>
</message>
<message name="recupererDetailPaiementSecuriseResponse">
<part name="parameters" element="tns:recupererDetailPaiementSecuriseResponse"/>
</message>
<portType name="PaiementSecuriseService">
<operation name="creerPaiementSecurise">
<input message="tns:creerPaiementSecurise"/>
<output message="tns:creerPaiementSecuriseResponse"/>
<fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
<fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
<fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
<fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
</operation>
<operation name="recupererDetailClient">
<input message="tns:recupererDetailClient"/>
<output message="tns:recupererDetailClientResponse"/>
<fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
<fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
<fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
<fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
</operation>
<operation name="recupererDetailPaiementSecurise">
<input message="tns:recupererDetailPaiementSecurise"/>
<output message="tns:recupererDetailPaiementSecuriseResponse"/>
<fault message="tns:FonctionnelleErreur" name="FonctionnelleErreur"/>
<fault message="tns:TechDysfonctionnementErreur" name="TechDysfonctionnementErreur"/>
<fault message="tns:TechIndisponibiliteErreur" name="TechIndisponibiliteErreur"/>
<fault message="tns:TechProtocolaireErreur" name="TechProtocolaireErreur"/>
</operation>
</portType>
<binding name="PaiementSecuriseServicePortBinding" type="tns:PaiementSecuriseService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="creerPaiementSecurise">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="FonctionnelleErreur">
<soap:fault name="FonctionnelleErreur" use="literal"/>
</fault>
<fault name="TechDysfonctionnementErreur">
<soap:fault name="TechDysfonctionnementErreur" use="literal"/>
</fault>
<fault name="TechIndisponibiliteErreur">
<soap:fault name="TechIndisponibiliteErreur" use="literal"/>
</fault>
<fault name="TechProtocolaireErreur">
<soap:fault name="TechProtocolaireErreur" use="literal"/>
</fault>
</operation>
<operation name="recupererDetailClient">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="FonctionnelleErreur">
<soap:fault name="FonctionnelleErreur" use="literal"/>
</fault>
<fault name="TechDysfonctionnementErreur">
<soap:fault name="TechDysfonctionnementErreur" use="literal"/>
</fault>
<fault name="TechIndisponibiliteErreur">
<soap:fault name="TechIndisponibiliteErreur" use="literal"/>
</fault>
<fault name="TechProtocolaireErreur">
<soap:fault name="TechProtocolaireErreur" use="literal"/>
</fault>
</operation>
<operation name="recupererDetailPaiementSecurise">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="FonctionnelleErreur">
<soap:fault name="FonctionnelleErreur" use="literal"/>
</fault>
<fault name="TechDysfonctionnementErreur">
<soap:fault name="TechDysfonctionnementErreur" use="literal"/>
</fault>
<fault name="TechIndisponibiliteErreur">
<soap:fault name="TechIndisponibiliteErreur" use="literal"/>
</fault>
<fault name="TechProtocolaireErreur">
<soap:fault name="TechProtocolaireErreur" use="literal"/>
</fault>
</operation>
</binding>
<service name="PaiementSecuriseService">
<port name="PaiementSecuriseServicePort" binding="tns:PaiementSecuriseServicePortBinding">
<soap:address location="http://www.tipi.budget.gouv.fr:80/tpa/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService"/>
</port>
</service>
</definitions>

View File

@ -0,0 +1,116 @@
<?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">
<xs:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/requete" schemaLocation="PaiementSecuriseService2.xsd"/>
<xs:import namespace="http://securite.service.tpa.cp.finances.gouv.fr/reponse" schemaLocation="PaiementSecuriseService3.xsd"/>
<xs:element name="FonctionnelleErreur" type="tns:FonctionnelleErreur"/>
<xs:element name="TechDysfonctionnementErreur" type="tns:TechDysfonctionnementErreur"/>
<xs:element name="TechIndisponibiliteErreur" type="tns:TechIndisponibiliteErreur"/>
<xs:element name="TechProtocolaireErreur" type="tns:TechProtocolaireErreur"/>
<xs:element name="creerPaiementSecurise" type="tns:creerPaiementSecurise"/>
<xs:element name="creerPaiementSecuriseResponse" type="tns:creerPaiementSecuriseResponse"/>
<xs:element name="recupererDetailClient" type="tns:recupererDetailClient"/>
<xs:element name="recupererDetailClientResponse" type="tns:recupererDetailClientResponse"/>
<xs:element name="recupererDetailPaiementSecurise" type="tns:recupererDetailPaiementSecurise"/>
<xs:element name="recupererDetailPaiementSecuriseResponse" type="tns:recupererDetailPaiementSecuriseResponse"/>
<xs:complexType name="creerPaiementSecurise">
<xs:sequence>
<xs:element name="arg0" type="ns1:CreerPaiementSecuriseRequest" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="creerPaiementSecuriseResponse">
<xs:sequence>
<xs:element name="return" type="ns2:CreerPaiementSecuriseResponse" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="FonctionnelleErreur">
<xs:sequence>
<xs:element name="code" type="xs:string" minOccurs="0"/>
<xs:element name="descriptif" type="xs:string" minOccurs="0"/>
<xs:element name="libelle" type="xs:string" minOccurs="0"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="severite" type="xs:int"/>
<xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="throwable">
<xs:sequence>
<xs:element name="stackTrace" type="tns:stackTraceElement" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="stackTraceElement" final="extension restriction">
<xs:sequence/>
</xs:complexType>
<xs:complexType name="TechDysfonctionnementErreur">
<xs:sequence>
<xs:element name="code" type="xs:string" minOccurs="0"/>
<xs:element name="descriptif" type="xs:string" minOccurs="0"/>
<xs:element name="libelle" type="xs:string" minOccurs="0"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="severite" type="xs:int"/>
<xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TechIndisponibiliteErreur">
<xs:sequence>
<xs:element name="code" type="xs:string" minOccurs="0"/>
<xs:element name="descriptif" type="xs:string" minOccurs="0"/>
<xs:element name="libelle" type="xs:string" minOccurs="0"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="severite" type="xs:int"/>
<xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TechProtocolaireErreur">
<xs:sequence>
<xs:element name="code" type="xs:string" minOccurs="0"/>
<xs:element name="descriptif" type="xs:string" minOccurs="0"/>
<xs:element name="libelle" type="xs:string" minOccurs="0"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="severite" type="xs:int"/>
<xs:element name="suppressed" type="tns:throwable" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="recupererDetailClient">
<xs:sequence>
<xs:element name="arg0" type="ns2:RecupererDetailClientRequest" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="recupererDetailClientResponse">
<xs:sequence>
<xs:element name="return" type="ns2:RecupererDetailClientResponse" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="recupererDetailPaiementSecurise">
<xs:sequence>
<xs:element name="arg0" type="ns2:RecupererDetailPaiementSecuriseRequest" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="recupererDetailPaiementSecuriseResponse">
<xs:sequence>
<xs:element name="return" type="ns2:RecupererDetailPaiementSecuriseResponse" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@ -0,0 +1,16 @@
<?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">
<xs:complexType name="CreerPaiementSecuriseRequest">
<xs:sequence>
<xs:element name="exer" type="xs:string" minOccurs="0"/>
<xs:element name="mel" type="xs:string" minOccurs="0"/>
<xs:element name="montant" type="xs:string" minOccurs="0"/>
<xs:element name="numcli" type="xs:string" minOccurs="0"/>
<xs:element name="objet" type="xs:string" minOccurs="0"/>
<xs:element name="refdet" type="xs:string" minOccurs="0"/>
<xs:element name="saisie" type="xs:string" minOccurs="0"/>
<xs:element name="urlnotif" type="xs:string" minOccurs="0"/>
<xs:element name="urlredirect" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@ -0,0 +1,47 @@
<?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">
<xs:complexType name="CreerPaiementSecuriseResponse">
<xs:sequence>
<xs:element name="idOp" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RecupererDetailClientRequest">
<xs:sequence>
<xs:element name="numCli" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RecupererDetailClientResponse">
<xs:sequence>
<xs:element name="libelleN1" type="xs:string" minOccurs="0"/>
<xs:element name="libelleN2" type="xs:string" minOccurs="0"/>
<xs:element name="libelleN3" type="xs:string" minOccurs="0"/>
<xs:element name="numcli" type="xs:string" minOccurs="0"/>
<xs:element name="IdentifiantGen" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RecupererDetailPaiementSecuriseRequest">
<xs:sequence>
<xs:element name="idOp" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RecupererDetailPaiementSecuriseResponse">
<xs:sequence>
<xs:element name="dattrans" type="xs:string" minOccurs="0"/>
<xs:element name="exer" type="xs:string" minOccurs="0"/>
<xs:element name="heurtrans" type="xs:string" minOccurs="0"/>
<xs:element name="idOp" type="xs:string" minOccurs="0"/>
<xs:element name="mel" type="xs:string" minOccurs="0"/>
<xs:element name="montant" type="xs:string" minOccurs="0"/>
<xs:element name="numauto" type="xs:string" minOccurs="0"/>
<xs:element name="numcli" type="xs:string" minOccurs="0"/>
<xs:element name="objet" type="xs:string" minOccurs="0"/>
<xs:element name="refdet" type="xs:string" minOccurs="0"/>
<xs:element name="resultrans" type="xs:string" minOccurs="0"/>
<xs:element name="saisie" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@ -123,6 +123,8 @@ setuptools.setup(
'pytz', 'pytz',
'requests', 'requests',
'six', 'six',
'click',
'zeep',
], ],
cmdclass={ cmdclass={
'sdist': eo_sdist, 'sdist': eo_sdist,

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailClient xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <numCli>090909</numCli>\n </arg0>\n </ns0:recupererDetailClient>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:recupererDetailClientResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <libelleN1>RR COMPOSTEURS INDIVIDUELS</libelleN1>\n <libelleN2>POUETPOUET</libelleN2>\n <libelleN3>COLLECTE VALORISATION DECHETS</libelleN3>\n <numcli>090909</numcli>\n </return>\n </ns2:recupererDetailClientResponse>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doeexample.com</mel>\n <montant>9990000001</montant>\n <numcli>090909</numcli>\n <objet>coucou</objet>\n <refdet>ABCDEF</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n <faultcode>S:Server</faultcode>\n <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n <detail>\n <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <code>A2</code>\n <descriptif/>\n <libelle>Adresse m&#233;l incorrecte. </libelle>\n <severite>2</severite>\n </ns2:FonctionnelleErreur>\n </detail>\n </S:Fault>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doe@example.com</mel>\n <montant>1000</montant>\n <numcli>090909</numcli>\n <objet>coucou</objet>\n <refdet>ABCDEFGH</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:creerPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </return>\n </ns2:creerPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doe@example.com</mel>\n <montant>1000</montant>\n <numcli>090909</numcli>\n <objet>coucou</objet>\n <refdet>ABCD</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n <faultcode>S:Server</faultcode>\n <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n <detail>\n <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <code>R3</code>\n <descriptif/>\n <libelle>Le format du param&#232;tre REFDET n'est pas conforme</libelle>\n <severite>2</severite>\n </ns2:FonctionnelleErreur>\n </detail>\n </S:Fault>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n <faultcode>S:Server</faultcode>\n <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n <detail>\n <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <code>P1</code>\n <descriptif/>\n <libelle>IdOp incorrect.</libelle>\n <severite>2</severite>\n </ns2:FonctionnelleErreur>\n </detail>\n </S:Fault>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\">\n <faultcode>S:Server</faultcode>\n <faultstring>fr.gouv.finances.cp.tpa.webservice.exceptions.FonctionnelleErreur</faultstring>\n <detail>\n <ns2:FonctionnelleErreur xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <code>P5</code><descriptif />\n <libelle>R&#233;sultat de la transaction non connu.</libelle><severite>2</severite>\n </ns2:FonctionnelleErreur>\n </detail>\n </S:Fault>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1 @@
[["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:recupererDetailPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <dattrans>12122019</dattrans><exer>20</exer><heurtrans>1311</heurtrans><idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp><mel>john.doe@example.com</mel><montant>1000</montant><numauto>112233445566-tip</numauto><numcli>090909</numcli><objet>coucou</objet><refdet>EFEFAEFG</refdet><resultrans>V</resultrans><saisie>T</saisie>\n </return>\n </ns2:recupererDetailPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"]]

View File

@ -0,0 +1,4 @@
[
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doe@example.com</mel>\n <montant>1000</montant>\n <numcli>090909</numcli>\n <refdet>201912261758460053903194</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:creerPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </return>\n </ns2:creerPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"],
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:recupererDetailPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <dattrans>12122019</dattrans><exer>20</exer><heurtrans>1311</heurtrans><idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp><mel>john.doe@example.com</mel><montant>1000</montant><numcli>090909</numcli><refdet>201912261758460053903194</refdet><resultrans>A</resultrans><saisie>T</saisie>\n </return>\n </ns2:recupererDetailPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"]
]

View File

@ -0,0 +1,4 @@
[
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doe@example.com</mel>\n <montant>1000</montant>\n <numcli>090909</numcli>\n <refdet>201912261758460053903194</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:creerPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </return>\n </ns2:creerPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"],
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:recupererDetailPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <dattrans>12122019</dattrans><exer>20</exer><heurtrans>1311</heurtrans><idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp><mel>john.doe@example.com</mel><montant>1000</montant><numcli>090909</numcli><refdet>201912261758460053903194</refdet><resultrans>R</resultrans><saisie>T</saisie>\n </return>\n </ns2:recupererDetailPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"]
]

View File

@ -0,0 +1,4 @@
[
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:creerPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <exer>2019</exer>\n <mel>john.doe@example.com</mel>\n <montant>1000</montant>\n <numcli>090909</numcli>\n <refdet>201912261758460053903194</refdet>\n <saisie>T</saisie>\n <urlnotif>https://notif.payfip.example.com/</urlnotif>\n <urlredirect>https://redirect.payfip.example.com/</urlredirect>\n </arg0>\n </ns0:creerPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:creerPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </return>\n </ns2:creerPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"],
["<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap-env:Body>\n <ns0:recupererDetailPaiementSecurise xmlns:ns0=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <arg0>\n <idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp>\n </arg0>\n </ns0:recupererDetailPaiementSecurise>\n </soap-env:Body>\n</soap-env:Envelope>\n", "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <S:Body>\n <ns2:recupererDetailPaiementSecuriseResponse xmlns:ns2=\"http://securite.service.tpa.cp.finances.gouv.fr/services/mas_securite/contrat_paiement_securise/PaiementSecuriseService\">\n <return>\n <dattrans>12122019</dattrans><exer>20</exer><heurtrans>1311</heurtrans><idOp>cc0cb210-1cd4-11ea-8cca-0213ad91a103</idOp><mel>john.doe@example.com</mel><montant>1000</montant><numauto>112233445566-tip</numauto><numcli>090909</numcli><refdet>201912261758460053903194</refdet><resultrans>P</resultrans><saisie>T</saisie>\n </return>\n </ns2:recupererDetailPaiementSecuriseResponse>\n </S:Body>\n</S:Envelope>\n"]
]

251
tests/test_payfip_ws.py Normal file
View File

@ -0,0 +1,251 @@
# coding: utf-8
#
# eopayment - online payment library
# Copyright (C) 2011-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function, unicode_literals
import json
import lxml.etree as ET
import httmock
import pytest
from zeep.plugins import HistoryPlugin
import eopayment
from eopayment.payfip_ws import PayFiP, PayFiPError
def xmlindent(content):
if hasattr(content, 'encode') or hasattr(content, 'decode'):
content = ET.fromstring(content)
return ET.tostring(content, pretty_print=True).decode('utf-8', 'ignore')
NUMCLI = '090909'
# freeze time to fix EXER field to 2019
@pytest.fixture(autouse=True)
def freezer(freezer):
freezer.move_to('2019-12-12')
class PayFiPHTTMock(object):
def __init__(self, request):
history_path = 'tests/data/payfip-%s.json' % request.function.__name__
with open(history_path) as fd:
self.history = json.load(fd)
self.counter = 0
@httmock.urlmatch()
def mock(self, url, request):
request_content, response_content = self.history[self.counter]
self.counter += 1
assert xmlindent(request.body) == request_content
return response_content
@pytest.fixture
def payfip(request):
history = HistoryPlugin()
@httmock.urlmatch()
def raise_on_request(url, request):
# ensure we do not access network
from requests.exceptions import RequestException
raise RequestException('huhu')
with httmock.HTTMock(raise_on_request):
payfip = PayFiP(wsdl_url='file://eopayment/resource/PaiementSecuriseService.wsdl',
zeep_client_kwargs={'plugins': [history]})
try:
if 'update_data' not in request.keywords:
with httmock.HTTMock(PayFiPHTTMock(request).mock):
yield payfip
else:
yield payfip
finally:
# add @pytest.mark.update_data to test to update fixtures data
if 'update_data' in request.keywords:
history_path = 'tests/data/payfip-%s.json' % request.function.__name__
d = [
(xmlindent(exchange['sent']['envelope']),
xmlindent(exchange['received']['envelope']))
for exchange in history._buffer
]
content = json.dumps(d)
with open(history_path, 'wb') as fd:
fd.write(content)
# pytestmark = pytest.mark.update_data
def test_get_client_info(payfip):
result = payfip.get_info_client(NUMCLI)
assert result.numcli == NUMCLI
assert result.libelleN2 == 'POUETPOUET'
NOTIF_URL = 'https://notif.payfip.example.com/'
REDIRECT_URL = 'https://redirect.payfip.example.com/'
def test_get_idop_ok(payfip):
result = payfip.get_idop(
numcli=NUMCLI,
exer='2019',
refdet='ABCDEFGH',
montant='1000',
mel='john.doe@example.com',
objet='coucou',
url_notification=NOTIF_URL,
url_redirect=REDIRECT_URL,
saisie='T')
assert result == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
def test_get_idop_refdet_error(payfip):
with pytest.raises(PayFiPError, match='.*R3.*Le format.*REFDET.*conforme'):
payfip.get_idop(
numcli=NUMCLI,
exer='2019',
refdet='ABCD',
montant='1000',
mel='john.doe@example.com',
objet='coucou',
url_notification='https://notif.payfip.example.com/',
url_redirect='https://redirect.payfip.example.com/',
saisie='T')
def test_get_idop_adresse_mel_incorrect(payfip):
with pytest.raises(PayFiPError, match='.*A2.*Adresse.*incorrecte'):
payfip.get_idop(
numcli=NUMCLI,
exer='2019',
refdet='ABCDEF',
montant='9990000001',
mel='john.doeexample.com',
objet='coucou',
url_notification='https://notif.payfip.example.com/',
url_redirect='https://redirect.payfip.example.com/',
saisie='T')
def test_get_info_paiement_ok(payfip):
result = payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
assert {k: result[k] for k in result} == {
'dattrans': '12122019',
'exer': '20',
'heurtrans': '1311',
'idOp': 'cc0cb210-1cd4-11ea-8cca-0213ad91a103',
'mel': 'john.doe@example.com',
'montant': '1000',
'numauto': '112233445566-tip',
'numcli': NUMCLI,
'objet': 'coucou',
'refdet': 'EFEFAEFG',
'resultrans': 'V',
'saisie': 'T'
}
def test_get_info_paiement_P1(payfip):
# idop par pas encore reçu par la plate-forme ou déjà nettoyé (la nuit)
with pytest.raises(PayFiPError, match='.*P1.*IdOp incorrect.*'):
payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
def test_get_info_paiement_P5(payfip):
# idop reçu par la plate-forme mais transaction en cours
with pytest.raises(PayFiPError, match='.*P5.*sultat de la transaction non connu.*'):
payfip.get_info_paiement('cc0cb210-1cd4-11ea-8cca-0213ad91a103')
def test_payment_ok(request):
payment = eopayment.Payment('payfip_ws', {
'numcli': '090909',
'automatic_return_url': NOTIF_URL,
'normal_return_url': REDIRECT_URL,
})
with httmock.HTTMock(PayFiPHTTMock(request).mock):
payment_id, kind, url = payment.request(
amount='10.00',
email='john.doe@example.com',
# make test deterministic
refdet='201912261758460053903194')
assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
assert kind == eopayment.URL
assert url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=cc0cb210-1cd4-11ea-8cca-0213ad91a103'
response = payment.response('idop=%s' % payment_id)
assert response.result == eopayment.PAID
assert response.bank_status == ''
assert response.order_id == payment_id
assert response.transaction_id == (
'201912261758460053903194 cc0cb210-1cd4-11ea-8cca-0213ad91a103 112233445566-tip')
def test_payment_denied(request):
payment = eopayment.Payment('payfip_ws', {
'numcli': '090909',
'automatic_return_url': NOTIF_URL,
'normal_return_url': REDIRECT_URL,
})
with httmock.HTTMock(PayFiPHTTMock(request).mock):
payment_id, kind, url = payment.request(
amount='10.00',
email='john.doe@example.com',
# make test deterministic
refdet='201912261758460053903194')
assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
assert kind == eopayment.URL
assert url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=cc0cb210-1cd4-11ea-8cca-0213ad91a103'
response = payment.response('idop=%s' % payment_id)
assert response.result == eopayment.DENIED
assert response.bank_status == 'refused'
assert response.order_id == payment_id
assert response.transaction_id == '201912261758460053903194 cc0cb210-1cd4-11ea-8cca-0213ad91a103'
def test_payment_cancelled(request):
payment = eopayment.Payment('payfip_ws', {
'numcli': '090909',
'automatic_return_url': NOTIF_URL,
'normal_return_url': REDIRECT_URL,
})
with httmock.HTTMock(PayFiPHTTMock(request).mock):
payment_id, kind, url = payment.request(
amount='10.00',
email='john.doe@example.com',
# make test deterministic
refdet='201912261758460053903194')
assert payment_id == 'cc0cb210-1cd4-11ea-8cca-0213ad91a103'
assert kind == eopayment.URL
assert url == 'https://www.tipi.budget.gouv.fr/tpa/paiementws.web?idop=cc0cb210-1cd4-11ea-8cca-0213ad91a103'
response = payment.response('idop=%s' % payment_id)
assert response.result == eopayment.CANCELLED
assert response.bank_status == 'cancelled'
assert response.order_id == payment_id
assert response.transaction_id == '201912261758460053903194 cc0cb210-1cd4-11ea-8cca-0213ad91a103'

View File

@ -18,3 +18,11 @@ deps = coverage
pytest-freezegun pytest-freezegun
py2: pytest-cov py2: pytest-cov
mock mock
httmock
lxml
[pytest]
filterwarnings =
ignore:defusedxml.lxml is no longer supported.*
markers =
update_data