You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1253 lines
38 KiB
1253 lines
38 KiB
# -*- coding: utf-8 -*- |
|
import django.contrib.auth.admin as auth_admin |
|
import django.contrib.auth.models as auth_models |
|
import django.db as db |
|
import django.forms as forms |
|
from django.contrib import admin, messages |
|
from django.forms.models import BaseInlineFormSet |
|
from django.urls import reverse |
|
from django.utils.html import format_html |
|
from django.utils.safestring import mark_safe |
|
from django.utils.translation import ugettext_lazy as _ |
|
|
|
import basket |
|
|
|
import contacts.admin_forms as admin_forms |
|
import contacts.admin_views as admv |
|
import contacts.forms as contacts_forms |
|
import contacts.models as contacts_models |
|
|
|
# from contacts.settings_messages import AVERTISSEMENT_MESSAGE as w_msg |
|
|
|
|
|
# Helper function |
|
def get_readonly_field(model_admin): |
|
"parse model_admin.fieldsets to set up a readonly mask" |
|
rof = [] |
|
if model_admin.fieldsets: |
|
for label, opt in model_admin.fieldsets: |
|
for field in opt['fields']: |
|
if isinstance(field, (tuple, list)): |
|
rof.extend(field) |
|
else: |
|
rof.append(field) |
|
elif model_admin.fields: |
|
rof.extend(model_admin.fields) |
|
return rof |
|
|
|
|
|
def debug_admin(model_admin, request, queryset): |
|
# import pdb; pdb.set_trace() |
|
return |
|
|
|
|
|
class PostSaveMsgMixin(object): |
|
"send message to user after save_related()" |
|
|
|
def save_related(self, request, form, formsets, change): |
|
"get info/warning message" |
|
super(PostSaveMsgMixin, self).save_related( |
|
request, form, formsets, change |
|
) |
|
mlist = getattr(form.instance, 'get_messages', lambda x: []) |
|
for msg in mlist(): |
|
messages.add_message(request, *msg) |
|
|
|
|
|
class LookupAllowedMixin(object): |
|
"""This class introduce lookup_allowed_tags in order to allow |
|
complex lookup with admin.SimpleListFilter not beiing catch |
|
by SuspiciousOperation""" |
|
|
|
def lookup_allowed(self, key, value): |
|
if self.lookup_allowed_tags and key in self.lookup_allowed_tags: |
|
return True |
|
return super(LookupAllowedMixin, self).lookup_allowed(key, value) |
|
|
|
|
|
class UserFilter(admin.SimpleListFilter): |
|
def lookups(self, request, models): |
|
list_tech = ( |
|
contacts_models.AdhLogin.objects.annotate( |
|
group_count=db.models.Count('groups') |
|
) |
|
.filter(is_active=True, group_count__gte=1) |
|
.order_by('username') |
|
) |
|
return [(t.id, t.username) for t in list_tech] |
|
|
|
def queryset(self, request, queryset): |
|
val = self.value() |
|
if val: |
|
return queryset.filter(**{self.parameter_name: val}) |
|
return queryset |
|
|
|
|
|
class TechnicienFilter(UserFilter): |
|
title = 'technicien' |
|
parameter_name = 'technicien__id__exact' |
|
|
|
|
|
class ProjetBioTechnicienFilter(UserFilter): |
|
title = 'projet bio suivi par' |
|
parameter_name = 'projet_bio__technicien__id__exact' |
|
|
|
|
|
# ## Admin des utilisateurs |
|
class AdminUser(auth_admin.UserAdmin): |
|
""" |
|
On redéfinit l'admin pour les utilisateurs pour éviter l'édition de |
|
champs |
|
inutiles. On hérite de auth_admin.UserAdmin qui définit les urls d'accès |
|
aux formulaire de changement de mot de passe, etc. |
|
""" |
|
|
|
ordering = ('username',) |
|
list_display = ('username', 'first_name', 'last_name', 'is_active') |
|
list_display_links = ('username',) |
|
list_filter = ('is_active',) |
|
|
|
fieldsets = ( |
|
(None, {'fields': ('username', 'password')}), |
|
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}), |
|
(_('Permissions'), {'fields': ('is_active', 'is_superuser')}), |
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}), |
|
(_('Groups'), {'fields': ('groups',)}), |
|
) |
|
readonly_fields = ('last_login', 'date_joined') |
|
|
|
def save_model(self, request, obj, form, change): |
|
""" |
|
Redéfinition de save_model pour forcer tous les utilisateurs à faire |
|
partie du staff (pour accéder à la partie admin) et superutilisateur |
|
(pour pouvoir tout modifier) puisqu'on n'utilise pas de droit. |
|
""" |
|
# on force aussi le username en minuscules pour éviter les ambiguités |
|
obj.username = obj.username.lower() |
|
obj.is_superuser = False |
|
obj.is_staff = True |
|
obj.save() |
|
|
|
|
|
class InlineStructure(admin.TabularInline): |
|
model = contacts_models.Structure |
|
extra = 0 |
|
readonly_fields = ('ville', 'type_pm', 'f_juridique', 'statut') |
|
fields = readonly_fields |
|
can_delete = False |
|
can_add = False |
|
verbose_name = "Personne Morale liée" |
|
verbose_name_plural = "Personnes Morales liées" |
|
fk_name = 'adherent' |
|
|
|
def struct_detail(self, obj): |
|
if obj.id is None: |
|
return "-" |
|
return format_html( |
|
'<a href="{0}">{1}</a>', mark_safe(obj.get_absolute_url()), obj |
|
) |
|
|
|
struct_detail.short_description = "Désignation" |
|
|
|
|
|
class AdminAdh(auth_admin.UserAdmin): |
|
""" |
|
On redéfinit l'admin pour les utilisateurs pour éviter l'édition de |
|
champs |
|
inutiles. On hérite de auth_admin.UserAdmin qui définit les urls d'accès |
|
aux formulaire de changement de mot de passe, etc. |
|
""" |
|
|
|
ordering = ('username',) |
|
list_display = ('username', 'is_active') |
|
list_display_links = ('username',) |
|
list_filter = ('is_active',) |
|
|
|
fieldsets = ( |
|
(None, {'fields': ('username', 'is_active', 'password')}), |
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}), |
|
) |
|
readonly_fields = ('last_login', 'date_joined') |
|
inlines = (InlineStructure,) |
|
|
|
def save_model(self, request, obj, form, change): |
|
""" |
|
Redéfinition de save_model pour forcer tous les utilisateurs à faire |
|
partie du staff (pour accéder à la partie admin) |
|
""" |
|
# on force aussi le username en minuscules pour éviter les ambiguités |
|
obj.username = obj.username.lower() |
|
obj.is_superuser = False |
|
obj.is_staff = True |
|
obj.save() |
|
|
|
|
|
# ## Inline |
|
# InlinePersonne doit être définie avant BaseAdminStructure |
|
class InlinePersonne(admin.StackedInline): |
|
""" |
|
Classe de personnalisation de l'admin pour le modèle Personne en inline. |
|
|
|
Note: on ne peut pas hériter de MixinAdminFiltrable à ce niveau à cause |
|
car le fonctionnement n'est pas le même. |
|
""" |
|
|
|
form = admin_forms.PersonneAdminForm |
|
model = contacts_models.Personne |
|
readonly_fields = ( |
|
'date_creation', |
|
'date_derniere_modification', |
|
'utilisateur_derniere_modification', |
|
) |
|
fieldsets = ( |
|
( |
|
'Désignation', |
|
{ |
|
'fields': ( |
|
('civilite', 'nom', 'prenom', 'fonction'), |
|
'structure', |
|
('date_naissance', 'date_installation'), |
|
'reseaux_engagements', |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
( |
|
'Coordonnées', |
|
{ |
|
'fields': ( |
|
'adresse', |
|
'commune', |
|
('code_postal', 'ville'), |
|
'courrier_structure', |
|
'tel_fixe', |
|
'tel_mobile', |
|
'fax', |
|
'courriel', |
|
'pas_de_courriel', |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
( |
|
'Enregistrement', |
|
{ |
|
'fields': ( |
|
( |
|
'date_creation', |
|
'date_derniere_modification', |
|
'utilisateur_derniere_modification', |
|
), |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
) |
|
extra = 0 |
|
|
|
|
|
class InlinePersonneRo(InlinePersonne): |
|
readonly_fields = get_readonly_field(InlinePersonne) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class FieldsProjetBio(object): |
|
radio_fields = { |
|
"pond_savoirfaire": admin.HORIZONTAL, |
|
"pond_motivation": admin.HORIZONTAL, |
|
"pond_entourage": admin.HORIZONTAL, |
|
"pond_foncier": admin.HORIZONTAL, |
|
"pond_materiel": admin.HORIZONTAL, |
|
"pond_reglementation": admin.HORIZONTAL, |
|
"pond_commercialisation": admin.HORIZONTAL, |
|
"pond_financement": admin.HORIZONTAL, |
|
"pond_maindoeuvre": admin.HORIZONTAL, |
|
} |
|
|
|
@classmethod |
|
def get_fieldsets(cls, collapse=False): |
|
return ( |
|
( |
|
'Projet', |
|
{ |
|
'fields': ( |
|
'agriculteur', |
|
'technicien', |
|
'description', |
|
'freins_identifies', |
|
'pond_savoirfaire', |
|
'pond_motivation', |
|
'pond_entourage', |
|
'pond_foncier', |
|
'pond_materiel', |
|
'pond_reglementation', |
|
'pond_commercialisation', |
|
'pond_financement', |
|
'pond_maindoeuvre', |
|
'suites_a_donner', |
|
'remarques', |
|
('date_probable_certification', 'date_certification'), |
|
('engagement_surf', 'engagement_oc_enjeu_eau'), |
|
('installation_bio', 'date_engagement_oc'), |
|
), |
|
'classes': ('collapse', 'wide') if collapse else ('wide',), |
|
}, |
|
), |
|
) |
|
|
|
|
|
class InlineProjetBio(admin.StackedInline): |
|
""" |
|
Inline pour affichage des projets bio dans le formulaire d'un Agriculteur. |
|
""" |
|
|
|
model = contacts_models.ProjetBio |
|
extra = 0 |
|
radio_fields = FieldsProjetBio.radio_fields |
|
fieldsets = FieldsProjetBio.get_fieldsets(collapse=True) |
|
|
|
def formfield_for_foreignkey(self, db_field, request, **kwargs): |
|
""" |
|
On exclut l'utilisateur « admin » de la liste des techniciens. |
|
""" |
|
if db_field.name == "technicien": |
|
kwargs["queryset"] = auth_models.User.objects.exclude( |
|
username='admin' |
|
) |
|
return super(InlineProjetBio, self).formfield_for_foreignkey( |
|
db_field, request, **kwargs |
|
) |
|
|
|
|
|
class InlineProjetBioRo(InlineProjetBio): |
|
readonly_fields = get_readonly_field(InlineProjetBio) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineAdhesionGabnorFormSet(BaseInlineFormSet): |
|
"limiter l'affichage des adhesions aux 5 dernieres" |
|
|
|
def get_queryset(self): |
|
return super(InlineAdhesionGabnorFormSet, self).get_queryset()[:5] |
|
|
|
|
|
class InlineAdhesionGabnor(admin.TabularInline): |
|
"" |
|
model = contacts_models.AdhesionGabnor |
|
verbose_name = "adhésion GAB" |
|
verbose_name_plural = "adhésions GAB" |
|
extra = 0 |
|
formset = InlineAdhesionGabnorFormSet |
|
fieldsets = ((None, {'fields': (('date', 'montant', 'mode_reg'),)}),) |
|
|
|
|
|
class InlineAdhesionGabnorRo(InlineAdhesionGabnor): |
|
readonly_fields = get_readonly_field(InlineAdhesionGabnor) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineRdv(admin.TabularInline): |
|
model = contacts_models.Rdv |
|
extra = 0 |
|
form = admin_forms.RdvForm |
|
verbose_name = "Rendez vous" |
|
verbose_name_plural = "Rendez vous" |
|
fields = ( |
|
'date', |
|
'technicien', |
|
'type_rdv', |
|
'projet_bio', |
|
'titre_evt', |
|
'lieu', |
|
'finance_prog', |
|
'est_confirme', |
|
) |
|
autocomplete_fields = ('lieu',) |
|
|
|
def get_formsets_with_inlines(self, *args, **kwargs): |
|
return super(InlineRdv, self).get_formsets_with_inlines( |
|
*args, **kwargs |
|
) |
|
|
|
|
|
class InlineRdvRo(InlineRdv): |
|
readonly_fields = get_readonly_field(InlineRdv) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineRdvPersonne(admin.TabularInline): |
|
model = contacts_models.RdvPersonne |
|
extra = 0 |
|
verbose_name = "Participation personne" |
|
verbose_name_plural = "Participations des personnes" |
|
readonly_fields = ['is_organisateur'] |
|
fields = ('rdv', 'personne', 'is_organisateur') |
|
autocomplete_fields = ('personne',) |
|
|
|
|
|
class InlineRdvPersonneRo(InlineRdvPersonne): |
|
readonly_fields = get_readonly_field(InlineRdvPersonne) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineRdvPersonneMorale(admin.StackedInline): |
|
model = contacts_models.RdvPersonneMorale |
|
extra = 0 |
|
verbose_name = "Participation personne morale " |
|
verbose_name_plural = "Participations des personnes morales" |
|
fields = ('rdv', 'rdv_detail', 'structure') |
|
readonly_fields = ('rdv_detail',) |
|
# Ce champs doit etre defini dans la classe qui herite _directement_ |
|
# de Stacked/Tabular Inline a cause d'une sombre histoire de metaclass |
|
|
|
def rdv_detail(self, obj): |
|
if obj.id is None or obj.rdv.id is None: |
|
return "-" |
|
return format_html( |
|
'<a href="{0}">{1}</a>', |
|
mark_safe(obj.rdv.get_absolute_url()), |
|
obj.rdv, |
|
) |
|
|
|
rdv_detail.short_description = "Détail rdv" |
|
|
|
|
|
class InlineRdvPersonneMoraleRo(InlineRdvPersonneMorale): |
|
readonly_fields = get_readonly_field(InlineRdvPersonneMorale) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineRdvPersonneMoraleStruct(InlineRdvPersonneMorale): |
|
verbose_name = "Participation aux rdv collectifs" |
|
verbose_name_plural = "Participations aux rdv collectifs" |
|
can_add = False |
|
fields = ('rdv_detail', 'structure') |
|
|
|
|
|
class InlineRdvPersonneMoraleStructRo(InlineRdvPersonneMoraleStruct): |
|
readonly_fields = get_readonly_field(InlineRdvPersonneMorale) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineAssolement(admin.TabularInline): |
|
""" |
|
Classe d'admin pour les données d'assolement de l'observatoire. |
|
""" |
|
|
|
model = contacts_models.Assolement |
|
form = admin_forms.FormAssolement |
|
verbose_name = "Assolement" |
|
verbose_name_plural = "Assolements" |
|
extra = 0 |
|
fieldsets = ( |
|
( |
|
None, |
|
{ |
|
'fields': ( |
|
('culture', 'detail_culture'), |
|
( |
|
'surface_bio', |
|
'surface_c1', |
|
'surface_c2', |
|
'surface_c3', |
|
'surface_conv', |
|
), |
|
('tonnage', 'prix', 'client', 'type_circuit'), |
|
) |
|
}, |
|
), |
|
) |
|
formfield_overrides = { |
|
db.models.DecimalField: {'widget': forms.TextInput(attrs={'size': 5})}, |
|
db.models.FloatField: {'widget': forms.TextInput(attrs={'size': 5})}, |
|
} |
|
|
|
|
|
class InlineAssolementRo(InlineAssolement): |
|
readonly_fields = get_readonly_field(InlineAssolement) |
|
form = admin_forms.FormAssolementRo |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineCommercialisation(admin.TabularInline): |
|
""" |
|
Classe d'admin pour les données de commercialisation de l'observatoire. |
|
""" |
|
|
|
model = contacts_models.Commercialisation |
|
verbose_name = "Commercialisation" |
|
verbose_name_plural = "Commercialisations" |
|
extra = 0 |
|
fieldsets = ( |
|
( |
|
None, |
|
{ |
|
'fields': ( |
|
'type_produit', |
|
'type_circuit', |
|
'ch_aff', |
|
'detail', |
|
'bio', |
|
) |
|
}, |
|
), |
|
) |
|
formfield_overrides = { |
|
db.models.TextField: {'widget': forms.Textarea(attrs={'rows': 2})} |
|
} |
|
|
|
|
|
class InlineCommercialisationRo(InlineCommercialisation): |
|
readonly_fields = get_readonly_field(InlineCommercialisation) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineTransformation(admin.TabularInline): |
|
""" |
|
Classe d'admin pour les données de transformation de l'observatoire. |
|
""" |
|
|
|
model = contacts_models.Transformation |
|
verbose_name = "Transformation" |
|
verbose_name_plural = "Transformations" |
|
extra = 0 |
|
formfield_overrides = { |
|
db.models.TextField: {'widget': forms.Textarea(attrs={'rows': 2})} |
|
} |
|
fieldsets = ( |
|
( |
|
None, |
|
{ |
|
'fields': ( |
|
('ferme', 'type_pduit'), |
|
'agrmt', |
|
'list_pduit', |
|
('part_vol_glob', 'est_bio'), |
|
'lait_abattoirs_vl', |
|
) |
|
}, |
|
), |
|
) |
|
|
|
|
|
class InlineTransformationRo(InlineTransformation): |
|
readonly_fields = get_readonly_field(InlineTransformation) |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
class InlineDocumentJoint(admin.TabularInline): |
|
fields = ('date_depot', 'document') |
|
readonly_fields = ('date_depot',) |
|
model = contacts_models.DocumentJoint |
|
extra = 0 |
|
|
|
|
|
class InlineDocumentJointRo(InlineDocumentJoint): |
|
def doc_detail(self, obj): |
|
if obj.id is None or obj.rdv.id is None: |
|
return "-" |
|
return format_html( |
|
'<a href="{0}">{1}</a>', |
|
mark_safe(obj.document.url), |
|
obj.document.name, |
|
) |
|
|
|
doc_detail.short_description = "Document" |
|
|
|
fields = ('date_depot', 'doc_detail') |
|
readonly_fields = fields |
|
can_delete = False |
|
can_add = False |
|
|
|
|
|
# ## ModelAdmin |
|
# Admin de Personne |
|
class AdminPersonne( |
|
PostSaveMsgMixin, basket.MixinBasketAdmin, admin.ModelAdmin |
|
): |
|
""" |
|
Classe de personnalisation de l'admin pour le modèle Personne. |
|
""" |
|
|
|
list_display = ('nom', 'prenom', 'structure') |
|
list_display_links = ('nom', 'prenom', 'structure') |
|
list_filter = ('structure__type_pm', 'structure__statut') |
|
actions = ( |
|
admv.gen_mailto, |
|
admv.gen_csv_publipostage, |
|
admv.gen_csv_complet, |
|
) |
|
basket_actions = actions |
|
search_fields = ('nom', 'prenom') |
|
|
|
def save_model(self, request, obj, form, change): |
|
"automatically assign user's name who modify form" |
|
obj.utilisateur_derniere_modification = request.user |
|
obj.save() |
|
|
|
inlines = (InlineRdvPersonne,) |
|
|
|
|
|
class AdminPersonneRo(AdminPersonne): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminPersonne) |
|
|
|
inlines = (InlineRdvPersonneRo,) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminPersonneRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
class AdminStructure( |
|
PostSaveMsgMixin, |
|
basket.MixinBigFilter, |
|
basket.MixinBasketAdmin, |
|
admin.ModelAdmin, |
|
): |
|
"Classe de personnalisation de l'admin pour le modèle Structure." |
|
|
|
class Media: |
|
css = {"all": ("css/contacts.css",)} |
|
js = ['js/list_filter_collapse.js'] |
|
|
|
# django.jQuery( |
|
# "div#rdvpersonnemorale_set-group > div[id!='rdvpersonnemorale_set-empty']" |
|
# ).toggle() |
|
|
|
# change_list |
|
list_display = ( |
|
'id', |
|
'nom_affichage', |
|
'statut', |
|
'f_juridique', |
|
'commune', |
|
'type', |
|
'get_date_premiere_conversion', |
|
) |
|
list_display_links = ('nom_affichage',) |
|
search_fields = ('designation', 'personne__nom', 'commune__nom') |
|
autocomplete_fields = ('commune',) |
|
list_filter = ( |
|
'type_pm', |
|
'statut', |
|
'f_juridique', |
|
'type_activite', |
|
'type_activite_pri', |
|
'commune__territoire', |
|
'commune__petite_region', |
|
'commune__arrondissement', |
|
) |
|
actions = ( |
|
admv.gen_mailto, |
|
admv.gen_mailto_sympa, |
|
admv.gen_csv_publipostage_pphy, |
|
admv.gen_csv_publipostage_wo_pphy, |
|
admv.gen_csv_complet, |
|
) |
|
basket_actions = actions |
|
form = admin_forms.AgriculteurAdminForm |
|
radio_fields = {"visibilite": admin.HORIZONTAL} |
|
date_hierarchie = 'date_creation' |
|
filter_horizontal = ('etiquettes', 'qual_compl', 'qual_compl_conv') |
|
readonly_fields = ( |
|
'date_creation', |
|
'date_derniere_modification', |
|
'utilisateur_derniere_modification', |
|
'premiere_adhesion', |
|
'renouvellement_adhesion', |
|
'adherent_edit', |
|
'ass_total', |
|
'ass_total_bio', |
|
) |
|
fieldsets = ( |
|
( |
|
'Désignation', |
|
{ |
|
'fields': ( |
|
('designation', 'type_pm'), |
|
('adherent', 'adherent_edit'), |
|
('siret', 'f_juridique', 'statut'), |
|
'commentaire', |
|
'visibilite', |
|
'etiquettes', |
|
) |
|
}, |
|
), |
|
( |
|
'Coordonnées', |
|
{ |
|
'fields': ( |
|
('adresse', 'non_courrier'), |
|
'commune', |
|
('code_postal', 'ville'), |
|
'tel_fixe', |
|
'tel_mobile', |
|
'fax', |
|
'courriel', |
|
'site_web', |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
( |
|
"Informations sur l'exploitation", |
|
{ |
|
'fields': ( |
|
('type_activite', 'type_activite_pri'), |
|
'qual_compl', |
|
'qual_compl_conv', |
|
('sau_eau', 'sau_eau_bio'), |
|
('ass_total', 'ass_total_bio'), |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
( |
|
'Infos adhésions Gabnor', |
|
{ |
|
'fields': (('premiere_adhesion', 'renouvellement_adhesion'),), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
( |
|
'Contact', |
|
{ |
|
'fields': ( |
|
'origine_contact', |
|
('annee_contact', 'mois_contact'), |
|
( |
|
'date_creation', |
|
'date_derniere_modification', |
|
'utilisateur_derniere_modification', |
|
), |
|
), |
|
'classes': ('collapse',), |
|
}, |
|
), |
|
) |
|
inlines = (InlineAdhesionGabnor, InlinePersonne, InlineProjetBio) |
|
classe_form_filtre = contacts_forms.FormFiltreStructure |
|
class_form_big_filter = contacts_forms.FormFiltreStructure |
|
|
|
def adherent_edit(self, obj): |
|
if obj.id is None or obj.adherent is None: |
|
return "-" |
|
return format_html( |
|
'<a href="{0}">{1}</a>', |
|
mark_safe( |
|
reverse( |
|
"admin:contacts_adhlogin_change", args=[obj.adherent.id] |
|
) |
|
), |
|
obj.adherent, |
|
) |
|
|
|
adherent_edit.short_description = "Détail compte adhérent" |
|
|
|
def get_formsets(self, request, obj=None): |
|
for inline in self.get_inline_instances(request): |
|
resp = inline.get_formset(request, obj) |
|
if resp.model == contacts_models.Rdv: |
|
pass |
|
yield resp |
|
|
|
def nom_affichage(self, obj): |
|
return str(obj) |
|
|
|
nom_affichage.short_description = "Structure ou personne" |
|
|
|
def save_model(self, request, obj, form, change): |
|
""" |
|
Redéfinition de save_model pour assigner automatiquement le nom de |
|
l'utilisateur ayant effectué la modification. |
|
""" |
|
obj.utilisateur_derniere_modification = request.user |
|
obj.save() |
|
|
|
def save_formset(self, request, form, formset, change): |
|
"update user who made last modification for inlines" |
|
instances = formset.save(commit=False) |
|
for instance in instances: |
|
instance.utilisateur_derniere_modification = request.user |
|
instance.save() |
|
formset.save_m2m() |
|
|
|
|
|
class AdminStructureRo(AdminStructure): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminStructure) |
|
|
|
inlines = (InlineAdhesionGabnorRo, InlinePersonneRo, InlineProjetBioRo) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminStructureRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
# ## Admin de ProjetBio et dépendances |
|
class AdminProjetBio( |
|
PostSaveMsgMixin, basket.MixinBasketAdmin, admin.ModelAdmin |
|
): |
|
""" |
|
Classe d'admin pour afficher les projets bio de façon indépendante. |
|
""" |
|
|
|
list_display = ('__str__', 'agri_id') |
|
list_display_links = ('__str__',) |
|
inlines = (InlineRdv,) |
|
search_fields = ( |
|
'agriculteur__designation', |
|
'agriculteur__personne__nom', |
|
'agriculteur__commune__nom', |
|
) |
|
list_filter = (TechnicienFilter,) |
|
actions = (admv.gen_csv_complet,) |
|
basket_actions = (admv.gen_csv_complet,) |
|
|
|
radio_fields = FieldsProjetBio.radio_fields |
|
fieldsets = FieldsProjetBio.get_fieldsets(collapse=False) |
|
|
|
def formfield_for_foreignkey(self, db_field, request, **kwargs): |
|
if db_field.name == "technicien": |
|
kwargs["queryset"] = auth_models.User.objects.exclude( |
|
username='admin' |
|
) |
|
return super(AdminProjetBio, self).formfield_for_foreignkey( |
|
db_field, request, **kwargs |
|
) |
|
|
|
|
|
class AdminProjetBioRo(AdminProjetBio): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminProjetBio) |
|
|
|
inlines = (InlineRdvRo,) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminProjetBioRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
class AdminDonneesBio( |
|
PostSaveMsgMixin, basket.MixinBasketAdmin, admin.ModelAdmin |
|
): |
|
""" |
|
Classe d'admin pour les données de l'observatoire (également éditées |
|
dans les formulaires des agriculteurs bio). |
|
""" |
|
|
|
inlines = (InlineAssolement, InlineCommercialisation, InlineTransformation) |
|
search_fields = ( |
|
'agriculteur_bio__designation', |
|
'agriculteur_bio__personne__nom', |
|
'agriculteur_bio__commune__nom', |
|
) |
|
list_filter = ('annee',) |
|
list_display = ('__str__', 'agri_id') |
|
# date_hierarchy = 'date_collecte' |
|
actions = ( |
|
admv.gen_csv_complet, |
|
admv.gen_csv_assolement, |
|
admv.gen_csv_commercialisation, |
|
admv.gen_csv_transformation, |
|
) |
|
basket_actions = (admv.gen_csv_complet,) |
|
# Ne fonctionne pas correctement -> à voir |
|
formfield_overrides = { |
|
db.models.BooleanField: {'widget': forms.CheckboxInput} |
|
} |
|
readonly_fields = ( |
|
'ass_total', |
|
'ass_total_bio', |
|
'com_ca_total', |
|
'com_pct_ca_bio', |
|
'agri_detail', |
|
) |
|
fieldsets = ( |
|
( |
|
None, |
|
{ |
|
'fields': ( |
|
('agriculteur_bio', 'agri_detail'), |
|
('date_collecte', 'technicien'), |
|
'annee', |
|
'organisme_certification', |
|
'biodynamie', |
|
'remarques', |
|
) |
|
}, |
|
), |
|
( |
|
"Aides", |
|
{ |
|
'fields': ( |
|
('aide_conversion_ab', 'date_aide_conversion_ab'), |
|
( |
|
'aide_maintien_ab', |
|
'aide_credit_impot', |
|
'aide_certification_bio', |
|
), |
|
('aide_investissement', 'aide_installation', 'aide_mae_t'), |
|
'aide_autres', |
|
('aide_accompagnement', 'aide_accompagnement_precisions'), |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Main d'œuvre", |
|
{ |
|
'fields': ( |
|
('etp_associes', 'etp_familiaux'), |
|
('etp_salaries_permanents', 'etp_saisonniers'), |
|
('etp_encadrants', 'personnes_insertion'), |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Transmission", |
|
{ |
|
'fields': ( |
|
('tr_date_fin_prevue', 'tr_repreneur_ident'), |
|
'tr_precisions', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Commercialisation", |
|
{ |
|
'fields': ( |
|
('statut_commercialisation', 'statut_choisi'), |
|
('com_ca_total', 'com_pct_ca_bio'), |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
'Accueil', |
|
{ |
|
'fields': ( |
|
('acc_act_tour', 'acc_act_peda'), |
|
('acc_rest_bio', 'acc_act_autre'), |
|
'detail_activites', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Lait de vaches", |
|
{ |
|
'fields': ( |
|
# lait |
|
('lait_vaches', 'lait_nb_vaches'), |
|
('lait_quota_laiterie', 'lait_quota_vente_directe'), |
|
('lait_prod_laiterie', 'lait_prod_vente_directe'), |
|
'lait_laiterie', |
|
# viande issue de vaches laitières |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Lait de chèvres", |
|
{ |
|
'fields': ( |
|
( |
|
'lait_chevres', |
|
'lait_nb_chevres', |
|
'lait_chevres_conversion', |
|
), |
|
'lait_chevres_prod', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Viande bovine", |
|
{ |
|
'fields': ( |
|
('bovine', 'bovine_nb_va'), |
|
('bovine_reformes_cl', 'bovine_taurillons_cl'), |
|
('bovine_adultes_cc', 'bovine_veaux_cc'), |
|
('lait_reformes_cl', 'lait_taurillons_cl'), |
|
('lait_adultes_cc', 'lait_veaux_cc'), |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Porcs", |
|
{ |
|
'fields': (('porcs', 'porcs_nb_truies'), 'porcs_nb_com'), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Moutons", |
|
{ |
|
'fields': ( |
|
('moutons', 'moutons_nb_brebis'), |
|
'moutons_nb_agn_com', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Petits animaux", |
|
{ |
|
'fields': ( |
|
('animaux_lapins', 'animaux_volailles'), |
|
'animaux_volailles_chair', |
|
'animaux_nb_poulets', |
|
'animaux_nb_lapins', |
|
'animaux_nb_autres_volailles', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Autres productions animales", |
|
{ |
|
'fields': ( |
|
'animaux_autres_prod', |
|
'animaux_details_autres_prod', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Œufs", |
|
{ |
|
'fields': ( |
|
'oeufs_production_bio', |
|
'oeufs_nb_pondeuses', |
|
'oeufs_nb_oeufs', |
|
'oeufs_acheteur_cl', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Miel", |
|
{ |
|
'fields': ('miel_production_bio', 'miel_nb_ruches'), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Formation", |
|
{ |
|
'fields': ( |
|
('formation_annee', 'formation_annee_laquelle'), |
|
'formation_annee_commentaire', |
|
('formation_avenir', 'formation_avenir_type'), |
|
'formation_avenir_details', |
|
), |
|
'classes': ('wide', 'collapse'), |
|
}, |
|
), |
|
( |
|
"Surface d'assolement", |
|
{ |
|
'fields': (('ass_total', 'ass_total_bio'),), |
|
'classes': ('wide',), |
|
}, |
|
), |
|
) |
|
|
|
|
|
class AdminDonneesBioRo(AdminDonneesBio): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminDonneesBio) |
|
|
|
inlines = ( |
|
InlineAssolementRo, |
|
InlineCommercialisationRo, |
|
InlineTransformationRo, |
|
) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminDonneesBioRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
# ## Admin de AdhesionGabnor |
|
class AdminAdhesionGabnor(basket.MixinBasketAdmin, admin.ModelAdmin): |
|
""" |
|
Classe d'admin pour les adhésions Gabnor (également éditées |
|
dans les formulaires des agriculteurs bio). |
|
""" |
|
|
|
date_hierarchy = 'date' |
|
list_filter = ('date', 'mode_reg') |
|
search_fields = ( |
|
'agriculteur_bio__designation', |
|
'agriculteur_bio__personne__nom', |
|
'agriculteur_bio__commune__nom', |
|
) |
|
actions = (admv.gen_csv_complet,) |
|
basket_actions = (admv.gen_csv_complet,) |
|
fields = ('agriculteur_bio', 'date', 'montant', 'mode_reg', 'annee') |
|
|
|
|
|
class AdminAdhesionGabnorRo(AdminAdhesionGabnor): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminAdhesionGabnor) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminAdhesionGabnorRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
class AdminRdv( |
|
PostSaveMsgMixin, |
|
basket.MixinBasketAdmin, |
|
LookupAllowedMixin, |
|
admin.ModelAdmin, |
|
): |
|
search_fields = ( |
|
'titre_evt__designation', |
|
'lieu__nom', |
|
'personne_morale__designation', |
|
'personne_morale__personne__nom', |
|
'rdvpersonnemorale__structure__designation', |
|
'rdvpersonnemorale__structure__personne__nom', |
|
) |
|
nop_autocomplete_fields = ( |
|
'personne_morale', |
|
'lieu', |
|
'organisateur', |
|
'intervenant', |
|
) |
|
lookup_allowed_tags = ( |
|
'projet_bio__technicien__id__exact', |
|
'personnes__structure', |
|
) |
|
|
|
list_filter = ('type_rdv', ProjetBioTechnicienFilter, TechnicienFilter) |
|
list_display = ( |
|
'date', |
|
'type_rdv', |
|
'technicien', |
|
'personne_morale', |
|
'titre_evt', |
|
) |
|
date_hierarchy = 'date' |
|
basket_actions = ( |
|
admv.gen_csv_rdv_ind, |
|
admv.gen_csv_rdv_coll, |
|
admv.gen_csv_rdv_coll_det, |
|
) |
|
actions = ( |
|
admv.gen_csv_rdv_ind, |
|
admv.gen_csv_rdv_coll, |
|
admv.gen_csv_rdv_coll_det, |
|
) |
|
|
|
readonly_fields = ('struct_af_org', 'struct_af_int') |
|
fieldsets = ( |
|
( |
|
None, |
|
{ |
|
'fields': ( |
|
('date', 'type_rdv'), |
|
('technicien', 'lieu'), |
|
'commentaire', |
|
('finance_prog', 'acc_duree', 'acc_distance'), |
|
) |
|
}, |
|
), |
|
( |
|
"Rendez vous individuels", |
|
{'fields': (('personne_morale', 'projet_bio'),)}, |
|
), |
|
( |
|
"Évenements collectifs", |
|
{ |
|
'fields': ( |
|
('est_confirme', 'titre_evt'), |
|
('territoire_cible', 'public_cible'), |
|
('organisateur', 'struct_af_org'), |
|
('intervenant', 'struct_af_int'), |
|
('objectif', 'res_attendu'), |
|
) |
|
}, |
|
), |
|
) |
|
form = admin_forms.RdvForm |
|
inlines = (InlineRdvPersonne, InlineDocumentJoint) |
|
|
|
|
|
class AdminRdvRo(AdminRdv): |
|
def get_readonly_fields(self, request, obj): |
|
return get_readonly_field(AdminRdv) |
|
|
|
inlines = (InlineRdvPersonneRo, InlineDocumentJointRo) |
|
|
|
def change_view(self, request, object_id, extra_context=None): |
|
"ensure no data is saved on a readonly ModelAdmin" |
|
request.method = 'GET' # never consider a POST |
|
return super(AdminRdvRo, self).change_view( |
|
request, object_id, extra_context |
|
) |
|
|
|
|
|
# ## Enregistrement des modèles à administrer |
|
def register_models(site): |
|
""" |
|
Enregistrement des modèles dans un AdminSite passé en paramètre. |
|
""" |
|
# Modèle User avec admin personnalisée |
|
site.register(auth_models.User, AdminUser) |
|
site.register(auth_models.Group, auth_admin.GroupAdmin) |
|
# Modèles principaux indispensables |
|
site.register(contacts_models.Structure, AdminStructure) |
|
site.register(contacts_models.StructureRo, AdminStructureRo) |
|
site.register(contacts_models.Personne, AdminPersonne) |
|
site.register(contacts_models.PersonneRo, AdminPersonneRo) |
|
# Facultatif: administration indépendante de données qu'on retrouve dans en |
|
# inline dans les autres pages. |
|
site.register(contacts_models.ProjetBio, AdminProjetBio) |
|
site.register(contacts_models.ProjetBioRo, AdminProjetBioRo) |
|
site.register(contacts_models.DonneesBio, AdminDonneesBio) |
|
site.register(contacts_models.DonneesBioRo, AdminDonneesBioRo) |
|
site.register(contacts_models.AdhesionGabnor, AdminAdhesionGabnor) |
|
site.register(contacts_models.AdhesionGabnorRo, AdminAdhesionGabnorRo) |
|
site.register(contacts_models.Rdv, AdminRdv) |
|
site.register(contacts_models.RdvRo, AdminRdvRo) |
|
site.register(contacts_models.DocumentJoint) |
|
site.register(contacts_models.AdhLogin, AdminAdh) |
|
|
|
|
|
# fait dans urls.py |
|
# register_models(site) |
|
|
|
# EOF
|
|
|