summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas NOEL <tnoel@entrouvert.com>2019-07-25 13:20:41 (GMT)
committerThomas NOEL <tnoel@entrouvert.com>2019-08-14 19:49:21 (GMT)
commit88f3a5ca208775268f676baff95f161aabc3eff4 (patch)
treefb2f0ec0505b6ec7510038ceee6877a0c89fe617
parent073520e11162779ef17c9a71278915522e987d36 (diff)
downloadcombo-wip/35052-lingo-french-commas.zip
combo-wip/35052-lingo-french-commas.tar.gz
combo-wip/35052-lingo-french-commas.tar.bz2
lingo: accept french amount format (#35052)wip/35052-lingo-french-commas
-rw-r--r--combo/apps/lingo/views.py45
-rw-r--r--tests/test_lingo_payment.py28
2 files changed, 58 insertions, 15 deletions
diff --git a/combo/apps/lingo/views.py b/combo/apps/lingo/views.py
index 4150d79..70ed64b 100644
--- a/combo/apps/lingo/views.py
+++ b/combo/apps/lingo/views.py
@@ -26,7 +26,7 @@ from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from django.http import HttpResponseForbidden, Http404, JsonResponse
from django.template.response import TemplateResponse
-from django.utils import timezone, dateparse
+from django.utils import timezone, dateparse, six
from django.utils.encoding import force_text
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View, DetailView, ListView, TemplateView
@@ -72,6 +72,14 @@ def lingo_check_request_signature(request):
return check_request_signature(request, keys=keys)
+class LocaleDecimal(Decimal):
+ # accept , instead of . for French users comfort
+ def __new__(cls, value="0", *args, **kwargs):
+ if isinstance(value, six.string_types) and settings.LANGUAGE_CODE.startswith('fr-'):
+ value = value.replace(',', '.')
+ return super(LocaleDecimal, cls).__new__(cls, value, *args, **kwargs)
+
+
class RegiesApiView(ListView):
model = Regie
@@ -94,9 +102,9 @@ class AddBasketItemApiView(View):
def get_amount(self, amount):
if isinstance(amount, list):
- d = Decimal(sum([Decimal(a) for a in amount]))
+ d = Decimal(sum([LocaleDecimal(a) for a in amount]))
else:
- d = Decimal(amount)
+ d = LocaleDecimal(amount)
return d.quantize(Decimal('0.01'), ROUND_HALF_UP)
def post(self, request, *args, **kwargs):
@@ -111,13 +119,22 @@ class AddBasketItemApiView(View):
raise Exception('missing amount parameter')
item = BasketItem(amount=0)
- item.amount = self.get_amount(request.GET.getlist('amount'))
+ try:
+ item.amount = self.get_amount(request.GET.getlist('amount'))
+ except ArithmeticError:
+ return HttpResponseBadRequest('invalid value for "amount" in query string')
if request_body.get('amount'):
- item.amount += self.get_amount(request_body['amount'])
+ try:
+ item.amount += self.get_amount(request_body['amount'])
+ except ArithmeticError:
+ return HttpResponseBadRequest('invalid value for "amount" in payload')
if extra.get('amount'):
- item.amount += self.get_amount(extra['amount'])
+ try:
+ item.amount += self.get_amount(extra['amount'])
+ except ArithmeticError:
+ return HttpResponseBadRequest('invalid value for "amount" in extra payload')
if 'extra' in request_body:
item.request_data = request_body.get('extra')
@@ -234,11 +251,11 @@ class ValidateTransactionApiView(View):
raise Http404
payment = get_eopayment_object(request, transaction.regie)
- amount = request.GET['amount']
+ amount = LocaleDecimal(request.GET['amount'])
logger.info(u'validating amount %s for transaction %s', amount, smart_text(transaction.id))
try:
- result = payment.backend.validate(Decimal(amount), transaction.bank_data)
+ result = payment.backend.validate(amount, transaction.bank_data)
except eopayment.ResponseError as e:
logger.error(u'failed in validation operation: %s', e)
response = HttpResponse(content_type='application/json')
@@ -247,7 +264,7 @@ class ValidateTransactionApiView(View):
logger.info(u'bank validation result: %r', result)
operation = TransactionOperation(transaction=transaction,
- kind='validation', amount=Decimal(amount), bank_result=result)
+ kind='validation', amount=amount, bank_result=result)
operation.save()
response = HttpResponse(content_type='application/json')
@@ -275,11 +292,11 @@ class CancelTransactionApiView(View):
raise Http404
payment = get_eopayment_object(request, transaction.regie)
- amount = request.GET['amount']
+ amount = LocaleDecimal(request.GET['amount'])
logger.info(u'cancelling amount %s for transaction %s', amount, smart_text(transaction.id))
try:
- result = payment.backend.cancel(Decimal(amount), transaction.bank_data)
+ result = payment.backend.cancel(amount, transaction.bank_data)
except eopayment.ResponseError as e:
logger.error(u'failed in cancel operation: %s', e)
response = HttpResponse(content_type='application/json')
@@ -288,7 +305,7 @@ class CancelTransactionApiView(View):
logger.info(u'bank cancellation result: %r', result)
operation = TransactionOperation(transaction=transaction,
- kind='cancellation', amount=Decimal(amount), bank_result=result)
+ kind='cancellation', amount=amount, bank_result=result)
operation.save()
response = HttpResponse(content_type='application/json')
@@ -710,11 +727,11 @@ class SelfInvoiceView(View):
except SelfDeclaredInvoicePayment.DoesNotExist:
raise Http404()
invoice_id = request.GET.get('invoice-number', '')
- invoice_amount = request.GET.get('invoice-amount', '').replace(',', '.')
+ invoice_amount = request.GET.get('invoice-amount', '')
msg = None
url = None
try:
- invoice_amount = Decimal(invoice_amount)
+ invoice_amount = LocaleDecimal(invoice_amount)
except ArithmeticError:
invoice_amount = '-'
msg = _('Sorry, the provided amount is invalid.')
diff --git a/tests/test_lingo_payment.py b/tests/test_lingo_payment.py
index eff7703..aaccf53 100644
--- a/tests/test_lingo_payment.py
+++ b/tests/test_lingo_payment.py
@@ -12,6 +12,7 @@ from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.core.wsgi import get_wsgi_application
from django.conf import settings
+from django.test import override_settings
from django.utils import timezone
from django.utils.six.moves.urllib import parse as urlparse
from django.contrib.messages.storage.session import SessionStorage
@@ -238,6 +239,31 @@ def test_add_amount_to_basket(app, key, regie, user):
assert json.loads(resp.content)['result'] == 'success'
assert BasketItem.objects.filter(amount=Decimal('81.22')).exists()
+ # accept french notation if settings.LANGUAGE_CODE is 'fr-*'
+ url = '%s?amount=10,00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
+ url = sign_url(url, key)
+ resp = app.post_json(url, params=data, status=400)
+ assert 'invalid value for "amount" in query string' in resp.content
+ data['amount'] = '1,10'
+ url = '%s?amount=10.00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
+ url = sign_url(url, key)
+ resp = app.post_json(url, params=data, status=400)
+ assert 'invalid value for "amount" in payload' in resp.content
+ data['amount'] = '1.10'
+ data['extra'] = {'amount': '0,01'}
+ resp = app.post_json(url, params=data, status=400)
+ assert 'invalid value for "amount" in extra payload' in resp.content
+
+ data['amount'] = '1,10'
+ data['extra'] = {'amount': '0,01'}
+ url = '%s?amount=10,00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
+ url = sign_url(url, key)
+ with override_settings(LANGUAGE_CODE='fr-be'):
+ resp = app.post_json(url, params=data, status=200)
+ assert resp.status_code == 200
+ assert json.loads(resp.content)['result'] == 'success'
+ assert BasketItem.objects.filter(amount=Decimal('11.11')).exists()
+
other_regie.is_default = True
other_regie.save()
data['amount'] = []
@@ -408,7 +434,7 @@ def test_pay_multiple_regies(app, key, regie, user):
resp = resp.forms[0].submit()
assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
- assert qs['amount'] == ['223.35']
+ assert qs['amount'] == ['234.46']
resp = login(app).get(page.get_online_url())
resp = resp.forms[1].submit()