Browse Source

amélioration de l’interface de la banque

Élie Bouttier 7 years ago
parent
commit
f7b9f5e30f

+ 1 - 1
adhesions/admin.py

@@ -240,7 +240,7 @@ class AdhesionAdmin(AdtSearchMixin, admin.ModelAdmin):
     get_id.admin_order_field = 'id'
 
     def get_membership_link(self, obj):
-        return format_html(u'<a href="{}">{}</a>', obj.membership.get_absolute_url(), obj.membership)
+        return format_html(u'<a href="{}">{}</a>', obj.membership.get_absolute_url(), obj.membership.get_current_payment_display())
     get_membership_link.short_description = 'Cotisation'
 
     def get_antennas_link(self, obj):

+ 135 - 54
banking/admin.py

@@ -19,23 +19,6 @@ 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 PaymentMethodFilter(admin.SimpleListFilter):
     title = 'méthode de paiement'
     parameter_name = 'method'
@@ -46,24 +29,74 @@ class PaymentMethodFilter(admin.SimpleListFilter):
     def queryset(self, request, queryset):
         if self.value() is not None:
             return queryset.filter(payment_method=self.value())
+        else:
+            return queryset.exclude(payment_method=PaymentUpdate.STOP)
 
 
 class PendingPaymentFilter(admin.SimpleListFilter):
-    title = 'opérations en attente'
-    parameter_name = 'pending'
+    title = 'statut'
+    parameter_name = 'status'
 
     def lookups(self, request, model_admin):
         return (
-            (0, 'À jour'),
-            (1, 'En attente'),
+            ('up-to-date', 'À jour'),
+            ('pending', '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)
+        if self.value() == 'up-to-date':
+            queryset = queryset.filter(last=True)
+        if self.value() == 'pending':
+            queryset = queryset.filter(last=False)
+        return queryset
+        payments = RecurringPayment.objects.annotate(
+            validated=models.Subquery(
+                            PaymentUpdate.objects.filter(payment=models.OuterRef('pk'))
+                                                 .filter(validated=True)
+                                                 .order_by('-start')
+                                                 .values('pk')[:1]
+            ),
+            pending=models.Subquery(
+                            PaymentUpdate.objects.filter(payment=models.OuterRef('pk'))
+                                                 .filter(validated=False)
+                                                 .order_by('-start')
+                                                 .values('pk')[:1]
+            ),
+        )
+        up_to_date = payments.filter(pending__isnull=True)
+        pending = payments.exclude(pending__isnull=True)
+        if self.value() == 'up-to-date':
+            p = up_to_date
+        elif self.value() == 'pending':
+            p = pending
+        else:
+            p = payments
+        queryset = queryset.filter(pk__in=p.values_list('validated', flat=True))
+        queryset = queryset.annotate(
+            last=models.Case(
+                models.When(pk__in=up_to_date.values_list('validated', flat=True), then=True),
+                default=False,
+                output_field=models.BooleanField(),
+            ),
+        )
+        return queryset
+
+
+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(payment__adhesion__isnull=False)
+        if self.value() == 'service':
+            return queryset.filter(payment__service__isnull=False)
 
 
 ### Inlines
@@ -86,7 +119,8 @@ class PendingPaymentUpdateInline(admin.TabularInline):
     model = PaymentUpdate
     formset = PendingPaymentUpdateFormSet
     extra = 1
-    verbose_name_plural = 'En attente de saisie bancaire'
+    max_num = 1
+    verbose_name_plural = 'Demande de saisie bancaire'
 
     def get_formset(self, request, obj=None, **kwargs):
         formset = super().get_formset(request, obj, **kwargs)
@@ -123,36 +157,9 @@ def prefix_search_field(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, PaymentMethodFilter, 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()
@@ -173,6 +180,9 @@ class RecurringPaymentAdmin(admin.ModelAdmin):
     def has_add_permission(self, request, obj=None):
         return False
 
+    def has_change_permission(self, request, obj=None):
+        return obj
+
     def has_delete_permission(self, request, obj=None):
         return False
 
@@ -201,4 +211,75 @@ class RecurringPaymentAdmin(admin.ModelAdmin):
         return TemplateResponse(request, 'banking/debtor.html', context)
 
 
+class PaymentUpdateAdmin(admin.ModelAdmin):
+    list_display = ('payment_type', 'payment_object_link', 'payment_link', 'last',)
+    list_select_related = ('payment', 'payment__adhesion', 'payment__service', 'payment__service__service_type',)
+    list_filter = (PaymentTypeFilter, PaymentMethodFilter, PendingPaymentFilter,)
+    list_display_links = None
+    search_fields = \
+        tuple([prefix_search_field('payment__adhesion', f) for f in AdhesionAdmin.search_fields]) \
+        + tuple([prefix_search_field('payment__service', f) for f in ServiceAdmin.search_fields])
+
+    def last(self, obj):
+        return obj.last
+    last.boolean = True
+    last.short_description = 'À jour'
+
+    def payment_type(self, update):
+        return update.payment.payment_type()
+    payment_type.short_description = 'Type'
+
+    def payment_object_link(self, update):
+        obj = update.payment.payment_object()
+        return format_html(u'<a href="{}">{}</a>', obj.get_absolute_url(), obj)
+    payment_object_link.short_description = 'Objet'
+
+    def payment_link(self, update):
+        payment = update.payment
+        return format_html(u'<a href="{}">{}</a>', payment.get_absolute_url(), update)
+    payment_link.short_description = 'Paiement'
+
+    def get_queryset(self, request):
+        qs = super().get_queryset(request)
+        payments = RecurringPayment.objects.annotate(
+            validated=models.Subquery(
+                            PaymentUpdate.objects.filter(payment=models.OuterRef('pk'))
+                                                 .filter(validated=True)
+                                                 .order_by('-start')
+                                                 .values('pk')[:1]
+            ),
+            pending=models.Subquery(
+                            PaymentUpdate.objects.filter(payment=models.OuterRef('pk'))
+                                                 .filter(validated=False)
+                                                 .order_by('-start')
+                                                 .values('pk')[:1]
+            ),
+        )
+        qs = qs.filter(pk__in=payments.values_list('validated', flat=True))
+        qs = qs.annotate(
+            last=models.Case(
+                models.When(pk__in=payments.filter(pending__isnull=True).values_list('validated', flat=True), then=True),
+                default=False,
+                output_field=models.BooleanField(),
+            ),
+        )
+        return qs
+
+    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_change_permission(self, request, obj=None):
+        return not obj
+
+    def has_delete_permission(self, request, obj=None):
+        return False
+
+
 admin.site.register(RecurringPayment, RecurringPaymentAdmin)
+admin.site.register(PaymentUpdate, PaymentUpdateAdmin)

+ 11 - 5
banking/models.py

@@ -47,19 +47,25 @@ class RecurringPayment(models.Model):
     def get_absolute_url(self):
         return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=(self.pk,))
 
-    @property
-    def current(self):
+    def get_current_payment(self):
         return self.updates.filter(validated=True).first()
 
-    def is_active(self):
-        return self.current and self.current.payment_method != PaymentUpdate.STOP
+    def get_current_payment_display(self):
+        current = self.get_current_payment()
+        if current:
+            return str(current)
+        else:
+            return 'non renseignée'
 
     class Meta:
         verbose_name = 'paiement récurrent'
         verbose_name_plural = 'paiements récurrents'
 
     def __str__(self):
-        return str(self.current or 'non renseignée')
+        if hasattr(self, 'adhesion'):
+            return "Cotisation %s" % self.adhesion
+        else:
+            return "Contribution %s" % self.service
 
 
 class PaymentUpdate(models.Model):

+ 11 - 0
banking/templates/admin/banking/recurringpayment/change_form.html

@@ -0,0 +1,11 @@
+{% extends "admin/change_form.html" %}
+{% load i18n admin_urls static admin_modify %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
+&rsaquo; <a href="{% url 'admin:banking_paymentupdate_changelist' %}">Paiements</a>
+&rsaquo; {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
+</div>
+{% endblock %}

+ 1 - 1
banking/templates/banking/debtor.html

@@ -5,7 +5,7 @@
 <div class="breadcrumbs">
 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
 &rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
-&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
+&rsaquo; <a href="{% url 'admin:banking_paymentupdate_changelist' %}">Paiements</a>
 &rsaquo; <a href="{% url opts|admin_urlname:'change' payment.pk %}">{{ payment|truncatewords:"18" }}</a>
 &rsaquo; Débiteur
 </div>

+ 1 - 1
services/admin.py

@@ -326,7 +326,7 @@ class ServiceAdmin(admin.ModelAdmin):
     get_adherent_link.short_description = Adhesion.get_adherent_link.short_description
 
     def get_contribution_link(self, obj):
-        return format_html(u'<a href="{}">{}</a>', obj.contribution.get_absolute_url(), obj.contribution)
+        return format_html(u'<a href="{}">{}</a>', obj.contribution.get_absolute_url(), obj.contribution.get_current_payment_display())
     get_contribution_link.short_description = 'Contribution financière'
 
     def get_inline_instances(self, request, obj=None):