|
@@ -1,16 +1,38 @@
|
|
|
from django.contrib import admin
|
|
|
from django.utils.html import format_html
|
|
|
from django.urls import reverse
|
|
|
+from django.db import models
|
|
|
|
|
|
from mptt.admin import MPTTModelAdmin
|
|
|
|
|
|
from .models import Equipment, Category, Location
|
|
|
|
|
|
|
|
|
-class EquipmentInline(admin.StackedInline):
|
|
|
+### Inlines
|
|
|
+
|
|
|
+class EquipmentInline(admin.TabularInline):
|
|
|
model = Equipment
|
|
|
- list_display = ('location', 'category', 'quantity',)
|
|
|
|
|
|
+class ExistingEquipmentInline(EquipmentInline):
|
|
|
+ max_num = 0
|
|
|
+ fields = ('location', 'category', 'quantity',)
|
|
|
+ readonly_fields = ('location', 'category',)
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ qs = super().get_queryset(request)
|
|
|
+ qs = qs.select_related('location', 'category',)
|
|
|
+ return qs
|
|
|
+
|
|
|
+class NewEquipmentInline(admin.TabularInline):
|
|
|
+ model = Equipment
|
|
|
+ extra = 0
|
|
|
+ verbose_name_plural = 'Nouveaux équipements'
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ return Equipment.objects.none()
|
|
|
+
|
|
|
+
|
|
|
+### Filters
|
|
|
|
|
|
class CategoryFilter(admin.SimpleListFilter):
|
|
|
title = 'Catégorie'
|
|
@@ -30,15 +52,22 @@ class CategoryFilter(admin.SimpleListFilter):
|
|
|
return queryset
|
|
|
|
|
|
|
|
|
-class CategoryAdmin(MPTTModelAdmin):
|
|
|
- search_fields = ['name']
|
|
|
- list_display = ('__str__', 'equipement_list_link',)
|
|
|
+### Mixins
|
|
|
|
|
|
- def equipement_list_link(self, category):
|
|
|
- url = reverse('admin:%s_%s_changelist' % (Equipment._meta.app_label, Equipment._meta.model_name))
|
|
|
- url += '?category=%d' % category.pk
|
|
|
- return format_html(u'<a href="{}">{}</a>', url, 'voir la liste des équipements')
|
|
|
- equipement_list_link.short_description = 'Équipements'
|
|
|
+class StockMixin:
|
|
|
+ search_fields = ('name',)
|
|
|
+ list_display = ('__str__', 'quantity',)
|
|
|
+ inlines = (ExistingEquipmentInline, NewEquipmentInline,)
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ qs = super().get_queryset(request)
|
|
|
+ qs = qs.annotate(quantity=models.Sum('equipments__quantity'))
|
|
|
+ return qs
|
|
|
+
|
|
|
+ def quantity(self, category):
|
|
|
+ return category.quantity
|
|
|
+ quantity.short_description = 'Quantité'
|
|
|
+ quantity.admin_order_field = 'quantity'
|
|
|
|
|
|
def get_actions(self, request):
|
|
|
actions = super().get_actions(request)
|
|
@@ -46,52 +75,43 @@ class CategoryAdmin(MPTTModelAdmin):
|
|
|
del actions['delete_selected']
|
|
|
return actions
|
|
|
|
|
|
- def has_delete_permission(self, request, obj=None):
|
|
|
- # Interdiction de supprimer la catégorie si elle contient des équipements
|
|
|
- return obj and not Equipment.objects.filter(category__in=obj.get_descendants(include_self=True)).exists()
|
|
|
|
|
|
+### Admins
|
|
|
|
|
|
-class LocationAdmin(admin.ModelAdmin):
|
|
|
- list_display = ('__str__', 'equipement_list_link',)
|
|
|
- inlines = (EquipmentInline,)
|
|
|
+class CategoryAdmin(StockMixin, MPTTModelAdmin):
|
|
|
+ def has_delete_permission(self, request, obj=None):
|
|
|
+ # Interdiction de supprimer la catégorie si elle contient des équipements
|
|
|
+ return obj \
|
|
|
+ and not obj.get_descendants().exists \
|
|
|
+ and not Equipment.objects.filter(category__in=obj.get_descendants(include_self=True)).exists()
|
|
|
|
|
|
- def equipement_list_link(self, location):
|
|
|
- url = reverse('admin:%s_%s_changelist' % (Equipment._meta.app_label, Equipment._meta.model_name))
|
|
|
- url += '?location__id__exact=%d' % location.pk
|
|
|
- return format_html(u'<a href="{}">{}</a>', url, 'voir la liste des équipements')
|
|
|
- equipement_list_link.short_description = 'Équipements'
|
|
|
-
|
|
|
- def get_actions(self, request):
|
|
|
- actions = super().get_actions(request)
|
|
|
- if 'delete_selected' in actions:
|
|
|
- del actions['delete_selected']
|
|
|
- return actions
|
|
|
|
|
|
+class LocationAdmin(StockMixin, admin.ModelAdmin):
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
|
# Interdiction de supprimer l’emplacement si il contient des équipements
|
|
|
return obj and not obj.equipment_set.exists()
|
|
|
|
|
|
|
|
|
-class EquipmentAdmin(admin.ModelAdmin):
|
|
|
- list_display = ('location', 'category', 'quantity',)
|
|
|
- list_display_links = ('location', 'category',)
|
|
|
- list_editable = ('quantity',)
|
|
|
- list_filter = (
|
|
|
- ('location', admin.RelatedOnlyFieldListFilter),
|
|
|
- CategoryFilter,
|
|
|
- )
|
|
|
-
|
|
|
- def get_actions(self, request):
|
|
|
- actions = super().get_actions(request)
|
|
|
- if 'delete_selected' in actions:
|
|
|
- del actions['delete_selected']
|
|
|
- return actions
|
|
|
-
|
|
|
- def has_delete_permission(self, request, obj=None):
|
|
|
- # Interdiction de supprimer le stock d’équipements s’il n’est pas vide
|
|
|
- return obj and obj.quantity == 0
|
|
|
+#class EquipmentAdmin(admin.ModelAdmin):
|
|
|
+# list_display = ('location', 'category', 'quantity',)
|
|
|
+# list_display_links = ('location', 'category',)
|
|
|
+# list_editable = ('quantity',)
|
|
|
+# list_filter = (
|
|
|
+# ('location', admin.RelatedOnlyFieldListFilter),
|
|
|
+# CategoryFilter,
|
|
|
+# )
|
|
|
+#
|
|
|
+# def get_actions(self, request):
|
|
|
+# actions = super().get_actions(request)
|
|
|
+# if 'delete_selected' in actions:
|
|
|
+# del actions['delete_selected']
|
|
|
+# return actions
|
|
|
+#
|
|
|
+# def has_delete_permission(self, request, obj=None):
|
|
|
+# # Interdiction de supprimer le stock d’équipements s’il n’est pas vide
|
|
|
+# return obj and obj.quantity == 0
|
|
|
|
|
|
|
|
|
admin.site.register(Category, CategoryAdmin)
|
|
|
admin.site.register(Location, LocationAdmin)
|
|
|
-admin.site.register(Equipment, EquipmentAdmin)
|
|
|
+#admin.site.register(Equipment, EquipmentAdmin)
|