diff --git a/lingo/urls.py b/lingo/urls.py index 70193c3..8ad1e37 100644 --- a/lingo/urls.py +++ b/lingo/urls.py @@ -19,7 +19,7 @@ from django.conf.urls import patterns, url, include from combo.urls_utils import decorated_includes, manager_required from .views import (RegiesApiView, AddBasketItemApiView, PayView, CallbackView, - ItemDownloadView, ItemView) + ReturnView, ItemDownloadView, ItemView) from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView, RegieDeleteView) @@ -38,6 +38,7 @@ urlpatterns = patterns('', name='api-add-basket-item'), url('^lingo/pay$', PayView.as_view(), name='lingo-pay'), url(r'^lingo/callback/(?P\w+)/$', CallbackView.as_view(), name='lingo-callback'), + url(r'^lingo/return/(?P\w+)/$', ReturnView.as_view(), name='lingo-return'), url(r'^manage/lingo/', decorated_includes(manager_required, include(lingo_manager_urls))), url(r'^lingo/item/(?P[\w,-]+)/(?P[\w,-]+)/pdf$', diff --git a/lingo/views.py b/lingo/views.py index a5418d0..009d7f8 100644 --- a/lingo/views.py +++ b/lingo/views.py @@ -141,11 +141,7 @@ class PayView(View): reverse('lingo-callback', kwargs={'regie_pk': regie.id})) (order_id, kind, data) = payment.request(total_amount, email=request.user.email, - next_url=request.build_absolute_uri('/'), - accepturl=return_url, - declineurl=return_url, - exceptionurl=return_url, - cancelurl=return_url) + next_url=return_url) transaction.order_id = order_id transaction.save() @@ -178,7 +174,7 @@ class CallbackView(View): assert transaction.regie == regie if payment_response.result != eopayment.PAID: - return HttpResponseRedirect('/') + return HttpResponse() for item in transaction.items.all(): item.payment_date = transaction.end_date @@ -192,7 +188,34 @@ class CallbackView(View): for item in transaction.remote_items.split(','): regie.pay_item(request, item) - return HttpResponseRedirect('/') + return HttpResponse() + + +class ReturnView(View): + + def get(self, request, *args, **kwargs): + regie = Regie.objects.get(id=kwargs.get('regie_pk')) + payment = eopayment.Payment(regie.service, regie.service_options) + try: + payment_response = payment.response(request.environ['QUERY_STRING']) + except: + # if eopayment can't get response from query string redirect to + # homepage + return HttpResponseRedirect('/') + + transaction = Transaction.objects.get(order_id=payment_response.order_id) + + if transaction.items: + # redirect to first transaction local item view + return HttpResponseRedirect(reverse('view-item', + kwargs={'regie_id': regie.pk, + 'item_id': transaction.items[0].id})) + if transaction.remote_items: + # redirect to first transaction remote item view + item = transaction.remote_items.split(',')[0] + return HttpResponseRedirect(reverse('view-item', + kwargs={'regie_id': regie.pk, + 'item_id': item.id})) class ItemDownloadView(View): diff --git a/tests/test_payment.py b/tests/test_payment.py new file mode 100644 index 0000000..529929f --- /dev/null +++ b/tests/test_payment.py @@ -0,0 +1,82 @@ +import pytest +from datetime import datetime, timedelta +import urlparse +from decimal import Decimal + +from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from django.core.wsgi import get_wsgi_application +from webtest import TestApp + +from django.test import Client + +from lingo.models import Regie, BasketItem, Transaction, RemoteItem + +pytestmark = pytest.mark.django_db + +client = Client() + +@pytest.fixture +def regie(): + try: + regie = Regie.objects.get(slug='test') + except Regie.DoesNotExist: + regie = Regie() + regie.label = 'Test' + regie.slug = 'test' + regie.description = 'test' + regie.payment_min_amount = Decimal(4.5) + regie.service = 'dummy' + regie.service_options = {'siret': '1234'} + regie.save() + return regie + +@pytest.fixture +def user(): + try: + user = User.objects.get(username='admin') + except User.DoesNotExist: + user = User.objects.create_user('admin', email=None, password='admin') + return user + +def login(username='admin', password='admin'): + resp = client.post('/login/', {'username': username, 'password': password}) + assert resp.status_code == 302 + +def test_payment_min_amount(regie, user): + items = {'item1': {'amount': '1.5', 'source_url': '/item/1'}, + 'item2': {'amount': '2.4', 'source_url': '/item/2'} + } + b_items = [] + for subject, details in items.iteritems(): + b_item = BasketItem.objects.create(user=user, regie=regie, + subject=subject, **details) + b_items.append(b_item.pk) + login() + resp = client.post(reverse('lingo-pay'), {'item': b_items, 'regie': regie.pk}) + assert resp.status_code == 403 + +def test_successfull_items_payment(regie, user): + items = {'item1': {'amount': '10.5', 'source_url': '/item/1'}, + 'item2': {'amount': '42', 'source_url': '/item/2'}, + 'item3': {'amount': '100', 'source_url': '/item/3'}, + 'item4': {'amount': '354', 'source_url': '/item/4'} + } + b_items = [] + for subject, details in items.iteritems(): + b_item = BasketItem.objects.create(user=user, regie=regie, + subject=subject, **details) + b_items.append(b_item.pk) + login() + resp = client.post(reverse('lingo-pay'), {'item': b_items, 'regie': regie.pk}) + assert resp.status_code == 302 + location = resp.get('location') + assert 'dummy-payment' in location + parsed = urlparse.urlparse(location) + # get return_url and transaction id from location + qs = urlparse.parse_qs(parsed.query) + args = {'transaction_id': qs['transaction_id'][0], 'signed': True, + 'ok': True, 'reason': 'Paid'} + # simulate backend callback call + resp = client.get(qs['return_url'][0], args) + assert resp.status_code == 200