Projet

Général

Profil

0001-lingo-accept-french-amount-format-35052.patch

Thomas Noël, 14 août 2019 21:51

Télécharger (8,56 ko)

Voir les différences:

Subject: [PATCH] lingo: accept french amount format (#35052)

 combo/apps/lingo/views.py   | 45 +++++++++++++++++++++++++------------
 tests/test_lingo_payment.py | 28 ++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 15 deletions(-)
combo/apps/lingo/views.py
26 26
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
27 27
from django.http import HttpResponseForbidden, Http404, JsonResponse
28 28
from django.template.response import TemplateResponse
29
from django.utils import timezone, dateparse
29
from django.utils import timezone, dateparse, six
30 30
from django.utils.encoding import force_text
31 31
from django.views.decorators.csrf import csrf_exempt
32 32
from django.views.generic import View, DetailView, ListView, TemplateView
......
72 72
    return check_request_signature(request, keys=keys)
73 73

  
74 74

  
75
class LocaleDecimal(Decimal):
76
    # accept , instead of . for French users comfort
77
    def __new__(cls, value="0", *args, **kwargs):
78
        if isinstance(value, six.string_types) and settings.LANGUAGE_CODE.startswith('fr-'):
79
            value = value.replace(',', '.')
80
        return super(LocaleDecimal, cls).__new__(cls, value, *args, **kwargs)
81

  
82

  
75 83
class RegiesApiView(ListView):
76 84
    model = Regie
77 85

  
......
94 102

  
95 103
    def get_amount(self, amount):
96 104
        if isinstance(amount, list):
97
            d = Decimal(sum([Decimal(a) for a in amount]))
105
            d = Decimal(sum([LocaleDecimal(a) for a in amount]))
98 106
        else:
99
            d = Decimal(amount)
107
            d = LocaleDecimal(amount)
100 108
        return d.quantize(Decimal('0.01'), ROUND_HALF_UP)
101 109

  
102 110
    def post(self, request, *args, **kwargs):
......
111 119
            raise Exception('missing amount parameter')
112 120

  
113 121
        item = BasketItem(amount=0)
114
        item.amount = self.get_amount(request.GET.getlist('amount'))
122
        try:
123
            item.amount = self.get_amount(request.GET.getlist('amount'))
124
        except ArithmeticError:
125
            return HttpResponseBadRequest('invalid value for "amount" in query string')
115 126

  
116 127
        if request_body.get('amount'):
117
            item.amount += self.get_amount(request_body['amount'])
128
            try:
129
                item.amount += self.get_amount(request_body['amount'])
130
            except ArithmeticError:
131
                return HttpResponseBadRequest('invalid value for "amount" in payload')
118 132

  
119 133
        if extra.get('amount'):
120
            item.amount += self.get_amount(extra['amount'])
134
            try:
135
                item.amount += self.get_amount(extra['amount'])
136
            except ArithmeticError:
137
                return HttpResponseBadRequest('invalid value for "amount" in extra payload')
121 138

  
122 139
        if 'extra' in request_body:
123 140
            item.request_data = request_body.get('extra')
......
234 251
            raise Http404
235 252

  
236 253
        payment = get_eopayment_object(request, transaction.regie)
237
        amount = request.GET['amount']
254
        amount = LocaleDecimal(request.GET['amount'])
238 255

  
239 256
        logger.info(u'validating amount %s for transaction %s', amount, smart_text(transaction.id))
240 257
        try:
241
            result = payment.backend.validate(Decimal(amount), transaction.bank_data)
258
            result = payment.backend.validate(amount, transaction.bank_data)
242 259
        except eopayment.ResponseError as e:
243 260
            logger.error(u'failed in validation operation: %s', e)
244 261
            response = HttpResponse(content_type='application/json')
......
247 264

  
248 265
        logger.info(u'bank validation result: %r', result)
249 266
        operation = TransactionOperation(transaction=transaction,
250
                kind='validation', amount=Decimal(amount), bank_result=result)
267
                kind='validation', amount=amount, bank_result=result)
251 268
        operation.save()
252 269

  
253 270
        response = HttpResponse(content_type='application/json')
......
275 292
            raise Http404
276 293

  
277 294
        payment = get_eopayment_object(request, transaction.regie)
278
        amount = request.GET['amount']
295
        amount = LocaleDecimal(request.GET['amount'])
279 296

  
280 297
        logger.info(u'cancelling amount %s for transaction %s', amount, smart_text(transaction.id))
281 298
        try:
282
            result = payment.backend.cancel(Decimal(amount), transaction.bank_data)
299
            result = payment.backend.cancel(amount, transaction.bank_data)
283 300
        except eopayment.ResponseError as e:
284 301
            logger.error(u'failed in cancel operation: %s', e)
285 302
            response = HttpResponse(content_type='application/json')
......
288 305

  
289 306
        logger.info(u'bank cancellation result: %r', result)
290 307
        operation = TransactionOperation(transaction=transaction,
291
                kind='cancellation', amount=Decimal(amount), bank_result=result)
308
                kind='cancellation', amount=amount, bank_result=result)
292 309
        operation.save()
293 310

  
294 311
        response = HttpResponse(content_type='application/json')
......
710 727
        except SelfDeclaredInvoicePayment.DoesNotExist:
711 728
            raise Http404()
712 729
        invoice_id = request.GET.get('invoice-number', '')
713
        invoice_amount = request.GET.get('invoice-amount', '').replace(',', '.')
730
        invoice_amount = request.GET.get('invoice-amount', '')
714 731
        msg = None
715 732
        url = None
716 733
        try:
717
            invoice_amount = Decimal(invoice_amount)
734
            invoice_amount = LocaleDecimal(invoice_amount)
718 735
        except ArithmeticError:
719 736
            invoice_amount = '-'
720 737
            msg = _('Sorry, the provided amount is invalid.')
tests/test_lingo_payment.py
12 12
from django.core.urlresolvers import reverse
13 13
from django.core.wsgi import get_wsgi_application
14 14
from django.conf import settings
15
from django.test import override_settings
15 16
from django.utils import timezone
16 17
from django.utils.six.moves.urllib import parse as urlparse
17 18
from django.contrib.messages.storage.session import SessionStorage
......
238 239
    assert json.loads(resp.content)['result'] == 'success'
239 240
    assert BasketItem.objects.filter(amount=Decimal('81.22')).exists()
240 241

  
242
    # accept french notation if settings.LANGUAGE_CODE is 'fr-*'
243
    url = '%s?amount=10,00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
244
    url = sign_url(url, key)
245
    resp = app.post_json(url, params=data, status=400)
246
    assert 'invalid value for "amount" in query string' in resp.content
247
    data['amount'] = '1,10'
248
    url = '%s?amount=10.00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
249
    url = sign_url(url, key)
250
    resp = app.post_json(url, params=data, status=400)
251
    assert 'invalid value for "amount" in payload' in resp.content
252
    data['amount'] = '1.10'
253
    data['extra'] = {'amount': '0,01'}
254
    resp = app.post_json(url, params=data, status=400)
255
    assert 'invalid value for "amount" in extra payload' in resp.content
256

  
257
    data['amount'] = '1,10'
258
    data['extra'] = {'amount': '0,01'}
259
    url = '%s?amount=10,00&email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
260
    url = sign_url(url, key)
261
    with override_settings(LANGUAGE_CODE='fr-be'):
262
        resp = app.post_json(url, params=data, status=200)
263
    assert resp.status_code == 200
264
    assert json.loads(resp.content)['result'] == 'success'
265
    assert BasketItem.objects.filter(amount=Decimal('11.11')).exists()
266

  
241 267
    other_regie.is_default = True
242 268
    other_regie.save()
243 269
    data['amount'] = []
......
408 434
    resp = resp.forms[0].submit()
409 435
    assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
410 436
    qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
411
    assert qs['amount'] == ['223.35']
437
    assert qs['amount'] == ['234.46']
412 438

  
413 439
    resp = login(app).get(page.get_online_url())
414 440
    resp = resp.forms[1].submit()
415
-