diff --git a/combo/apps/lingo/manager_views.py b/combo/apps/lingo/manager_views.py index 2897b2bc..af373085 100644 --- a/combo/apps/lingo/manager_views.py +++ b/combo/apps/lingo/manager_views.py @@ -18,13 +18,16 @@ import csv import datetime from dateutil import parser as date_parser +from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse_lazy from django.db.models import Q from django.db.models.expressions import RawSQL from django.utils import six from django.utils.timezone import make_aware, now -from django.views.generic import CreateView, UpdateView, ListView, DeleteView +from django.views.generic import CreateView, UpdateView, ListView, DeleteView, View from django.http import HttpResponse +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse import eopayment @@ -142,6 +145,20 @@ class BasketItemErrorListView(ListView): return queryset1.union(queryset2).order_by('-creation_date') +class BasketItemMarkAsNotifiedView(View): + def get(self, request, *args, **kwargs): + item = get_object_or_404( + BasketItem.objects.exclude(source_url=''), + pk=kwargs['item_id'], + regie__webservice_url='', + notification_date__isnull=True, + cancellation_date__isnull=True, + payment_date__lt=now() - datetime.timedelta(minutes=300)) + item.notify_payment(notify_origin=False) + + return HttpResponseRedirect(reverse('lingo-manager-payment-error-list')) + + def download_transactions_csv(request): if request.method == 'POST': form = TransactionExportForm(data=request.POST) diff --git a/combo/apps/lingo/models.py b/combo/apps/lingo/models.py index 7bbb1efb..83b4ded5 100644 --- a/combo/apps/lingo/models.py +++ b/combo/apps/lingo/models.py @@ -373,8 +373,9 @@ class BasketItem(models.Model): data=json.dumps(message), headers=headers, timeout=15) r.raise_for_status() - def notify_payment(self): - self.notify('paid') + def notify_payment(self, notify_origin=True): + if notify_origin: + self.notify('paid') self.notification_date = timezone.now() self.save() self.regie.compute_extra_fees(user=self.user) diff --git a/combo/apps/lingo/templates/lingo/basketitem_error_list.html b/combo/apps/lingo/templates/lingo/basketitem_error_list.html index b4102975..2f4f5e4b 100644 --- a/combo/apps/lingo/templates/lingo/basketitem_error_list.html +++ b/combo/apps/lingo/templates/lingo/basketitem_error_list.html @@ -34,6 +34,10 @@ {% if object.transaction_status != 99 %} {% trans "See transaction" %} + {% if object.source_url %} +
+ {% trans "Mark as notified" %} + {% endif %} {% endif %} diff --git a/combo/apps/lingo/urls.py b/combo/apps/lingo/urls.py index a0d0a61e..902d8954 100644 --- a/combo/apps/lingo/urls.py +++ b/combo/apps/lingo/urls.py @@ -26,11 +26,13 @@ from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView, RegieDeleteView, TransactionListView, BasketItemErrorListView, download_transactions_csv, PaymentBackendListView, PaymentBackendCreateView, PaymentBackendUpdateView, - PaymentBackendDeleteView) + PaymentBackendDeleteView, BasketItemMarkAsNotifiedView) lingo_manager_urls = [ url('^$', TransactionListView.as_view(), name='lingo-manager-homepage'), url('^payments/error/$', BasketItemErrorListView.as_view(), name='lingo-manager-payment-error-list'), + url(r'^item/(?P\d+)/mark-as-notified/$', + BasketItemMarkAsNotifiedView.as_view(), name='lingo-manager-basket-item-mark-as-notified'), url('^transactions/download-csv/$', download_transactions_csv, name='lingo-manager-transactions-download'), url('^regies/$', RegieListView.as_view(), name='lingo-manager-regie-list'), url('^regies/add/$', RegieCreateView.as_view(), name='lingo-manager-regie-add'), diff --git a/tests/test_lingo_manager.py b/tests/test_lingo_manager.py index 05ab92c5..2c7769c7 100644 --- a/tests/test_lingo_manager.py +++ b/tests/test_lingo_manager.py @@ -3,9 +3,9 @@ import datetime from django.contrib.auth.models import User -from django.core.wsgi import get_wsgi_application from django.utils.timezone import now -from webtest import TestApp + +import mock import pytest import eopayment @@ -364,33 +364,54 @@ def test_basketitem_error_list(app, admin_user, payment_backend): bank_transaction_id='bank_id_5_bis', amount=55555) transaction5_bis.items.add(item5_bis) - - # item with payment_date, no notification_date, but a cancellation_date, in the past - # => not displayed + # item with payment_date but no notification_date, in the past + # => displayed item6 = BasketItem.objects.create( user=user, regie=regie, subject='item 6', - source_url='http://example.net/6', + source_url='', # without source_url amount=6, payment_date=date_in_past, - notification_date=None, - cancellation_date=date_now) + notification_date=None) transaction6 = Transaction.objects.create( order_id='order id 6', bank_transaction_id='bank_id_6', amount=6) transaction6.items.add(item6) + # item with payment_date, no notification_date, but a cancellation_date, in the past + # => not displayed + item7 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 7', + source_url='http://example.net/7', + amount=7, + payment_date=date_in_past, + notification_date=None, + cancellation_date=date_now) + transaction7 = Transaction.objects.create( + order_id='order id 7', + bank_transaction_id='bank_id_7', + amount=7) + transaction7.items.add(item7) + app = login(app) resp = app.get('/manage/lingo/payments/error/', status=200) - assert list(resp.context['object_list']) == [item5, item3, item2] + assert list(resp.context['object_list']) == [item6, item5, item3, item2] + assert '' % item6.source_url not in resp.text assert '' % item5.source_url in resp.text assert '' % item3.source_url in resp.text assert '' % item2.source_url not in resp.text + assert '/manage/lingo/?q=%s' % transaction6.bank_transaction_id in resp.text assert '/manage/lingo/?q=%s' % transaction5.bank_transaction_id in resp.text assert '/manage/lingo/?q=%s' % transaction3.bank_transaction_id not in resp.text assert '/manage/lingo/?q=%s' % transaction22.bank_transaction_id not in resp.text + assert '/manage/lingo/item/%s/mark-as-notified/' % item6.pk not in resp.text + assert '/manage/lingo/item/%s/mark-as-notified/' % item5.pk in resp.text + assert '/manage/lingo/item/%s/mark-as-notified/' % item3.pk not in resp.text + assert '/manage/lingo/item/%s/mark-as-notified/' % item2.pk not in resp.text def test_basketitem_error_list_search(app, admin_user, payment_backend): @@ -428,6 +449,63 @@ def test_basketitem_error_list_search(app, admin_user, payment_backend): assert list(resp.context['object_list']) == [item] +def test_basketitem_mark_as_notified(app, admin_user, payment_backend): + regie = Regie.objects.create( + label='test-regie', slug='test-regie', payment_backend=payment_backend) + user = User.objects.create_user('dimebag', 'dime@bag.pan', 'pwd') + + date_now = now() + date_in_past = date_now - datetime.timedelta(minutes=300) + + item = BasketItem.objects.create( + user=user, + regie=regie, + subject='item', + source_url='http://example.net/', + amount=42, + payment_date=date_in_past, + notification_date=date_in_past) + + app = login(app) + + # notification_date is not None + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=404) + # payment_date is not old enough + item.notification_date = None + item.payment_date = date_now + item.save() + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=404) + # cancellation_date is not None + item.payment_date = date_in_past + item.cancellation_date = date_now + item.save() + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=404) + # notification_date and cancellation_date are None, payment_date is old enough + # but webservice_url is not None + item.cancellation_date = None + item.save() + regie.webservice_url = 'http://example.net' + regie.save() + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=404) + # notification_date and cancellation_date are None, payment_date is old enough + # but source_url is not set + regie.webservice_url = '' + regie.save() + item.source_url = '' + item.save() + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=404) + + # source_url is set + item.source_url = 'http://example.com' + item.save() + with mock.patch('combo.apps.lingo.models.BasketItem.notify') as mock_notify: + resp = app.get('/manage/lingo/item/%s/mark-as-notified/' % item.pk, status=302) + assert mock_notify.call_args_list == [] + assert resp.location.endswith('/manage/lingo/payments/error/') + item.refresh_from_db() + assert item.notification_date is not None + + def test_configure_tipi_cell(app, admin_user): page = Page(title='tipi', slug='tipi', template_name='standard') page.save()