admin.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.conf.urls import url
  4. from django.shortcuts import get_object_or_404
  5. from django.contrib import admin, messages
  6. from django.contrib.auth import get_user_model
  7. from django.core.urlresolvers import reverse
  8. from django.http import HttpResponseRedirect
  9. import autocomplete_light
  10. from .models import ItemType, Item, Loan, Storage
  11. import coin.members.admin
  12. User = get_user_model()
  13. admin.site.register(ItemType)
  14. def give_back_loan(request, id):
  15. # could be better : could not be a POST, and could not rely on HTTP_REFERER
  16. # We could for that rely on django-inline-actions, but the version
  17. # we could use with our Django 1.9 is outdated and buggy
  18. # We could also offer an intermediate page to specify the storage
  19. redirect_url = request.META['HTTP_REFERER']
  20. loan = get_object_or_404(Loan, pk=id)
  21. loan.item.give_back()
  22. messages.success(
  23. request,
  24. "{} a bien été marqué comme rendu".format(loan.item),
  25. )
  26. return HttpResponseRedirect(redirect_url)
  27. class OwnerFilter(admin.SimpleListFilter):
  28. title = "Propriétaire"
  29. parameter_name = 'owner'
  30. def lookups(self, request, model_admin):
  31. owners = [
  32. (i.pk, i) for i in User.objects.filter(items__isnull=False)]
  33. return [(None, "L'association")] + owners
  34. def queryset(self, request, queryset):
  35. if self.value():
  36. return queryset.filter(owner__pk=self.value())
  37. else:
  38. return queryset
  39. class AvailabilityFilter(admin.SimpleListFilter):
  40. title = "Disponibilité"
  41. parameter_name = 'availability'
  42. def lookups(self, request, model_admin):
  43. return [
  44. ('available', 'Disponible'),
  45. ('borrowed', 'Emprunté'),
  46. ('deployed', 'Déployé'),
  47. ]
  48. def queryset(self, request, queryset):
  49. if self.value() == 'available':
  50. return queryset.available()
  51. elif self.value() == 'borrowed':
  52. return queryset.borrowed()
  53. elif self.value() == 'deployed':
  54. return queryset.deployed()
  55. else:
  56. return queryset
  57. class CurrentLoanInline(admin.TabularInline):
  58. model = Loan
  59. extra = 0
  60. fields = ('user', 'item', 'short_date', 'notes', 'action_buttons')
  61. readonly_fields = ('user', 'item', 'short_date', 'notes', 'action_buttons')
  62. verbose_name_plural = "Emprunt en cours"
  63. show_change_link = True
  64. def get_queryset(self, request):
  65. qs = super(CurrentLoanInline, self).get_queryset(request)
  66. return qs.running()
  67. def has_add_permission(self, request, obj=None):
  68. return False
  69. def has_delete_permission(self, request, obj=None):
  70. return False
  71. def action_buttons(self, obj):
  72. if obj.is_running():
  73. return """<a class="button "href="{}">Déclarer rendu</a>""".format(
  74. reverse('admin:loan-give_back', args=[obj.pk]))
  75. else:
  76. return ''
  77. action_buttons.short_description = 'Actions'
  78. action_buttons.allow_tags = True
  79. class LoanHistoryInline(admin.TabularInline):
  80. model = Loan
  81. extra = 0
  82. fields = ('user', 'item', 'short_date', 'short_date_end', 'notes')
  83. readonly_fields = ('user', 'item', 'short_date', 'short_date_end', 'notes')
  84. ordering = ['-loan_date_end']
  85. verbose_name_plural = "Historique de prêt de cet objet"
  86. show_change_link = True
  87. classes = ['collapse'] # Django >= 1.10-ready
  88. def get_queryset(self, request):
  89. qs = super(LoanHistoryInline, self).get_queryset(request)
  90. return qs.finished()
  91. def has_add_permission(self, request, obj=None):
  92. return False
  93. def has_delete_permission(self, request, obj=None):
  94. return False
  95. class AddLoanInline(admin.StackedInline):
  96. model = Loan
  97. extra = 1
  98. max_num = 1
  99. fields = ('user', 'item', 'loan_date', 'notes')
  100. verbose_name_plural = "Déclarer le prêt de cet objet"
  101. classes = ['collapse'] # Django >= 1.10-ready
  102. form = autocomplete_light.modelform_factory(Loan, fields='__all__')
  103. def get_queryset(self, request):
  104. qs = super(AddLoanInline, self).get_queryset(request)
  105. return qs.none()
  106. def has_delete_permission(self, request, obj=None):
  107. return False
  108. class BorrowerFilter(admin.SimpleListFilter):
  109. title = 'Adhérent emprunteur'
  110. parameter_name = 'user'
  111. def _filter_loans(self, items_queryset, user_pk=None):
  112. qs = Loan.objects.running().filter(item__in=items_queryset)
  113. if user_pk is not None:
  114. qs.filter(user=user_pk)
  115. return qs
  116. def lookups(self, request, model_admin):
  117. # Get relevant (and authorized) users only
  118. relevant_items = model_admin.get_queryset(request)
  119. users = set()
  120. for loan in self._filter_loans(relevant_items):
  121. users.add((loan.user.pk, loan.user))
  122. return users
  123. def queryset(self, request, queryset):
  124. if self.value():
  125. loans_qs = self._filter_loans(queryset).filter(
  126. user__pk=self.value(),
  127. )
  128. return queryset.filter(loans__in=loans_qs)
  129. else:
  130. return queryset
  131. @admin.register(Item)
  132. class ItemAdmin(admin.ModelAdmin):
  133. list_display = (
  134. 'designation',
  135. 'current_borrower',
  136. 'get_mac_and_serial',
  137. 'deployed', 'is_available', 'storage',
  138. 'buy_date', 'owner',
  139. )
  140. list_filter = (
  141. AvailabilityFilter, 'type', 'storage',
  142. 'buy_date', BorrowerFilter, OwnerFilter)
  143. search_fields = (
  144. 'designation', 'mac_address', 'serial',
  145. 'owner__email', 'owner__nickname',
  146. 'owner__first_name', 'owner__last_name')
  147. save_as = True
  148. actions = ['give_back']
  149. form = autocomplete_light.modelform_factory(Loan, fields='__all__')
  150. inlines = [AddLoanInline, CurrentLoanInline, LoanHistoryInline]
  151. def give_back(self, request, queryset):
  152. for item in queryset.filter(loans__loan_date_end=None):
  153. item.give_back()
  154. give_back.short_description = 'Rendre le matériel'
  155. def get_urls(self):
  156. urls = super(ItemAdmin, self).get_urls()
  157. my_urls = [
  158. url(
  159. r'^give_back/(?P<id>.+)$',
  160. self.admin_site.admin_view(give_back_loan),
  161. name='loan-give_back'),
  162. ]
  163. return my_urls + urls
  164. class StatusFilter(admin.SimpleListFilter):
  165. title = 'Statut'
  166. parameter_name = 'status'
  167. def lookups(self, request, model_admin):
  168. return [
  169. ('all', 'Tout'),
  170. (None, 'En cours'),
  171. ('finished', 'Passés'),
  172. ]
  173. def choices(self, cl):
  174. for lookup, title in self.lookup_choices:
  175. yield {
  176. 'selected': self.value() == lookup,
  177. 'query_string': cl.get_query_string({
  178. self.parameter_name: lookup,
  179. }, []),
  180. 'display': title,
  181. }
  182. def queryset(self, request, queryset):
  183. v = self.value()
  184. if v in (None, 'running'):
  185. return queryset.running()
  186. elif v == 'finished':
  187. return queryset.finished()
  188. else:
  189. return queryset
  190. @admin.register(Storage)
  191. class StorageAdmin(admin.ModelAdmin):
  192. list_display = ('name', 'truncated_notes', 'items_count')
  193. def truncated_notes(self, obj):
  194. if len(obj.notes) > 50:
  195. return '{}…'.format(obj.notes[:50])
  196. else:
  197. return obj.notes
  198. truncated_notes.short_description = 'notes'
  199. class LoanInline(admin.TabularInline):
  200. model = Loan
  201. extra = 0
  202. exclude = ('notes',)
  203. readonly_fields = ('item', 'get_mac_and_serial', 'loan_date', 'loan_date_end', 'is_running')
  204. show_change_link = True
  205. def get_queryset(self, request):
  206. qs = super(LoanInline, self).get_queryset(request)
  207. return qs.order_by('-loan_date_end')
  208. def has_add_permission(self, request, obj=None):
  209. return False
  210. def has_delete_permission(self, request, obj=None):
  211. return False
  212. class MemberAdmin(coin.members.admin.MemberAdmin):
  213. inlines = coin.members.admin.MemberAdmin.inlines + [LoanInline]
  214. admin.site.unregister(coin.members.admin.Member)
  215. admin.site.register(coin.members.admin.Member, MemberAdmin)