Projet

Général

Profil

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

Thomas Noël, 26 juillet 2019 15:53

Télécharger (8,55 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 == 'fr-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
......
236 237
    assert json.loads(resp.content)['result'] == 'success'
237 238
    assert BasketItem.objects.filter(amount=Decimal('81.22')).exists()
238 239

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

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

  
239 265
    other_regie.is_default = True
240 266
    other_regie.save()
241 267
    data['amount'] = []
......
406 432
    resp = resp.forms[0].submit()
407 433
    assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
408 434
    qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
409
    assert qs['amount'] == ['223.35']
435
    assert qs['amount'] == ['234.46']
410 436

  
411 437
    resp = login(app).get(page.get_online_url())
412 438
    resp = resp.forms[1].submit()
413
-