admin.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. from django.contrib import admin
  2. from django.contrib.contenttypes.admin import GenericStackedInline, GenericTabularInline
  3. from django.db.models import Q
  4. from django.contrib.contenttypes.models import ContentType
  5. from django.contrib.auth.models import User as AuthUser
  6. from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
  7. from django.http import HttpResponseRedirect
  8. from django.utils.html import format_html, mark_safe
  9. from django.urls import reverse
  10. from django.utils import timezone
  11. from django.conf.urls import url
  12. from django.template.response import TemplateResponse
  13. from .forms import UserCreationForm
  14. from .models import User, Corporation, Adhesion
  15. from accounts.models import Profile
  16. from services.models import Service
  17. from djadhere.utils import ActiveFilter, get_active_filter
  18. from banking.models import PaymentUpdate
  19. from datetime import timedelta
  20. ### Inlines
  21. class ProfileInline(admin.StackedInline):
  22. model = Profile
  23. def has_add_permission(self, request):
  24. return False
  25. def has_delete_permission(self, request, obj=None):
  26. return False
  27. class AdhesionInline(admin.StackedInline):
  28. model = Adhesion
  29. fields = ('id', 'notes',)
  30. def has_add_permission(self, request):
  31. return False
  32. def has_delete_permission(self, request, obj=None):
  33. return False
  34. class ServiceInline(admin.StackedInline):
  35. model = Service
  36. extra = 0
  37. show_change_link = True
  38. fields = ('service_type', 'label',)
  39. readonly_fields = ('service_type', 'label',)
  40. def has_add_permission(self, request):
  41. return False
  42. def has_delete_permission(self, request, obj=None):
  43. return False
  44. class ActiveServiceInline(ServiceInline):
  45. verbose_name_plural = 'Services actifs'
  46. def get_queryset(self, request):
  47. return super().get_queryset(request).filter(active=True)
  48. class InactiveServiceInline(ServiceInline):
  49. verbose_name_plural = 'Anciens services'
  50. def get_queryset(self, request):
  51. return super().get_queryset(request).filter(active=False)
  52. ### Filters
  53. class AdherentTypeFilter(admin.SimpleListFilter):
  54. title = 'type d’adhérent·e'
  55. parameter_name = 'type'
  56. def lookups(self, request, model_admin):
  57. return (
  58. ('physique', 'Personne physique'),
  59. ('morale', 'Personne morale'),
  60. )
  61. def queryset(self, request, queryset):
  62. if self.value() == 'physique':
  63. return queryset.filter(user__isnull=False)
  64. if self.value() == 'morale':
  65. return queryset.filter(corporation__isnull=False)
  66. ### Mixins
  67. class AdtSearchMixin:
  68. adhesion_search_field = 'id'
  69. def get_search_results(self, request, queryset, search_term):
  70. queryset, use_distinct = super().get_search_results(request, queryset, search_term)
  71. if search_term[:3] == 'ADT':
  72. try:
  73. adh_id = int(search_term[3:])
  74. except ValueError:
  75. pass
  76. else:
  77. queryset |= self.model.objects.filter(**{self.adhesion_search_field: adh_id})
  78. return queryset, use_distinct
  79. ### ModelAdmin
  80. class UserAdmin(AdtSearchMixin, AuthUserAdmin):
  81. list_display = AuthUserAdmin.list_display + ('get_adhesion_link',)
  82. list_select_related = ('profile', 'adhesion',)
  83. ordering = ('adhesion__id',)
  84. search_fields = AuthUserAdmin.search_fields \
  85. + ('profile__phone_number', 'profile__address', 'profile__notes',) \
  86. + ('=adhesion__id', 'adhesion__notes',)
  87. readonly_fields = ('get_adhesion_link',)
  88. adhesion_search_field = 'adhesion__id'
  89. get_adhesion_link = lambda self, corporation: corporation.adhesion.get_adhesion_link()
  90. get_adhesion_link.short_description = Adhesion.get_adhesion_link.short_description
  91. get_adhesion_link.admin_order_field = 'adhesion__id'
  92. def get_inline_instances(self, request, obj=None):
  93. if obj:
  94. inlines = (ProfileInline, AdhesionInline,)
  95. else:
  96. inlines = ()
  97. return [inline(self.model, self.admin_site) for inline in inlines]
  98. def get_form(self, request, obj=None, **kwargs):
  99. if obj:
  100. return super().get_form(request, obj, **kwargs)
  101. else:
  102. return UserCreationForm
  103. def get_fieldsets(self, request, obj=None):
  104. if obj:
  105. fieldsets = (
  106. (AuthUserAdmin.fieldsets[1][0], {
  107. 'fields': ('get_adhesion_link',) + AuthUserAdmin.fieldsets[1][1]['fields'],
  108. }),
  109. ('Nom d’utilisateur et mot de passe', {
  110. 'classes': ('collapse',),
  111. 'fields': AuthUserAdmin.fieldsets[0][1]['fields'],
  112. }),
  113. (AuthUserAdmin.fieldsets[2][0], {
  114. 'classes': ('collapse',),
  115. 'fields': ('is_active', 'is_staff', 'is_superuser', 'groups',), # removing user_permissions
  116. }),
  117. (AuthUserAdmin.fieldsets[3][0], {
  118. 'classes': ('collapse',),
  119. 'fields': AuthUserAdmin.fieldsets[3][1]['fields'],
  120. }),
  121. )
  122. else:
  123. fieldsets = (
  124. (None, {
  125. 'fields': ('first_name', 'last_name', 'username', 'email',),
  126. }),
  127. )
  128. return fieldsets
  129. def get_actions(self, request):
  130. actions = super().get_actions(request)
  131. if 'delete_selected' in actions:
  132. del actions['delete_selected']
  133. return actions
  134. def has_delete_permission(self, request, obj=None):
  135. return obj and not obj.adhesion
  136. class CorporationAdmin(AdtSearchMixin, admin.ModelAdmin):
  137. list_display = ('social_reason', 'get_adhesion_link',)
  138. list_select_related = ('adhesion',)
  139. ordering = ('adhesion__id',)
  140. search_fields = ('social_reason', 'description', 'email', 'phone_number', 'address', 'notes', 'adhesion__id', 'adhesion__notes',)
  141. readonly_fields = ('get_adhesion_link',)
  142. filter_horizontal = ('members',)
  143. adhesion_search_field = 'adhesion__id'
  144. get_adhesion_link = lambda self, corporation: corporation.adhesion.get_adhesion_link()
  145. get_adhesion_link.short_description = Adhesion.get_adhesion_link.short_description
  146. get_adhesion_link.admin_order_field = 'adhesion__id'
  147. def get_inline_instances(self, request, obj=None):
  148. if obj:
  149. inlines = (AdhesionInline,)
  150. else:
  151. inlines = ()
  152. return [inline(self.model, self.admin_site) for inline in inlines]
  153. def get_actions(self, request):
  154. actions = super().get_actions(request)
  155. if 'delete_selected' in actions:
  156. del actions['delete_selected']
  157. return actions
  158. def get_fieldsets(self, request, obj=None):
  159. fieldsets = super().get_fieldsets(request, obj)
  160. # put adhesion id on top
  161. if obj:
  162. fields = fieldsets[0][1]['fields']
  163. fields.remove('get_adhesion_link')
  164. fieldsets = (
  165. (None, {
  166. 'fields': ['get_adhesion_link'] + fields,
  167. }),
  168. )
  169. return fieldsets
  170. def has_delete_permission(self, request, obj=None):
  171. return False
  172. class AdhesionAdmin(AdtSearchMixin, admin.ModelAdmin):
  173. list_display = ('get_id', 'type', 'get_adherent_link', 'is_active')
  174. list_filter = (AdherentTypeFilter, ActiveFilter)
  175. list_select_related = ('user', 'user__profile', 'corporation',)
  176. fields = ('id', 'type', 'get_adherent_link', 'get_membership_link', 'get_antennas_link',)
  177. readonly_fields = ('id', 'type', 'get_adherent_link', 'get_membership_link', 'get_antennas_link',)
  178. search_fields = ('=id', 'notes',) \
  179. + tuple(['user__%s' % f for f in UserAdmin.search_fields if 'adhesion' not in f]) \
  180. + tuple(['corporation__%s' % f for f in CorporationAdmin.search_fields if 'adhesion' not in f])
  181. inlines = (ActiveServiceInline, InactiveServiceInline,)
  182. def get_id(self, obj):
  183. return 'ADT%d' % obj.id
  184. get_id.short_description = 'Numéro d’adhérent·e'
  185. get_id.admin_order_field = 'id'
  186. def get_membership_link(self, obj):
  187. return format_html(u'<a href="{}">{}</a>', obj.membership.get_absolute_url(), obj.membership.get_current_payment_display())
  188. get_membership_link.short_description = 'Cotisation'
  189. def get_antennas_link(self, obj):
  190. return mark_safe('<br />'.join(map(lambda antenna: antenna.get_absolute_link(), obj.antenna_set.all())))
  191. get_antennas_link.short_description = 'Antennes'
  192. def get_actions(self, request):
  193. actions = super().get_actions(request)
  194. if 'delete_selected' in actions:
  195. del actions['delete_selected']
  196. return actions
  197. def has_add_permission(self, request):
  198. return False
  199. def has_delete_permission(self, request, obj=None):
  200. if not obj:
  201. return False
  202. one_year_ago = timezone.now() - timedelta(days=365)
  203. membership = obj.membership.updates.filter(validated=True).first()
  204. # si l’adhésion n’a pas été résilié il y a plus d’un an
  205. if not membership or membership.payment_method != PaymentUpdate.STOP or membership.start > one_year_ago:
  206. return False
  207. # si l’adhérent·e est référent pour une antenne
  208. if obj.antenna_set.exists():
  209. return False
  210. # si l’adherent a un service
  211. if obj.services.exists():
  212. return False
  213. return True
  214. def contact_view(self, request):
  215. adhesions = request.GET.get('pk').split(',')
  216. adhesions = Adhesion.objects.filter(pk__in=adhesions)
  217. user_email = filter(lambda x: x, adhesions.values_list('user__email', flat=True))
  218. corp_email = filter(lambda x: x, adhesions.values_list('corporation__email', flat=True))
  219. user_tel = filter(lambda x: x, adhesions.values_list('user__profile__phone_number', flat=True))
  220. corp_tel = filter(lambda x: x, adhesions.values_list('corporation__phone_number', flat=True))
  221. sms_filter = lambda x: x[:2] == '06' or x[:2] == '07' or x[:3] == '+336' or x[:3] == '+337'
  222. return TemplateResponse(request, 'adhesions/contact.html', dict(
  223. adhesions = adhesions,
  224. emails = set(user_email) | set(corp_email),
  225. sms = filter(sms_filter, set(user_tel) | set(corp_tel))
  226. ))
  227. def get_urls(self):
  228. my_urls = [
  229. url(r'^contact/$', self.admin_site.admin_view(self.contact_view, cacheable=True), name='contact-adherents'),
  230. ]
  231. return my_urls + super().get_urls()
  232. admin.site.unregister(AuthUser)
  233. admin.site.register(User, UserAdmin)
  234. admin.site.register(Corporation, CorporationAdmin)
  235. admin.site.register(Adhesion, AdhesionAdmin)