From a046ddf78796bc8fa67401091132e681d9372aae Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Wed, 19 Sep 2018 17:46:16 +0200 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(-) diff --git a/combo/apps/lingo/urls.py b/combo/apps/lingo/urls.py index 33d7ac41..eede96a0 100644 --- a/combo/apps/lingo/urls.py +++ b/combo/apps/lingo/urls.py @@ -21,7 +21,7 @@ from combo.urls_utils import decorated_includes, manager_required from .views import (RegiesApiView, AddBasketItemApiView, PayView, CallbackView, ReturnView, ItemDownloadView, ItemView, CancelItemView, RemoveBasketItemApiView, ValidateTransactionApiView, - CancelTransactionApiView, SelfInvoiceView) + CancelTransactionApiView, SelfInvoiceView, BasketItemPayView) from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView, RegieDeleteView, TransactionListView, download_transactions_csv) @@ -56,6 +56,8 @@ urlpatterns = [ ItemDownloadView.as_view(), name='download-item-pdf'), url(r'^lingo/item/(?P[\w,-]+)/(?P[\w,-]+)/$', ItemView.as_view(), name='view-item'), + url(r'^lingo/item/(?P\d+)/pay$', + BasketItemPayView.as_view(), name='basket-item-pay-view'), url(r'^lingo/self-invoice/(?P\w+)/$', SelfInvoiceView.as_view(), name='lingo-self-invoice'), ] diff --git a/combo/apps/lingo/views.py b/combo/apps/lingo/views.py index 3e07d6bd..b33db475 100644 --- a/combo/apps/lingo/views.py +++ b/combo/apps/lingo/views.py @@ -165,7 +165,9 @@ class AddBasketItemApiView(View): item.regie.compute_extra_fees(user=item.user) response = HttpResponse(content_type='application/json') - response.write(json.dumps({'result': 'success', 'id': str(item.id)})) + payment_url = reverse('basket-item-pay-view', kwargs={'item_id': item.id}) + response.write(json.dumps({'result': 'success', 'id': str(item.id), + 'payment_url': request.build_absolute_uri(payment_url)})) return response @@ -391,6 +393,23 @@ class PayView(PayMixin, View): return self.handle_payment(request, regie, items, remote_items, next_url, email) +class BasketItemPayView(PayMixin, View): + def get(self, request, *args, **kwargs): + next_url = request.GET.get('next_url') or '/' + if not (request.user and request.user.is_authenticated()): + return HttpResponseForbidden(_('No item payment allowed for anonymous users.')) + + item = BasketItem.objects.get(pk=kwargs['item_id']) + regie = item.regie + if regie.extra_fees_ws_url: + return HttpResponseForbidden(_('No item payment allowed as extra fees set.')) + + if item.user != request.user: + return HttpResponseForbidden(_('Wrong item: payment not allowed.')) + + return self.handle_payment(request, regie, [item], [], next_url) + + class PaymentException(Exception): pass diff --git a/tests/test_lingo_payment.py b/tests/test_lingo_payment.py index b1186217..245cc361 100644 --- a/tests/test_lingo_payment.py +++ b/tests/test_lingo_payment.py @@ -199,8 +199,11 @@ def test_add_amount_to_basket(app, key, regie, user): url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email) url = sign_url(url, settings.LINGO_API_SIGN_KEY) resp = app.post_json(url, params=data) + item = BasketItem.objects.get(amount=Decimal('22.23')) assert resp.status_code == 200 - assert json.loads(resp.content)['result'] == 'success' + response = json.loads(resp.content) + assert response['result'] == 'success' + assert response['payment_url'].endswith('/lingo/item/%s/pay' % item.id) assert BasketItem.objects.filter(amount=Decimal('22.23')).exists() assert BasketItem.objects.filter(amount=Decimal('22.23'))[0].regie_id == other_regie.id @@ -230,6 +233,57 @@ def test_add_amount_to_basket(app, key, regie, user): resp = app.post_json(url, params=data, status=400) assert resp.text == 'Unknown regie' +def test_pay_single_basket_item(app, key, regie, user, john_doe): + page = Page(title='xxx', slug='index', template_name='standard') + page.save() + cell = LingoBasketCell(page=page, placeholder='content', order=0) + cell.save() + + amount = 12 + data = {'amount': amount, 'display_name': 'test amount', + 'url': 'http://example.com'} + url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user.email) + url = sign_url(url, key) + resp = app.post_json(url, params=data) + # check that an unpaid item exists in basket + assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=True).exists() + payment_url = json.loads(resp.content)['payment_url'] + resp = app.get(payment_url, status=403) + assert 'No item payment allowed for anonymous users.' in resp.text + + login(app, username='john.doe', password='john.doe') + resp = app.get(payment_url, status=403) + assert 'Wrong item: payment not allowed.' in resp.text + + # forbid payment to regie with extra_fees_ws_url + regie.extra_fees_ws_url = 'http://example.com/extra-fees' + regie.save() + app.reset() + login(app) + resp = app.get(payment_url, status=403) + assert 'No item payment allowed as extra fees set.' in resp.text + + regie.extra_fees_ws_url = '' + regie.save() + + resp = app.get(payment_url, params={'next_url': 'http://example.net/form/id/'}) + + # make sure the redirection is done to the payment backend + assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/') + qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query) + assert qs['amount'] == ['12.00'] + + # simulate successfull payment response from dummy backend + data = {'transaction_id': qs['transaction_id'][0], 'ok': True, + 'amount': qs['amount'][0], 'signed': True} + # simulate payment backend redirecting to /ling/return/, which is passed by + # lingo when initiating the payment + resp = app.get(qs['return_url'][0], params=data) + # check that item is paid + assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=False).exists() + # check that user is redirected to the next_url passed previously + assert resp.location == 'http://example.net/form/id/' + def test_pay_multiple_regies(app, key, regie, user): test_add_amount_to_basket(app, key, regie, user) -- 2.19.0