X-Git-Url: http://git.auf.org/?p=auf_rh_dae.git;a=blobdiff_plain;f=project%2Fdae%2Fforms.py;h=80b277470aef11ca70e2bc6b129d6752326c3e93;hp=cadb9483395788f159c8f6f3ef9307a250b8a2db;hb=e6f524025e89223368ece09e83cf38bd408066d7;hpb=ce110fb913c5650372667ee0aa8cf912d2c18d1a diff --git a/project/dae/forms.py b/project/dae/forms.py index cadb948..80b2774 100644 --- a/project/dae/forms.py +++ b/project/dae/forms.py @@ -1,38 +1,116 @@ # -*- encoding: utf-8 -*- from django import forms - +from django.forms.models import inlineformset_factory +from django.contrib.admin import widgets as admin_widgets +from ajax_select.fields import AutoCompleteSelectField +from auf.django.workflow.forms import WorkflowFormMixin from datamaster_modeles import models as ref from dae import models as dae from rh_v1 import models as rh +def label_poste_display(poste): + """Formate un visuel pour un poste dans une liste déroulante""" + label = u"%s - %s [%s]" %(poste.type_poste, poste.type_poste.famille_emploi.nom, poste.id) + return label + +class PostePieceForm(inlineformset_factory(dae.Poste, dae.PostePiece)): + pass + +class DossierPieceForm(inlineformset_factory(dae.Dossier, dae.DossierPiece)): + pass + +class FinancementForm(inlineformset_factory(dae.Poste, dae.PosteFinancement, extra=1)): + pass + +class JustificationNouvelEmployeForm(inlineformset_factory(dae.Dossier, + dae.JustificationNouvelEmploye, + extra=0, + can_delete=False, + exclude=('question',))): + """ + Formulaire de justification d'un nouvel employé. + Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions. + """ + def __init__(self, *args, **kwargs): + instance = kwargs['instance'] + if instance.id: + q_ids = [j.question.id for j in instance.justificationnouvelemploye_set.filter(dossier=instance)] + for q in dae.JustificationQuestion.objects.filter(type="N"): + if q.id in q_ids: + continue + j = dae.JustificationNouvelEmploye() + j.dossier = instance + j.question = q + j.save() + super(self.__class__, self).__init__(*args, **kwargs) + +class JustificationAutreEmployeForm(inlineformset_factory(dae.Dossier, + dae.JustificationAutreEmploye, + extra=0, + can_delete=False, + exclude=('question',))): + """ + Formulaire de justification d'un nouvel employé. + Le dossier a besoin d'être enregistré une première fois afin de prépopuler les questions. + """ + def __init__(self, *args, **kwargs): + instance = kwargs['instance'] + if instance.id: + q_ids = [j.question.id for j in instance.justificationautreemploye_set.filter(dossier=instance)] + for q in dae.JustificationQuestion.objects.filter(type="R"): + if q.id in q_ids: + continue + j = dae.JustificationAutreEmploye() + j.dossier = instance + j.question = q + j.save() + super(self.__class__, self).__init__(*args, **kwargs) -class PosteForm(forms.ModelForm): +class PosteForm(WorkflowFormMixin): """ Formulaire des postes. """ + + class Meta: model = dae.Poste fields = ('poste', 'implantation', 'type_poste', 'service', 'nom', - 'responsable', 'statut_residence', 'mise_a_disposition', + 'responsable', 'local', 'expatrie', 'mise_a_disposition', 'appel', 'date_debut', 'date_fin', 'actif', 'regime_travail', 'regime_travail_nb_heure_semaine', 'classement_min', 'classement_max', 'valeur_point_min', 'valeur_point_max', + 'devise_min', 'devise_max', 'salaire_min', 'salaire_max', 'indemn_min', 'indemn_max', 'autre_min', 'autre_max', 'devise_comparaison', 'comp_locale_min', 'comp_locale_max', 'comp_universite_min', 'comp_universite_max', 'comp_fonctionpub_min', 'comp_fonctionpub_max', 'comp_ong_min', 'comp_ong_max', - 'comp_autre_min', 'comp_autre_max',) - widgets = dict(statut_residence=forms.RadioSelect(), - appel=forms.RadioSelect(), - nom=forms.TextInput(attrs={'size': 60 }), -) + 'comp_autre_min', 'comp_autre_max', + 'justification', + 'etat', + ) + widgets = dict(appel=forms.RadioSelect(), + nom=forms.TextInput(attrs={'size': 60},), + date_debut=admin_widgets.AdminDateWidget(), + date_fin=admin_widgets.AdminDateWidget(), + justification=forms.Textarea(attrs={'cols': 80},), + #devise_min=forms.Select(attrs={'disabled':'disabled'}), + #devise_max=forms.Select(attrs={'disabled':'disabled'}), + ) + + responsable=AutoCompleteSelectField('responsables', required=True) + #responsable = forms.ModelChoiceField( + # queryset=rh.Poste.objects.select_related(depth=1)) # La liste des choix est laissée vide. Voir __init__ pour la raison. - poste = forms.ChoiceField(label="Nouveau poste, ou évolution du poste", choices=(), required=False) + poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste", + choices=(), required=False) + + valeur_point_min = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False) + valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False) def __init__(self, *args, **kwargs): """ Mise à jour dynamique du contenu du menu des postes. @@ -42,10 +120,21 @@ class PosteForm(forms.ModelForm): reflète pas les changements apportés par les ajouts, modifications, etc... + Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField + car le "id" de chaque choix est spécial (voir _poste_choices). + """ super(PosteForm, self).__init__(*args, **kwargs) self.fields['poste'].choices = self._poste_choices() + # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1 + if self.instance and self.instance.id is None: + dossiers = self.instance.get_dossiers() + if len(dossiers) > 0: + self.initial['service'] = dossiers[0].service_id + self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom()) + + def _poste_choices(self): """ Menu déroulant pour les postes. @@ -53,19 +142,119 @@ class PosteForm(forms.ModelForm): d'équivalent dans dae. """ - dae_ = dae.Poste.objects.filter(id_rh__isnull=True) + dae_ = dae.Poste.objects.filter(actif=True, id_rh__isnull=True) copies = dae.Poste.objects.exclude(id_rh__isnull=True) id_copies = [p.id_rh_id for p in copies.all()] - rhv1 = rh.Poste.objects.exclude(id__in=id_copies) + rhv1 = rh.Poste.objects.filter(actif=True).exclude(id__in=id_copies) + # Optimisation de la requête + rhv1 = rhv1.select_related(depth=1) return [('', 'Nouveau poste')] + \ - sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies] + - [('rh-%s' % p.id, unicode(p)) for p in rhv1], + sorted([('dae-%s' % p.id, label_poste_display(p)) for p in dae_ | copies] + + [('rh-%s' % p.id, label_poste_display(p)) for p in rhv1], + key=lambda t: t[1]) + + def clean(self): + """ + Validation conditionnelles de certains champs. + """ + cleaned_data = self.cleaned_data + + # Gestion de la mise à disposition + mise_a_disposition = cleaned_data.get("mise_a_disposition") + valeur_point_min = cleaned_data.get("valeur_point_min") + valeur_point_max = cleaned_data.get("valeur_point_max") + if mise_a_disposition is False and (valeur_point_min is None or valeur_point_max is None): + msg = u"Ce champ est obligatoire." + self._errors["valeur_point_min"] = self.error_class([msg]) + self._errors["valeur_point_max"] = self.error_class([msg]) + raise forms.ValidationError("Les valeurs de point sont vides") + + return cleaned_data + + + + def save(self, *args, **kwargs): + kwargs2 = kwargs.copy() + kwargs2['commit'] = False + poste = super(PosteForm, self).save(*args, **kwargs2) + # id_rh + if 'commit' not in kwargs or kwargs['commit']: + poste.save() + return poste + + +class ChoosePosteForm(forms.ModelForm): + class Meta: + model = dae.Poste + fields = ('poste',) + + # La liste des choix est laissée vide. Voir PosteForm.__init__. + poste = forms.ChoiceField(choices=(), required=False) + + def __init__(self, *args, **kwargs): + super(ChoosePosteForm, self).__init__(*args, **kwargs) + self.fields['poste'].choices = self._poste_choices() + + def _poste_choices(self): + """ Menu déroulant pour les postes. """ + dae_ = dae.Poste.objects.filter(id_rh__isnull=True) + copies = dae.Poste.objects.exclude(id_rh__isnull=True) + id_copies = [p.id_rh_id for p in copies.all()] + + return [('', '----------')] + \ + sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies], key=lambda t: t[1]) -class PosteFinancementForm(forms.ModelForm): - """ Formulaire des sources de financement pour un poste. """ +class EmployeForm(forms.ModelForm): + """ Formulaire des employés. """ + class Meta: + model = dae.Employe + fields = ('employe', 'nom', 'prenom', 'genre') + + # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison. + employe = forms.ChoiceField(choices=(), required=False) + + def __init__(self, *args, **kwargs): + """ Mise à jour dynamique du contenu du menu des employés. """ + super(EmployeForm, self).__init__(*args, **kwargs) + self.fields['employe'].choices = self._employe_choices() + + def _employe_choices(self): + """ Menu déroulant pour les employés. """ + dae_ = dae.Employe.objects.filter(id_rh__isnull=True) + copies = dae.Employe.objects.exclude(id_rh__isnull=True) + id_copies = [p.id_rh_id for p in copies.all()] + rhv1 = rh.Employe.objects.exclude(id__in=id_copies) + + def option_label(employe): + return "%s %s" % (employe.nom.upper(), employe.prenom.title()) + + return [('', 'Nouvel employé')] + \ + sorted([('dae-%s' % p.id, option_label(p)) for p in dae_ | copies] + + [('rh-%s' % p.id, option_label(p)) for p in rhv1], + key=lambda t: t[1]) + + +class DossierForm(forms.ModelForm): + """ Formulaire des dossiers. """ + class Meta: + exclude= ('etat', ) + model = dae.Dossier + widgets = dict(statut_residence=forms.RadioSelect(), + contrat_date_debut=admin_widgets.AdminDateWidget(), + contrat_date_fin=admin_widgets.AdminDateWidget(), + ) + +class PosteWorkflowForm(WorkflowFormMixin): + + class Meta: + fields = ('etat', ) + model = dae.Poste + +class DossierWorkflowForm(WorkflowFormMixin): + class Meta: - model = dae.PosteFinancement - fields = ('type', 'montant', 'pourcentage', 'commentaire') + fields = ('etat', ) + model = dae.Dossier