Gestion de contact et suivi de conversion pour les groupement d'agriculture biologique
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.
 
 
 
 
 

415 lines
14 KiB

# -*- coding: utf-8 -*-
import datetime
import re
import django.forms as forms
import django.http as http
import django.views.generic as generic_views
from django.conf import settings
from django.contrib import messages
from django.db.models import Count
from django.shortcuts import render
from django.urls import NoReverseMatch, reverse
import model_walk
import contacts.models as contacts_models
import contacts.utils as contacts_utils
try: # On utilise cStringIO si possible
from io import StringIO
except ImportError:
from io import StringIO
# the docstring of the following function that starts with "gen_"
# is used as 'short_description' for django
# ## admin_actions
def _gen_mailto(queryset, sympa=False):
"shared code between full views and admin_action"
adresses = []
sans_adresse = []
for contact in queryset:
liste_adr = contact.get_courriels()
if liste_adr:
# on collecte l'adresse si elle n'est pas déjà sélectionnée
adrs = {}
for nom, email in liste_adr:
if email not in adrs:
adrs[email] = True
##
ext_mail = re.sub(
' *',
' ',
email.replace(',', ' ').replace(';', ' ').strip(),
).split(' ')
for sub_mail in ext_mail:
if nom:
dest = (
'{1} "{0}"' if sympa else '"{0}" <{1}>'
).format(nom.strip(), sub_mail)
else:
dest = email
adresses.append(dest)
else:
sans_adresse.append(
(str(contact), contact.get_absolute_url()) # noqa: F821
)
return (adresses, sans_adresse)
def _gen_mailto_gen(model_admin, request, queryset, sympa=False):
"suitable for admin action"
dest, no_adr = _gen_mailto(queryset, sympa)
mc = model_admin.model
url_changelist = reverse(
'admin:{}_{}_changelist'.format(
mc._meta.app_label, mc.__name__.lower()
)
)
context = {
'sympa': sympa,
'destinataires': dest,
'sans_adresse': no_adr,
'nom_objet': {
'singulier': mc._meta.verbose_name,
'pluriel': mc._meta.verbose_name_plural,
},
'css_app': settings.STATIC_URL + "css/contacts.css",
'url_retour': url_changelist,
}
return render(request, 'admin/contacts/mailto.html', context)
def gen_mailto(model_admin, request, queryset):
"Envoyer un courriel"
return _gen_mailto_gen(model_admin, request, queryset)
def gen_mailto_sympa(model_admin, request, queryset):
"Génerer une liste pour Sympa"
return _gen_mailto_gen(model_admin, request, queryset, sympa=True)
def _gen_csv(
request,
model,
queryset,
incl_p_assoc=False,
nom_fichier='export.csv',
msg_aucun_objet="Le panier ne contient pas d'objet correspondant",
classe_export=None,
attr_liste=None,
):
object_list = []
for obj in queryset:
object_list.append(obj)
if incl_p_assoc:
object_list.extend(
[
passoc
for passoc in obj.liste_contacts_associes()
if passoc.courrier_structure
]
)
if len(object_list) == 0:
messages.error(request, msg_aucun_objet)
try:
url_back = reverse(
'admin:{}_{}_changelist'.format(
model._meta.app_label, model.__name__.lower()
)
)
except NoReverseMatch:
url_back = reverse('admin:index')
return http.HttpResponseRedirect(url_back)
buffer = StringIO()
csvdoc = classe_export(buffer, attr_liste)
csvdoc.generer(object_list)
response = http.HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=' + nom_fichier
response.write(buffer.getvalue())
buffer.close()
return response
def gen_csv_complet(model_admin, request, queryset):
"Exporter les données en CSV"
return _gen_csv(
request,
model_admin.model,
queryset,
nom_fichier='export_donnees.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_assolement(model_admin, request, queryset):
"Exporter les assolements des données en CSV"
assolement = contacts_models.Assolement.objects.filter(
donneesbio__in=queryset
)
return _gen_csv(
request,
contacts_models.Assolement,
assolement,
nom_fichier='export_assolements_donnees.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_commercialisation(model_admin, request, queryset):
"Exporter les commercialisations des données en CSV"
commercialisation = contacts_models.Commercialisation.objects.filter(
donneesbio__in=queryset
)
return _gen_csv(
request,
contacts_models.Commercialisation,
commercialisation,
nom_fichier='export_commercialisations_donnees.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_transformation(model_admin, request, queryset):
"Exporter les transformations des données en CSV"
transformation = contacts_models.Transformation.objects.filter(
donneesbio__in=queryset
)
return _gen_csv(
request,
contacts_models.Transformation,
transformation,
nom_fichier='export_transformations_donnees.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_publipostage(model_admin, request, queryset):
"Exporter pour publipostage (detail personnes)"
return _gen_csv(
request,
model_admin.model,
queryset,
nom_fichier='publipostage_contacts.csv',
classe_export=contacts_utils.ExportCSV,
attr_liste='attrs_publipostage',
)
def gen_csv_publipostage_pphy(model_admin, request, queryset):
"Export publipostage [1/2] (detail personnes)"
pphy_qs = contacts_models.Personne.objects.filter(
structure__in=queryset
).order_by('structure__designation', 'nom')
return _gen_csv(
request,
model_admin.model,
pphy_qs,
nom_fichier='publipostage_contacts_detail.csv',
classe_export=contacts_utils.ExportCSV,
attr_liste='attrs_publipostage',
)
def gen_csv_publipostage_wo_pphy(model_admin, request, queryset):
"Export publipostage [2/2] (pers. morale sans pers. phy.)"
struct_qs = queryset.annotate(nb_pp=Count('personne')).filter(nb_pp=0)
return _gen_csv(
request,
model_admin.model,
struct_qs,
nom_fichier='publipostage_contacts_detail.csv',
classe_export=contacts_utils.ExportCSV,
attr_liste='attrs_publipostage',
)
def gen_csv_rdv_ind(model_admin, request, queryset):
"Exporter les rdv ind. en CSV"
return _gen_csv(
request,
model_admin.model,
queryset,
nom_fichier='export_rdv_ind.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_rdv_coll_det(model_admin, request, queryset):
"Exporter les rdv coll. en CSV (détail part.)"
qs_part_rdv = contacts_models.RdvPersonne.objects.filter(rdv__in=queryset)
return _gen_csv(
request,
contacts_models.RdvPersonne,
qs_part_rdv,
nom_fichier='export_rdv_coll_det.csv',
classe_export=contacts_utils.ExportCSV,
)
def gen_csv_rdv_coll(model_admin, request, queryset):
"Exporter les rdv coll. en CSV"
return _gen_csv(
request,
model_admin.model,
queryset,
nom_fichier='export_rdv_coll.csv',
classe_export=contacts_utils.ExportCSV,
attr_liste='attrs_rdv_coll',
)
class ToggleValDonneesBio(
generic_views.detail.SingleObjectMixin, generic_views.RedirectView
):
action = 'toggle'
model = contacts_models.DonneesBio
def get(self, request, *args, **kwargs):
self.obj = self.get_object()
today = datetime.date.today()
self.obj.date_validation = {
'toggle': None if self.obj.date_validation else today,
'validate': today,
'unvalidate': None,
}.get(self.action)
self.obj.save()
messages.info(
request,
"Les données ont été {0}validées".format(
"" if self.obj.date_validation else "dé - "
),
)
return super(ToggleValDonneesBio, self).get(request, *args, **kwargs)
def get_redirect_url(self, *args, **kwargs):
return reverse('admin:contacts_donneesbio_change', args=[self.obj.id])
# ## ---------------------------------------------------------------------------
# Vue créant un nouvel objet DonneesBio pour un agriculteur bio et redirigant
# vers le formulaire de modification de cet objet.
# (évite l'utilisation de la longue liste des agriculteurs bio).
def adapt_fk_field(list_fk, init_dict):
"transform foreign key field label by appending '_id' at end"
for item in list_fk:
if item in init_dict:
init_dict[item + '_id'] = init_dict[item]
del init_dict[item]
return init_dict
def split_m2m_field(list_m2m, init_dict):
m2m_dict = {}
for item in list_m2m:
if item in init_dict:
m2m_dict[item] = init_dict[item]
del init_dict[item]
return (init_dict, m2m_dict)
class CreeDonneesBio(generic_views.base.RedirectView):
""
option_duplication = True
def get(self, request, *args, **kwargs):
""
agri = contacts_models.Structure.objects.get(pk=self.kwargs['pk'])
this_year = datetime.date.today().year
last_donneesbio = agri.last_donneesbio()
if last_donneesbio:
if last_donneesbio.annee == this_year:
self.donneesbio = last_donneesbio
messages.warning(
self.request,
"Les données de l'année existe déjà"
" redirection vers les données {0}".format(this_year),
)
else:
if self.option_duplication:
# preremplir avec last_donneesbio
init_dict = forms.model_to_dict(last_donneesbio)
del init_dict['id']
init_dict.update(
{
'date_collecte': None,
'date_validation': None,
'date_modification': None,
'annee': this_year,
'remarques': "Attention copie de {}\n{}".format(
last_donneesbio.annee,
init_dict['remarques'] or '',
),
}
)
list_fk = model_walk.get_fk_name_from_model(
last_donneesbio
)
adapt_fk_field(list_fk, init_dict)
list_m2m = model_walk.get_m2m_name_from_model(
last_donneesbio
)
init_dict, m2m_dict = split_m2m_field(list_m2m, init_dict)
self.donneesbio = contacts_models.DonneesBio.objects.create(
**init_dict
)
for key, val in m2m_dict.items():
setattr(self.donneesbio, key, val)
self.creeInlineDonneesBio(
last_donneesbio, contacts_models.Commercialisation
)
self.creeInlineDonneesBio(
last_donneesbio, contacts_models.Assolement
)
self.creeInlineDonneesBio(
last_donneesbio, contacts_models.Transformation
)
else:
# creation ex-nihilo en attendant que la fonction
# soit prete
self.donneesbio = contacts_models.DonneesBio.objects.create(
agriculteur_bio=agri
)
else:
# creation ex-nihilo
self.donneesbio = contacts_models.DonneesBio.objects.create(
agriculteur_bio=agri
)
return super(CreeDonneesBio, self).get(request, *args, **kwargs)
def creeInlineDonneesBio(self, last_donneesbio, model):
list_instance = model.objects.filter(donneesbio__id=last_donneesbio.id)
for instance in list_instance:
init_dict = forms.model_to_dict(instance)
del init_dict['id']
init_dict.update({'donneesbio': self.donneesbio.id})
list_fk = model_walk.get_fk_name_from_model(instance)
adapt_fk_field(list_fk, init_dict)
list_m2m = model_walk.get_m2m_name_from_model(instance)
init_dict, m2m_dict = split_m2m_field(list_m2m, init_dict)
self.instance = model.objects.create(**init_dict)
for key, val in m2m_dict.items():
setattr(self.instance, key, val)
def get_redirect_url(self, **kwargs):
"""
Retourne l'URL de la vue de modification de l'objet DonneesBio
récemment créé.
"""
return reverse(
'admin:contacts_donneesbio_change', args=[self.donneesbio.pk]
)
# this code set short_description to docstrings
for f_name, func in list(globals().items()):
if callable(func) and f_name.startswith('gen_'):
func.short_description = func.__doc__
# EOF
Map all the world