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. """
151 fields
= ('poste', 'implantation', 'type_poste', 'service', 'nom',
152 'responsable', 'local', 'expatrie', 'mise_a_disposition',
153 'appel', 'date_debut', 'date_fin', 'actif',
154 'regime_travail', 'regime_travail_nb_heure_semaine',
155 'classement_min', 'classement_max',
156 'valeur_point_min', 'valeur_point_max',
157 'devise_min', 'devise_max',
158 'salaire_min', 'salaire_max', 'indemn_min', 'indemn_max',
159 'autre_min', 'autre_max', 'devise_comparaison',
160 'comp_locale_min', 'comp_locale_max',
161 'comp_universite_min', 'comp_universite_max',
162 'comp_fonctionpub_min', 'comp_fonctionpub_max',
163 'comp_ong_min', 'comp_ong_max',
164 'comp_autre_min', 'comp_autre_max',
167 widgets
= dict(appel
=forms
.RadioSelect(),
168 nom
=forms
.TextInput(attrs
={'size': 60},),
169 date_debut
=admin_widgets
.AdminDateWidget(),
170 date_fin
=admin_widgets
.AdminDateWidget(),
171 justification
=forms
.Textarea(attrs
={'cols': 80},),
172 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
173 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
176 responsable
=AutoCompleteSelectField('responsables', required
=True)
177 #responsable = forms.ModelChoiceField(
178 # queryset=rh.Poste.objects.select_related(depth=1))
180 # La liste des choix est laissée vide. Voir __init__ pour la raison.
181 poste
= forms
.ChoiceField(label
="Nouveau poste ou évolution du poste",
182 choices
=(), required
=False)
184 valeur_point_min
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
185 valeur_point_max
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
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")
251 def save(self
, *args
, **kwargs
):
252 kwargs2
= kwargs
.copy()
253 kwargs2
['commit'] = False
254 poste
= super(PosteForm
, self
).save(*args
, **kwargs2
)
256 if 'commit' not in kwargs
or kwargs
['commit']:
261 class ChoosePosteForm(forms
.ModelForm
):
266 # La liste des choix est laissée vide. Voir PosteForm.__init__.
267 poste
= forms
.ChoiceField(choices
=(), required
=False)
269 def __init__(self
, request
=None, *args
, **kwargs
):
270 super(ChoosePosteForm
, self
).__init__(*args
, **kwargs
)
271 self
.fields
['poste'].choices
= self
._poste_choices(request
)
273 def _poste_choices(self
, request
):
274 """ Menu déroulant pour les postes. """
275 dae_
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(id_rh__isnull
=True)
276 copies
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).exclude(id_rh__isnull
=True)
277 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
279 return [('', '----------')] + \
280 sorted([('dae-%s' % p
.id, unicode(p
)) for p
in dae_ | copies
],
284 class EmployeForm(forms
.ModelForm
):
285 """ Formulaire des employés. """
288 fields
= ('employe', 'nom', 'prenom', 'genre')
290 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
291 employe
= forms
.ChoiceField(choices
=(), required
=False)
293 def __init__(self
, *args
, **kwargs
):
294 """ Mise à jour dynamique du contenu du menu des employés. """
295 request
= kwargs
.pop('request', None)
296 super(EmployeForm
, self
).__init__(*args
, **kwargs
)
297 self
.fields
['employe'].choices
= _employe_choices(self
, request
)
301 class DossierForm(forms
.ModelForm
):
302 """ Formulaire des dossiers. """
306 widgets
= dict(statut_residence
=forms
.RadioSelect(),
307 contrat_date_debut
=admin_widgets
.AdminDateWidget(),
308 contrat_date_fin
=admin_widgets
.AdminDateWidget(),
311 WF_HELP_TEXT
= """Ce champs affiche par défaut l'étape de traitement de la demande.
312 La liste déroulante vous permet de sélectionner l'étape suivante."""
314 class PosteWorkflowForm(WorkflowFormMixin
):
320 def __init__(self
, *args
, **kwargs
):
321 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
322 self
.fields
['etat'].help_text
= WF_HELP_TEXT
325 class DossierWorkflowForm(WorkflowFormMixin
):
331 def __init__(self
, *args
, **kwargs
):
332 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
333 self
.fields
['etat'].help_text
= WF_HELP_TEXT