common: add method for checking amount value (#39377)

This commit is contained in:
Valentin Deniaud 2020-03-04 11:12:22 +01:00
parent 74a42e542d
commit 4eff1c29f3
7 changed files with 23 additions and 36 deletions

View File

@ -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',

View File

@ -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],

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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',