ajout des filtrages de region/service
[auf_rh_dae.git] / project / dae / forms.py
1 # -*- encoding: utf-8 -*-
2
3 from django.db.models import Q
4 from django import forms
5 from django.forms.models import inlineformset_factory
6 from django.contrib.admin import widgets as admin_widgets
7 from ajax_select.fields import AutoCompleteSelectField
8 from auf.django.workflow.forms import WorkflowFormMixin
9 from datamaster_modeles import models as ref
10 from dae import models as dae
11 from utils import get_employe_from_user, is_user_dans_service
12 from rh_v1 import models as rh
13 from workflow import grp_drh
14
15 def _implantation_choices(obj, request):
16 # TRAITEMENT NORMAL
17 employe = get_employe_from_user(request.user)
18 # SERVICE
19 if is_user_dans_service(request.user):
20 q = Q(**{ 'id' : employe.implantation_id })
21 # REGION
22 else:
23 q = Q(**{ 'region' : employe.implantation.region })
24
25 # TRAITEMENT DRH
26 if grp_drh in request.user.groups.all():
27 q = Q()
28 return [('', '----------')] + [(i.id, unicode(i), )for i in ref.Implantation.objects.filter(q)]
29
30 def _employe_choices(obj, request):
31 q = Q(id_rh__isnull=True) & Q(id_rh__isnull=True)
32
33 # TRAITEMENT NORMAL
34 employe = get_employe_from_user(request.user)
35 # SERVICE
36 if is_user_dans_service(request.user):
37 q_region_service = Q(implantation1=employe.implantation) | Q(implantation2=employe.implantation)
38 # REGION
39 else:
40 q_region_service = Q(implantation1__region=employe.implantation.region) | Q(implantation2__region=employe.implantation.region)
41 # TRAITEMENT DRH
42 if grp_drh in request.user.groups.all():
43 q_region_service = Q()
44
45 # Construction de la liste des employés en puisant dans DAE (pas d'info) et dans rh_v1
46 # Pour le filtrage par région/service, on est obligé d'aller regarder le dossier rh_v1
47 # car l'information dans le modèle rh_v1.Employe n'existe pas.
48 dae_ = dae.Employe.objects.filter(id_rh__isnull=True)
49 copies = dae.Employe.objects.filter(Q(id_rh__isnull=False))
50 id_copies = [p.id_rh_id for p in copies.all()]
51 employes_ids = list(set([d.employe_id for d in rh.Dossier.objects.filter(q_region_service)]))
52 rhv1 = rh.Employe.objects.filter(id__in=employes_ids).exclude(id__in=id_copies)
53
54 def option_label(employe):
55 return "%s %s" % (employe.nom.upper(), employe.prenom.title())
56
57 return [('', 'Nouvel employé')] + \
58 sorted([('dae-%s' % p.id, option_label(p)) for p in dae_ | copies] +
59 [('rh-%s' % p.id, option_label(p)) for p in rhv1],
60 key=lambda t: t[1])
61
62
63 def label_poste_display(poste):
64 """Formate un visuel pour un poste dans une liste déroulante"""
65 label = u"%s - %s [%s]" %(poste.type_poste, poste.type_poste.famille_emploi.nom, poste.id)
66 return label
67
68 class PostePieceForm(inlineformset_factory(dae.Poste, dae.PostePiece)):
69 pass
70
71 class DossierPieceForm(inlineformset_factory(dae.Dossier, dae.DossierPiece)):
72 pass
73
74 class FinancementForm(inlineformset_factory(dae.Poste, dae.PosteFinancement, extra=1)):
75 pass
76
77 class JustificationNouvelEmployeForm(inlineformset_factory(dae.Dossier,
78 dae.JustificationNouvelEmploye,
79 extra=0,
80 can_delete=False,
81 exclude=('question',))):
82 """
83 Formulaire de justification d'un nouvel employé.
84 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
85 """
86 def __init__(self, *args, **kwargs):
87 instance = kwargs['instance']
88 if instance.id:
89 q_ids = [j.question.id for j in instance.justificationnouvelemploye_set.filter(dossier=instance)]
90 for q in dae.JustificationQuestion.objects.filter(type="N"):
91 if q.id in q_ids:
92 continue
93 j = dae.JustificationNouvelEmploye()
94 j.dossier = instance
95 j.question = q
96 j.save()
97 super(self.__class__, self).__init__(*args, **kwargs)
98
99 class JustificationAutreEmployeForm(inlineformset_factory(dae.Dossier,
100 dae.JustificationAutreEmploye,
101 extra=0,
102 can_delete=False,
103 exclude=('question',))):
104 """
105 Formulaire de justification d'un nouvel employé.
106 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
107 """
108 def __init__(self, *args, **kwargs):
109 instance = kwargs['instance']
110 if instance.id:
111 q_ids = [j.question.id for j in instance.justificationautreemploye_set.filter(dossier=instance)]
112 for q in dae.JustificationQuestion.objects.filter(type="R"):
113 if q.id in q_ids:
114 continue
115 j = dae.JustificationAutreEmploye()
116 j.dossier = instance
117 j.question = q
118 j.save()
119 super(self.__class__, self).__init__(*args, **kwargs)
120
121 class PosteForm(forms.ModelForm):
122 """ Formulaire des postes. """
123
124
125 class Meta:
126 model = dae.Poste
127
128 fields = ('poste', 'implantation', 'type_poste', 'service', 'nom',
129 'responsable', 'local', 'expatrie', 'mise_a_disposition',
130 'appel', 'date_debut', 'date_fin', 'actif',
131 'regime_travail', 'regime_travail_nb_heure_semaine',
132 'classement_min', 'classement_max',
133 'valeur_point_min', 'valeur_point_max',
134 'devise_min', 'devise_max',
135 'salaire_min', 'salaire_max', 'indemn_min', 'indemn_max',
136 'autre_min', 'autre_max', 'devise_comparaison',
137 'comp_locale_min', 'comp_locale_max',
138 'comp_universite_min', 'comp_universite_max',
139 'comp_fonctionpub_min', 'comp_fonctionpub_max',
140 'comp_ong_min', 'comp_ong_max',
141 'comp_autre_min', 'comp_autre_max',
142 'justification',
143 'etat',
144 )
145 widgets = dict(appel=forms.RadioSelect(),
146 nom=forms.TextInput(attrs={'size': 60},),
147 date_debut=admin_widgets.AdminDateWidget(),
148 date_fin=admin_widgets.AdminDateWidget(),
149 justification=forms.Textarea(attrs={'cols': 80},),
150 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
151 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
152 )
153
154 responsable=AutoCompleteSelectField('responsables', required=True)
155 #responsable = forms.ModelChoiceField(
156 # queryset=rh.Poste.objects.select_related(depth=1))
157
158 # La liste des choix est laissée vide. Voir __init__ pour la raison.
159 poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste",
160 choices=(), required=False)
161
162 valeur_point_min = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
163 valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
164
165 def __init__(self, request, *args, **kwargs):
166 """ Mise à jour dynamique du contenu du menu des postes.
167
168 Si on ne met le menu à jour de cette façon, à chaque instantiation du
169 formulaire, son contenu est mis en cache par le système et il ne
170 reflète pas les changements apportés par les ajouts, modifications,
171 etc...
172
173 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
174 car le "id" de chaque choix est spécial (voir _poste_choices).
175
176 """
177 super(PosteForm, self).__init__(*args, **kwargs)
178 self.fields['poste'].choices = self._poste_choices(request)
179 self.fields['implantation'].choices = _implantation_choices(self, request)
180
181 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
182 if self.instance and self.instance.id is None:
183 dossiers = self.instance.get_dossiers()
184 if len(dossiers) > 0:
185 self.initial['service'] = dossiers[0].service_id
186 self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom())
187
188
189 def _poste_choices(self, request):
190 """ Menu déroulant pour les postes.
191
192 Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
193 d'équivalent dans dae.
194
195 """
196 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(actif=True, id_rh__isnull=True)
197 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
198 id_copies = [p.id_rh_id for p in copies.all()]
199 rhv1 = rh.Poste.objects.ma_region_ou_service(request.user).filter(actif=True).exclude(id__in=id_copies)
200 # Optimisation de la requête
201 rhv1 = rhv1.select_related(depth=1)
202
203 return [('', 'Nouveau poste')] + \
204 sorted([('dae-%s' % p.id, label_poste_display(p)) for p in dae_ | copies] +
205 [('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
206 key=lambda t: t[1])
207
208 def clean(self):
209 """
210 Validation conditionnelles de certains champs.
211 """
212 cleaned_data = self.cleaned_data
213
214 # Gestion de la mise à disposition
215 mise_a_disposition = cleaned_data.get("mise_a_disposition")
216 valeur_point_min = cleaned_data.get("valeur_point_min")
217 valeur_point_max = cleaned_data.get("valeur_point_max")
218 if mise_a_disposition is False and (valeur_point_min is None or valeur_point_max is None):
219 msg = u"Ce champ est obligatoire."
220 self._errors["valeur_point_min"] = self.error_class([msg])
221 self._errors["valeur_point_max"] = self.error_class([msg])
222 raise forms.ValidationError("Les valeurs de point sont vides")
223
224 return cleaned_data
225
226
227
228 def save(self, *args, **kwargs):
229 kwargs2 = kwargs.copy()
230 kwargs2['commit'] = False
231 poste = super(PosteForm, self).save(*args, **kwargs2)
232 # id_rh
233 if 'commit' not in kwargs or kwargs['commit']:
234 poste.save()
235 return poste
236
237
238 class ChoosePosteForm(forms.ModelForm):
239 class Meta:
240 model = dae.Poste
241 fields = ('poste',)
242
243 # La liste des choix est laissée vide. Voir PosteForm.__init__.
244 poste = forms.ChoiceField(choices=(), required=False)
245
246 def __init__(self, request=None, *args, **kwargs):
247 super(ChoosePosteForm, self).__init__(*args, **kwargs)
248 self.fields['poste'].choices = self._poste_choices(request)
249
250 def _poste_choices(self, request):
251 """ Menu déroulant pour les postes. """
252 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(id_rh__isnull=True)
253 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
254 id_copies = [p.id_rh_id for p in copies.all()]
255
256 return [('', '----------')] + \
257 sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies],
258 key=lambda t: t[1])
259
260
261 class EmployeForm(forms.ModelForm):
262 """ Formulaire des employés. """
263 class Meta:
264 model = dae.Employe
265 fields = ('employe', 'nom', 'prenom', 'genre')
266
267 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
268 employe = forms.ChoiceField(choices=(), required=False)
269
270 def __init__(self, request, *args, **kwargs):
271 """ Mise à jour dynamique du contenu du menu des employés. """
272 super(EmployeForm, self).__init__(*args, **kwargs)
273 self.fields['employe'].choices = _employe_choices(self, request)
274
275
276
277 class DossierForm(forms.ModelForm):
278 """ Formulaire des dossiers. """
279 class Meta:
280 exclude= ('etat', )
281 model = dae.Dossier
282 widgets = dict(statut_residence=forms.RadioSelect(),
283 contrat_date_debut=admin_widgets.AdminDateWidget(),
284 contrat_date_fin=admin_widgets.AdminDateWidget(),
285 )
286
287 class PosteWorkflowForm(WorkflowFormMixin):
288
289 class Meta:
290 fields = ('etat', )
291 model = dae.Poste
292
293 class DossierWorkflowForm(WorkflowFormMixin):
294
295 class Meta:
296 fields = ('etat', )
297 model = dae.Dossier