Projet

Général

Profil

0001-lingo-handle-single-basket-item-payment-25725.patch

Serghei Mihai (congés, retour 15/05), 03 octobre 2018 23:33

Télécharger (7,25 ko)

Voir les différences:

Subject: [PATCH] lingo: handle single basket item payment (#25725)

 combo/apps/lingo/urls.py    |  4 ++-
 combo/apps/lingo/views.py   | 25 +++++++++++++---
 tests/test_lingo_payment.py | 57 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 80 insertions(+), 6 deletions(-)
combo/apps/lingo/urls.py
21 21
from .views import (RegiesApiView, AddBasketItemApiView, PayView, CallbackView,
22 22
                    ReturnView, ItemDownloadView, ItemView, CancelItemView,
23 23
                    RemoveBasketItemApiView, ValidateTransactionApiView,
24
                    CancelTransactionApiView, SelfInvoiceView)
24
                    CancelTransactionApiView, SelfInvoiceView, BasketItemPayView)
25 25
from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView,
26 26
        RegieDeleteView, TransactionListView, download_transactions_csv)
27 27

  
......
56 56
        ItemDownloadView.as_view(), name='download-item-pdf'),
57 57
    url(r'^lingo/item/(?P<regie_id>[\w,-]+)/(?P<item_crypto_id>[\w,-]+)/$',
58 58
        ItemView.as_view(), name='view-item'),
59
    url(r'^lingo/item/(?P<item_id>\d+)/pay$',
60
        BasketItemPayView.as_view(), name='basket-item-pay-view'),
59 61
    url(r'^lingo/self-invoice/(?P<cell_id>\w+)/$', SelfInvoiceView.as_view(),
60 62
        name='lingo-self-invoice'),
61 63
]
combo/apps/lingo/views.py
24 24
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
25 25
from django.core.urlresolvers import reverse
26 26
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
27
from django.http import HttpResponseForbidden, Http404
27
from django.http import HttpResponseForbidden, Http404, JsonResponse
28 28
from django.template.response import TemplateResponse
29 29
from django.utils import timezone
30 30
from django.utils.encoding import force_text
......
164 164
        item.save()
165 165
        item.regie.compute_extra_fees(user=item.user)
166 166

  
167
        response = HttpResponse(content_type='application/json')
168
        response.write(json.dumps({'result': 'success', 'id': str(item.id)}))
169
        return response
167
        payment_url = reverse('basket-item-pay-view', kwargs={'item_id': item.id})
168
        return JsonResponse({'result': 'success', 'id': str(item.id),
169
                             'payment_url': request.build_absolute_uri(payment_url)})
170 170

  
171 171

  
172 172
class RemoveBasketItemApiView(View):
......
391 391
        return self.handle_payment(request, regie, items, remote_items, next_url, email)
392 392

  
393 393

  
394
class BasketItemPayView(PayMixin, View):
395
    def get(self, request, *args, **kwargs):
396
        next_url = request.GET.get('next_url') or '/'
397
        if not (request.user and request.user.is_authenticated()):
398
            return HttpResponseForbidden(_('No item payment allowed for anonymous users.'))
399

  
400
        item = BasketItem.objects.get(pk=kwargs['item_id'])
401
        regie = item.regie
402
        if regie.extra_fees_ws_url:
403
            return HttpResponseForbidden(_('No item payment allowed as extra fees set.'))
404

  
405
        if item.user != request.user:
406
            return HttpResponseForbidden(_('Wrong item: payment not allowed.'))
407

  
408
        return self.handle_payment(request, regie, [item], [], next_url)
409

  
410

  
394 411
class PaymentException(Exception):
395 412
    pass
396 413

  
tests/test_lingo_payment.py
199 199
    url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
200 200
    url = sign_url(url, settings.LINGO_API_SIGN_KEY)
201 201
    resp = app.post_json(url, params=data)
202
    item = BasketItem.objects.get(amount=Decimal('22.23'))
202 203
    assert resp.status_code == 200
203
    assert json.loads(resp.content)['result'] == 'success'
204
    response = json.loads(resp.content)
205
    assert response['result'] == 'success'
206
    assert response['payment_url'].endswith('/lingo/item/%s/pay' % item.id)
204 207
    assert BasketItem.objects.filter(amount=Decimal('22.23')).exists()
205 208
    assert BasketItem.objects.filter(amount=Decimal('22.23'))[0].regie_id == other_regie.id
206 209

  
......
230 233
    resp = app.post_json(url, params=data, status=400)
231 234
    assert resp.text == 'Unknown regie'
232 235

  
236
def test_pay_single_basket_item(app, key, regie, user, john_doe):
237
    page = Page(title='xxx', slug='index', template_name='standard')
238
    page.save()
239
    cell = LingoBasketCell(page=page, placeholder='content', order=0)
240
    cell.save()
241

  
242
    amount = 12
243
    data = {'amount': amount,
244
            'display_name': 'test amount',
245
            'url': 'http://example.com'}
246
    url = '%s?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)
249
    # check that an unpaid item exists in basket
250
    assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=True).exists()
251
    payment_url = resp.json['payment_url']
252
    resp = app.get(payment_url, status=403)
253
    assert 'No item payment allowed for anonymous users.' in resp.text
254

  
255
    login(app, username='john.doe', password='john.doe')
256
    resp = app.get(payment_url, status=403)
257
    assert 'Wrong item: payment not allowed.' in resp.text
258

  
259
    # forbid payment to regie with extra_fees_ws_url
260
    regie.extra_fees_ws_url = 'http://example.com/extra-fees'
261
    regie.save()
262
    app.reset()
263
    login(app)
264
    resp = app.get(payment_url, status=403)
265
    assert 'No item payment allowed as extra fees set.' in resp.text
266

  
267
    regie.extra_fees_ws_url = ''
268
    regie.save()
269

  
270
    resp = app.get(payment_url, params={'next_url': 'http://example.net/form/id/'})
271

  
272
    # make sure the redirection is done to the payment backend
273
    assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
274
    qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
275
    assert qs['amount'] == ['12.00']
276

  
277
    # simulate successful payment response from dummy backend
278
    data = {'transaction_id': qs['transaction_id'][0], 'ok': True,
279
            'amount': qs['amount'][0], 'signed': True}
280
    # simulate payment service redirecting the user to /lingo/return/... (eopayment
281
    # dummy module put that URL in return_url query string parameter).
282
    resp = app.get(qs['return_url'][0], params=data)
283
    # check that item is paid
284
    assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=False).exists()
285
    # check that user is redirected to the next_url passed previously
286
    assert resp.location == 'http://example.net/form/id/'
287

  
233 288
def test_pay_multiple_regies(app, key, regie, user):
234 289
    test_add_amount_to_basket(app, key, regie, user)
235 290

  
236
-