fix #1475
[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
d8cfc3d5 11from utils import get_employe_from_user, is_user_dans_services_centraux
5d680e84 12from rh_v1 import models as rh
56589624 13from workflow import grp_drh, POSTE_ETATS_BOUTONS
f258e4e7
OL
14
15def _implantation_choices(obj, request):
16 # TRAITEMENT NORMAL
17 employe = get_employe_from_user(request.user)
18 # SERVICE
d8cfc3d5 19 if is_user_dans_services_centraux(request.user):
f258e4e7
OL
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
d8cfc3d5 36 if is_user_dans_services_centraux(request.user):
f258e4e7
OL
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
e2185d45 74class FinancementForm(inlineformset_factory(dae.Poste, dae.PosteFinancement, extra=2)):
151e7bd0
OL
75 pass
76
03b395db
OL
77
78class 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
03b395db
OL
86class DossierComparaisonForm(inlineformset_factory(dae.Dossier, dae.DossierComparaison, extra=3, max_num=3, form=DossierComparaisonForm)):
87 pass
88
068d1462
OL
89class PosteComparaisonForm(forms.ModelForm):
90
91 recherche = AutoCompleteSelectField('postes', required=False)
92
93 class Model:
94 model = dae.PosteComparaison
95
96class PosteComparaisonForm(inlineformset_factory(dae.Poste, dae.PosteComparaison, extra=3, max_num=3, form=PosteComparaisonForm)):
97 pass
98
0a085c42
OL
99class FlexibleRemunForm(forms.ModelForm):
100
101 montant_mensuel = forms.DecimalField(required=False)
102 montant = forms.DecimalField(required=True, label='Montant annuel')
103
104 class Meta:
105 model = dae.Remuneration
106
107class RemunForm(inlineformset_factory(dae.Dossier, dae.Remuneration, extra=5, form=FlexibleRemunForm)):
108 pass
109
1b217058 110class PosteForm(forms.ModelForm):
5d680e84 111 """ Formulaire des postes. """
12c7f8a7
OL
112
113 responsable=AutoCompleteSelectField('responsables', required=True)
114 #responsable = forms.ModelChoiceField(
115 # queryset=rh.Poste.objects.select_related(depth=1))
116
117 # La liste des choix est laissée vide. Voir __init__ pour la raison.
118 poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste",
119 choices=(), required=False)
120
121 valeur_point_min = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
122 valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
3121c13c
OL
123
124
5d680e84
NC
125 class Meta:
126 model = dae.Poste
b15bf543 127 exclude = ('actif', )
c3be904d
OL
128 fields = ('type_intervention',
129 'poste', 'implantation', 'type_poste', 'service', 'nom',
154677c3 130 'responsable', 'local', 'expatrie', 'mise_a_disposition',
b15bf543 131 'appel', 'date_debut', 'date_fin',
5d680e84
NC
132 'regime_travail', 'regime_travail_nb_heure_semaine',
133 'classement_min', 'classement_max',
134 'valeur_point_min', 'valeur_point_max',
3d627bfd 135 'devise_min', 'devise_max',
5f61bccb
OL
136 'salaire_min', 'salaire_max',
137 'indemn_expat_min', 'indemn_expat_max',
138 'indemn_fct_min', 'indemn_fct_max',
139 'charges_patronales_min', 'charges_patronales_max',
5d680e84
NC
140 'autre_min', 'autre_max', 'devise_comparaison',
141 'comp_locale_min', 'comp_locale_max',
142 'comp_universite_min', 'comp_universite_max',
143 'comp_fonctionpub_min', 'comp_fonctionpub_max',
144 'comp_ong_min', 'comp_ong_max',
8fa94e8b 145 'comp_autre_min', 'comp_autre_max',
2e092e0c 146 'justification',
8fa94e8b 147 )
c3be904d
OL
148 widgets = dict(type_intervention=forms.RadioSelect(),
149 appel=forms.RadioSelect(),
3d627bfd 150 nom=forms.TextInput(attrs={'size': 60},),
e88caaf0
OL
151 date_debut=admin_widgets.AdminDateWidget(),
152 date_fin=admin_widgets.AdminDateWidget(),
2e092e0c 153 justification=forms.Textarea(attrs={'cols': 80},),
3d627bfd 154 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
155 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
156 )
5d680e84 157
c2458db6 158 def __init__(self, *args, **kwargs):
5d680e84
NC
159 """ Mise à jour dynamique du contenu du menu des postes.
160
161 Si on ne met le menu à jour de cette façon, à chaque instantiation du
162 formulaire, son contenu est mis en cache par le système et il ne
163 reflète pas les changements apportés par les ajouts, modifications,
164 etc...
165
139686f2
NC
166 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
167 car le "id" de chaque choix est spécial (voir _poste_choices).
168
5d680e84 169 """
c2458db6 170 request = kwargs.pop('request')
5d680e84 171 super(PosteForm, self).__init__(*args, **kwargs)
f258e4e7
OL
172 self.fields['poste'].choices = self._poste_choices(request)
173 self.fields['implantation'].choices = _implantation_choices(self, request)
5d680e84 174
cc3098d0
OL
175 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
176 if self.instance and self.instance.id is None:
177 dossiers = self.instance.get_dossiers()
178 if len(dossiers) > 0:
179 self.initial['service'] = dossiers[0].service_id
9508a5b8
OL
180 self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom())
181
cc3098d0 182
f258e4e7 183 def _poste_choices(self, request):
5d680e84
NC
184 """ Menu déroulant pour les postes.
185
186 Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
187 d'équivalent dans dae.
188
189 """
f258e4e7
OL
190 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(actif=True, id_rh__isnull=True)
191 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
5d680e84 192 id_copies = [p.id_rh_id for p in copies.all()]
f258e4e7 193 rhv1 = rh.Poste.objects.ma_region_ou_service(request.user).filter(actif=True).exclude(id__in=id_copies)
139686f2
NC
194 # Optimisation de la requête
195 rhv1 = rhv1.select_related(depth=1)
5d680e84 196
98d51b59 197 return [('', 'Nouveau poste')] + \
4bce4d24
OL
198 sorted([('dae-%s' % p.id, label_poste_display(p)) for p in dae_ | copies] +
199 [('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
5d680e84 200 key=lambda t: t[1])
3ed49093 201
4dd75e7b
OL
202 def clean(self):
203 """
204 Validation conditionnelles de certains champs.
205 """
206 cleaned_data = self.cleaned_data
207
208 # Gestion de la mise à disposition
209 mise_a_disposition = cleaned_data.get("mise_a_disposition")
210 valeur_point_min = cleaned_data.get("valeur_point_min")
211 valeur_point_max = cleaned_data.get("valeur_point_max")
212 if mise_a_disposition is False and (valeur_point_min is None or valeur_point_max is None):
213 msg = u"Ce champ est obligatoire."
214 self._errors["valeur_point_min"] = self.error_class([msg])
215 self._errors["valeur_point_max"] = self.error_class([msg])
216 raise forms.ValidationError("Les valeurs de point sont vides")
f42c6e20 217
f42c6e20
OL
218 if cleaned_data.get("local") is False and cleaned_data.get("expatrie") is False:
219 msg = "Le poste doit au moins être ouvert localement ou aux expatriés"
220 self._errors["local"] = self.error_class([msg])
221 self._errors["expatrie"] = ''
222 raise forms.ValidationError(msg)
223
224
4dd75e7b
OL
225 return cleaned_data
226
227
228
494ff2be
NC
229 def save(self, *args, **kwargs):
230 kwargs2 = kwargs.copy()
231 kwargs2['commit'] = False
232 poste = super(PosteForm, self).save(*args, **kwargs2)
233 # id_rh
234 if 'commit' not in kwargs or kwargs['commit']:
235 poste.save()
236 return poste
237
3ed49093 238
139686f2
NC
239class ChoosePosteForm(forms.ModelForm):
240 class Meta:
241 model = dae.Poste
242 fields = ('poste',)
243
244 # La liste des choix est laissée vide. Voir PosteForm.__init__.
245 poste = forms.ChoiceField(choices=(), required=False)
246
4ee6d70a 247 def __init__(self, request=None, *args, **kwargs):
139686f2 248 super(ChoosePosteForm, self).__init__(*args, **kwargs)
4ee6d70a 249 self.fields['poste'].choices = self._poste_choices(request)
139686f2 250
4ee6d70a 251 def _poste_choices(self, request):
139686f2 252 """ Menu déroulant pour les postes. """
4ee6d70a
OL
253 dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(id_rh__isnull=True)
254 copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
139686f2
NC
255 id_copies = [p.id_rh_id for p in copies.all()]
256
98d51b59 257 return [('', '----------')] + \
139686f2
NC
258 sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies],
259 key=lambda t: t[1])
260
261
139686f2
NC
262class EmployeForm(forms.ModelForm):
263 """ Formulaire des employés. """
264 class Meta:
265 model = dae.Employe
266 fields = ('employe', 'nom', 'prenom', 'genre')
267
268 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
269 employe = forms.ChoiceField(choices=(), required=False)
270
ac6235f6 271 def __init__(self, *args, **kwargs):
139686f2 272 """ Mise à jour dynamique du contenu du menu des employés. """
ac6235f6 273 request = kwargs.pop('request', None)
139686f2 274 super(EmployeForm, self).__init__(*args, **kwargs)
f258e4e7 275 self.fields['employe'].choices = _employe_choices(self, request)
139686f2 276
139686f2
NC
277
278
279class DossierForm(forms.ModelForm):
280 """ Formulaire des dossiers. """
281 class Meta:
b1baa306 282 exclude= ('etat', )
139686f2 283 model = dae.Dossier
4d25e2ba 284 widgets = dict(statut_residence=forms.RadioSelect(),
0e0aeb7e
OL
285 contrat_date_debut=admin_widgets.AdminDateWidget(),
286 contrat_date_fin=admin_widgets.AdminDateWidget(),
4d25e2ba 287 )
e6f52402 288
3799cafc 289WF_HELP_TEXT = ""
e0b93e3a 290
e6f52402 291class PosteWorkflowForm(WorkflowFormMixin):
56589624 292 bouton_libelles = POSTE_ETATS_BOUTONS
e6f52402
OL
293 class Meta:
294 fields = ('etat', )
295 model = dae.Poste
56589624 296
e0b93e3a
OL
297 def __init__(self, *args, **kwargs):
298 super(self.__class__, self).__init__(*args, **kwargs)
299 self.fields['etat'].help_text = WF_HELP_TEXT
300
301
e6f52402 302class DossierWorkflowForm(WorkflowFormMixin):
56589624 303 bouton_libelles = POSTE_ETATS_BOUTONS # meme workflow que poste...
e6f52402
OL
304 class Meta:
305 fields = ('etat', )
306 model = dae.Dossier
e0b93e3a
OL
307
308 def __init__(self, *args, **kwargs):
309 super(self.__class__, self).__init__(*args, **kwargs)
310 self.fields['etat'].help_text = WF_HELP_TEXT
311