diff --git a/combo/apps/lingo/manager_views.py b/combo/apps/lingo/manager_views.py index 0dc5fd36..1c264701 100644 --- a/combo/apps/lingo/manager_views.py +++ b/combo/apps/lingo/manager_views.py @@ -20,8 +20,9 @@ from dateutil import parser as date_parser 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 +from django.utils.timezone import make_aware, now from django.views.generic import CreateView, UpdateView, ListView, DeleteView from django.http import HttpResponse from django.template.response import TemplateResponse @@ -30,7 +31,7 @@ import eopayment from .forms import RegieForm from .forms import TransactionExportForm -from .models import PaymentBackend, Regie, Transaction +from .models import BasketItem, PaymentBackend, Regie, Transaction class RegieListView(ListView): @@ -103,6 +104,34 @@ class TransactionListView(ListView): return qs +class BasketItemErrorListView(ListView): + model = BasketItem + template_name = 'lingo/basketitem_error_list.html' + paginate_by = 10 + + def get_queryset(self): + raw = ( + 'SELECT %s FROM lingo_transaction ' + 'INNER JOIN lingo_transaction_items ' + 'ON "lingo_transaction"."id" = "lingo_transaction_items"."transaction_id" ' + 'AND "lingo_transaction_items"."basketitem_id"="lingo_basketitem"."id" ' + 'ORDER BY start_date DESC LIMIT 1') + queryset = ( + BasketItem.objects + .annotate(bank_transaction_id=RawSQL(raw % 'bank_transaction_id', [])) + .annotate(transaction_status=RawSQL(raw % 'status', [])) + .filter(regie__webservice_url='') + .order_by()) + queryset1 = ( + queryset + .filter( + notification_date__isnull=True, + cancellation_date__isnull=True, + payment_date__lt=now() - datetime.timedelta(minutes=300))) + queryset2 = queryset.filter(transaction_status=eopayment.ERROR) + return queryset1.union(queryset2).order_by('-creation_date') + + def download_transactions_csv(request): if request.method == 'POST': form = TransactionExportForm(data=request.POST) diff --git a/combo/apps/lingo/templates/lingo/basketitem_error_list.html b/combo/apps/lingo/templates/lingo/basketitem_error_list.html new file mode 100644 index 00000000..a689e379 --- /dev/null +++ b/combo/apps/lingo/templates/lingo/basketitem_error_list.html @@ -0,0 +1,50 @@ +{% extends "lingo/manager_base.html" %} +{% load i18n %} + +{% block appbar %} +

{% trans 'Payments in error' %}

+{% endblock %} + +{% block breadcrumb %} +{{ block.super }} +{% trans 'Payments in error' %} +{% endblock %} + +{% block content %} + +{% if object_list %} + + + + + + + + + +{% for object in object_list %} + + + + + + +{% endfor %} + +
{% trans 'Item' %}{% trans 'Amount' %}{% trans 'Date' %}
{% if object.source_url %}{{ object.subject }}{% else %}{{ object.subject }}{% endif %}{{ object.amount }} €{{ object.payment_date }} + {% if object.transaction_status != 99 %} + {% trans "See transaction" %} + {% endif %} +
+ +{% include "gadjo/pagination.html" %} + +{% else %} +
+ {% blocktrans %} + This site doesn't have any payment in error. + {% endblocktrans %} +
+{% endif %} + +{% endblock %} diff --git a/combo/apps/lingo/templates/lingo/transaction_list.html b/combo/apps/lingo/templates/lingo/transaction_list.html index 25300308..6dd650f2 100644 --- a/combo/apps/lingo/templates/lingo/transaction_list.html +++ b/combo/apps/lingo/templates/lingo/transaction_list.html @@ -4,6 +4,7 @@ {% block appbar %}

{% trans 'Transactions' %}

+{% trans 'Payments in error' %} {% trans 'Payment backends' %} {% trans 'Regies' %} {% trans 'download CSV' %} diff --git a/combo/apps/lingo/urls.py b/combo/apps/lingo/urls.py index 5498d9f1..a0d0a61e 100644 --- a/combo/apps/lingo/urls.py +++ b/combo/apps/lingo/urls.py @@ -23,12 +23,14 @@ from .views import (RegiesApiView, AddBasketItemApiView, PayView, CallbackView, RemoveBasketItemApiView, ValidateTransactionApiView, CancelTransactionApiView, SelfInvoiceView, BasketItemPayView) from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView, - RegieDeleteView, TransactionListView, download_transactions_csv, - PaymentBackendListView, PaymentBackendCreateView, - PaymentBackendUpdateView, PaymentBackendDeleteView) + RegieDeleteView, TransactionListView, BasketItemErrorListView, + download_transactions_csv, PaymentBackendListView, + PaymentBackendCreateView, PaymentBackendUpdateView, + PaymentBackendDeleteView) lingo_manager_urls = [ url('^$', TransactionListView.as_view(), name='lingo-manager-homepage'), + url('^payments/error/$', BasketItemErrorListView.as_view(), name='lingo-manager-payment-error-list'), 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 34212420..f1f4c42d 100644 --- a/tests/test_lingo_manager.py +++ b/tests/test_lingo_manager.py @@ -227,6 +227,172 @@ def test_transactions_search(app, admin_user): assert resp.text.count(' not displayed + item1 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 1', + source_url='http://example.net/1', + amount=1, + payment_date=date_in_past, + notification_date=date_in_past) + transaction11 = Transaction.objects.create( + status=eopayment.ERROR, + order_id='order id 1.1', + bank_transaction_id='bank_id_11', + amount=1) + transaction11.items.add(item1) + transaction12 = Transaction.objects.create( + status=eopayment.PAID, + order_id='order id 1.2', + bank_transaction_id='bank_id_12', + amount=1) + transaction12.items.add(item1) + + # item with payment_date and notification_date, status ERROR + # => displayed + item2 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 2', + source_url='', + amount=2, + payment_date=date_in_past, + notification_date=date_in_past) + transaction21 = Transaction.objects.create( + status=eopayment.ERROR, + order_id='order id 2.1', + bank_transaction_id='bank_id_21', + amount=2) + transaction21.items.add(item2) + transaction22 = Transaction.objects.create( + status=eopayment.ERROR, + order_id='order id 2.2', + bank_transaction_id='bank_id_22', + amount=2) + transaction22.items.add(item2) + # the same but for the other regie + item2_bis = BasketItem.objects.create( + user=user, + regie=regie_with_webservice_url, + subject='item 2 bis', + source_url='', + amount=22222, + payment_date=date_in_past, + notification_date=date_in_past) + transaction2_bis = Transaction.objects.create( + status=eopayment.ERROR, + order_id='order id 2 bis', + bank_transaction_id='bank_id_2_bis', + amount=22222) + transaction2_bis.items.add(item2_bis) + + # item without dates, status ERROR + # => displayed + item3 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 3', + source_url='http://example.net/3', + amount=3) + transaction3 = Transaction.objects.create( + status=eopayment.ERROR, + order_id='order id 3', + bank_transaction_id='bank_id_3', + amount=3) + transaction3.items.add(item3) + + # item with payment_date but no notification_date, too young + # => not displayed + item4 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 4', + source_url='http://example.net/4', + amount=4, + payment_date=date_now, + notification_date=None) + transaction4 = Transaction.objects.create( + order_id='order id 4', + bank_transaction_id='bank_id_4', + amount=4) + transaction4.items.add(item4) + + # item with payment_date but no notification_date, in the past + # => displayed + item5 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 5', + source_url='http://example.net/5', + amount=5, + payment_date=date_in_past, + notification_date=None) + transaction5 = Transaction.objects.create( + order_id='order id 5', + bank_transaction_id='bank_id_5', + amount=5) + transaction5.items.add(item5) + # the same but for the other regie + item5_bis = BasketItem.objects.create( + user=user, + regie=regie_with_webservice_url, + subject='item 5 bis', + source_url='http://example.net/5_bis', + amount=55555, + payment_date=date_in_past, + notification_date=None) + transaction5_bis = Transaction.objects.create( + order_id='order id 5 bis', + 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 + item6 = BasketItem.objects.create( + user=user, + regie=regie, + subject='item 6', + source_url='http://example.net/6', + amount=6, + payment_date=date_in_past, + notification_date=None, + cancellation_date=date_now) + transaction6 = Transaction.objects.create( + order_id='order id 6', + bank_transaction_id='bank_id_6', + amount=6) + transaction6.items.add(item6) + + app = login(app) + resp = app.get('/manage/lingo/payments/error/', status=200) + assert list(resp.context['object_list']) == [item5, item3, item2] + 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' % 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 + + def test_configure_tipi_cell(app, admin_user): page = Page(title='tipi', slug='tipi', template_name='standard') page.save()