admin.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. from django.contrib import admin
  2. from django.db import models
  3. from django.core.urlresolvers import reverse
  4. from django.forms import BaseInlineFormSet
  5. from django.utils.html import format_html
  6. from django.conf.urls import url
  7. from django.shortcuts import get_object_or_404
  8. from django.template.response import TemplateResponse
  9. from functools import update_wrapper
  10. from services.models import ServiceType
  11. from services.admin import ServiceAdmin
  12. from adhesions.admin import AdhesionAdmin
  13. from .models import RecurringPayment, PaymentUpdate
  14. from .utils import notify_payment_update
  15. ### Inlines
  16. class PaymentTypeFilter(admin.SimpleListFilter):
  17. title = 'type'
  18. parameter_name = 'type'
  19. def lookups(self, request, model_admin):
  20. return (
  21. ('adhesion', 'Adhésion'),
  22. ('service', 'Service'),
  23. )
  24. def queryset(self, request, queryset):
  25. if self.value() == 'adhesion':
  26. return queryset.filter(adhesion__isnull=False)
  27. if self.value() == 'service':
  28. return queryset.filter(service__isnull=False)
  29. class PaymentStatusFilter(admin.SimpleListFilter):
  30. title = 'actif'
  31. parameter_name = 'active'
  32. def lookups(self, request, model_admin):
  33. return (
  34. (0, 'Inactif'),
  35. (1, 'Actif'),
  36. )
  37. def queryset(self, request, queryset):
  38. payments = PaymentUpdate.objects.filter(validated=True).order_by('payment', '-start')\
  39. .distinct('payment').values('payment_method', 'payment__pk')
  40. actives = filter(lambda p: p['payment_method'] != PaymentUpdate.STOP, payments)
  41. actives = map(lambda p: p['payment__pk'], actives)
  42. if self.value() == '0':
  43. return queryset.exclude(pk__in=actives)
  44. if self.value() == '1':
  45. return queryset.filter(pk__in=actives)
  46. class PendingPaymentFilter(admin.SimpleListFilter):
  47. title = 'opérations en attente'
  48. parameter_name = 'pending'
  49. def lookups(self, request, model_admin):
  50. return (
  51. (0, 'À jour'),
  52. (1, 'En attente'),
  53. )
  54. def queryset(self, request, queryset):
  55. pending = PaymentUpdate.objects.filter(validated=False).values_list('payment__pk', flat=True)
  56. if self.value() == '0':
  57. return queryset.exclude(pk__in=pending)
  58. if self.value() == '1':
  59. return queryset.filter(pk__in=pending)
  60. ### Inlines
  61. class PendingPaymentUpdateFormSet(BaseInlineFormSet):
  62. def save_new(self, form, commit=True):
  63. obj = super().save_new(form, commit)
  64. if not obj.validated:
  65. notify_payment_update(self.request, obj)
  66. return obj
  67. def save_existing(self, form, instance, commit=True):
  68. old = PaymentUpdate.objects.get(pk=instance.pk)
  69. if not instance.validated:
  70. notify_payment_update(self.request, instance, old)
  71. return super().save_existing(form, instance, commit)
  72. class PendingPaymentUpdateInline(admin.TabularInline):
  73. model = PaymentUpdate
  74. formset = PendingPaymentUpdateFormSet
  75. extra = 1
  76. verbose_name_plural = 'En attente de saisie bancaire'
  77. def get_formset(self, request, obj=None, **kwargs):
  78. formset = super().get_formset(request, obj, **kwargs)
  79. formset.request = request
  80. return formset
  81. def get_queryset(self, request):
  82. return super().get_queryset(request).filter(validated=False)
  83. class ValidatedPaymentUpdateInline(admin.TabularInline):
  84. model = PaymentUpdate
  85. verbose_name_plural = 'Historique'
  86. max_num = 0
  87. fields = ('amount', 'period', 'payment_method', 'start',)
  88. readonly_fields = ('amount', 'period', 'payment_method', 'start',)
  89. def has_delete_permission(self, request, obj=None):
  90. return False
  91. def get_queryset(self, request):
  92. return super().get_queryset(request).filter(validated=True)
  93. ### Helpers
  94. def prefix_search_field(prefix, field):
  95. if field[0] == '=':
  96. return '=' + prefix + '__' + field[1:]
  97. else:
  98. return prefix + '__' + field
  99. ### ModelAdmin
  100. class RecurringPaymentAdmin(admin.ModelAdmin):
  101. list_display = ('id', 'payment_type', 'payment_object_link', 'get_active', 'get_last_validated_update', 'get_pending',)
  102. list_select_related = ('adhesion', 'service', 'service__service_type',)
  103. inlines = (PendingPaymentUpdateInline, ValidatedPaymentUpdateInline,)
  104. list_filter = (PaymentTypeFilter, PaymentStatusFilter, PendingPaymentFilter,)
  105. fields = ('payment_type', 'payment_object_link', 'debtor_link',)
  106. readonly_fields = ('payment_type', 'payment_object_link', 'debtor_link',)
  107. search_fields = \
  108. tuple([prefix_search_field('adhesion', f) for f in AdhesionAdmin.search_fields]) \
  109. + tuple([prefix_search_field('service', f) for f in ServiceAdmin.search_fields])
  110. def get_queryset(self, request):
  111. qs = super().get_queryset(request)
  112. qs = qs.prefetch_related('updates')
  113. qs = qs.prefetch_related(
  114. models.Prefetch(
  115. 'updates',
  116. queryset=PaymentUpdate.objects.filter(validated=False),
  117. to_attr='pending_updates'
  118. )
  119. )
  120. return qs
  121. def get_pending(self, obj):
  122. return len(obj.pending_updates)
  123. get_pending.short_description = 'Opérations en attente'
  124. def get_active(self, obj):
  125. return obj.active
  126. get_active.short_description = 'Actif'
  127. get_active.boolean = True
  128. def payment_object_link(self, obj):
  129. obj = obj.payment_object()
  130. return format_html(u'<a href="{}">{}</a>', obj.get_absolute_url(), obj)
  131. payment_object_link.short_description = 'Objet'
  132. def debtor_link(self, obj):
  133. url = reverse(viewname='admin:%s_%s_debtor' % (obj._meta.app_label, obj._meta.model_name), args=[obj.pk])
  134. return format_html(u'<a href="{}">{}</a>', url, obj.debtor)
  135. debtor_link.short_description = 'Débiteur'
  136. def get_actions(self, request):
  137. actions = super().get_actions(request)
  138. if 'delete_selected' in actions:
  139. del actions['delete_selected']
  140. return actions
  141. def has_add_permission(self, request, obj=None):
  142. return False
  143. def has_delete_permission(self, request, obj=None):
  144. return False
  145. def get_urls(self):
  146. info = self.model._meta.app_label, self.model._meta.model_name
  147. urls = [
  148. url(r'^(.*)/debtor/$', self.admin_site.admin_view(self.debtor_view), name='%s_%s_debtor' % info),
  149. ]
  150. return urls + super().get_urls()
  151. def debtor_view(self, request, payment_pk):
  152. payment = get_object_or_404(RecurringPayment, pk=payment_pk)
  153. adhesion = payment.debtor
  154. context = dict(
  155. self.admin_site.each_context(request),
  156. opts=self.model._meta,
  157. payment=payment,
  158. adhesion=adhesion,
  159. adherent=adhesion.adherent,
  160. )
  161. return TemplateResponse(request, 'banking/debtor.html', context)
  162. admin.site.register(RecurringPayment, RecurringPaymentAdmin)