fix form poste
[auf_rh_dae.git] / project / dae / forms.py
CommitLineData
5d680e84 1# -*- encoding: utf-8 -*-
ce110fb9 2
f258e4e7 3from django.db.models import Q
5d680e84 4from django import forms
36341125 5from django.forms.models import inlineformset_factory
e88caaf0 6from django.contrib.admin import widgets as admin_widgets
afc204bf 7from ajax_select.fields import AutoCompleteSelectField
8fa94e8b 8from auf.django.workflow.forms import WorkflowFormMixin
5d680e84 9from datamaster_modeles import models as ref
5d680e84 10from dae import models as dae
f258e4e7 11from utils import get_employe_from_user, is_user_dans_service
5d680e84 12from rh_v1 import models as rh
f258e4e7
OL
13from workflow import grp_drh
14
15def _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
30def _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
5d680e84 62
4bce4d24
OL
63def 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
9cb4de55
OL
67
68class PostePieceForm(inlineformset_factory(dae.Poste, dae.PostePiece)):
69 pass
70
71class DossierPieceForm(inlineformset_factory(dae.Dossier, dae.DossierPiece)):
72 pass
73
151e7bd0
OL
74class FinancementForm(inlineformset_factory(dae.Poste, dae.PosteFinancement, extra=1)):
75 pass
76
72db8238
OL
77class 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:
1cc5e025 89 q_ids = [j.question.id for j in instance.justificationnouvelemploye_set.filter(dossier=instance)]
72db8238
OL
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
99class 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:
1cc5e025 111 q_ids = [j.question.id for j in instance.justificationautreemploye_set.filter(dossier=instance)]
72db8238
OL
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)
5d680e84 120
1b217058 121class PosteForm(forms.ModelForm):
5d680e84 122 """ Formulaire des postes. """
3121c13c
OL
123
124
5d680e84
NC
125 class Meta:
126 model = dae.Poste
ce110fb9 127
5d680e84 128 fields = ('poste', 'implantation', 'type_poste', 'service', 'nom',
154677c3 129 'responsable', 'local', 'expatrie', 'mise_a_disposition',
5d680e84
NC
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',
3d627bfd 134 'devise_min', 'devise_max',
5d680e84
NC
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',
8fa94e8b 141 'comp_autre_min', 'comp_autre_max',
2e092e0c 142 'justification',
8fa94e8b 143 )
154677c3 144 widgets = dict(appel=forms.RadioSelect(),
3d627bfd 145 nom=forms.TextInput(attrs={'size': 60},),
e88caaf0
OL
146 date_debut=admin_widgets.AdminDateWidget(),
147 date_fin=admin_widgets.AdminDateWidget(),
2e092e0c 148 justification=forms.Textarea(attrs={'cols': 80},),
3d627bfd 149 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
150 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
151 )
5d680e84 152
3121c13c
OL
153 responsable=AutoCompleteSelectField('responsables', required=True)
154 #responsable = forms.ModelChoiceField(
155 # queryset=rh.Poste.objects.select_related(depth=1))
139686f2 156
5d680e84 157 # La liste des choix est laissée vide. Voir __init__ pour la raison.
5efcd48e 158 poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste",
d949462d 159 choices=(), required=False)
5d680e84 160
4dd75e7b
OL
161 valeur_point_min = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
162 valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
6301bd59 163
c2458db6 164 def __init__(self, *args, **kwargs):
5d680e84
NC
165 """ Mise à jour dynamique du contenu du menu des postes.
166
167 Si on ne met le menu à jour de cette façon, à chaque instantiation du
168 formulaire, son contenu est mis en cache par le système et il ne
169 reflète pas les changements apportés par les ajouts, modifications,
170 etc...
171
139686f2
NC
172 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
173 car le "id" de chaque choix est spécial (voir _poste_choices).
174
5d680e84 175 """
c2458db6 176 request = kwargs.pop('request')
5d680e84 177 super(PosteForm, self).__init__(*args, **kwargs)
f258e4e7
OL
178 self.fields['poste'].choices = self._poste_choices(request)
179 self.fields['implantation'].choices = _implantation_choices(self, request)
5d680e84 180
cc3098d0
OL
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
9508a5b8
OL
186 self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom())
187
cc3098d0 188
f258e4e7 189 def _poste_choices(self, request):
5d680e84
NC
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 """
f258e4e7
OL
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)
5d680e84 198 id_copies = [p.id_rh_id for p in copies.all()]
f258e4e7 199 rhv1 = rh.Poste.objects.ma_region_ou_service(request.user).filter(actif=True).exclude(id__in=id_copies)
139686f2
NC
200 # Optimisation de la requête
201 rhv1 = rhv1.select_related(depth=1)
5d680e84 202
98d51b59 203 return [('', 'Nouveau poste')] + \
4bce4d24
OL
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],
5d680e84 206 key=lambda t: t[1])
3ed49093 207
4dd75e7b
OL
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
494ff2be
NC
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
3ed49093 237
139686f2
NC
238class 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
4ee6d70a 246 def __init__(self, request=None, *args, **kwargs):
139686f2 247 super(ChoosePosteForm, self).__init__(*args, **kwargs)
4ee6d70a 248 self.fields['poste'].choices = self._poste_choices(request)
139686f2 249
4ee6d70a 250 def _poste_choices(self, request):
139686f2 251 """ Menu déroulant pour les postes. """
4ee6d70a
OL
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)
139686f2
NC
254 id_copies = [p.id_rh_id for p in copies.all()]
255
98d51b59 256 return [('', '----------')] + \
139686f2
NC
257 sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies],
258 key=lambda t: t[1])
259
260
139686f2
NC
261class 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
f258e4e7 270 def __init__(self, request, *args, **kwargs):
139686f2
NC
271 """ Mise à jour dynamique du contenu du menu des employés. """
272 super(EmployeForm, self).__init__(*args, **kwargs)
f258e4e7 273 self.fields['employe'].choices = _employe_choices(self, request)
139686f2 274
139686f2
NC
275
276
277class DossierForm(forms.ModelForm):
278 """ Formulaire des dossiers. """
279 class Meta:
b1baa306 280 exclude= ('etat', )
139686f2 281 model = dae.Dossier
4d25e2ba 282 widgets = dict(statut_residence=forms.RadioSelect(),
0e0aeb7e
OL
283 contrat_date_debut=admin_widgets.AdminDateWidget(),
284 contrat_date_fin=admin_widgets.AdminDateWidget(),
4d25e2ba 285 )
e6f52402
OL
286
287class PosteWorkflowForm(WorkflowFormMixin):
288
289 class Meta:
290 fields = ('etat', )
291 model = dae.Poste
292
293class DossierWorkflowForm(WorkflowFormMixin):
294
295 class Meta:
296 fields = ('etat', )
297 model = dae.Dossier