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