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_services_centraux
12 from rh_v1
import models
as rh
13 from workflow
import grp_drh
, POSTE_ETATS_BOUTONS
15 def _implantation_choices(obj
, request
):
17 employe
= get_employe_from_user(request
.user
)
19 if is_user_dans_services_centraux(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_services_centraux(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
=2)):
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 PosteComparaisonForm(forms
.ModelForm
):
91 recherche
= AutoCompleteSelectField('postes', required
=False)
94 model
= dae
.PosteComparaison
96 class PosteComparaisonForm(inlineformset_factory(dae
.Poste
, dae
.PosteComparaison
, extra
=3, max_num
=3, form
=PosteComparaisonForm
)):
99 class FlexibleRemunForm(forms
.ModelForm
):
101 montant_mensuel
= forms
.DecimalField(required
=False)
102 montant
= forms
.DecimalField(required
=True, label
='Montant annuel')
105 model
= dae
.Remuneration
107 class RemunForm(inlineformset_factory(dae
.Dossier
, dae
.Remuneration
, extra
=5, form
=FlexibleRemunForm
)):
110 class PosteForm(forms
.ModelForm
):
111 """ Formulaire des postes. """
113 # On ne propose que les services actifs
114 services_actifs
= [(s
.id, unicode(s
), ) for s
in rh
.Service
.objects
.filter(actif
=True)]
115 service
= forms
.ChoiceField(choices
=services_actifs
, required
=True)
117 responsable
=AutoCompleteSelectField('responsables', required
=True)
118 #responsable = forms.ModelChoiceField(
119 # queryset=rh.Poste.objects.select_related(depth=1))
121 # La liste des choix est laissée vide. Voir __init__ pour la raison.
122 poste
= forms
.ChoiceField(label
="Nouveau poste ou évolution du poste",
123 choices
=(), required
=False)
125 valeur_point_min
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
126 valeur_point_max
= forms
.ModelChoiceField(queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False)
131 exclude
= ('actif', )
132 fields
= ('type_intervention',
133 'poste', 'implantation', 'type_poste', 'service', 'nom',
134 'responsable', 'local', 'expatrie', 'mise_a_disposition',
135 'appel', 'date_debut', 'date_fin',
136 'regime_travail', 'regime_travail_nb_heure_semaine',
137 'classement_min', 'classement_max',
138 'valeur_point_min', 'valeur_point_max',
139 'devise_min', 'devise_max',
140 'salaire_min', 'salaire_max',
141 'indemn_expat_min', 'indemn_expat_max',
142 'indemn_fct_min', 'indemn_fct_max',
143 'charges_patronales_min', 'charges_patronales_max',
144 'autre_min', 'autre_max', 'devise_comparaison',
145 'comp_locale_min', 'comp_locale_max',
146 'comp_universite_min', 'comp_universite_max',
147 'comp_fonctionpub_min', 'comp_fonctionpub_max',
148 'comp_ong_min', 'comp_ong_max',
149 'comp_autre_min', 'comp_autre_max',
152 widgets
= dict(type_intervention
=forms
.RadioSelect(),
153 appel
=forms
.RadioSelect(),
154 nom
=forms
.TextInput(attrs
={'size': 60},),
155 date_debut
=admin_widgets
.AdminDateWidget(),
156 date_fin
=admin_widgets
.AdminDateWidget(),
157 justification
=forms
.Textarea(attrs
={'cols': 80},),
158 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
159 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
162 def __init__(self
, *args
, **kwargs
):
163 """ Mise à jour dynamique du contenu du menu des postes.
165 Si on ne met le menu à jour de cette façon, à chaque instantiation du
166 formulaire, son contenu est mis en cache par le système et il ne
167 reflète pas les changements apportés par les ajouts, modifications,
170 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
171 car le "id" de chaque choix est spécial (voir _poste_choices).
174 request
= kwargs
.pop('request')
175 super(PosteForm
, self
).__init__(*args
, **kwargs
)
176 self
.fields
['poste'].choices
= self
._poste_choices(request
)
177 self
.fields
['implantation'].choices
= _implantation_choices(self
, request
)
179 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
180 if self
.instance
and self
.instance
.id is None:
181 dossiers
= self
.instance
.get_dossiers()
182 if len(dossiers
) > 0:
183 self
.initial
['service'] = dossiers
[0].service_id
184 self
.initial
['nom'] = "%s %s" % (self
.initial
['nom'], self
.instance
.get_complement_nom())
187 def _poste_choices(self
, request
):
188 """ Menu déroulant pour les postes.
190 Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
191 d'équivalent dans dae.
194 dae_
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(actif
=True, id_rh__isnull
=True)
195 copies
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).exclude(id_rh__isnull
=True)
196 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
197 rhv1
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(actif
=True).exclude(id__in
=id_copies
)
198 # Optimisation de la requête
199 rhv1
= rhv1
.select_related(depth
=1)
201 return [('', 'Nouveau poste')] + \
202 sorted([('dae-%s' % p
.id, label_poste_display(p
)) for p
in dae_ | copies
] +
203 [('rh-%s' % p
.id, label_poste_display(p
)) for p
in rhv1
],
208 Validation conditionnelles de certains champs.
210 cleaned_data
= self
.cleaned_data
212 # Gestion de la mise à disposition
213 mise_a_disposition
= cleaned_data
.get("mise_a_disposition")
214 valeur_point_min
= cleaned_data
.get("valeur_point_min")
215 valeur_point_max
= cleaned_data
.get("valeur_point_max")
216 if mise_a_disposition
is False and (valeur_point_min
is None or valeur_point_max
is None):
217 msg
= u
"Ce champ est obligatoire."
218 self
._errors
["valeur_point_min"] = self
.error_class([msg
])
219 self
._errors
["valeur_point_max"] = self
.error_class([msg
])
220 raise forms
.ValidationError("Les valeurs de point sont vides")
222 if cleaned_data
.get("local") is False and cleaned_data
.get("expatrie") is False:
223 msg
= "Le poste doit au moins être ouvert localement ou aux expatriés"
224 self
._errors
["local"] = self
.error_class([msg
])
225 self
._errors
["expatrie"] = ''
226 raise forms
.ValidationError(msg
)
233 def save(self
, *args
, **kwargs
):
234 kwargs2
= kwargs
.copy()
235 kwargs2
['commit'] = False
236 poste
= super(PosteForm
, self
).save(*args
, **kwargs2
)
238 if 'commit' not in kwargs
or kwargs
['commit']:
243 class ChoosePosteForm(forms
.ModelForm
):
248 # La liste des choix est laissée vide. Voir PosteForm.__init__.
249 poste
= forms
.ChoiceField(choices
=(), required
=False)
251 def __init__(self
, request
=None, *args
, **kwargs
):
252 super(ChoosePosteForm
, self
).__init__(*args
, **kwargs
)
253 self
.fields
['poste'].choices
= self
._poste_choices(request
)
255 def _poste_choices(self
, request
):
256 """ Menu déroulant pour les postes. """
257 dae_
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).filter(id_rh__isnull
=True)
258 copies
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
).exclude(id_rh__isnull
=True)
259 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
261 return [('', '----------')] + \
262 sorted([('dae-%s' % p
.id, unicode(p
)) for p
in dae_ | copies
],
266 class EmployeForm(forms
.ModelForm
):
267 """ Formulaire des employés. """
270 fields
= ('employe', 'nom', 'prenom', 'genre')
272 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
273 employe
= forms
.ChoiceField(choices
=(), required
=False)
275 def __init__(self
, *args
, **kwargs
):
276 """ Mise à jour dynamique du contenu du menu des employés. """
277 request
= kwargs
.pop('request', None)
278 super(EmployeForm
, self
).__init__(*args
, **kwargs
)
279 self
.fields
['employe'].choices
= _employe_choices(self
, request
)
283 class DossierForm(forms
.ModelForm
):
284 """ Formulaire des dossiers. """
288 widgets
= dict(statut_residence
=forms
.RadioSelect(),
289 contrat_date_debut
=admin_widgets
.AdminDateWidget(),
290 contrat_date_fin
=admin_widgets
.AdminDateWidget(),
295 class PosteWorkflowForm(WorkflowFormMixin
):
296 bouton_libelles
= POSTE_ETATS_BOUTONS
301 def __init__(self
, *args
, **kwargs
):
302 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
303 self
.fields
['etat'].help_text
= WF_HELP_TEXT
306 class DossierWorkflowForm(WorkflowFormMixin
):
307 bouton_libelles
= POSTE_ETATS_BOUTONS
# meme workflow que poste...
312 def __init__(self
, *args
, **kwargs
):
313 super(self
.__class__
, self
).__init__(*args
, **kwargs
)
314 self
.fields
['etat'].help_text
= WF_HELP_TEXT