diff --git a/eopayment/common.py b/eopayment/common.py index b79d9d4..614984b 100644 --- a/eopayment/common.py +++ b/eopayment/common.py @@ -19,6 +19,7 @@ import os import random import logging from datetime import date +from decimal import ROUND_DOWN, Decimal import six @@ -167,6 +168,19 @@ class PaymentCommon(object): os.close(fd) return id + @staticmethod + def clean_amount(amount, min_amount=0, max_amount=None): + try: + amount = Decimal(amount) + except ValueError: + raise ValueError('invalid amount %s: it must be a decimal integer with two digits ' + 'at most after the decimal point', amount) + if int(amount) < min_amount or (max_amount and int(amount) > max_amount): + raise ValueError('amount %s is not in range [%s, %s]' % (amount, min_amount, max_amount)) + amount *= Decimal('100') # convert to cents + amount = amount.to_integral_value(ROUND_DOWN) + return str(amount) + class Form(object): def __init__(self, url, method, fields, encoding='utf-8', diff --git a/eopayment/paybox.py b/eopayment/paybox.py index c629f68..2fc4bb7 100644 --- a/eopayment/paybox.py +++ b/eopayment/paybox.py @@ -25,7 +25,6 @@ import requests import pytz -from decimal import Decimal, ROUND_DOWN from Crypto.Signature import PKCS1_v1_5 from Crypto.PublicKey import RSA from Crypto.Hash import SHA @@ -287,7 +286,7 @@ class Payment(PaymentCommon): d['PBX_SITE'] = force_text(self.site) d['PBX_RANG'] = force_text(self.rang).strip()[-2:] d['PBX_IDENTIFIANT'] = force_text(self.identifiant) - d['PBX_TOTAL'] = (amount * Decimal(100)).to_integral_value(ROUND_DOWN) + d['PBX_TOTAL'] = self.clean_amount(amount) d['PBX_DEVISE'] = force_text(self.devise) transaction_id = kwargs.get('transaction_id') or \ self.transaction_id(12, string.digits, 'paybox', self.site, @@ -410,7 +409,7 @@ class Payment(PaymentCommon): 'RANG': self.rang.strip(), 'CLE': force_text(self.cle), 'NUMQUESTION': bank_data['numero_transaction'][0].zfill(10), - 'MONTANT': (amount * Decimal(100)).to_integral_value(ROUND_DOWN), + 'MONTANT': self.clean_amount(amount), 'DEVISE': force_text(self.devise), 'NUMTRANS': bank_data['numero_transaction'][0], # paybox transaction number 'NUMAPPEL': bank_data['numero_appel'][0], diff --git a/eopayment/payfip_ws.py b/eopayment/payfip_ws.py index 4446f8a..29166d6 100644 --- a/eopayment/payfip_ws.py +++ b/eopayment/payfip_ws.py @@ -191,20 +191,7 @@ class Payment(PaymentCommon): 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)) + montant = self.clean_amount(amount, max_amount=100000) numcli = self.numcli urlnotif = self.automatic_return_url diff --git a/eopayment/sips.py b/eopayment/sips.py index 669264a..c7ac619 100644 --- a/eopayment/sips.py +++ b/eopayment/sips.py @@ -18,7 +18,6 @@ from six.moves.urllib import parse as urlparse import string import subprocess -from decimal import Decimal import logging import os import os.path @@ -163,7 +162,7 @@ class Payment(PaymentCommon): params[TRANSACTION_ID] = transaction_id params[ORDER_ID] = orderid or str(uuid.uuid4()) params[ORDER_ID] = params[ORDER_ID].replace('-', '') - params['amount'] = str(int(Decimal(amount) * 100)) + params['amount'] = self.clean_amount(amount) if email: params['customer_email'] = email normal_return_url = self.normal_return_url diff --git a/eopayment/sips2.py b/eopayment/sips2.py index f84f5a6..ee8b7d1 100644 --- a/eopayment/sips2.py +++ b/eopayment/sips2.py @@ -205,7 +205,7 @@ class Payment(PaymentCommon): data['statementReference'] = force_text(info1) else: data['statementReference'] = data['transactionReference'] - data['amount'] = force_text(int(Decimal(amount) * 100)) + data['amount'] = self.clean_amount(amount) if email: data['billingContact.email'] = email if 'capture_day' in kwargs: @@ -323,13 +323,13 @@ class Payment(PaymentCommon): def cancel(self, amount, bank_data, **kwargs): data = {} - data['operationAmount'] = force_text(int(Decimal(amount) * 100)) + data['operationAmount'] = self.clean_amount(amount) data['transactionReference'] = bank_data.get('transactionReference') return self.perform_cash_management_operation('cancel', data) def validate(self, amount, bank_data, **kwargs): data = {} - data['operationAmount'] = force_text(int(Decimal(amount) * 100)) + data['operationAmount'] = self.clean_amount(amount) data['transactionReference'] = bank_data.get('transactionReference') return self.perform_cash_management_operation('validate', data) diff --git a/eopayment/tipi.py b/eopayment/tipi.py index ee30c50..d76afe4 100644 --- a/eopayment/tipi.py +++ b/eopayment/tipi.py @@ -16,7 +16,6 @@ import re import random -from decimal import Decimal, ROUND_DOWN from .common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED, CANCELLED, ERROR, ResponseError) @@ -90,18 +89,7 @@ class Payment(PaymentCommon): def request(self, amount, next_url=None, exer=None, orderid=None, refdet=None, objet=None, email=None, saisie=None, **kwargs): - try: - montant = Decimal(amount) - if Decimal('0') > montant > Decimal('9999.99'): - raise ValueError('MONTANT > 9999.99 euros') - montant = montant * Decimal('100') - montant = montant.to_integral_value(ROUND_DOWN) - 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)) + montant = self.clean_amount(amount, max_amount=9999.99) automatic_return_url = self.automatic_return_url if next_url and not automatic_return_url: diff --git a/tests/test_paybox.py b/tests/test_paybox.py index dd11160..577825e 100644 --- a/tests/test_paybox.py +++ b/tests/test_paybox.py @@ -260,7 +260,7 @@ class PayboxTests(TestCase): 'CLE': 'cancelling_key', 'VERSION': '00103', 'TYPE': operation_code, - 'MONTANT': Decimal('1000'), + 'MONTANT': '1000', 'NUMAPPEL': '30310733', 'NUMTRANS': '13957441', 'NUMQUESTION': '0013957441',