Merge branch 'master' into recrutement
authorPA Parent <paparent@paparent.me>
Tue, 12 Jun 2012 19:46:04 +0000 (15:46 -0400)
committerPA Parent <paparent@paparent.me>
Tue, 12 Jun 2012 19:46:04 +0000 (15:46 -0400)
13 files changed:
project/dashboard.py
project/decorators.py
project/rh/admin.py
project/rh/forms.py
project/rh/managers.py
project/rh/models.py
project/rh/templates/rh/include/employe.html
project/rh/templates/rh/rapports/contrats.html
project/rh/templates/rh/rapports/employes_sans_contrat.html
project/rh/urls.py
project/rh/views.py
project/utils.py [deleted file]
src/qbe/django_qbe/admin.py

index 8ef431a..22b476d 100644 (file)
@@ -85,7 +85,7 @@ class CustomIndexDashboard(Dashboard):
         self.children.append(modules.AppList(
             _(u'Inter-systèmes'),
             models=(
-                'project.rh.models.ResponsableImplantation',
+                'project.rh.models.ResponsableImplantationProxy',
             ),
         ))
 
index a5e3805..8b56060 100644 (file)
@@ -6,8 +6,7 @@ from django.http import HttpResponseRedirect
 from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth import REDIRECT_FIELD_NAME
-from django.contrib.auth.decorators import user_passes_test
-from django.core.urlresolvers import reverse
+from django.db.models import Q
 from django.utils.http import urlquote
 
 from project.groups import grp_drh, grp_drh2, grp_correspondants_rh
@@ -21,9 +20,13 @@ def redirect_interdiction(request, msg=u"Vous n'avez pas accès à cette page"):
     login_url = settings.LOGIN_URL
     path = urlquote(request.get_full_path())
     tup = login_url, REDIRECT_FIELD_NAME, path
-    messages.add_message(request, messages.ERROR, "Votre compte ne permet pas d'accéder à cette partie de l'application.")
+    messages.add_message(
+        request, messages.ERROR,
+        "Votre compte ne permet pas d'accéder à cette partie de l'application."
+    )
     return HttpResponseRedirect('%s?%s=%s' % tup)
-    
+
+
 def in_drh_or_admin(user):
     """
     Teste si un user Django fait parti du groupe DRH, DRH2 ou s'il est admin
@@ -35,7 +38,8 @@ def in_drh_or_admin(user):
         return True
     else:
         return False
-        
+
+
 def drh_or_admin_required(fn):
     """
     Teste si un user Django fait parti du groupe DRH, DRH2 ou s'il est admin
@@ -50,7 +54,8 @@ def drh_or_admin_required(fn):
         return redirect_interdiction(request, msg)
 
     return inner
-    
+
+
 def region_protected(model):
     def wrapper(func):
         def wrapped(request, id):
index c2eec9e..8f10421 100644 (file)
@@ -1,7 +1,7 @@
 # -*- encoding: utf-8 -*-
 
 import datetime
-        
+
 from django.core.urlresolvers import reverse
 from django.contrib import admin
 from django.conf import settings
@@ -20,8 +20,9 @@ from project.groups import grp_correspondants_rh
 from project.groups import get_employe_from_user
 
 import project.rh.models as rh
-from project.rh.forms import \
-        ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect, DossierForm
+from project.rh.forms import ContratForm, AyantDroitForm, EmployeAdminForm, \
+          AjaxSelect, DossierForm, ResponsableInlineForm
+        
 from project.rh.change_list import ChangeList
 
 
@@ -720,6 +721,7 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
             'implantation__nom',
             'implantation__region__code',
             'implantation__region__nom',
+            'rh_dossiers__employe__id',
             'rh_dossiers__employe__nom',
             'rh_dossiers__employe__prenom',
             )
@@ -944,15 +946,24 @@ class ResponsableInline(admin.TabularInline):
     model = rh.ResponsableImplantation
     extra = 0
     fk_name = "implantation"
+    form = ResponsableInlineForm
 
 
 class ResponsableImplantationAdmin(BaseAdmin):
     actions = None
+    fields = ('nom', )
+    inlines = (ResponsableInline, )
     list_filter = ('region', 'statut', )
     list_display = ('_region', '_nom', 'statut', '_responsable', )
+    list_display_links = ('_nom',)
     readonly_fields = ('nom', )
-    fields = ('nom', )
-    inlines = (ResponsableInline, )
+    search_fields = (
+            'nom',
+            'responsable__employe__id',
+            'responsable__employe__nom',
+            'responsable__employe__prenom',
+            )
+    ordering = ('nom',)
     
     def _region(self, obj):
         return obj.region.code
@@ -981,6 +992,7 @@ class ResponsableImplantationAdmin(BaseAdmin):
             return u"<span %s>Pas de responsable</span>" % css
     _responsable.allow_tags = True
     _responsable.short_description = u"Responsable"
+    _responsable.admin_order_field = 'responsable__employe__nom'
 
     def has_add_permission(self, request=None):
         return False
index 1b08bc1..a1671a2 100644 (file)
@@ -2,16 +2,23 @@
 
 from django import forms
 from ajax_select.fields import AutoCompleteSelectField
-from project.rh.models import Dossier, Contrat, AyantDroit, Employe
+from project.rh.models import Dossier, Contrat, AyantDroit, Employe, \
+        ResponsableImplantation
 
 
 class AjaxSelect(object):
 
     class Media:
         css = {
-            'all': ('jquery-autocomplete/jquery.autocomplete.css', 'css/select.css', )
+            'all': (
+                'jquery-autocomplete/jquery.autocomplete.css',
+                'css/select.css',
+            )
         }
-        js = ('js/jquery-1.5.1.min.js', 'jquery-autocomplete/jquery.autocomplete.js', )
+        js = (
+            'js/jquery-1.5.1.min.js',
+            'jquery-autocomplete/jquery.autocomplete.js',
+        )
 
 
 class FormDate(object):
@@ -19,14 +26,17 @@ class FormDate(object):
     def clean_date_fin(self):
         date_fin = self.cleaned_data['date_fin']
         if date_fin is None:
-          return date_fin
+            return date_fin
         date_debut = self.cleaned_data['date_debut']
         if date_fin < date_debut:
-            raise forms.ValidationError(u"La date de fin est antérieure à la date de début")
+            raise forms.ValidationError(
+                u"La date de fin est antérieure à la date de début"
+            )
         return date_fin
 
+
 class DossierForm(forms.ModelForm, FormDate):
-    
+
     class Model:
         model = Dossier
 
@@ -36,10 +46,10 @@ class ContratForm(forms.ModelForm, FormDate):
     class Model:
         model = Contrat
 
+
 class AyantDroitForm(forms.ModelForm, AjaxSelect):
 
     # ne fonctionne pas dans un inline
-    #nationalite = AutoCompleteSelectField('pays', help_text="Taper le nom ou le code du pays", required=False)
 
     def __init__(self, *args, **kwargs):
         super(AyantDroitForm, self).__init__(*args, **kwargs)
@@ -51,8 +61,12 @@ class AyantDroitForm(forms.ModelForm, AjaxSelect):
 
 class EmployeAdminForm(forms.ModelForm, AjaxSelect):
 
-    nationalite = AutoCompleteSelectField('pays', help_text="Taper le nom ou le code du pays", required=False)
-    pays = AutoCompleteSelectField('pays', help_text="Taper le nom ou le code du pays", required=False)
+    nationalite = AutoCompleteSelectField(
+        'pays', help_text="Taper le nom ou le code du pays", required=False
+    )
+    pays = AutoCompleteSelectField(
+        'pays', help_text="Taper le nom ou le code du pays", required=False
+    )
 
     class Meta:
         model = Employe
@@ -62,3 +76,9 @@ class EmployeAdminForm(forms.ModelForm, AjaxSelect):
         self.fields['date_naissance'].widget = forms.widgets.DateInput()
 
 
+class ResponsableInlineForm(forms.ModelForm):
+    employes_actifs = Employe.objects.actifs()
+    employe = forms.ModelChoiceField(queryset=employes_actifs)
+
+    class Meta:
+        model = ResponsableImplantation
index 73f91e5..15ee63e 100644 (file)
@@ -1,11 +1,12 @@
 # -*- encoding: utf-8 -*-
 
 import datetime
+from datetime import date
 
 from django.db import models
 from django.db.models import Q
 
-from auf.django.metadata.managers import NoDeleteManager
+from auf.django.metadata.managers import NoDeleteManager, NoDeleteQuerySet
 
 from project.groups import get_employe_from_user
 from project.groups import grp_administrateurs, \
@@ -121,6 +122,34 @@ class DossierManager(SecurityManager, NoDeleteManager):
         return super(DossierManager, self).ma_region_ou_service(user)
 
 
+class EmployeQuerySet(NoDeleteQuerySet):
+    def actifs(self, date_min=None, date_max=None, annee=None):
+        qs = self
+        if annee:
+            janvier = date(annee, 1, 1)
+            decembre = date(annee, 12, 31)
+            date_min = max(janvier, date_min) if date_min else janvier
+            date_max = min(decembre, date_max) if date_max else decembre
+        if not date_min and not date_max:
+            date_min = date_max = date.today()
+        if date_min:
+            qs = qs.filter(
+                Q(rh_dossiers__date_fin__gte=date_min) | Q(rh_dossiers__date_fin=None)
+            )
+        if date_max:
+            qs = qs.filter(
+                Q(rh_dossiers__date_debut__lte=date_max) | Q(rh_dossiers__date_debut=None)
+            )
+        return qs.distinct()
+
+class EmployeManager(NoDeleteManager):
+    def get_query_set(self):
+        return EmployeQuerySet(self.model) \
+                .filter(supprime=False)
+
+    def actifs(self, *args, **kwargs):
+        return self.get_query_set().actifs(*args, **kwargs)
+
 class PosteComparaisonManager(SecurityManager):
     use_for_related_fields = True
     prefixe_implantation = "implantation__region"
index 6c809d0..f39e795 100644 (file)
@@ -19,7 +19,8 @@ from project.rh.change_list import \
         RechercheTemporelle, KEY_STATUT, STATUT_ACTIF, STATUT_INACTIF, \
         STATUT_FUTUR
 from project.rh.managers import \
-        PosteManager, DossierManager, DossierComparaisonManager, \
+        PosteManager, DossierManager, EmployeManager, \
+        DossierComparaisonManager, \
         PosteComparaisonManager, DeviseManager, ServiceManager, \
         TypeRemunerationManager
 from project.rh.validators import validate_date_passee
@@ -450,6 +451,9 @@ class Employe(AUFMetadata):
     Cette classe aurait pu avantageusement s'appeler Personne car la notion
     d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
     """
+
+    objects = EmployeManager()
+    
     # Identification
     nom = models.CharField(max_length=255)
     prenom = models.CharField(u"prénom", max_length=255)
@@ -1510,6 +1514,9 @@ class TypeContrat(AUFMetadata):
 
 class ResponsableImplantationProxy(ref.Implantation):
 
+    def save(self):
+        pass
+
     class Meta:
         proxy = True
         verbose_name = u"Responsable d'implantation"
index cee91db..3c1131c 100644 (file)
@@ -3,6 +3,7 @@
     {% include "rh/form-row.html" with label="Nom" value=employe.nom %}
     {% include "rh/form-row.html" with label="Prénom" value=employe.prenom %}
     {% include "rh/form-row.html" with label="Nom d'affichage" value=employe.nom_affichage|default:"" %}
+    {% include "rh/form-row.html" with label="Genre" value=employe.get_genre_display %}
     {% include "rh/form-row.html" with label="Nationalité" value=employe.nationalite %}
     {% include "rh/form-row.html" with label="Date de naissance" value=employe.date_naissance %}
     {% include "rh/form-row.html" with label="Situation familiale" value=employe.situation_famille.nom %}
@@ -24,7 +25,7 @@
 <fieldset class="module aligned">
     <h2>Ayants droit</h2>
     {% for ay in employe.ayantdroits.all %}
-        {% include "rh/form-row.html" with label=ay value=ay.lien_parente %}
+        {% include "rh/form-row.html" with label=ay value=ay.lien_parente|default_if_none:"Lien de parenté inconnu" %}
     {% endfor %}
 </fieldset>
 
index 1b61199..e897205 100644 (file)
@@ -2,62 +2,69 @@
 {% load adminmedia rapports i18n change_list %}
 
 {% block extrastyle %}
-{{ block.super }}
-<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}/css/admin_custom.css">
+  {{ block.super }}
+  <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}/css/admin_custom.css">
 {% endblock %}
 
 {% block extrahead %}
-<script type="text/javascript" src="/admin/jsi18n"></script>
-<script type="text/javascript" src="{{ STATIC_URL }}/admin/js/core.js"></script>
-{{ block.super }}
+  <script type="text/javascript" src="/admin/jsi18n"></script>
+  <script type="text/javascript" src="{{ STATIC_URL }}/admin/js/core.js"></script>
+  {{ block.super }}
 {% endblock %}
 
-{% block nomrapport %}Rapport Contrats{% endblock %}
+{% block nomrapport %}
+  Rapport Contrats
+{% endblock %}
 
-{% block count_elements %}<h2>{{ count }} contrats pour {{ count_employe }} employés</h2>{% endblock %}
+{% block count_elements %}
+  <h2>{{ contrats.count }} contrats pour {{ count_employe }} employés</h2>
+{% endblock %}
 
 {% block contentrapport %}
-
 <div id="changelist-filter">
-<h2>{% trans 'Filter' %}</h2>
-{% filter_region_contrat %}
-{% filter_implantation_contrat %}
-{% filter_type_contrat %}
-{% filter_echeance_contrat %}
-{% filter_debut_contrat %}
-{% filter_a_venir %}
+  <h2>{% trans 'Filter' %}</h2>
+  
+  {% filter_region_contrat %}
+  {% filter_implantation_contrat %}
+  {% filter_type_contrat %}
+  {% filter_echeance_contrat %}
+  {% filter_debut_contrat %}
+  {% filter_a_venir %}
 </div>
 
-
 {% recherche_par_annees cl %}
 
 <table id="result_list" class="results">
-<thead>
-<tr>
-    {% table_header headers %}
-</tr>
-</thead>
-{% spaceless %}{% for contrat in contrats %}
-<tr class="{% cycle 'row1' 'row2' %}">
-    <td style="text-align:right"><a href="{% url employe_apercu contrat.dossier.employe.id %}">{{ contrat.dossier.employe.id }}</a></td>
-    <td><a href="{% url admin:rh_employe_change contrat.dossier.employe.id %}">
-            {{ contrat.dossier.employe.nom|upper }}
-            {{contrat.dossier.employe.prenom|title }}</a></td>
-    <td><a href="{% url admin:rh_poste_change contrat.dossier.poste.id %}">{{ contrat.dossier.poste.nom }}</a></td>
-    <td>{{ contrat.dossier.poste.implantation.region }}</td>
-    <td>{{ contrat.dossier.poste.implantation }}</td>
+  <thead>
+    <tr>{% table_header headers %}</tr>
+  </thead>
+  {% spaceless %}
+  {% for contrat in contrats %}
+  <tr class="{% cycle 'row1' 'row2' %}">
+    <td style="text-align:right">
+        {{ contrat.dossier.employe.id }}
+    </td>
+    <td>{{ contrat.dossier.employe.nom|upper }} {{ contrat.dossier.employe.prenom|title }}</td>
     <td>
-        {% if contrat.fichier %}
-        <a href="{{ contrat.fichier.url }}">{{ contrat.type_contrat.nom }}</a>
-        {% else %}
-            {{ contrat.type_contrat.nom }}
-        {% endif %}
+      <a href="{% url admin:rh_dossier_change contrat.dossier.id %}">
+        Dossier
+      </a> 
+      : {{ contrat.dossier.poste.nom }}
+    </td>
+    <td>
+    {% if contrat.fichier %}
+      <a href="{{ contrat.fichier.url }}">{{ contrat.type_contrat.nom }}</a>
+    {% else %}
+      {{ contrat.type_contrat.nom }}
+    {% endif %}
     </td>
-    <td>{{ contrat.dossier.get_statut_residence_display }}</td>
     <td>{{ contrat.date_debut }}</td>
     <td>{{ contrat.date_fin|default:'' }}</td>
-</tr>
-{% endfor %}{% endspaceless %}
+    <td>{{ contrat.dossier.get_statut_residence_display }}</td>
+    <td>{{ contrat.dossier.poste.implantation.region.nom }}</td>
+    <td>{{ contrat.dossier.poste.implantation.nom }}</td>
+  </tr>
+  {% endfor %}
+  {% endspaceless %}
 </table>
-
 {% endblock %}
index 43aae60..c1b9bbb 100644 (file)
@@ -28,7 +28,7 @@
   {% spaceless %}
     {% for e in employes %}
     <tr class="{% cycle 'row1' 'row2' %}">
-      <td>{{ e.id }}</td>
+      <td style="text-align:right">{{ e.id }}</td>
       <td>{{ e.nom|upper }} {{ e.prenom }}</td>
       <td>
         {% for d in e.rh_dossiers.all %}
index c1eec7d..d4bfdf5 100644 (file)
@@ -3,6 +3,7 @@
 from django.conf.urls.defaults import patterns, url
 
 urlpatterns = patterns('project.rh.views',
+    # rapports
     url(r'^admin/rh/rapports/employes_sans_contrats$',
         'rapports_employes_sans_contrat', name='rhr_employe_sans_contrat'),
     url(r'^admin/rh/rapports/contrats$', 'rapports_contrat',
index fed110b..eb9bde6 100644 (file)
@@ -75,6 +75,7 @@ def employe(request, id):
 @login_required
 @drh_or_admin_required
 def rapports_contrat(request):
+    # statut default = actif?
     if 'HTTP_REFERER' in request.META.keys():
         referer = request.META['HTTP_REFERER']
         referer = "/".join(referer.split('/')[3:])
@@ -84,48 +85,51 @@ def rapports_contrat(request):
             params.update({'statut': 'Actif'})
             request.GET = params
 
-    lookup_params = get_lookup_params(request)
-
     contrats = rh.Contrat.objects.select_related(
         'dossier', 'dossier__poste', 'dossier__poste__implantation',
         'type_contrat', 'dossier__employe'
     )
 
+    # filters et recherche temporelle
     cl = RechercheTemporelle(dict(request.GET.items()), rh.Contrat)
+    lookup_params = get_lookup_params(request)
     lookup_params = cl.purge_params(lookup_params)
     q_temporel = cl.get_q_temporel(contrats)
     q = Q(**lookup_params) & q_temporel
     contrats = contrats.filter(q).exclude(dossier__employe__supprime=1)
 
+    # tri
     if 'o' in request.GET:
         contrats = contrats.order_by(
             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
         )
 
+    # affichage
     employes = set([c.dossier.employe_id for c in contrats])
 
     headers = [
-        ("dossier__employe__id", u"# de l'employé"),
+        ("dossier__employe__id", u"#"),
         ("dossier__employe__nom", u"Employé"),
-        ("dossier__poste__nom", u"Poste"),
+        ("dossier", u"Dossier : Poste"),
+        ("type_contrat__nom", u"Contrat"),
+        ("date_debut", u"Début contrat"),
+        ("date_fin", u"Fin contrat"),
+        ("dossier__statut_residence", u"Statut"),
         ("dossier__poste__implantation__region", u"Région"),
         ("dossier__poste__implantation", u"Implantation"),
-        ("type_contrat__nom", u"Type de contrat"),
-        ("dossier__statut_residence", u"Statut de résidence"),
-        ("date_debut", u"Date début"),
-        ("date_fin", u"Date fin"),
     ]
-    h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
+    h = SortHeaders(
+        request, headers, order_field_type="ot", order_field="o",
+        not_sortable=('dossier',)
+    )
 
     c = {
         'cl': cl,
         'title': 'Rapport des contrats',
         'contrats': contrats,
-        'count': len(contrats),
         'count_employe': len(employes),
         'headers': list(h.headers()),
     }
-
     return render(request, 'rh/rapports/contrats.html', c)
 
 
@@ -260,7 +264,9 @@ def rapports_employes_sans_contrat(request):
         )
     
     # employés sans contrat
-    employes = rh.Employe.objects.filter(rh_dossiers__in=dossiers_sans_contrat).distinct()
+    employes = rh.Employe.objects.filter(
+            rh_dossiers__in=dossiers_sans_contrat
+        ).distinct()
     if 'o' in request.GET:
         employes = employes.order_by(
             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
@@ -268,11 +274,11 @@ def rapports_employes_sans_contrat(request):
 
     # affichage
     headers = [
-        ("id", u"# de l'employé"),
+        ("id", u"#"),
         ("nom", u"Employé"),
         ("dossier", u"Dossier : Poste"),
-        ("dossier_date_debut", u"Début occupation poste"),
-        ("dossier_date_fin", u"Fin occupation poste"),
+        ("dossier_date_debut", u"Début dossier"),
+        ("dossier_date_fin", u"Fin dossier"),
     ]
     h = SortHeaders(
         request, headers, order_field_type="ot", order_field="o",
diff --git a/project/utils.py b/project/utils.py
deleted file mode 100644 (file)
index a62d2f9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- encoding: utf-8 -*-
-
-import auf.django.references.models as ref
-
-
-
-
index 77dc37e..738730d 100644 (file)
@@ -44,8 +44,9 @@ class SavedQueryAdmin(admin.ModelAdmin):
 
     def save_model(self, request, obj, form, change):
         query_hash = request.GET.get("query_hash", "")
-        query_key = "qbe_query_%s" % query_hash
-        obj.query_data = request.session[query_key]
+        if query_hash:
+            query_key = "qbe_query_%s" % query_hash
+            obj.query_data = request.session[query_key]
 
         if not change:
             obj.user_created = request.user