admin.py 7.2 KB

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