diff --git a/README.txt b/README.txt index e82cdba..4a4f34b 100644 --- a/README.txt +++ b/README.txt @@ -69,3 +69,113 @@ You can test your PayFiP regie web-service connection with an integrated CLI uti Options: --help Show this message and exit. + + +Generic CLI Tool +================ + +You can put some configuration in ~/.config/eopayment.init :: + + [default] + debug=yes + + [systempayv2] + # same name as passed in the options argument to Payment.__init__() + vads_site_id=12345678 + secret_test=xyzabcdefgh + vads_ctx_mode=TEST + + $ python3 -m eopayment --option vads_site_id=56781234 request 10.0 --param transaction_id=1234 --param email=john.doe@example.com + Transaction ID: 1234 +
+ + + + + + + + + + + + + + + + + + + + + +
+ [ Local browser is automatically opened with this form which is auto-submitted ] + + $ python3 -m eopayment --debug response 'vads_amount=1010&vads_auth_mode=FULL&vads_auth_number=3fd070&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB&vads_card_number=597010XXXXXX0018&vads_payment_certificate=f582e920616a33bdaa0c242ee3fc3d435d367575&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1010&vads_effective_currency=978&vads_site_id=12345678&vads_trans_date=20201029093825&vads_trans_id=Vlco55&vads_trans_uuid=e8defc7bd32c418c93c4b2be676d2796&vads_validation_mode=0&vads_version=V2&vads_warranty_result=&vads_payment_src=EC&vads_cust_country=FR&vads_contrib=eopayment&vads_tid=001&vads_sequence_number=1&vads_contract_used=2334410&vads_trans_status=AUTHORISED&vads_expiry_month=6&vads_expiry_year=2021&vads_bank_label=Banque+de+d%C3%A9mo+et+de+l%27innovation&vads_bank_product=MCW&vads_pays_ip=FR&vads_presentation_date=20201029093826&vads_effective_creation_date=20201029093826&vads_operation_type=DEBIT&vads_result=00&vads_extra_result=&vads_card_country=FR&vads_language=fr&vads_brand_management=%7B%22userChoice%22%3Afalse%2C%22brandList%22%3A%22CB%7CMASTERCARD%22%2C%22brand%22%3A%22CB%22%7D&vads_action_mode=INTERACTIVE&vads_payment_config=SINGLE&vads_page_action=PAYMENT&vads_threeds_enrolled=Y&vads_threeds_auth_type=CHALLENGE&vads_threeds_eci=02&vads_threeds_xid=RFBSMkdWdFE0Wk15VWw0RkJjMzU%3D&vads_threeds_cavvAlgorithm=2&vads_threeds_status=Y&vads_threeds_sign_valid=1&vads_threeds_error_code=&vads_threeds_exit_status=10&vads_threeds_cavv=jG26AYSjvclBARFYSf%2FtXRmjGXM%3D&signature=5594aa2bc35c9e45e759b08df339e5f8ecf2c410' + result : 3 + signed : True + bank_data : + {'__bank_id': '3fd070', + 'signature': '5594aa2bc35c9e45e759b08df339e5f8ecf2c410', + 'vads_action_mode': 'INTERACTIVE', + 'vads_amount': '1010', + 'vads_auth_mode': 'FULL', + 'vads_auth_number': '3fd070', + 'vads_auth_result': '00', + 'vads_auth_result_message': 'Transaction approuvée ou traitée avec succès', + 'vads_bank_label': "Banque de démo et de l'innovation", + 'vads_bank_product': 'MCW', + 'vads_brand_management': '{"userChoice":false,"brandList":"CB|MASTERCARD","brand":"CB"}', + 'vads_capture_delay': '0', + 'vads_card_brand': 'CB', + 'vads_card_country': 'FR', + 'vads_card_number': '597010XXXXXX0018', + 'vads_contract_used': '2334410', + 'vads_contrib': 'eopayment', + 'vads_ctx_mode': 'TEST', + 'vads_currency': '978', + 'vads_cust_country': 'FR', + 'vads_effective_amount': '1010', + 'vads_effective_creation_date': '20201029093826', + 'vads_effective_currency': '978', + 'vads_expiry_month': '6', + 'vads_expiry_year': '2021', + 'vads_extra_result': '', + 'vads_extra_result_message': 'Pas de contrôle effectué.', + 'vads_language': 'fr', + 'vads_operation_type': 'DEBIT', + 'vads_page_action': 'PAYMENT', + 'vads_payment_certificate': 'f582e920616a33bdaa0c242ee3fc3d435d367575', + 'vads_payment_config': 'SINGLE', + 'vads_payment_src': 'EC', + 'vads_pays_ip': 'FR', + 'vads_presentation_date': '20201029093826', + 'vads_result': '00', + 'vads_result_message': 'Paiement réalisé avec succés.', + 'vads_sequence_number': '1', + 'vads_site_id': '12345678', + 'vads_threeds_auth_type': 'CHALLENGE', + 'vads_threeds_cavv': 'jG26AYSjvclBARFYSf/tXRmjGXM=', + 'vads_threeds_cavvAlgorithm': '2', + 'vads_threeds_eci': '02', + 'vads_threeds_enrolled': 'Y', + 'vads_threeds_error_code': '', + 'vads_threeds_exit_status': '10', + 'vads_threeds_sign_valid': '1', + 'vads_threeds_status': 'Y', + 'vads_threeds_xid': 'RFBSMkdWdFE0Wk15VWw0RkJjMzU=', + 'vads_tid': '001', + 'vads_trans_date': '20201029093825', + 'vads_trans_id': 'Vlco55', + 'vads_trans_status': 'AUTHORISED', + 'vads_trans_uuid': 'e8defc7bd32c418c93c4b2be676d2796', + 'vads_validation_mode': '0', + 'vads_version': 'V2', + 'vads_warranty_result': ''} + return_content : None + bank_status : Paiement réalisé avec succés. + transaction_id : 3fd070 + order_id : 20201029093825_Vlco55 + test : True + transaction_date : 2020-10-29 09:38:26+00:00 diff --git a/eopayment/__main__.py b/eopayment/__main__.py new file mode 100644 index 0000000..71fd4ea --- /dev/null +++ b/eopayment/__main__.py @@ -0,0 +1,125 @@ +# eopayment - online payment library +# Copyright (C) 2011-2020 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 . + +from __future__ import print_function + +import configparser +import decimal +import logging +import os.path +import pprint +import subprocess +import tempfile + +import click + +from . import Payment, FORM, URL + + +def option(value): + try: + name, value = value.split('=', 1) + except Exception: + raise ValueError('invalid option %s' % value) + return (name, value) + + +@click.group() +@click.option('--option', type=option, multiple=True) +@click.option('--name', type=str, default='') +@click.option('--backend', type=str) +@click.option('--debug/--no-debug', default=None) +@click.pass_context +def main(ctx, backend, debug, option, name): + config_file = os.path.expanduser('~/.config/eopayment.ini') + option = list(option) + if os.path.exists(config_file): + parser = configparser.ConfigParser(interpolation=None) + with open(config_file) as fd: + parser.read_file(fd) + if debug is None: + debug = parser.getboolean('default', 'debug', fallback=False) + if debug is True: + logging.basicConfig(level=logging.DEBUG) + for section in parser.sections(): + if section == 'default': + continue + if ':' in section: + config_backend, config_name = section.split(':', 1) + else: + config_backend, config_name = section, None + load = False + if not name and not backend: + # use first section + logging.debug('no backend and not name given using first section found') + backend = config_backend + load = True + elif name and backend: + load = (config_backend == backend and config_name == name) + elif name: + load = config_name == name + elif backend: + load = config_backend == backend + if load: + logging.debug('loading configuration "%s"', section) + backend = backend or config_backend + option.extend(parser.items(section=section)) + break + else: + if not backend: + raise ValueError('no backend found') + + if parser.has_section(backend): + option.extend(parser.items(section=backend)) + if debug is True: + logging.basicConfig(level=logging.DEBUG) + ctx.obj = Payment(backend, dict(option)) + + +@main.command() +@click.argument('amount', type=decimal.Decimal) +@click.option('--param', type=option, multiple=True) +@click.pass_obj +def request(backend, amount, param): + transaction_id, kind, what = backend.request(amount, **dict(param)) + print('Transaction ID:', transaction_id) + if kind == FORM: + print(what) + with tempfile.NamedTemporaryFile(mode='w', delete=False) as fd: + print(what, file=fd) + print('''''', file=fd) + subprocess.call(['gnome-www-browser', fd.name]) + elif kind == URL: + print('Please click on URL:', what) + subprocess.call(['gnome-www-browser', what]) + + +@main.command() +@click.argument('query_string', type=str) +@click.option('--param', type=option, multiple=True) +@click.pass_obj +def response(backend, query_string, param): + payment_response = backend.response(query_string, **dict(param)) + for key, value in payment_response.__dict__.items(): + if not isinstance(value, (dict, list)): + print(' ', key, ':', value) + else: + print(' ', key, ':') + formatted_value = pprint.pformat(value) + for line in formatted_value.splitlines(False): + print(' ', line) + +main()