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