from django.contrib import admin from django.db import models from django.urls import reverse from django.forms import BaseInlineFormSet from django.utils.html import format_html from django.conf.urls import url from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse from functools import update_wrapper from services.models import ServiceType from services.admin import ServiceAdmin from adhesions.admin import AdhesionAdmin from djadhere.utils import ActiveFilter from .models import RecurringPayment, PaymentUpdate from .utils import notify_payment_update ### Inlines class PaymentTypeFilter(admin.SimpleListFilter): title = 'type' parameter_name = 'type' def lookups(self, request, model_admin): return ( ('adhesion', 'Adhésion'), ('service', 'Service'), ) def queryset(self, request, queryset): if self.value() == 'adhesion': return queryset.filter(adhesion__isnull=False) if self.value() == 'service': return queryset.filter(service__isnull=False) class PendingPaymentFilter(admin.SimpleListFilter): title = 'opérations en attente' parameter_name = 'pending' def lookups(self, request, model_admin): return ( (0, 'À jour'), (1, 'En attente'), ) def queryset(self, request, queryset): pending = PaymentUpdate.objects.filter(validated=False).values_list('payment__pk', flat=True) if self.value() == '0': return queryset.exclude(pk__in=pending) if self.value() == '1': return queryset.filter(pk__in=pending) ### Inlines class PendingPaymentUpdateFormSet(BaseInlineFormSet): def save_new(self, form, commit=True): obj = super().save_new(form, commit) if not obj.validated: notify_payment_update(self.request, obj) return obj def save_existing(self, form, instance, commit=True): old = PaymentUpdate.objects.get(pk=instance.pk) if not instance.validated: notify_payment_update(self.request, instance, old) return super().save_existing(form, instance, commit) class PendingPaymentUpdateInline(admin.TabularInline): model = PaymentUpdate formset = PendingPaymentUpdateFormSet extra = 1 verbose_name_plural = 'En attente de saisie bancaire' def get_formset(self, request, obj=None, **kwargs): formset = super().get_formset(request, obj, **kwargs) formset.request = request return formset def get_queryset(self, request): return super().get_queryset(request).filter(validated=False) class ValidatedPaymentUpdateInline(admin.TabularInline): model = PaymentUpdate verbose_name_plural = 'Historique' max_num = 0 fields = ('amount', 'period', 'payment_method', 'start',) readonly_fields = ('amount', 'period', 'payment_method', 'start',) def has_delete_permission(self, request, obj=None): return False def get_queryset(self, request): return super().get_queryset(request).filter(validated=True) ### Helpers def prefix_search_field(prefix, field): if field[0] == '=': return '=' + prefix + '__' + field[1:] else: return prefix + '__' + field ### ModelAdmin class RecurringPaymentAdmin(admin.ModelAdmin): list_display = ('id', 'payment_type', 'payment_object_link', 'get_active', 'get_pending',) list_select_related = ('adhesion', 'service', 'service__service_type',) inlines = (PendingPaymentUpdateInline, ValidatedPaymentUpdateInline,) list_filter = (PaymentTypeFilter, ActiveFilter, PendingPaymentFilter,) fields = ('payment_type', 'payment_object_link', 'debtor_link',) readonly_fields = ('payment_type', 'payment_object_link', 'debtor_link',) search_fields = \ tuple([prefix_search_field('adhesion', f) for f in AdhesionAdmin.search_fields]) \ + tuple([prefix_search_field('service', f) for f in ServiceAdmin.search_fields]) def get_queryset(self, request): qs = super().get_queryset(request) qs = qs.prefetch_related('updates') qs = qs.prefetch_related( models.Prefetch( 'updates', queryset=PaymentUpdate.objects.filter(validated=False), to_attr='pending_updates' ) ) return qs def get_pending(self, obj): return len(obj.pending_updates) get_pending.short_description = 'Opérations en attente' def get_active(self, obj): return obj.active get_active.short_description = 'Actif' get_active.boolean = True def payment_object_link(self, obj): obj = obj.payment_object() return format_html(u'{}', obj.get_absolute_url(), obj) payment_object_link.short_description = 'Objet' def debtor_link(self, obj): url = reverse(viewname='admin:%s_%s_debtor' % (obj._meta.app_label, obj._meta.model_name), args=[obj.pk]) return format_html(u'{}', url, obj.debtor) debtor_link.short_description = 'Débiteur' def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False def get_urls(self): info = self.model._meta.app_label, self.model._meta.model_name urls = [ url(r'^(.*)/debtor/$', self.admin_site.admin_view(self.debtor_view), name='%s_%s_debtor' % info), ] return urls + super().get_urls() def debtor_view(self, request, payment_pk): payment = get_object_or_404(RecurringPayment, pk=payment_pk) adhesion = payment.debtor if adhesion.is_physical(): profile = adhesion.user.profile else: profile = adhesion.corporation context = dict( self.admin_site.each_context(request), opts=self.model._meta, payment=payment, adhesion=adhesion, adherent=adhesion.adherent, profile=profile, ) return TemplateResponse(request, 'banking/debtor.html', context) admin.site.register(RecurringPayment, RecurringPaymentAdmin)