Browse Source

When invoice is validated, do not permit editing it (including InvoiceDetail inline)

Fabs 10 years ago
parent
commit
8b0a451c24
1 changed files with 79 additions and 14 deletions
  1. 79 14
      coin/billing/admin.py

+ 79 - 14
coin/billing/admin.py

@@ -4,6 +4,7 @@ from django.contrib import admin
 from django.contrib import messages
 from django.http import HttpResponseRedirect
 from django.conf.urls import url
+from django.contrib.admin.util import flatten_fieldsets
 
 from coin.filtering_queryset import LimitedAdminInlineMixin
 from coin.billing.models import Invoice, InvoiceDetail, Payment
@@ -35,6 +36,32 @@ class InvoiceDetailInline(LimitedAdminInlineMixin, admin.StackedInline):
         return self.readonly_fields
 
 
+class InvoiceDetailInlineReadOnly(admin.StackedInline):
+    """
+    Lorsque la facture est validée, il n'est plus possible de la modifier
+    Ce inline est donc identique à InvoiceDetailInline, mais tous
+    les champs sont en lecture seule
+    """
+    model = InvoiceDetail
+    extra = 0
+    fields = InvoiceDetailInline.fields
+    can_delete = False
+
+    def has_add_permission(self, request):
+        return False
+
+    def get_readonly_fields(self, request, obj=None):
+        if self.declared_fieldsets:
+            result = flatten_fieldsets(self.declared_fieldsets)
+        else:
+            result = list(set(
+                    [field.name for field in self.opts.local_fields] +
+                    [field.name for field in self.opts.local_many_to_many]
+                ))
+            result.remove('id')
+        return result
+
+
 class PaymentInline(admin.StackedInline):
     model = Payment
     extra = 0
@@ -44,7 +71,6 @@ class PaymentInline(admin.StackedInline):
 class InvoiceAdmin(admin.ModelAdmin):
     list_display = ('number', 'date', 'status', 'amount', 'member', 'validated')
     list_display_links = ('number', 'date')
-    inlines = [InvoiceDetailInline, PaymentInline]
     fields = (('number', 'date', 'status'),
        ('date_due'),
        ('member'),
@@ -53,29 +79,68 @@ class InvoiceAdmin(admin.ModelAdmin):
     readonly_fields = ('amount','amount_paid','validated','pdf')
     form = autocomplete_light.modelform_factory(Invoice)
 
-    def get_formsets(self, request, obj=None):
+    def get_readonly_fields(self, request, obj=None):
         """
-        Lorsque l'on est en création d'objet (obj=None) alors ne renvoi pas les
-        formsets des inlines.
-        Cela permet de ne pas afficher les champs détails de facture et paiement
-        tant que la facture n'a pas été enregistré.
-        Cette subtilité permet de s'assurer que le select "Abonnement" de
-        InvoiceDetail est bien filtré avec le member de la facture
+        Si la facture est validée, passe tous les champs en readonly
         """
-        if obj:
-            for _ in super(InvoiceAdmin, self).get_formsets(request, obj):
-                yield _
-        else:
-            pass
+        if obj and obj.validated:
+            if self.declared_fieldsets:
+                return flatten_fieldsets(self.declared_fieldsets)
+            else:
+                return list(set(
+                    [field.name for field in self.opts.local_fields] +
+                    [field.name for field in self.opts.local_many_to_many]
+                ))
+        return self.readonly_fields
+
+    def get_inline_instances(self, request, obj=None):
+        """
+        Renvoi les inlines selon le context :
+        * Si création, alors ne renvoi aucun inline
+        * Si modification, renvoi InvoiceDetail et PaymentInline
+        * Si facture validée, renvoi InvoiceDetail en ReadOnly et PaymentInline
+        """
+        inlines = []
+        inline_instances = []
+
+        if obj is not None:
+            if obj.validated:
+                inlines = [InvoiceDetailInlineReadOnly]
+            else:
+                inlines = [InvoiceDetailInline]
+
+            inlines += [PaymentInline]
+
+        for inline_class in inlines:
+            inline = inline_class(self.model, self.admin_site)
+
+            if request:
+                if not (inline.has_add_permission(request) or
+                        inline.has_change_permission(request) or
+                        inline.has_delete_permission(request)):
+                    continue
+                if not inline.has_add_permission(request):
+                    inline.max_num = 0
+            inline_instances.append(inline)
+
+        return inline_instances
 
     def get_urls(self):
+        """
+        Custom admin urls
+        """
         urls = super(InvoiceAdmin, self).get_urls()
         my_urls = [
-            url(r'^validate/(?P<id>.+)$', self.admin_site.admin_view(self.validate_view), name='invoice_validate'),
+            url(r'^validate/(?P<id>.+)$', self.admin_site.admin_view(self.validate_view),
+                name='invoice_validate'),
         ]
         return my_urls + urls
 
     def validate_view(self, request, id):
+        """
+        Vue appelée lorsque l'admin souhaite valider une facture (et générer le pdf)
+        """
+        #TODO : Add better perm here
         if request.user.is_superuser:
             invoice = get_invoice_from_id_or_number(id)
             invoice.validate()