lingo: handle single basket item payment (#25725)

This commit is contained in:
Serghei Mihai 2018-09-19 17:46:16 +02:00
parent 13bbfa8bf1
commit a7076e6e18
3 changed files with 80 additions and 6 deletions

View File

@ -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<regie_id>[\w,-]+)/(?P<item_crypto_id>[\w,-]+)/$',
ItemView.as_view(), name='view-item'),
url(r'^lingo/item/(?P<item_id>\d+)/pay$',
BasketItemPayView.as_view(), name='basket-item-pay-view'),
url(r'^lingo/self-invoice/(?P<cell_id>\w+)/$', SelfInvoiceView.as_view(),
name='lingo-self-invoice'),
]

View File

@ -24,7 +24,7 @@ from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from django.http import HttpResponseForbidden, Http404
from django.http import HttpResponseForbidden, Http404, JsonResponse
from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.encoding import force_text
@ -164,9 +164,9 @@ class AddBasketItemApiView(View):
item.save()
item.regie.compute_extra_fees(user=item.user)
response = HttpResponse(content_type='application/json')
response.write(json.dumps({'result': 'success', 'id': str(item.id)}))
return response
payment_url = reverse('basket-item-pay-view', kwargs={'item_id': item.id})
return JsonResponse({'result': 'success', 'id': str(item.id),
'payment_url': request.build_absolute_uri(payment_url)})
class RemoveBasketItemApiView(View):
@ -391,6 +391,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

View File

@ -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,58 @@ 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 = resp.json['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 successful payment response from dummy backend
data = {'transaction_id': qs['transaction_id'][0], 'ok': True,
'amount': qs['amount'][0], 'signed': True}
# simulate payment service redirecting the user to /lingo/return/... (eopayment
# dummy module put that URL in return_url query string parameter).
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)