123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- 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 PaymentMethodFilter(admin.SimpleListFilter):
- title = 'méthode de paiement'
- parameter_name = 'method'
- def lookups(self, request, model_admin):
- return PaymentUpdate.PAYMENT_CHOICES
- 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 = 'statut'
- parameter_name = 'status'
- def lookups(self, request, model_admin):
- return (
- ('up-to-date', 'À jour'),
- ('pending', 'En attente'),
- )
- def queryset(self, request, queryset):
- 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
- 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
- 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)
- 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):
- inlines = (PendingPaymentUpdateInline, ValidatedPaymentUpdateInline,)
- fields = ('payment_type', 'payment_object_link', 'debtor_link',)
- readonly_fields = ('payment_type', 'payment_object_link', 'debtor_link',)
- def payment_object_link(self, obj):
- obj = obj.payment_object()
- return format_html(u'<a href="{}">{}</a>', 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'<a href="{}">{}</a>', 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_change_permission(self, request, obj=None):
- return obj
- 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)
- 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)
|