diff --git a/orchestra/contrib/bills/admin.py b/orchestra/contrib/bills/admin.py index 4c5c55fb..10301e09 100644 --- a/orchestra/contrib/bills/admin.py +++ b/orchestra/contrib/bills/admin.py @@ -4,7 +4,7 @@ from django.contrib import admin, messages from django.contrib.admin.utils import unquote from django.core.urlresolvers import reverse from django.db import models -from django.db.models import F, Sum +from django.db.models import F, Sum, Prefetch from django.db.models.functions import Coalesce from django.templatetags.static import static from django.utils.safestring import mark_safe @@ -17,8 +17,10 @@ from orchestra.contrib.accounts.admin import AccountAdminMixin, AccountAdmin from orchestra.forms.widgets import paddingCheckboxSelectMultiple from . import settings, actions -from .filters import BillTypeListFilter, HasBillContactListFilter, TotalListFilter, PaymentStateListFilter -from .models import Bill, Invoice, AmendmentInvoice, Fee, AmendmentFee, ProForma, BillLine, BillContact +from .filters import (BillTypeListFilter, HasBillContactListFilter, TotalListFilter, + PaymentStateListFilter, AmendedListFilter) +from .models import (Bill, Invoice, AmendmentInvoice, Fee, AmendmentFee, ProForma, BillLine, + BillContact) PAYMENT_STATE_COLORS = { @@ -185,8 +187,12 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): 'number', 'type_link', 'account_link', 'created_on_display', 'num_lines', 'display_total', 'display_payment_state', 'is_open', 'is_sent' ) - list_filter = (BillTypeListFilter, 'is_open', 'is_sent', TotalListFilter, PaymentStateListFilter) + list_filter = ( + BillTypeListFilter, 'is_open', 'is_sent', TotalListFilter, PaymentStateListFilter, + AmendedListFilter + ) add_fields = ('account', 'type', 'amend_of', 'is_open', 'due_on', 'comments') + change_list_template = 'admin/bills/change_list.html' fieldsets = ( (None, { 'fields': ('number', 'type', 'amend_of_link', 'account_link', 'display_total', @@ -243,9 +249,13 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): url = reverse('admin:%s_%s_changelist' % (t_opts.app_label, t_opts.model_name)) url += '?bill=%i' % bill.pk state = bill.get_payment_state_display().upper() + title = '' + if bill.closed_amends: + state += '*' + title = _("This bill has been amended, this value may not be valid.") color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey') - return '{name}'.format( - url=url, color=color, name=state) + return '{name}'.format( + url=url, color=color, name=state, title=title) display_payment_state.allow_tags = True display_payment_state.short_description = _("Payment") @@ -309,6 +319,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): (F('lines__subtotal') + Coalesce(F('lines__sublines__total'), 0)) * (1+F('lines__tax')/100) ), ) + qs = qs.prefetch_related(Prefetch('amends', queryset=Bill.objects.filter(is_open=False), to_attr='closed_amends')) return qs def change_view(self, request, object_id, **kwargs): diff --git a/orchestra/contrib/bills/filters.py b/orchestra/contrib/bills/filters.py index 8df9ffee..dae95794 100644 --- a/orchestra/contrib/bills/filters.py +++ b/orchestra/contrib/bills/filters.py @@ -91,7 +91,6 @@ class PaymentStateListFilter(SimpleListFilter): ('PAID', _("Paid")), ('PENDING', _("Pending")), ('BAD_DEBT', _("Bad debt")), - ('AMENDED', _("Amended")), ) def queryset(self, request, queryset): @@ -128,7 +127,29 @@ class PaymentStateListFilter(SimpleListFilter): Q(transactions__state=Transaction.REJECTED) | Q(transactions__isnull=True) ) - elif self.value() == 'AMENDED': - amendeds = queryset.filter(type__in=Bill.AMEND_MAP.values(), is_open=False) - amendeds_ids = amendeds.values_list('amend_of', flat=True) - return queryset.filter(id__in=amendeds) + + +class AmendedListFilter(SimpleListFilter): + title = _("amended") + parameter_name = 'amended' + + def lookups(self, request, model_admin): + return ( + ('1', _("Closed amends")), + ('-1', _("Open or closed amends")), + ('0', _("No closed amends")), + ('-0', _("No amends")), + ) + + def queryset(self, request, queryset): + if self.value() is None: + return queryset + amended = queryset.filter(type__in=Bill.AMEND_MAP.values(), amend_of__isnull=False) + if not self.value().startswith('-'): + amended = amended.filter(is_open=False) + amended_ids = amended.distinct().values_list('amend_of_id', flat=True) + if self.value().endswith('1'): + return queryset.filter(id__in=amended_ids) + else: + return queryset.exclude(id__in=amended_ids) + diff --git a/orchestra/contrib/bills/models.py b/orchestra/contrib/bills/models.py index d7d933ea..84166d81 100644 --- a/orchestra/contrib/bills/models.py +++ b/orchestra/contrib/bills/models.py @@ -140,8 +140,6 @@ class Bill(models.Model): def payment_state(self): if self.is_open or self.get_type() == self.PROFORMA: return self.OPEN - elif self.amends.filter(is_open=False).exists(): - return self.AMENDED secured = 0 pending = 0 created = False diff --git a/orchestra/contrib/bills/templates/admin/bills/change_list.html b/orchestra/contrib/bills/templates/admin/bills/change_list.html new file mode 100644 index 00000000..da8cbc0e --- /dev/null +++ b/orchestra/contrib/bills/templates/admin/bills/change_list.html @@ -0,0 +1,12 @@ +{% extends "admin/change_list.html" %} +{% load i18n admin_urls %} + + +{% block object-tools-items %} +