admin.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.contrib import admin
  4. from django.contrib import messages
  5. from django.http import HttpResponseRedirect
  6. from django.conf.urls import url
  7. from django.contrib.admin.util import flatten_fieldsets
  8. from coin.filtering_queryset import LimitedAdminInlineMixin
  9. from coin.billing.models import Invoice, InvoiceDetail, Payment
  10. from coin.billing.utils import get_invoice_from_id_or_number
  11. from django.core.urlresolvers import reverse
  12. import autocomplete_light
  13. class InvoiceDetailInline(LimitedAdminInlineMixin, admin.StackedInline):
  14. model = InvoiceDetail
  15. extra = 0
  16. fields = (('label', 'amount', 'quantity', 'tax'),
  17. ('offersubscription', 'period_from', 'period_to'))
  18. def get_filters(self, obj):
  19. """
  20. Le champ "Abonnement" est filtré afin de n'afficher que les abonnements
  21. du membre choisi dans la facture. Si pas de membre alors renvoi
  22. une liste vide
  23. """
  24. if obj and obj.member:
  25. return (('offersubscription', {'member': obj.member}),)
  26. else:
  27. return (('offersubscription', None),)
  28. def get_readonly_fields(self, request, obj=None):
  29. if not obj or not obj.member:
  30. return self.readonly_fields + ('offersubscription',)
  31. return self.readonly_fields
  32. class InvoiceDetailInlineReadOnly(admin.StackedInline):
  33. """
  34. Lorsque la facture est validée, il n'est plus possible de la modifier
  35. Ce inline est donc identique à InvoiceDetailInline, mais tous
  36. les champs sont en lecture seule
  37. """
  38. model = InvoiceDetail
  39. extra = 0
  40. fields = InvoiceDetailInline.fields
  41. can_delete = False
  42. def has_add_permission(self, request):
  43. return False
  44. def get_readonly_fields(self, request, obj=None):
  45. if self.declared_fieldsets:
  46. result = flatten_fieldsets(self.declared_fieldsets)
  47. else:
  48. result = list(set(
  49. [field.name for field in self.opts.local_fields] +
  50. [field.name for field in self.opts.local_many_to_many]
  51. ))
  52. result.remove('id')
  53. return result
  54. class PaymentInlineAdd(admin.StackedInline):
  55. model = Payment
  56. extra = 0
  57. fields = (('date', 'payment_mean', 'amount'),)
  58. can_delete = False
  59. verbose_name_plural = "Ajouter des paiements"
  60. def has_change_permission(self, request):
  61. return False
  62. class PaymentInlineReadOnly(admin.StackedInline):
  63. model = Payment
  64. extra = 0
  65. fields = PaymentInlineAdd.fields
  66. can_delete = False
  67. verbose_name = None
  68. verbose_name_plural = "Paiements"
  69. def has_add_permission(self, request):
  70. return False
  71. def get_readonly_fields(self, request, obj=None):
  72. return flatten_fieldsets(self.declared_fieldsets)
  73. class InvoiceAdmin(admin.ModelAdmin):
  74. list_display = ('number', 'date', 'status', 'amount', 'member',
  75. 'validated')
  76. list_display_links = ('number', 'date')
  77. fields = (('number', 'date', 'status'),
  78. ('date_due'),
  79. ('member'),
  80. ('amount', 'amount_paid'),
  81. ('validated', 'pdf'))
  82. readonly_fields = ('amount', 'amount_paid', 'validated', 'pdf', 'number')
  83. form = autocomplete_light.modelform_factory(Invoice, fields='__all__')
  84. def get_readonly_fields(self, request, obj=None):
  85. """
  86. Si la facture est validée, passe tous les champs en readonly
  87. """
  88. if obj and obj.validated:
  89. if self.declared_fieldsets:
  90. return flatten_fieldsets(self.declared_fieldsets)
  91. else:
  92. return list(set(
  93. [field.name for field in self.opts.local_fields] +
  94. [field.name for field in self.opts.local_many_to_many]
  95. ))
  96. return self.readonly_fields
  97. def get_inline_instances(self, request, obj=None):
  98. """
  99. Renvoi les inlines selon le context :
  100. * Si création, alors ne renvoi aucun inline
  101. * Si modification, renvoi InvoiceDetail et PaymentInline
  102. * Si facture validée, renvoi InvoiceDetail en ReadOnly et PaymentInline
  103. """
  104. inlines = []
  105. inline_instances = []
  106. if obj is not None:
  107. if obj.validated:
  108. inlines = [InvoiceDetailInlineReadOnly]
  109. else:
  110. inlines = [InvoiceDetailInline]
  111. if obj.status == 'open' and obj.validated:
  112. inlines += [PaymentInlineReadOnly]
  113. inlines += [PaymentInlineAdd]
  114. for inline_class in inlines:
  115. inline = inline_class(self.model, self.admin_site)
  116. if request:
  117. if not (inline.has_add_permission(request) or
  118. inline.has_change_permission(request) or
  119. inline.has_delete_permission(request)):
  120. continue
  121. if not inline.has_add_permission(request):
  122. inline.max_num = 0
  123. inline_instances.append(inline)
  124. return inline_instances
  125. def get_urls(self):
  126. """
  127. Custom admin urls
  128. """
  129. urls = super(InvoiceAdmin, self).get_urls()
  130. my_urls = [
  131. url(r'^validate/(?P<id>.+)$',
  132. self.admin_site.admin_view(self.validate_view),
  133. name='invoice_validate'),
  134. ]
  135. return my_urls + urls
  136. def validate_view(self, request, id):
  137. """
  138. Vue appelée lorsque l'admin souhaite valider une facture et
  139. générer son pdf
  140. """
  141. # TODO : Add better perm here
  142. if request.user.is_superuser:
  143. invoice = get_invoice_from_id_or_number(id)
  144. if invoice.amount() == 0:
  145. messages.error(request, 'Une facture validée ne peut pas avoir'
  146. ' un total de 0€.')
  147. else:
  148. invoice.validate()
  149. messages.success(request, 'La facture a été validée.')
  150. else:
  151. messages.error(
  152. request, 'Vous n\'avez pas l\'autorisation de valider '
  153. 'une facture.')
  154. return HttpResponseRedirect(reverse('admin:billing_invoice_change',
  155. args=(id,)))
  156. class PaymentAdmin(admin.ModelAdmin):
  157. list_display = ('name', 'member', 'payment_mean', 'amount', 'date',
  158. 'invoice', 'amount_already_allocated', 'label')
  159. list_display_links = ()
  160. fields = (('member'),
  161. ('amount', 'payment_mean', 'date', 'label'))
  162. readonly_fields = ('amount_already_allocated', 'label')
  163. form = autocomplete_light.modelform_factory(Payment, fields='__all__')
  164. def get_readonly_fields(self, request, obj=None):
  165. # If payment already started to be allocated or already have a member
  166. if obj and (obj.amount_already_allocated != 0 or obj.member != None):
  167. # All fields are readonly
  168. return flatten_fieldsets(self.declared_fieldsets)
  169. else:
  170. return self.readonly_fields
  171. admin.site.register(Invoice, InvoiceAdmin)
  172. admin.site.register(Payment, PaymentAdmin)