Projet

Général

Profil

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

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

Télécharger (6,7 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   | 21 +++++++++++++-
 tests/test_lingo_payment.py | 56 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 78 insertions(+), 3 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
165 165
        item.regie.compute_extra_fees(user=item.user)
166 166

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

  
171 173

  
......
391 393
        return self.handle_payment(request, regie, items, remote_items, next_url, email)
392 394

  
393 395

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

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

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

  
410
        return self.handle_payment(request, regie, [item], [], next_url)
411

  
412

  
394 413
class PaymentException(Exception):
395 414
    pass
396 415

  
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, 'display_name': 'test amount',
244
            'url': 'http://example.com'}
245
    url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user.email)
246
    url = sign_url(url, key)
247
    resp = app.post_json(url, params=data)
248
    # check that an unpaid item exists in basket
249
    assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=True).exists()
250
    payment_url = json.loads(resp.content)['payment_url']
251
    resp = app.get(payment_url, status=403)
252
    assert 'No item payment allowed for anonymous users.' in resp.text
253

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

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

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

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

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

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

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

  
236
-