Merge branch 'reversion'
authorOlivier Larchevêque <olivier.larcheveque@auf.org>
Thu, 5 Jul 2012 18:27:48 +0000 (14:27 -0400)
committerOlivier Larchevêque <olivier.larcheveque@auf.org>
Thu, 5 Jul 2012 18:27:48 +0000 (14:27 -0400)
project/dae/forms.py
project/dae/management/__init__.py [new file with mode: 0644]
project/dae/management/commands/__init__.py [new file with mode: 0644]
project/dae/management/commands/dae.py [new file with mode: 0644]
project/dae/templates/dae/embauche-remun-consulter.html
project/dae/templates/dae/embauches_finalisees.html
project/dae/templates/dae/poste.html
project/dae/views.py
project/dae/workflow.py
project/templates/menu.html

index bd7a334..0de2b4b 100644 (file)
@@ -3,6 +3,7 @@
 import datetime
 
 from django import forms
+from django.forms.models import BaseInlineFormSet
 from django.contrib.admin import widgets as admin_widgets
 from django.db.models import Q, Max
 from django.forms.models import inlineformset_factory, modelformset_factory
@@ -17,8 +18,71 @@ from project.groups import \
         get_employe_from_user, is_user_dans_services_centraux
 
 from project.dae import models as dae
-from project.dae.workflow import \
-        grp_drh, POSTE_ETATS_BOUTONS, POSTE_ETAT_FINALISE
+from project.dae.workflow import grp_drh, POSTE_ETATS_BOUTONS
+
+
+class BaseInlineFormSetWithInitial(BaseInlineFormSet):
+    """
+    Cette classe permet de fournir l'option initial aux inlineformsets.
+    Elle devient désuette en django 1.4.
+    """
+    def __init__(self, data=None, files=None, instance=None,
+                 save_as_new=False, prefix=None, queryset=None, **kwargs):
+
+        self.initial_extra = kwargs.pop('initial', None)
+
+        from django.db.models.fields.related import RelatedObject
+        if instance is None:
+            self.instance = self.fk.rel.to()
+        else:
+            self.instance = instance
+        self.save_as_new = save_as_new
+        # is there a better way to get the object descriptor?
+        self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
+        if queryset is None:
+            queryset = self.model._default_manager
+        qs = queryset.filter(**{self.fk.name: self.instance})
+        super(BaseInlineFormSetWithInitial, self).__init__(data, files, prefix=prefix,
+                                                queryset=qs, **kwargs)
+
+    def _construct_form(self, i, **kwargs):
+        if self.is_bound and i < self.initial_form_count():
+            # Import goes here instead of module-level because importing
+            # django.db has side effects.
+            from django.db import connections
+            pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
+            pk = self.data[pk_key]
+            pk_field = self.model._meta.pk
+            pk = pk_field.get_db_prep_lookup('exact', pk,
+                connection=connections[self.get_queryset().db])
+            if isinstance(pk, list):
+                pk = pk[0]
+            kwargs['instance'] = self._existing_object(pk)
+        if i < self.initial_form_count() and not kwargs.get('instance'):
+            kwargs['instance'] = self.get_queryset()[i]
+        if i >= self.initial_form_count() and self.initial_extra:
+            # Set initial values for extra forms
+            try:
+                kwargs['initial'] = self.initial_extra[i-self.initial_form_count()]
+            except IndexError:
+                pass
+
+        defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)}
+        if self.is_bound:
+            defaults['data'] = self.data
+            defaults['files'] = self.files
+        if self.initial:
+            try:
+                defaults['initial'] = self.initial[i]
+            except IndexError:
+                pass
+        # Allow extra forms to be empty.
+        if i >= self.initial_form_count():
+            defaults['empty_permitted'] = True
+        defaults.update(kwargs)
+        form = self.form(**defaults)
+        self.add_fields(form, i)
+        return form
 
 
 def _implantation_choices(obj, request):
@@ -113,16 +177,30 @@ def label_poste_display(poste):
     annee = ""
     if poste.date_debut:
         annee = poste.date_debut.year
+
+    nom = poste.nom
+    
     label = u"%s %s - %s [%s]" % (
-        annee, poste.type_poste, poste.type_poste.categorie_emploi.nom,
-        poste.id
+        annee, nom, poste.type_poste.categorie_emploi.nom, poste.id
     )
     return label
 
-PostePieceForm = inlineformset_factory(dae.Poste, dae.PostePiece)
+
+PostePieceFormSet = inlineformset_factory(dae.Poste, dae.PostePiece,)
 DossierPieceForm = inlineformset_factory(dae.Dossier, dae.DossierPiece)
-FinancementForm = inlineformset_factory(
-    dae.Poste, dae.PosteFinancement, extra=2
+
+# Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
+# données de RH
+FinancementFormSetInitial = inlineformset_factory(
+    dae.Poste,
+    dae.PosteFinancement,
+    formset=BaseInlineFormSetWithInitial,
+    extra=2
+)
+FinancementFormSet = inlineformset_factory(
+    dae.Poste,
+    dae.PosteFinancement,
+    extra=2
 )
 
 
@@ -150,8 +228,22 @@ class PosteComparaisonForm(forms.ModelForm):
         model = dae.PosteComparaison
         exclude = ('poste',)
 
-PosteComparaisonFormSet = modelformset_factory(
-    dae.PosteComparaison, extra=3, max_num=3, form=PosteComparaisonForm
+# Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
+# données de RH
+PosteComparaisonFormSetInitial = inlineformset_factory(
+    dae.Poste,
+    dae.PosteComparaison,
+    extra=3,
+    max_num=3,
+    form=PosteComparaisonForm,
+    formset=BaseInlineFormSetWithInitial,
+)
+PosteComparaisonFormSet = inlineformset_factory(
+    dae.Poste,
+    dae.PosteComparaison,
+    extra=3,
+    max_num=3,
+    form=PosteComparaisonForm,
 )
 
 
@@ -254,6 +346,7 @@ class PosteForm(forms.ModelForm):
         request = kwargs.pop('request')
         super(PosteForm, self).__init__(*args, **kwargs)
         self.fields['poste'].choices = self._poste_choices(request)
+        
         self.fields['implantation'].choices = \
                 _implantation_choices(self, request)
 
@@ -265,23 +358,14 @@ class PosteForm(forms.ModelForm):
 
     def _poste_choices(self, request):
         """ Menu déroulant pour les postes.
-
-        Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
-        d'équivalent dans dae.
-
+        Constitué des postes de RH
         """
-        copies = dae.Poste.objects \
-                .ma_region_ou_service(request.user) \
-                .exclude(id_rh__isnull=True) \
-                .filter(etat=POSTE_ETAT_FINALISE)
-        id_copies = [p.id_rh_id for p in copies.all()]
-        rhv1 = rh.Poste.objects.ma_region_ou_service(request.user) \
-                .exclude(id__in=id_copies)
-        # Optimisation de la requête
-        rhv1 = rhv1.select_related(depth=1)
+        postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).all()
+        postes_rh = postes_rh.select_related(depth=1)
 
         return [('', 'Nouveau poste')] + \
-               sorted([('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
+               sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
+                   postes_rh],
                       key=lambda t: t[1])
 
     def clean(self):
diff --git a/project/dae/management/__init__.py b/project/dae/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/project/dae/management/commands/__init__.py b/project/dae/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/project/dae/management/commands/dae.py b/project/dae/management/commands/dae.py
new file mode 100644 (file)
index 0000000..43f7e2a
--- /dev/null
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+
+import sys
+import codecs
+from django.core.management.base import BaseCommand
+from project.rh import models as rh
+from project.dae import models as dae
+
+class Command(BaseCommand):
+
+    def handle(self, *args, **options):
+
+        stdout = options.get('stdout', sys.stdout)
+        self.stdout = codecs.getwriter('utf8')(stdout)
+
+        if args[0] == "liste_poste":
+            for poste in dae.Poste.objects.filter(id_rh__isnull=False):
+                self.stdout.write(u"%s: %s %s [%s]\n" % (poste.id, poste.nom,
+                        poste.implantation, poste.etat))
+
+        if args[0] == "importer_poste":
+            poste = dae.Poste.objects.get(id=args[1])
+            poste.importer_dans_rh()
+            self.stdout.write(u"DAE:%s => RH:%s\n" % (poste.id, poste.id_rh.id))
index a887f4a..329f848 100644 (file)
@@ -22,7 +22,7 @@
     <td class="montant">{{ remun.montant|floatformat:0 }} {{ remun.devise.code }}</td>
     <td class="montant">{{ remun.montant_euro_mois|floatformat:0 }}€</td>
     <td class="montant">{{ remun.montant_euros }}€</td>
-    <td>{{ remun.precision }}</td>
+    <td>{{ remun.commentaire }}</td>
   </tr>
 {% endfor %}
 
@@ -41,7 +41,7 @@
     <td class="montant">{{ remun.montant|floatformat:0 }} {{ remun.devise.code }}</td>
     <td class="montant">{{ remun.montant_euro_mois|floatformat:0 }}€</td>
     <td class="montant">{{ remun.montant_euros }}€</td>
-    <td>{{ remun.precision }}</td>
+    <td>{{ remun.commentaire }}</td>
   </tr>
 {% endfor %}
 
@@ -66,7 +66,7 @@
     <td class="montant">{{ remun.montant|floatformat:0 }} {{ remun.devise.code }}</td>
     <td class="montant">{{ remun.montant_euro_mois|floatformat:0 }}€</td>
     <td class="montant">{{ remun.montant_euros }}€</td>
-    <td>{{ remun.precision }}</td>
+    <td>{{ remun.commentaire }}</td>
   </tr>
 {% endfor %}
 <tr>
     <td class="montant">{{ remun.montant|floatformat:0 }} {{ remun.devise.code }}</td>
     <td class="montant">{{ remun.montant_euro_mois|floatformat:0 }}€</td>
     <td class="montant">{{ remun.montant_euros }}€</td>
-    <td>{{ remun.precision }}</td>
+    <td>{{ remun.commentaire }}</td>
   </tr>
 {% endfor %}
 {% endwith %}
index 9ed6f0b..5975162 100644 (file)
@@ -46,7 +46,7 @@
         <td><input type="checkbox" name="ids" value="{{ dossier.id }}"></td>
         <td>{{ dossier.poste.implantation|region_ou_service }}</td>
         <td>{{ dossier.poste.implantation }}</td>
-        <td><a href="{% url embauche_consulter dossier.id %}">{{ dossier.poste.nom }}</a></td>
+        <td><a href="{% url poste_consulter dossier.poste.key %}">{{ dossier.poste.nom }}</a></td>
         <td><a href="{% url embauche_consulter dossier.id %}">{{ dossier.employe }}</a></td>
         <td>{{ dossier.contrat_date_debut|date:"d-m-Y" }}</td>
         <td>{{ dossier.contrat_date_fin|date:"d-m-Y" }}</td>
index 1bf7167..52e3d06 100644 (file)
@@ -320,6 +320,10 @@ Demande d'autorisation d'engagement
     <fieldset>
     <h2>Pièces jointes</h2>
     <p class="info">Compléter uniquement lors de la création d'un poste</p>
+    <ul>{% for piece in poste_rh.rh_pieces.all %}
+        <li>Ce <a target="_blank" href="{{ piece.fichier.url }}">{{ piece.nom }}</a> RH sera automatiquement
+    ajouté.</li>
+    {% endfor %}</ul>
     {% include "dae/pieces.html" %}
     </fieldset>
 
index e19db0e..925f530 100644 (file)
@@ -23,9 +23,11 @@ from project.dae.decorators import \
         employe_dans_ma_region_ou_service, \
         dossier_est_modifiable, \
         poste_est_modifiable, get_contrat
+from project.dae.forms import FinancementFormSet, FinancementFormSetInitial
+from project.dae.forms import PosteComparaisonFormSet, PosteComparaisonFormSetInitial
 from project.dae.forms import \
-        PosteWorkflowForm, PosteForm, FinancementForm, PostePieceForm, \
-        PosteComparaisonFormSet, DossierWorkflowForm, ChoosePosteForm, \
+        PosteWorkflowForm, PosteForm, PostePieceFormSet, \
+        DossierWorkflowForm, ChoosePosteForm, \
         EmployeForm, DossierForm, DossierPieceForm, \
         DossierComparaisonFormSet, RemunForm, ContratForm, DAENumeriseeForm, \
         label_poste_display, DAEFinaliseesSearchForm
@@ -115,46 +117,70 @@ def poste(request, key=None):
     il est automatiquement copié dans dae.
 
     """
+
+    def _dupliquer_poste(poste_dae, poste_rh):
+        """
+        Recopie les fields d'un poste RH dans un poste DAE
+        avec ceux-ci précédemment crées
+        """
+        exclus = ('id', 'supprime', 'date_creation',
+                'user_creation', 'date_modification',
+                'user_modification', )
+        fields = [f for f in poste_rh._meta.fields if f.name not in exclus]
+        for field in fields:
+            setattr(poste_dae, field.name, getattr(poste_rh, field.name))
+        return poste_dae
+
     poste, data, vars = None, dict(), dict()
 
-    if key:
-        # Poste existant
+    # Sans key, c'est un nouveau poste
+    if key is None:
+        new = True
+    else:
+        new = False
+
+    # Poste existant
+    poste_rh = None
+    if not new:
         source, id = key.split('-')
 
         if source == 'dae':
             poste = get_object_or_404(dae.Poste, pk=id)
+            #data['poste'] = key
         elif source == 'rh':
-            p = get_object_or_404(rh.Poste, pk=id)
+            poste_rh = get_object_or_404(rh.Poste, pk=id)
+            poste = dae.Poste(id_rh=poste_rh)
             # Initialisation avec les valeurs du poste de rh_v1
-            poste = dae.Poste(id_rh=p, nom=p.type_poste.nom)
-            for field in ('implantation', 'type_poste', ):
-                setattr(poste, field, getattr(p, field))
-        if poste.id_rh_id:
-            data['poste'] = 'rh-' + str(poste.id_rh_id)
-        else:
-            data['poste'] = key
+            poste = _dupliquer_poste(poste, poste_rh)
+            #data['poste'] = 'rh-' + str(poste.id_rh_id)
+
+    # prépopuler pour la modification de poste
+    if poste_rh is not None:
+        FinancementForm = FinancementFormSetInitial
+        PosteComparaisonForm = PosteComparaisonFormSetInitial
+
+        qs_financements = poste_rh.rh_financements.all()
+        qs_comparaisons = poste_rh.rh_comparaisons_internes.all()
+        financements = [{'type': f.type, 'pourcentage': f.pourcentage,
+            'commentaire': f.commentaire} for f in qs_financements]
+        comparaisons = [{'implantation': c.implantation, 'nom': c.nom,
+            'montant': c.montant, 'devise': c.devise} for c in qs_comparaisons]
+    # formulaires normaux, avec modifications des objects FK
     else:
-        # Nouveau poste
-        vars['new'] = True
+        FinancementForm = FinancementFormSet
+        PosteComparaisonForm = PosteComparaisonFormSet
+        financements = []
+        comparaisons = []
+
 
     if request.POST:
         data.update(dict(request.POST.items()))
         form = PosteForm(data, instance=poste, request=request)
-        financementForm = FinancementForm(request.POST, instance=poste)
-        piecesForm = PostePieceForm(
-            request.POST, request.FILES, instance=poste
-        )
-        if isinstance(poste, dae.Poste):
-            comparaisons_formset = PosteComparaisonFormSet(
+        financementForm = FinancementForm(request.POST, instance=poste, )
+        piecesForm = PostePieceFormSet(request.POST, request.FILES, instance=poste, )
+        comparaisons_formset = PosteComparaisonForm(
                 request.POST,
-                queryset=poste.dae_comparaisons_internes.ma_region_ou_service(
-                    request.user
-                )
-            )
-        else:
-            comparaisons_formset = PosteComparaisonFormSet(
-                request.POST,
-                queryset=dae.PosteComparaison.objects.none()
+                instance=poste,
             )
         if form.is_valid() and piecesForm.is_valid() and \
            financementForm.is_valid() and comparaisons_formset.is_valid():
@@ -170,6 +196,11 @@ def poste(request, key=None):
                 comparaison.poste = poste
                 comparaison.save()
 
+            # dans le cas d'une modification de poste de RH, on recopie les PJ
+            if poste_rh is not None:
+                for piece in poste_rh.rh_pieces.all():
+                    dae.PostePiece(poste=poste, nom=piece.nom,
+                            fichier=piece.fichier).save()
             messages.add_message(
                 request, messages.SUCCESS,
                 "Le poste %s a été sauvegardé." % poste
@@ -189,23 +220,24 @@ def poste(request, key=None):
         # 'initial' évite la validation prémature lors d'une copie de poste de
         # rh_v1 vers dae.
         form = PosteForm(initial=data, instance=poste, request=request)
-        piecesForm = PostePieceForm(instance=poste)
-        financementForm = FinancementForm(instance=poste)
-        if isinstance(poste, dae.Poste):
-            comparaisons_formset = PosteComparaisonFormSet(
-                queryset=poste.dae_comparaisons_internes.ma_region_ou_service(
-                    request.user
-                )
+        piecesForm = PostePieceFormSet(instance=poste)
+
+        if poste_rh is not None:
+            financementForm = FinancementForm(initial=financements, instance=poste)
+            comparaisons_formset = PosteComparaisonForm(
+                initial=comparaisons,
+                instance=poste,
             )
+        # cas de la création d'un nouveau poste
         else:
-            comparaisons_formset = PosteComparaisonFormSet(
-                queryset=dae.PosteComparaison.objects.none()
-            )
+            financementForm = FinancementForm(instance=poste)
+            comparaisons_formset = PosteComparaisonForm(instance=poste)
 
     vars.update(dict(
         form=form, poste=poste, poste_key=key, piecesForm=piecesForm,
         financementForm=financementForm,
-        comparaisons_formset=comparaisons_formset
+        comparaisons_formset=comparaisons_formset,
+        poste_rh=poste_rh,
     ))
 
     return render(request, 'dae/poste.html', vars)
@@ -843,26 +875,20 @@ def liste_postes(request):
     params = getattr(request, method, [])
     data = []
 
-    # Voir le code de _poste_choices dans forms.py
-    copies = dae.Poste.objects.exclude(id_rh__isnull=True) \
-            .filter(etat=POSTE_ETAT_FINALISE)
-    rh_postes_actifs = rh.Poste.objects.all()
-
     if 'implantation_id' in params \
        and params.get('implantation_id') is not u"":
         implantation_id = params.get('implantation_id')
-        copies = copies.filter(implantation__id=implantation_id)
-        rh_postes_actifs = rh_postes_actifs.filter(
-            implantation__id=implantation_id
-        )
+        q = Q(implantation__id=implantation_id)
+    else:
+        q = Q()
 
-    id_copies = [p.id_rh_id for p in copies.all()]
-    rhv1 = rh_postes_actifs.exclude(id__in=id_copies)
-    rhv1 = rhv1.select_related(depth=1)
+    postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).filter(q)
+    postes_rh = postes_rh.select_related(depth=1)
 
     data = [('', 'Nouveau poste')] + \
-            sorted([('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
-                   key=lambda t: t[1])
+           sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
+               postes_rh],
+                  key=lambda t: t[1])
     return HttpResponse(dumps(data))
 
 
index 0296206..a893c75 100644 (file)
@@ -135,14 +135,14 @@ POSTE_ACTIONS = {
         'etat_initial': (POSTE_ETAT_DEMANDE_MODIF,),
         'etat_final': POSTE_ETAT_DRH_CONTROLE,
     },
-    POSTE_ACTION_ENVOYER_ACCIOR: {
-        'nom': u'Envoyer',
-        'etat_initial': (POSTE_ETAT_DRH_2,),
-        'etat_final': POSTE_ETAT_ACCIOR,
-    },
+    #POSTE_ACTION_ENVOYER_ACCIOR: {
+    #    'nom': u'Envoyer',
+    #    'etat_initial': (POSTE_ETAT_DRH_2,),
+    #    'etat_final': POSTE_ETAT_ACCIOR,
+    #},
     POSTE_ACTION_ENVOYER_ABF: {
         'nom': u'Envoyer',
-        'etat_initial': (POSTE_ETAT_ACCIOR,),
+        'etat_initial': (POSTE_ETAT_ACCIOR, POSTE_ETAT_DRH_2),
         'etat_final': POSTE_ETAT_ABF,
     },
     POSTE_ACTION_ENVOYER_HAUTE_DIRECTION: {
index ec22fd2..cf44590 100644 (file)
         </li>
         {% endif %}
         <li class="{% menu_actif request '^embauches$' %}">
-          <a href="{% url dae_embauches_liste %}">Embauches : voir et valider</a>
+          <a href="{% url dae_embauches_liste %}">Personnel : voir et valider</a>
         </li>
         <li class="{% menu_actif request '^embauches_finalisees$' %}">
-          <a href="{% url embauches_finalisees %}">Embauches finalisées</a>
+          <a href="{% url embauches_finalisees %}">DAE finalisées</a>
         </li>
     </ul>
   </li>