fix #1428 comparaison salariales
[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
78 class DossierComparaisonForm(forms.ModelForm):
79
80 recherche = AutoCompleteSelectField('dossiers', required=False)
81 poste = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'size':'60'}))
82
83 class Model:
84 model = dae.DossierComparaison
85
86
87 class DossierComparaisonForm(inlineformset_factory(dae.Dossier, dae.DossierComparaison, extra=3, max_num=3, form=DossierComparaisonForm)):
88 pass
89
90 class JustificationNouvelEmployeForm(inlineformset_factory(dae.Dossier,
91 dae.JustificationNouvelEmploye,
92 extra=0,
93 can_delete=False,
94 exclude=('question',))):
95 """
96 Formulaire de justification d'un nouvel employé.
97 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
98 """
99 def __init__(self, *args, **kwargs):
100 instance = kwargs['instance']
101 if instance.id:
102 q_ids = [j.question.id for j in instance.justificationnouvelemploye_set.filter(dossier=instance)]
103 for q in dae.JustificationQuestion.objects.filter(type="N"):
104 if q.id in q_ids:
105 continue
106 j = dae.JustificationNouvelEmploye()
107 j.dossier = instance
108 j.question = q
109 j.save()
110 super(self.__class__, self).__init__(*args, **kwargs)
111
112 class JustificationAutreEmployeForm(inlineformset_factory(dae.Dossier,
113 dae.JustificationAutreEmploye,
114 extra=0,
115 can_delete=False,
116 exclude=('question',))):
117 """
118 Formulaire de justification d'un nouvel employé.
119 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
120 """
121 def __init__(self, *args, **kwargs):
122 instance = kwargs['instance']
123 if instance.id:
124 q_ids = [j.question.id for j in instance.justificationautreemploye_set.filter(dossier=instance)]
125 for q in dae.JustificationQuestion.objects.filter(type="R"):
126 if q.id in q_ids:
127 continue
128 j = dae.JustificationAutreEmploye()
129 j.dossier = instance
130 j.question = q
131 j.save()
132 super(self.__class__, self).__init__(*args, **kwargs)
133
134 class PosteForm(forms.ModelForm):
135 """ Formulaire des postes. """
136
137
138 class Meta:
139 model = dae.Poste
140
141 fields = ('poste', 'implantation', 'type_poste', 'service', 'nom',
142 'responsable', 'local', 'expatrie', 'mise_a_disposition',
143 'appel', 'date_debut', 'date_fin', 'actif',
144 'regime_travail', 'regime_travail_nb_heure_semaine',
145 'classement_min', 'classement_max',
146 'valeur_point_min', 'valeur_point_max',
147 'devise_min', 'devise_max',
148 'salaire_min', 'salaire_max', 'indemn_min', 'indemn_max',
149 'autre_min', 'autre_max', 'devise_comparaison',
150 'comp_locale_min', 'comp_locale_max',
151 'comp_universite_min', 'comp_universite_max',
152 'comp_fonctionpub_min', 'comp_fonctionpub_max',
153 'comp_ong_min', 'comp_ong_max',
154 'comp_autre_min', 'comp_autre_max',
155 'justification',
156 )
157 widgets = dict(appel=forms.RadioSelect(),
158 nom=forms.TextInput(attrs={'size': 60},),
159 date_debut=admin_widgets.AdminDateWidget(),
160 date_fin=admin_widgets.AdminDateWidget(),
161 justification=forms.Textarea(attrs={'cols': 80},),
162 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
163 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
164 )
165
166 responsable=AutoCompleteSelectField('responsables', required=True)
167 #responsable = forms.ModelChoiceField(
168 # queryset=rh.Poste.objects.select_related(depth=1))
169
170 # La liste des choix est laissée vide. Voir __init__ pour la raison.
171 poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste",
172 choices=(), required=False)
173
174 valeur_point_min = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
175 valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
176
177 def __init__(self, *args, **kwargs):
178 """ Mise à jour dynamique du contenu du menu des postes.
179
180 Si on ne met le menu à jour de cette façon, à chaque instantiation du
181 formulaire, son contenu est mis en cache par le système et il ne
182 reflète pas les changements apportés par les ajouts, modifications,
183 etc...
184
185 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
186 car le "id" de chaque choix est spécial (voir _poste_choices).
187
188 """
189 request = kwargs.pop('request')
190 super(PosteForm, self).__init__(*args, **kwargs)
191 self.fields['poste'].choices = self._poste_choices(request)
192 self.fields['implantation'].choices = _implantation_choices(self, request)
193
194 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
195 if self.instance and self.instance.id is None:
196 dossiers = self.instance.get_dossiers()
197 if len(dossiers) > 0:
198 self.initial['service'] = dossiers[0].service_id
199 self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom())
200
201
202 def _poste_choices(self, request):
203 """ Menu déroulant pour les postes.
204
205 Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
206 d'équivalent dans dae.
207
208 """
209 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(actif=True, id_rh__isnull=True)
210 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
211 id_copies = [p.id_rh_id for p in copies.all()]
212 rhv1 = rh.Poste.objects.ma_region_ou_service(request.user).filter(actif=True).exclude(id__in=id_copies)
213 # Optimisation de la requête
214 rhv1 = rhv1.select_related(depth=1)
215
216 return [('', 'Nouveau poste')] + \
217 sorted([('dae-%s' % p.id, label_poste_display(p)) for p in dae_ | copies] +
218 [('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
219 key=lambda t: t[1])
220
221 def clean(self):
222 """
223 Validation conditionnelles de certains champs.
224 """
225 cleaned_data = self.cleaned_data
226
227 # Gestion de la mise à disposition
228 mise_a_disposition = cleaned_data.get("mise_a_disposition")
229 valeur_point_min = cleaned_data.get("valeur_point_min")
230 valeur_point_max = cleaned_data.get("valeur_point_max")
231 if mise_a_disposition is False and (valeur_point_min is None or valeur_point_max is None):
232 msg = u"Ce champ est obligatoire."
233 self._errors["valeur_point_min"] = self.error_class([msg])
234 self._errors["valeur_point_max"] = self.error_class([msg])
235 raise forms.ValidationError("Les valeurs de point sont vides")
236
237 return cleaned_data
238
239
240
241 def save(self, *args, **kwargs):
242 kwargs2 = kwargs.copy()
243 kwargs2['commit'] = False
244 poste = super(PosteForm, self).save(*args, **kwargs2)
245 # id_rh
246 if 'commit' not in kwargs or kwargs['commit']:
247 poste.save()
248 return poste
249
250
251 class ChoosePosteForm(forms.ModelForm):
252 class Meta:
253 model = dae.Poste
254 fields = ('poste',)
255
256 # La liste des choix est laissée vide. Voir PosteForm.__init__.
257 poste = forms.ChoiceField(choices=(), required=False)
258
259 def __init__(self, request=None, *args, **kwargs):
260 super(ChoosePosteForm, self).__init__(*args, **kwargs)
261 self.fields['poste'].choices = self._poste_choices(request)
262
263 def _poste_choices(self, request):
264 """ Menu déroulant pour les postes. """
265 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(id_rh__isnull=True)
266 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
267 id_copies = [p.id_rh_id for p in copies.all()]
268
269 return [('', '----------')] + \
270 sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies],
271 key=lambda t: t[1])
272
273
274 class EmployeForm(forms.ModelForm):
275 """ Formulaire des employés. """
276 class Meta:
277 model = dae.Employe
278 fields = ('employe', 'nom', 'prenom', 'genre')
279
280 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
281 employe = forms.ChoiceField(choices=(), required=False)
282
283 def __init__(self, *args, **kwargs):
284 """ Mise à jour dynamique du contenu du menu des employés. """
285 request = kwargs.pop('request', None)
286 super(EmployeForm, self).__init__(*args, **kwargs)
287 self.fields['employe'].choices = _employe_choices(self, request)
288
289
290
291 class DossierForm(forms.ModelForm):
292 """ Formulaire des dossiers. """
293 class Meta:
294 exclude= ('etat', )
295 model = dae.Dossier
296 widgets = dict(statut_residence=forms.RadioSelect(),
297 contrat_date_debut=admin_widgets.AdminDateWidget(),
298 contrat_date_fin=admin_widgets.AdminDateWidget(),
299 )
300
301 class PosteWorkflowForm(WorkflowFormMixin):
302
303 class Meta:
304 fields = ('etat', )
305 model = dae.Poste
306
307 class DossierWorkflowForm(WorkflowFormMixin):
308
309 class Meta:
310 fields = ('etat', )
311 model = dae.Dossier