import autocomplete_light from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail from django.contrib import admin from django.db.models import Sum, Count from django.template.defaultfilters import pluralize from django.utils import timezone from django import forms from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente class ReadOnlyMixin(object): readonly_fields_update = () def get_readonly_fields(self, request, obj=None): readonly_fields = super().get_readonly_fields(request, obj) if obj is None: return readonly_fields else: return readonly_fields + self.readonly_fields_update class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle sortable_field_name = "priority" class AttributionTabularAdminForm(forms.ModelForm): listing = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) spectacles = Spectacle.objects.select_related('location') if self.listing is not None: spectacles = spectacles.filter(listing=self.listing) self.fields['spectacle'].queryset = spectacles class WithoutListingAttributionTabularAdminForm(AttributionTabularAdminForm): listing = False class WithListingAttributionTabularAdminForm(AttributionTabularAdminForm): listing = True class AttributionInline(admin.TabularInline): model = Attribution extra = 0 listing = None def get_queryset(self, request): qs = super().get_queryset(request) if self.listing is not None: qs = qs.filter(spectacle__listing=self.listing) return qs class WithListingAttributionInline(AttributionInline): exclude = ('given', ) form = WithListingAttributionTabularAdminForm listing = True class WithoutListingAttributionInline(AttributionInline): form = WithoutListingAttributionTabularAdminForm listing = False class ParticipantAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['choicesrevente'].queryset = ( Spectacle.objects .select_related('location') ) class ParticipantAdmin(ReadOnlyMixin, admin.ModelAdmin): inlines = [WithListingAttributionInline, WithoutListingAttributionInline] def get_queryset(self, request): return Participant.objects.annotate(nb_places=Count('attributions'), total=Sum('attributions__price')) def nb_places(self, obj): return obj.nb_places nb_places.admin_order_field = "nb_places" nb_places.short_description = "Nombre de places" def total(self, obj): tot = obj.total if tot: return "%.02f €" % tot else: return "0 €" total.admin_order_field = "total" total.short_description = "Total à payer" list_display = ("user", "nb_places", "total", "paid", "paymenttype", "tirage") list_filter = ("paid", "tirage") search_fields = ('user__username', 'user__first_name', 'user__last_name') actions = ['send_attribs', ] actions_on_bottom = True list_per_page = 400 readonly_fields = ("total",) readonly_fields_update = ('user', 'tirage') form = ParticipantAdminForm def send_attribs(self, request, queryset): datatuple = [] for member in queryset.all(): attribs = member.attributions.all() context = {'member': member.user} shortname = "" if len(attribs) == 0: shortname = "bda-attributions-decus" else: shortname = "bda-attributions" context['places'] = attribs print(context) datatuple.append((shortname, context, "bda@ens.fr", [member.user.email])) send_mass_custom_mail(datatuple) count = len(queryset.all()) if count == 1: message_bit = "1 membre a" plural = "" else: message_bit = "%d membres ont" % count plural = "s" self.message_user(request, "%s été informé%s avec succès." % (message_bit, plural)) send_attribs.short_description = "Envoyer les résultats par mail" class AttributionAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'spectacle' in self.fields: self.fields['spectacle'].queryset = ( Spectacle.objects .select_related('location') ) if 'participant' in self.fields: self.fields['participant'].queryset = ( Participant.objects .select_related('user', 'tirage') ) def clean(self): cleaned_data = super(AttributionAdminForm, self).clean() participant = cleaned_data.get("participant") spectacle = cleaned_data.get("spectacle") if participant and spectacle: if participant.tirage != spectacle.tirage: raise forms.ValidationError( "Erreur : le participant et le spectacle n'appartiennent" "pas au même tirage") return cleaned_data class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin): def paid(self, obj): return obj.participant.paid paid.short_description = 'A payé' paid.boolean = True list_display = ("id", "spectacle", "participant", "given", "paid") search_fields = ('spectacle__title', 'participant__user__username', 'participant__user__first_name', 'participant__user__last_name') form = AttributionAdminForm readonly_fields_update = ('spectacle', 'participant') class ChoixSpectacleAdmin(admin.ModelAdmin): form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) def tirage(self, obj): return obj.participant.tirage list_display = ("participant", "tirage", "spectacle", "priority", "double_choice") list_filter = ("double_choice", "participant__tirage") search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name', 'spectacle__title') class QuoteInline(admin.TabularInline): model = Quote class SpectacleAdmin(admin.ModelAdmin): inlines = [QuoteInline] model = Spectacle list_display = ("title", "date", "tirage", "location", "slots", "price", "listing") list_filter = ("location", "tirage",) search_fields = ("title", "location__name") readonly_fields = ("rappel_sent", ) class TirageAdmin(admin.ModelAdmin): model = Tirage list_display = ("title", "ouverture", "fermeture", "active", "enable_do_tirage") readonly_fields = ("tokens", ) list_filter = ("active", ) search_fields = ("title", ) class SalleAdmin(admin.ModelAdmin): model = Salle search_fields = ('name', 'address') class SpectacleReventeAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['answered_mail'].queryset = ( Participant.objects .select_related('user', 'tirage') ) self.fields['seller'].queryset = ( Participant.objects .select_related('user', 'tirage') ) self.fields['soldTo'].queryset = ( Participant.objects .select_related('user', 'tirage') ) class SpectacleReventeAdmin(admin.ModelAdmin): """ Administration des reventes de spectacles """ model = SpectacleRevente def spectacle(self, obj): """ Raccourci vers le spectacle associé à la revente. """ return obj.attribution.spectacle list_display = ("spectacle", "seller", "date", "soldTo") raw_id_fields = ("attribution",) readonly_fields = ("date_tirage",) search_fields = ['attribution__spectacle__title', 'seller__user__username', 'seller__user__first_name', 'seller__user__last_name'] actions = ['transfer', 'reinit'] actions_on_bottom = True form = SpectacleReventeAdminForm def transfer(self, request, queryset): """ Effectue le transfert des reventes pour lesquels on connaît l'acheteur. """ reventes = queryset.exclude(soldTo__isnull=True).all() count = reventes.count() for revente in reventes: attrib = revente.attribution attrib.participant = revente.soldTo attrib.save() self.message_user( request, "%d attribution%s %s été transférée%s avec succès." % ( count, pluralize(count), pluralize(count, "a,ont"), pluralize(count)) ) transfer.short_description = "Transférer les reventes sélectionnées" def reinit(self, request, queryset): """ Réinitialise les reventes. """ count = queryset.count() for revente in queryset.filter( attribution__spectacle__date__gte=timezone.now()): revente.date = timezone.now() - timedelta(hours=1) revente.soldTo = None revente.notif_sent = False revente.tirage_done = False if revente.answered_mail: revente.answered_mail.clear() revente.save() self.message_user( request, "%d attribution%s %s été réinitialisée%s avec succès." % ( count, pluralize(count), pluralize(count, "a,ont"), pluralize(count)) ) reinit.short_description = "Réinitialiser les reventes sélectionnées" admin.site.register(CategorieSpectacle) admin.site.register(Spectacle, SpectacleAdmin) admin.site.register(Salle, SalleAdmin) admin.site.register(Participant, ParticipantAdmin) admin.site.register(Attribution, AttributionAdmin) admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin) admin.site.register(Tirage, TirageAdmin) admin.site.register(SpectacleRevente, SpectacleReventeAdmin)