1 # -*- encoding: utf-8 -*-
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
15 def _implantation_choices(obj
, request
):
17 employe
= get_employe_from_user(request
.user
)
19 if is_user_dans_service(request
.user
):
20 q
= Q(**{ 'id' : employe
.implantation_id
})
23 q
= Q(**{ 'region' : employe
.implantation
.region
})
26 if grp_drh
in request
.user
.groups
.all():
28 return [('', '----------')] + [(i
.id, unicode(i
), )for i
in ref
.Implantation
.objects
.filter(q
)]
30 def _employe_choices(obj
, request
):
31 q
= Q(id_rh__isnull
=True) & Q(id_rh__isnull
=True)
34 employe
= get_employe_from_user(request
.user
)
36 if is_user_dans_service(request
.user
):
37 q_region_service
= Q(implantation1
=employe
.implantation
) |
Q(implantation2
=employe
.implantation
)
40 q_region_service
= Q(implantation1__region
=employe
.implantation
.region
) |
Q(implantation2__region
=employe
.implantation
.region
)
42 if grp_drh
in request
.user
.groups
.all():
43 q_region_service
= Q()
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
)
54 def option_label(employe
):
55 return "%s %s" % (employe
.nom
.upper(), employe
.prenom
.title())
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
],
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)
68 class PostePieceForm(inlineformset_factory(dae
.Poste
, dae
.PostePiece
)):
71 class DossierPieceForm(inlineformset_factory(dae
.Dossier
, dae
.DossierPiece
)):
74 class FinancementForm(inlineformset_factory(dae
.Poste
, dae
.PosteFinancement
, extra
=1)):
78 class DossierComparaisonForm(forms
.ModelForm
):
80 recherche
= AutoCompleteSelectField('dossiers', required
=False)
81 poste
= forms
.CharField(max_length
=255, widget
=forms
.TextInput(attrs
={'size':'60'}))
84 model
= dae
.DossierComparaison
86 class DossierComparaisonForm(inlineformset_factory(dae
.Dossier
, dae
.DossierComparaison
, extra
=3, max_num
=3, form
=DossierComparaisonForm
)):
89 class FlexibleRemunForm(forms
.ModelForm
):
91 montant_mensuel
= forms
.DecimalField(required
=False)
92 montant
= forms
.DecimalField(required
=True, label
='Montant annuel')
95 model
= dae
.Remuneration
97 class RemunForm(inlineformset_factory(dae
.Dossier
, dae
.Remuneration
, extra
=5, form
=FlexibleRemunForm
)):
100 class JustificationNouvelEmployeForm(inlineformset_factory(dae
.Dossier
,
101 dae
.JustificationNouvelEmploye
,
104 exclude
=('question',))):
106 Formulaire de justification d'un nouvel employé.
107 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
109 def __init__(self
, *args
, **kwargs
):
110 instance
= kwargs
['instance']
112 q_ids
= [j
.question
.id for j
in instance
.justificationnouvelemploye_set
.filter(dossier
=instance
)]
113 for q
in dae
.JustificationQuestion
.objects
.filter(type="N"):
116 j
= dae
.JustificationNouvelEmploye()
120 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
122 class JustificationAutreEmployeForm(inlineformset_factory(dae
.Dossier
,
123 dae
.JustificationAutreEmploye
,
126 exclude
=('question',))):
128 Formulaire de justification d'un nouvel employé.
129 Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions.
131 def __init__(self
, *args
, **kwargs
):
132 instance
= kwargs
['instance']
134 q_ids
= [j
.question
.id for j
in instance
.justificationautreemploye_set
.filter(dossier
=instance
)]
135 for q
in dae
.JustificationQuestion
.objects
.filter(type="R"):
138 j
= dae
.JustificationAutreEmploye()
142 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
144 class PosteForm(forms
.ModelForm
):
145 """ Formulaire des postes. """
147 responsable
=AutoCompleteSelectField('responsables', required
=True)
148 #responsable = forms.ModelChoiceField(
149 # queryset=rh.Poste.objects.select_related(depth=1))
151 # La liste des choix est laissée vide. Voir __init__ pour la raison.
152 poste
= forms
.ChoiceField(label
="Nouveau poste ou évolution du poste",
153 choices
=(), required
=False)
155 valeur_point_min
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
156 valeur_point_max
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
161 exclude
= ('actif', )
162 fields
= ('poste', 'implantation', 'type_poste', 'service', 'nom',
163 'responsable', 'local', 'expatrie', 'mise_a_disposition',
164 'appel', 'date_debut', 'date_fin',
165 'regime_travail', 'regime_travail_nb_heure_semaine',
166 'classement_min', 'classement_max',
167 'valeur_point_min', 'valeur_point_max',
168 'devise_min', 'devise_max',
169 'salaire_min', 'salaire_max', 'indemn_min', 'indemn_max',
170 'autre_min', 'autre_max', 'devise_comparaison',
171 'comp_locale_min', 'comp_locale_max',
172 'comp_universite_min', 'comp_universite_max',
173 'comp_fonctionpub_min', 'comp_fonctionpub_max',
174 'comp_ong_min', 'comp_ong_max',
175 'comp_autre_min', 'comp_autre_max',
178 widgets
= dict(appel
=forms
.RadioSelect(),
179 nom
=forms
.TextInput(attrs
={'size': 60},),
180 date_debut
=admin_widgets
.AdminDateWidget(),
181 date_fin
=admin_widgets
.AdminDateWidget(),
182 justification
=forms
.Textarea(attrs
={'cols': 80},),
183 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
184 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
187 def __init__(self
, *args
, **kwargs
):
188 """ Mise à jour dynamique du contenu du menu des postes.
190 Si on ne met le menu à jour de cette façon, à chaque instantiation du
191 formulaire, son contenu est mis en cache par le système et il ne
192 reflète pas les changements apportés par les ajouts, modifications,
195 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
196 car le "id" de chaque choix est spécial (voir _poste_choices).
199 request
= kwargs
.pop('request')
200 super(PosteForm
, self
).__init__(*args
, **kwargs
)
201 self
.fields
['poste'].choices
= self
._poste_choices(request
)
202 self
.fields
['implantation'].choices
= _implantation_choices(self
, request
)
204 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
205 if self
.instance
and self
.instance
.id is None:
206 dossiers
= self
.instance
.get_dossiers()
207 if len(dossiers
) > 0:
208 self
.initial
['service'] = dossiers
[0].service_id
209 self
.initial
['nom'] = "%s %s" % (self
.initial
['nom'], self
.instance
.get_complement_nom())
212 def _poste_choices(self
, request
):
213 """ Menu déroulant pour les postes.
215 Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
216 d'équivalent dans dae.
219 dae_
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(actif
=True, id_rh__isnull
=True)
220 copies
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).exclude(id_rh__isnull
=True)
221 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
222 rhv1
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(actif
=True).exclude(id__in
=id_copies
)
223 # Optimisation de la requête
224 rhv1
= rhv1
.select_related(depth
=1)
226 return [('', 'Nouveau poste')] + \
227 sorted([('dae-%s' % p
.id, label_poste_display(p
)) for p
in dae_ | copies
] +
228 [('rh-%s' % p
.id, label_poste_display(p
)) for p
in rhv1
],
233 Validation conditionnelles de certains champs.
235 cleaned_data
= self
.cleaned_data
237 # Gestion de la mise à disposition
238 mise_a_disposition
= cleaned_data
.get("mise_a_disposition")
239 valeur_point_min
= cleaned_data
.get("valeur_point_min")
240 valeur_point_max
= cleaned_data
.get("valeur_point_max")
241 if mise_a_disposition
is False and (valeur_point_min
is None or valeur_point_max
is None):
242 msg
= u
"Ce champ est obligatoire."
243 self
._errors
["valeur_point_min"] = self
.error_class([msg
])
244 self
._errors
["valeur_point_max"] = self
.error_class([msg
])
245 raise forms
.ValidationError("Les valeurs de point sont vides")
247 print cleaned_data
.get("local")
248 if cleaned_data
.get("local") is False and cleaned_data
.get("expatrie") is False:
249 msg
= "Le poste doit au moins être ouvert localement ou aux expatriés"
250 self
._errors
["local"] = self
.error_class([msg
])
251 self
._errors
["expatrie"] = ''
252 raise forms
.ValidationError(msg
)
259 def save(self
, *args
, **kwargs
):
260 kwargs2
= kwargs
.copy()
261 kwargs2
['commit'] = False
262 poste
= super(PosteForm
, self
).save(*args
, **kwargs2
)
264 if 'commit' not in kwargs
or kwargs
['commit']:
269 class ChoosePosteForm(forms
.ModelForm
):
274 # La liste des choix est laissée vide. Voir PosteForm.__init__.
275 poste
= forms
.ChoiceField(choices
=(), required
=False)
277 def __init__(self
, request
=None, *args
, **kwargs
):
278 super(ChoosePosteForm
, self
).__init__(*args
, **kwargs
)
279 self
.fields
['poste'].choices
= self
._poste_choices(request
)
281 def _poste_choices(self
, request
):
282 """ Menu déroulant pour les postes. """
283 dae_
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(id_rh__isnull
=True)
284 copies
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).exclude(id_rh__isnull
=True)
285 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
287 return [('', '----------')] + \
288 sorted([('dae-%s' % p
.id, unicode(p
)) for p
in dae_ | copies
],
292 class EmployeForm(forms
.ModelForm
):
293 """ Formulaire des employés. """
296 fields
= ('employe', 'nom', 'prenom', 'genre')
298 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
299 employe
= forms
.ChoiceField(choices
=(), required
=False)
301 def __init__(self
, *args
, **kwargs
):
302 """ Mise à jour dynamique du contenu du menu des employés. """
303 request
= kwargs
.pop('request', None)
304 super(EmployeForm
, self
).__init__(*args
, **kwargs
)
305 self
.fields
['employe'].choices
= _employe_choices(self
, request
)
309 class DossierForm(forms
.ModelForm
):
310 """ Formulaire des dossiers. """
314 widgets
= dict(statut_residence
=forms
.RadioSelect(),
315 contrat_date_debut
=admin_widgets
.AdminDateWidget(),
316 contrat_date_fin
=admin_widgets
.AdminDateWidget(),
319 WF_HELP_TEXT
= """Ce champs affiche par défaut l'étape de traitement de la demande.
320 La liste déroulante vous permet de sélectionner l'étape suivante."""
322 class PosteWorkflowForm(WorkflowFormMixin
):
328 def __init__(self
, *args
, **kwargs
):
329 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
330 self
.fields
['etat'].help_text
= WF_HELP_TEXT
333 class DossierWorkflowForm(WorkflowFormMixin
):
339 def __init__(self
, *args
, **kwargs
):
340 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
341 self
.fields
['etat'].help_text
= WF_HELP_TEXT