|
@@ -2,10 +2,12 @@
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
-
|
|
|
-from django.contrib import admin
|
|
|
+from django.conf.urls import url
|
|
|
+from django.shortcuts import get_object_or_404
|
|
|
+from django.contrib import admin, messages
|
|
|
from django.contrib.auth import get_user_model
|
|
|
-from django.forms import ModelChoiceField
|
|
|
+from django.core.urlresolvers import reverse
|
|
|
+from django.http import HttpResponseRedirect
|
|
|
import autocomplete_light
|
|
|
|
|
|
from .models import ItemType, Item, Loan, Storage
|
|
@@ -17,6 +19,21 @@ User = get_user_model()
|
|
|
admin.site.register(ItemType)
|
|
|
|
|
|
|
|
|
+def give_back_loan(request, id):
|
|
|
+ # could be better : could not be a POST, and could not rely on HTTP_REFERER
|
|
|
+ # We could for that rely on django-inline-actions, but the version
|
|
|
+ # we could use with our Django 1.9 is outdated and buggy
|
|
|
+ # We could also offer an intermediate page to specify the storage
|
|
|
+ redirect_url = request.META['HTTP_REFERER']
|
|
|
+ loan = get_object_or_404(Loan, pk=id)
|
|
|
+ loan.item.give_back()
|
|
|
+ messages.success(
|
|
|
+ request,
|
|
|
+ "{} a bien été marqué comme rendu".format(loan.item),
|
|
|
+ )
|
|
|
+ return HttpResponseRedirect(redirect_url)
|
|
|
+
|
|
|
+
|
|
|
class OwnerFilter(admin.SimpleListFilter):
|
|
|
title = "Propriétaire"
|
|
|
parameter_name = 'owner'
|
|
@@ -56,14 +73,113 @@ class AvailabilityFilter(admin.SimpleListFilter):
|
|
|
return queryset
|
|
|
|
|
|
|
|
|
+class CurrentLoanInline(admin.TabularInline):
|
|
|
+ model = Loan
|
|
|
+ extra = 0
|
|
|
+ fields = ('user', 'item', 'short_date', 'notes', 'action_buttons')
|
|
|
+ readonly_fields = ('user', 'item', 'short_date', 'notes', 'action_buttons')
|
|
|
+ verbose_name_plural = "Emprunt en cours"
|
|
|
+ show_change_link = True
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ qs = super(CurrentLoanInline, self).get_queryset(request)
|
|
|
+ return qs.running()
|
|
|
+
|
|
|
+ def has_add_permission(self, request, obj=None):
|
|
|
+ return False
|
|
|
+
|
|
|
+ def has_delete_permission(self, request, obj=None):
|
|
|
+ return False
|
|
|
+
|
|
|
+ def action_buttons(self, obj):
|
|
|
+ if obj.is_running():
|
|
|
+ return """<a class="button "href="{}">Déclarer rendu</a>""".format(
|
|
|
+ reverse('admin:loan-give_back', args=[obj.pk]))
|
|
|
+ else:
|
|
|
+ return ''
|
|
|
+ action_buttons.short_description = 'Actions'
|
|
|
+ action_buttons.allow_tags = True
|
|
|
+
|
|
|
+
|
|
|
+class LoanHistoryInline(admin.TabularInline):
|
|
|
+ model = Loan
|
|
|
+ extra = 0
|
|
|
+ fields = ('user', 'item', 'short_date', 'short_date_end', 'notes')
|
|
|
+ readonly_fields = ('user', 'item', 'short_date', 'short_date_end', 'notes')
|
|
|
+ ordering = ['-loan_date_end']
|
|
|
+ verbose_name_plural = "Historique de prêt de cet objet"
|
|
|
+ show_change_link = True
|
|
|
+ classes = ['collapse'] # Django >= 1.10-ready
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ qs = super(LoanHistoryInline, self).get_queryset(request)
|
|
|
+ return qs.finished()
|
|
|
+
|
|
|
+ def has_add_permission(self, request, obj=None):
|
|
|
+ return False
|
|
|
+
|
|
|
+ def has_delete_permission(self, request, obj=None):
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+class AddLoanInline(admin.StackedInline):
|
|
|
+ model = Loan
|
|
|
+ extra = 1
|
|
|
+ max_num = 1
|
|
|
+ fields = ('user', 'item', 'loan_date', 'notes')
|
|
|
+ verbose_name_plural = "Déclarer le prêt de cet objet"
|
|
|
+ classes = ['collapse'] # Django >= 1.10-ready
|
|
|
+
|
|
|
+ form = autocomplete_light.modelform_factory(Loan, fields='__all__')
|
|
|
+
|
|
|
+ def get_queryset(self, request):
|
|
|
+ qs = super(AddLoanInline, self).get_queryset(request)
|
|
|
+ return qs.none()
|
|
|
+
|
|
|
+ def has_delete_permission(self, request, obj=None):
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+class BorrowerFilter(admin.SimpleListFilter):
|
|
|
+ title = 'Adhérent emprunteur'
|
|
|
+ parameter_name = 'user'
|
|
|
+
|
|
|
+ def _filter_loans(self, items_queryset, user_pk=None):
|
|
|
+ qs = Loan.objects.running().filter(item__in=items_queryset)
|
|
|
+ if user_pk is not None:
|
|
|
+ qs.filter(user=user_pk)
|
|
|
+ return qs
|
|
|
+
|
|
|
+ def lookups(self, request, model_admin):
|
|
|
+ # Get relevant (and authorized) users only
|
|
|
+ relevant_items = model_admin.get_queryset(request)
|
|
|
+ users = set()
|
|
|
+ for loan in self._filter_loans(relevant_items):
|
|
|
+ users.add((loan.user.pk, loan.user))
|
|
|
+ return users
|
|
|
+
|
|
|
+ def queryset(self, request, queryset):
|
|
|
+ if self.value():
|
|
|
+ loans_qs = self._filter_loans(queryset).filter(
|
|
|
+ user__pk=self.value(),
|
|
|
+ )
|
|
|
+ return queryset.filter(loans__in=loans_qs)
|
|
|
+ else:
|
|
|
+ return queryset
|
|
|
+
|
|
|
+
|
|
|
@admin.register(Item)
|
|
|
class ItemAdmin(admin.ModelAdmin):
|
|
|
list_display = (
|
|
|
- 'designation', 'mac_address', 'serial', 'owner',
|
|
|
- 'buy_date', 'deployed', 'is_available', 'storage')
|
|
|
+ 'designation',
|
|
|
+ 'current_borrower',
|
|
|
+ 'get_mac_and_serial',
|
|
|
+ 'deployed', 'is_available', 'storage',
|
|
|
+ 'buy_date', 'owner',
|
|
|
+ )
|
|
|
list_filter = (
|
|
|
AvailabilityFilter, 'type', 'storage',
|
|
|
- 'buy_date', OwnerFilter)
|
|
|
+ 'buy_date', BorrowerFilter, OwnerFilter)
|
|
|
search_fields = (
|
|
|
'designation', 'mac_address', 'serial',
|
|
|
'owner__email', 'owner__nickname',
|
|
@@ -73,11 +189,23 @@ class ItemAdmin(admin.ModelAdmin):
|
|
|
|
|
|
form = autocomplete_light.modelform_factory(Loan, fields='__all__')
|
|
|
|
|
|
+ inlines = [AddLoanInline, CurrentLoanInline, LoanHistoryInline]
|
|
|
+
|
|
|
def give_back(self, request, queryset):
|
|
|
for item in queryset.filter(loans__loan_date_end=None):
|
|
|
item.give_back()
|
|
|
give_back.short_description = 'Rendre le matériel'
|
|
|
|
|
|
+ def get_urls(self):
|
|
|
+ urls = super(ItemAdmin, self).get_urls()
|
|
|
+ my_urls = [
|
|
|
+ url(
|
|
|
+ r'^give_back/(?P<id>.+)$',
|
|
|
+ self.admin_site.admin_view(give_back_loan),
|
|
|
+ name='loan-give_back'),
|
|
|
+ ]
|
|
|
+ return my_urls + urls
|
|
|
+
|
|
|
|
|
|
class StatusFilter(admin.SimpleListFilter):
|
|
|
title = 'Statut'
|
|
@@ -110,54 +238,6 @@ class StatusFilter(admin.SimpleListFilter):
|
|
|
return queryset
|
|
|
|
|
|
|
|
|
-class BorrowerFilter(admin.SimpleListFilter):
|
|
|
- title = 'Adhérent emprunteur'
|
|
|
- parameter_name = 'user'
|
|
|
-
|
|
|
- def lookups(self, request, model_admin):
|
|
|
- users = set()
|
|
|
- for loan in model_admin.get_queryset(request):
|
|
|
- users.add((loan.user.pk, loan.user))
|
|
|
- return users
|
|
|
-
|
|
|
- def queryset(self, request, queryset):
|
|
|
- if self.value():
|
|
|
- return queryset.filter(user=self.value())
|
|
|
- else:
|
|
|
- return queryset
|
|
|
-
|
|
|
-
|
|
|
-class ItemChoiceField(ModelChoiceField):
|
|
|
- # On surcharge cette méthode pour afficher mac et n° de série dans le menu
|
|
|
- # déroulant de sélection d'un objet dans la création d'un prêt.
|
|
|
- def label_from_instance(self, obj):
|
|
|
- return obj.designation + ' ' + obj.get_mac_and_serial()
|
|
|
-
|
|
|
-@admin.register(Loan)
|
|
|
-class LoanAdmin(admin.ModelAdmin):
|
|
|
- list_display = ('item', 'get_mac_and_serial', 'user', 'loan_date', 'loan_date_end')
|
|
|
- list_filter = (StatusFilter, BorrowerFilter, 'item__designation')
|
|
|
- search_fields = (
|
|
|
- 'item__designation',
|
|
|
- 'user__nickname', 'user__username',
|
|
|
- 'user__first_name', 'user__last_name', )
|
|
|
- actions = ['end_loan']
|
|
|
-
|
|
|
- def end_loan(self, request, queryset):
|
|
|
- queryset.filter(loan_date_end=None).update(
|
|
|
- loan_date_end=datetime.now())
|
|
|
- end_loan.short_description = 'Mettre fin au prêt'
|
|
|
-
|
|
|
- form = autocomplete_light.modelform_factory(Loan, fields='__all__')
|
|
|
-
|
|
|
- def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
|
|
- if db_field.name == 'item':
|
|
|
- kwargs['queryset'] = Item.objects.all()
|
|
|
- return ItemChoiceField(**kwargs)
|
|
|
- else:
|
|
|
- return super(LoanAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
|
|
|
-
|
|
|
-
|
|
|
@admin.register(Storage)
|
|
|
class StorageAdmin(admin.ModelAdmin):
|
|
|
list_display = ('name', 'truncated_notes', 'items_count')
|
|
@@ -187,8 +267,10 @@ class LoanInline(admin.TabularInline):
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
|
return False
|
|
|
|
|
|
+
|
|
|
class MemberAdmin(coin.members.admin.MemberAdmin):
|
|
|
inlines = coin.members.admin.MemberAdmin.inlines + [LoanInline]
|
|
|
|
|
|
+
|
|
|
admin.site.unregister(coin.members.admin.Member)
|
|
|
admin.site.register(coin.members.admin.Member, MemberAdmin)
|