Merge branch 'dev'
authorEric Mc Sween <eric.mcsween@auf.org>
Thu, 21 Jun 2012 17:58:54 +0000 (13:58 -0400)
committerEric Mc Sween <eric.mcsween@auf.org>
Thu, 21 Jun 2012 17:58:54 +0000 (13:58 -0400)
Conflicts:
project/rh/admin.py

22 files changed:
buildout.cfg
project/formats/__init__.py [new file with mode: 0644]
project/formats/fr/__init__.py [new file with mode: 0644]
project/formats/fr/formats.py [new file with mode: 0644]
project/menu.py
project/rh/admin.py
project/rh/forms.py
project/rh/managers.py
project/rh/masse_salariale.py [deleted file]
project/rh/migrations/0030_auto__chg_field_postecomparaison_implantation__chg_field_dossiercompar.py [new file with mode: 0644]
project/rh/models.py
project/rh/ods.py
project/rh/static/rh/FixedHeader.min.js [new file with mode: 0644]
project/rh/templates/rh/include/rapports_contrat.html [new file with mode: 0644]
project/rh/templates/rh/include/rapports_dossier_poste.html [new file with mode: 0644]
project/rh/templates/rh/rapports/base.html
project/rh/templates/rh/rapports/contrats.html
project/rh/templates/rh/rapports/employes_sans_contrat.html
project/rh/templates/rh/rapports/masse_salariale.html
project/rh/views.py
project/settings.py
versions.cfg

index 0213d45..076ff10 100644 (file)
@@ -13,8 +13,9 @@ find-links = http://pypi.auf.org/simple/auf.recipe.django/
     http://pypi.auf.org/simple/auf.django.admingroup/
     http://pypi.auf.org/simple/auf.django.permissions/
     http://pypi.auf.org/simple/auf.django.emploi/
-    http://pypi.auf.org/django-alphafilter/
     http://pypi.auf.org/simple/auf.django.references/
+    http://pypi.auf.org/simple/django-alphafilter/
+    http://pypi.auf.org/simple/odsgen/
 develop = src/qbe
     src/auf.django.metadata
 eggs =
@@ -40,7 +41,7 @@ eggs =
     auf.django.skin
     auf.django.workflow
     auf.recipe.django
-    odfpy
+    odsgen
     django-picklefield
     pygraphviz
     simplejson
diff --git a/project/formats/__init__.py b/project/formats/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/project/formats/fr/__init__.py b/project/formats/fr/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/project/formats/fr/formats.py b/project/formats/fr/formats.py
new file mode 100644 (file)
index 0000000..ecb6222
--- /dev/null
@@ -0,0 +1,7 @@
+THOUSAND_SEPARATOR = u'\xa0'
+NUMBER_GROUPING = 3
+DATE_FORMAT = 'd-m-Y'
+DATE_INPUT_FORMATS = (
+    '%d-%m-%Y', '%d/%m/%Y', '%d %m %Y',
+)
+SHORT_DATE_FORMAT = 'd-m-Y'
index c0bd428..f818fe4 100644 (file)
@@ -24,10 +24,10 @@ class CustomMenu(Menu):
         self.children += [
             items.MenuItem(_('Dashboard'), reverse('admin:index')),
             #items.Bookmarks(),
-            items.AppList(
-                _('Applications'),
-                exclude=('django.contrib.*', 'project.rh.models.EmployeProxy')
-            ),
+            #items.AppList(
+            #    _('Applications'),
+            #    exclude=('django.contrib.*', 'project.rh.models.EmployeProxy')
+            #),
             items.AppList(
                 _('Administration'),
                 models=('django.contrib.*',)
index e64ed9a..f815ade 100644 (file)
@@ -7,6 +7,7 @@ from django.contrib import admin
 from django.conf import settings
 from django.db.models import Q, Count
 from django.template.defaultfilters import date
+from django.utils.formats import date_format
 
 from ajax_select import make_ajax_form
 
@@ -18,13 +19,11 @@ import auf.django.references.models as ref
 from project.decorators import in_drh_or_admin
 from project.groups import grp_correspondants_rh
 from project.groups import get_employe_from_user
-
-import project.rh.models as rh
+from project.rh import models as rh
+from project.rh.change_list import ChangeList
 from project.rh.forms import ContratForm, AyantDroitForm, EmployeAdminForm, \
           AjaxSelect, DossierForm, ResponsableInlineForm
 
-from project.rh.change_list import ChangeList
-
 
 class BaseAdmin(admin.ModelAdmin):
 
@@ -330,12 +329,13 @@ class DossierAdmin(DateRangeMixin, AUFMetadataAdminMixin,
         '_id',
         '_apercu',
         '_nom',
-        '_poste',
         '_employe',
+        '_poste',
+        '_region',
+        '_implantation',
         '_date_debut',
         '_date_fin',
         '_date_modification',
-        'user_modification',
         '_dae',
     )
     list_display_links = ('_nom',)
@@ -396,14 +396,6 @@ class DossierAdmin(DateRangeMixin, AUFMetadataAdminMixin,
     _id.short_description = u"#"
     _id.admin_order_field = "id"
 
-    def _nom(self, obj):
-        return "%d : %s&nbsp;%s" % (
-                        obj.date_debut.year,
-                        obj.employe.nom.upper(),
-                        obj.employe.prenom)
-    _nom.allow_tags = True
-    _nom.short_description = u"Dossier"
-
     def _apercu(self, d):
         apercu_link = u"""<a title="Aperçu du dossier"
                              onclick="return showAddAnotherPopup(this);"
@@ -417,72 +409,88 @@ class DossierAdmin(DateRangeMixin, AUFMetadataAdminMixin,
     _apercu.allow_tags = True
     _apercu.short_description = u""
 
-    def _dae(self, d):
-        apercu_link = ""
-        dossiers_dae = d.dossiers_dae.all()
-        if len(dossiers_dae) > 0:
-            dossier_dae = dossiers_dae[0]
-            apercu_link = u"""<a title="Aperçu du dossier"
-                                 onclick="return showAddAnotherPopup(this);"
-                                 href='%s'>
-                                 <img src="%simg/loupe.png" />
-                                 </a>""" % \
-                    (reverse('embauche_consulter', args=(dossier_dae.id,)),
-                     settings.STATIC_URL,
-                     )
-        return apercu_link
-    _dae.allow_tags = True
-    _dae.short_description = u"DAE"
-
-    def _date_debut(self, obj):
-        return date(obj.date_debut)
-
-    _date_debut.short_description = u'Occupation début'
-    _date_debut.admin_order_field = 'date_debut'
+    def _nom(self, obj):
+        return "Dossier"
+    _nom.allow_tags = True
+    _nom.short_description = u"Dossier"
 
-    def _date_fin(self, obj):
-        return date(obj.date_fin)
-    _date_fin.short_description = u'Occupation fin'
-    _date_fin.admin_order_field = 'date_fin'
+    def _employe(self, obj):
+        employe = obj.employe
+        view_link = reverse('employe_apercu', args=(employe.id,))
+        edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
 
-    def _date_modification(self, obj):
-        return date(obj.date_modification) \
-                if obj.date_modification is not None else "(aucune)"
-    _date_modification.short_description = u'date modification'
-    _date_modification.admin_order_field = 'date_modification'
+        style = ""
+        view = u"""<a href="%s"
+                      title="Aperçu l'employé"
+                      onclick="return showAddAnotherPopup(this);">
+                      <img src="%simg/employe-apercu.png" />
+                    </a>""" % (view_link, settings.STATIC_URL,)
+        return u"""%s<a href='%s' style="%s;">%s</a>""" % \
+        (view, edit_link, style, employe)
+    _employe.allow_tags = True
+    _employe.short_description = u"Employé"
+    _employe.admin_order_field = "employe__nom"
 
     def _poste(self, dossier):
         link = u"""<a title="Aperçu du poste"
                       onclick="return showAddAnotherPopup(this);"
                       href='%s'><img src="%simg/poste-apercu.png" />
                     </a>
-                    <a href="%s" title="Modifier le poste">%s</a>""" % \
+                    <a href="%s" title="Modifier le poste">%s [%d]</a>""" % \
                 (reverse('poste_apercu', args=(dossier.poste.id,)),
                  settings.STATIC_URL,
                  reverse('admin:rh_poste_change', args=(dossier.poste.id,)),
-                 dossier.poste,
+                 dossier.poste.nom,
+                 dossier.poste.id,
                  )
         return link
     _poste.allow_tags = True
     _poste.short_description = u'Poste'
     _poste.admin_order_field = 'poste__nom'
 
-    def _employe(self, obj):
-        employe = obj.employe
-        view_link = reverse('employe_apercu', args=(employe.id,))
-        edit_link = reverse('admin:rh_employe_change', args=(employe.id,))
+    def _region(self, obj):
+        return obj.poste.implantation.region.code
+    _region.short_description = u"Région"
+    _region.admin_order_field = 'poste__implantation__region__code'
 
-        style = ""
-        view = u"""<a href="%s"
-                      title="Aperçu l'employé"
-                      onclick="return showAddAnotherPopup(this);">
-                      <img src="%simg/employe-apercu.png" />
-                    </a>""" % (view_link, settings.STATIC_URL,)
-        return u"""%s<a href='%s' style="%s;">%s</a>""" % \
-        (view, edit_link, style, employe)
-    _employe.allow_tags = True
-    _employe.short_description = u"Employé"
-    _employe.admin_order_field = "employe__nom"
+    def _implantation(self, obj):
+        return obj.poste.implantation.nom
+    _implantation.short_description = u"Implantation"
+    _implantation.admin_order_field = 'poste__implantation__nom'
+
+    def _date_debut(self, obj):
+        return date(obj.date_debut)
+
+    _date_debut.short_description = u'Début'
+    _date_debut.admin_order_field = 'date_debut'
+
+    def _date_fin(self, obj):
+        return date(obj.date_fin)
+    _date_fin.short_description = u'Fin'
+    _date_fin.admin_order_field = 'date_fin'
+
+    def _date_modification(self, obj):
+        return date(obj.date_modification) \
+                if obj.date_modification is not None else "(aucune)"
+    _date_modification.short_description = u'date modification'
+    _date_modification.admin_order_field = 'date_modification'
+
+    def _dae(self, d):
+        apercu_link = ""
+        dossiers_dae = d.dossiers_dae.all()
+        if len(dossiers_dae) > 0:
+            dossier_dae = dossiers_dae[0]
+            apercu_link = u"""<a title="Aperçu du dossier"
+                                 onclick="return showAddAnotherPopup(this);"
+                                 href='%s'>
+                                 <img src="%simg/loupe.png" />
+                                 </a>""" % \
+                    (reverse('embauche_consulter', args=(dossier_dae.id,)),
+                     settings.STATIC_URL,
+                     )
+        return apercu_link
+    _dae.allow_tags = True
+    _dae.short_description = u"DAE"
 
     def save_formset(self, request, form, formset, change):
         instances = formset.save(commit=False)
@@ -510,9 +518,10 @@ class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
             '_apercu',
             '_nom',
             '_dossiers_postes',
+            '_region',
+            '_implantation',
             'date_entree',
             '_date_modification',
-            'user_modification',
             )
     list_display_links = ('_nom',)
     list_filter = (
@@ -547,6 +556,11 @@ class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
             ),
         )
 
+    def _id(self, obj):
+        return obj.id
+    _id.short_description = u"#"
+    _id.admin_order_field = "id"
+
     def _apercu(self, obj):
         return u"""<a title="Aperçu de l'employé"
                       onclick="return showAddAnotherPopup(this);"
@@ -565,31 +579,45 @@ class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
     _nom.short_description = u"Employé"
     _nom.admin_order_field = "nom"
 
-    def _id(self, obj):
-        return obj.id
-    _id.short_description = u"#"
-    _id.admin_order_field = "id"
+    def _region(self, obj):
+        try:
+            d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
+            region = d.poste.implantation.region.code
+        except:
+            region = None
+        return region
+    _region.short_description = u"Région"
 
-    def _date_modification(self, obj):
-        return date(obj.date_modification) \
-                if obj.date_modification is not None else "(aucune)"
-    _date_modification.short_description = u'date modification'
-    _date_modification.admin_order_field = 'date_modification'
+    def _implantation(self, obj):
+        try:
+            d = rh.Dossier.objects.filter(employe=obj.id, principal=True)[0]
+            implantation = d.poste.implantation.nom
+        except:
+            implantation = None
+        return implantation
+    _implantation.short_description = u"Implantation"
 
     def _dossiers_postes(self, obj):
         l = []
         for d in obj.rh_dossiers.all().order_by('-date_debut'):
+            link_style = u''
+            list_style = u''
+            if d.date_fin is not None and d.date_fin < datetime.date.today():
+                link_style = u' style="color:#666;"'
+                list_style = u' style="color:grey;"'
+
             dossier = u"""<a title="Aperçu du dossier"
                              href="%s"
                              onclick="return showAddAnotherPopup(this);"
                              title="Aperçu du dossier">
                              <img src="%simg/dossier-apercu.png" />
                           </a>
-                          <a href="%s">Dossier</a>
+                          <a href="%s"%s>Dossier</a>
                           &nbsp;""" % \
                 (reverse('dossier_apercu', args=(d.id,)),
                  settings.STATIC_URL,
-                 reverse('admin:rh_dossier_change', args=(d.id,)))
+                 reverse('admin:rh_dossier_change', args=(d.id,)),
+                 link_style,)
 
             poste = u"""<a title="Aperçu du poste"
                            href="%s"
@@ -597,31 +625,29 @@ class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
                            title="Aperçu du poste">
                            <img src="%simg/poste-apercu.png" />
                         </a>
-                        <a href="%s">Poste</a>
+                        <a href="%s"%s>%s [%d]</a>
                         &nbsp;""" % \
                 (reverse('poste_apercu', args=(d.poste.id,)),
                  settings.STATIC_URL,
-                 reverse('admin:rh_poste_change', args=(d.poste.id,)))
-            link = u"""<li>%s %s - %s : [%s] %s</li>""" % \
-                (dossier, poste,
-                 d.date_debut.year,
-                 d.poste.id,
+                 reverse('admin:rh_poste_change', args=(d.poste.id,)),
+                 link_style,
                  d.poste.nom,
-                 )
+                 d.poste.id)
 
-            # Dossier terminé en gris non cliquable
-            if d.date_fin is not None and d.date_fin < datetime.date.today():
-                link = u"""<li style="color: grey">%s : [%s] %s</li>""" % \
-                    (d.date_debut.year,
-                     d.poste.id,
-                     d.poste.nom,
-                    )
+            link = u"""<li%s>%s %s</li>""" % \
+                (list_style, dossier, poste)
 
             l.append(link)
         return "<ul>%s</ul>" % "\n".join(l)
     _dossiers_postes.allow_tags = True
     _dossiers_postes.short_description = u"Dossiers et postes"
 
+    def _date_modification(self, obj):
+        return date(obj.date_modification) \
+                if obj.date_modification is not None else "(aucune)"
+    _date_modification.short_description = u'date modification'
+    _date_modification.admin_order_field = 'date_modification'
+
     def queryset(self, request):
         qs = super(EmployeAdmin, self).queryset(request)
         return qs.select_related(depth=1).order_by('nom')
@@ -637,6 +663,7 @@ class EmployeAdmin(DateRangeMixin, AUFMetadataAdminMixin,
 
 class EmployeProxyAdmin(EmployeAdmin):
     list_display = ('_id', '_apercu', '_nom', '_organigramme')
+    list_per_page = 500
     actions = None
 
     def __init__(self, *args, **kwargs):
@@ -664,10 +691,9 @@ class EmployeProxyAdmin(EmployeAdmin):
                         reverse('rho_employe_sans_niveau', args=(d.poste.id,)),
                         d.poste.id
                     )
-            link = u"""<li>%s - [%s] %s : %s</li>""" % (
-                    d.date_debut.year,
-                    d.poste.id,
+            link = u"""<li>%s [%s]:<br />%s</li>""" % (
                     d.poste.nom,
+                    d.poste.id,
                     organigramme
             )
             l.append(link)
@@ -737,13 +763,13 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
         '_apercu',
         '_nom',
         '_occupe_par',
+        '_region',
         '_implantation',
         '_service',
         '_responsable',
-        'date_debut',
-        'date_fin',
+        '_date_debut',
+        '_date_fin',
         '_date_modification',
-        'user_modification',
         '_dae',
         )
     list_filter = (
@@ -819,6 +845,11 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
             'service__isnull', 'vacant__exact', 'vacant__isnull',
         ) or super(PosteAdmin, self).lookup_allowed(key, value)
 
+    def _id(self, obj):
+        return "%s" % obj.id
+    _id.short_description = '#'
+    _id.admin_order_field = 'id'
+
     def _apercu(self, poste):
         view_link = u"""<a onclick="return showAddAnotherPopup(this);"
                            title="Aperçu du poste"
@@ -831,25 +862,48 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
     _apercu.allow_tags = True
     _apercu.short_description = ''
 
-    def _dae(self, poste):
-        apercu_link = ""
-        postes_dae = poste.postes_dae.all()
-        if len(postes_dae) > 0:
-            poste_dae = postes_dae[0]
-            apercu_link = \
-                    u'<a title="Aperçu du dossier" href="%s" ' \
-                    u'onclick="return showAddAnotherPopup(this);">' \
-                    u'<img src="%simg/loupe.png" /></a>' % (reverse(
-                        'poste_consulter', args=("dae-%s" % poste_dae.id,)
-                    ), settings.STATIC_URL)
-        return apercu_link
-    _dae.allow_tags = True
-    _dae.short_description = u"DAE"
+    def _nom(self, poste):
+        return """<a href="%s">%s</a>""" % \
+                (reverse('admin:rh_poste_change', args=(poste.id,)),
+                poste.nom)
+    _nom.allow_tags = True
+    _nom.short_description = u'Poste'
+    _nom.admin_order_field = 'nom'
 
-    def _id(self, obj):
-        return "%s" % obj.id
-    _id.short_description = '#'
-    _id.admin_order_field = 'id'
+    def _occupe_par(self, obj):
+        """Formatte la méthode Poste.occupe_par() pour l'admin"""
+        output = u"Vacant"
+        if obj.date_fin is not None and obj.date_fin < datetime.date.today():
+            return u"s/o"
+        employes = obj.occupe_par()
+        if employes:
+            l = []
+            for e in employes:
+                link = u"""<a href='%s'
+                              title='Aperçu de l\'employé'
+                              onclick='return showAddAnotherPopup(this)'>
+                              <img src='%simg/employe-apercu.png' />
+                            </a>
+                            <a href='%s'>%s</a>""" % \
+                     (reverse('employe_apercu', args=(e.id,)),
+                     settings.STATIC_URL,
+                     reverse('admin:rh_employe_change', args=(e.id,)),
+                     e)
+                l.append(link)
+            output = "\n<br />".join(l)
+        return output
+    _occupe_par.allow_tags = True
+    _occupe_par.short_description = "Occupé par"
+
+    def _region(self, poste):
+        return poste.implantation.region.code
+    _region.short_description = 'Région'
+    _region.admin_order_field = 'implantation__region__code'
+
+    def _implantation(self, poste):
+        return poste.implantation.nom
+    _implantation.short_description = 'Implantation'
+    _implantation.admin_order_field = 'implantation'
 
     def _service(self, obj):
         if obj.service.supprime:
@@ -866,12 +920,13 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
                                 <img src="%simg/poste-apercu.png"
                                      title="Aperçu du poste" />
                               </a>
-                              <a href="%s">%s</a>
+                              <a href="%s">%s [%d]</a>
                               <br />""" % \
                 (reverse('poste_apercu', args=(obj.responsable.id,)),
                 settings.STATIC_URL,
                 reverse('admin:rh_poste_change', args=(obj.responsable.id,)),
-                obj.responsable.nom)
+                obj.responsable.nom,
+                obj.responsable.id)
         except:
             responsable = ''
 
@@ -897,48 +952,35 @@ class PosteAdmin(DateRangeMixin, AUFMetadataAdminMixin,
     _responsable.short_description = 'Responsable'
     _responsable.allow_tags = True
 
-    def _implantation(self, poste):
-        return poste.implantation.nom
-    _implantation.short_description = 'Implantation'
-    _implantation.admin_order_field = 'implantation'
+    def _date_debut(self, obj):
+        return date_format(obj.date_debut)
+    _date_debut.short_description = u'Début'
+    _date_debut.admin_order_field = 'date_debut'
 
-    def _nom(self, poste):
-        return """<a href="%s">%s</a>""" % \
-                (reverse('admin:rh_poste_change', args=(poste.id,)),
-                poste.nom)
-    _nom.allow_tags = True
-    _nom.short_description = u'Poste'
-    _nom.admin_order_field = 'nom'
+    def _date_fin(self, obj):
+        return date_format(obj.date_fin)
+    _date_fin.short_description = u'Fin'
+    _date_fin.admin_order_field = 'date_fin'
 
     def _date_modification(self, obj):
         return date(obj.date_modification)
     _date_modification.short_description = u'date modification'
     _date_modification.admin_order_field = 'date_modification'
 
-    def _occupe_par(self, obj):
-        """Formatte la méthode Poste.occupe_par() pour l'admin"""
-        output = u"Vacant"
-        if obj.date_fin is not None and obj.date_fin < datetime.date.today():
-            return u"s/o"
-        employes = obj.occupe_par()
-        if employes:
-            l = []
-            for e in employes:
-                link = u"""<a href='%s'
-                              title='Aperçu de l\'employé'
-                              onclick='return showAddAnotherPopup(this)'>
-                              <img src='%simg/employe-apercu.png' />
-                            </a>
-                            <a href='%s'>%s</a>""" % \
-                     (reverse('employe_apercu', args=(e.id,)),
-                     settings.STATIC_URL,
-                     reverse('admin:rh_employe_change', args=(e.id,)),
-                     e)
-                l.append(link)
-            output = "\n<br />".join(l)
-        return output
-    _occupe_par.allow_tags = True
-    _occupe_par.short_description = "Occupé par"
+    def _dae(self, poste):
+        apercu_link = ""
+        postes_dae = poste.postes_dae.all()
+        if len(postes_dae) > 0:
+            poste_dae = postes_dae[0]
+            apercu_link = \
+                    u'<a title="Aperçu du dossier" href="%s" ' \
+                    u'onclick="return showAddAnotherPopup(this);">' \
+                    u'<img src="%simg/loupe.png" /></a>' % (reverse(
+                        'poste_consulter', args=("dae-%s" % poste_dae.id,)
+                    ), settings.STATIC_URL)
+        return apercu_link
+    _dae.allow_tags = True
+    _dae.short_description = u"DAE"
 
     def save_formset(self, request, form, formset, change):
         instances = formset.save(commit=False)
@@ -964,6 +1006,7 @@ class ResponsableImplantationAdmin(BaseAdmin):
     list_filter = ('region', 'statut', )
     list_display = ('_region', '_nom', 'statut', '_responsable', )
     list_display_links = ('_nom',)
+    list_per_page = 500
     readonly_fields = ('nom', )
     search_fields = (
             'nom',
index a1671a2..c2d1aff 100644 (file)
@@ -1,9 +1,15 @@
 # -*- encoding: utf-8 -*-
 
-from django import forms
+from datetime import date
+
 from ajax_select.fields import AutoCompleteSelectField
-from project.rh.models import Dossier, Contrat, AyantDroit, Employe, \
-        ResponsableImplantation
+from auf.django.references import models as ref
+from django import forms
+from django.db.models import Min
+
+from project.groups import get_employe_from_user
+from project.permissions import user_gere_obj_de_sa_region
+from project.rh import models as rh
 
 
 class AjaxSelect(object):
@@ -38,13 +44,13 @@ class FormDate(object):
 class DossierForm(forms.ModelForm, FormDate):
 
     class Model:
-        model = Dossier
+        model = rh.Dossier
 
 
 class ContratForm(forms.ModelForm, FormDate):
 
     class Model:
-        model = Contrat
+        model = rh.Contrat
 
 
 class AyantDroitForm(forms.ModelForm, AjaxSelect):
@@ -56,11 +62,10 @@ class AyantDroitForm(forms.ModelForm, AjaxSelect):
         self.fields['date_naissance'].widget = forms.widgets.DateInput()
 
     class Meta:
-        model = AyantDroit
+        model = rh.AyantDroit
 
 
 class EmployeAdminForm(forms.ModelForm, AjaxSelect):
-
     nationalite = AutoCompleteSelectField(
         'pays', help_text="Taper le nom ou le code du pays", required=False
     )
@@ -69,7 +74,7 @@ class EmployeAdminForm(forms.ModelForm, AjaxSelect):
     )
 
     class Meta:
-        model = Employe
+        model = rh.Employe
 
     def __init__(self, *args, **kwargs):
         super(EmployeAdminForm, self).__init__(*args, **kwargs)
@@ -77,8 +82,41 @@ class EmployeAdminForm(forms.ModelForm, AjaxSelect):
 
 
 class ResponsableInlineForm(forms.ModelForm):
-    employes_actifs = Employe.objects.actifs()
+    employes_actifs = rh.Employe.objects.actifs()
     employe = forms.ModelChoiceField(queryset=employes_actifs)
 
     class Meta:
-        model = ResponsableImplantation
+        model = rh.ResponsableImplantation
+
+
+class MasseSalarialeForm(forms.Form):
+    region = forms.ModelChoiceField(
+        label=u'Région', queryset=ref.Region.objects.all(), required=False
+    )
+    implantation = forms.ModelChoiceField(
+        label=u'Implantation', queryset=ref.Implantation.objects.all(),
+        required=False
+    )
+
+    def __init__(self, user, *args, **kwargs):
+        super(MasseSalarialeForm, self).__init__(*args, **kwargs)
+        min_date = rh.Remuneration.objects \
+                .aggregate(Min('date_debut'))['date_debut__min']
+        years = range(
+            date.today().year,
+            min_date.year if min_date else 1997,
+            -1
+        )
+        self.fields['annee'] = forms.TypedChoiceField(
+            label='Année', choices=zip(years, years), coerce=int,
+            required=False
+        )
+        if user_gere_obj_de_sa_region(user):
+            employe = get_employe_from_user(user)
+            self.fields['region'].queryset = ref.Region.objects.filter(
+                id=employe.implantation.region.id
+            )
+            self.fields['implantation'].queryset = \
+                    ref.Implantation.objects.filter(
+                        region=employe.implantation.region
+                    )
index 15ee63e..1459184 100644 (file)
@@ -1,23 +1,17 @@
 # -*- encoding: utf-8 -*-
 
-import datetime
 from datetime import date
 
 from django.db import models
 from django.db.models import Q
+from django.db.models.query import QuerySet
 
 from auf.django.metadata.managers import NoDeleteManager, NoDeleteQuerySet
 
 from project.groups import get_employe_from_user
-from project.groups import grp_administrateurs, \
-                     grp_directeurs_bureau, \
-                     grp_drh, \
-                     grp_drh2, \
-                     grp_accior, \
-                     grp_abf, \
-                     grp_haute_direction, \
-                     grp_service_utilisateurs, \
-                     grp_correspondants_rh
+from project.groups import \
+        grp_drh, grp_drh2, grp_accior, grp_abf, grp_haute_direction, \
+        grp_service_utilisateurs
 
 
 class SecurityManager(models.Manager):
@@ -28,8 +22,8 @@ class SecurityManager(models.Manager):
     def ma_region_ou_service(self, user):
         """
         Filtrage des postes en fonction du user connecté (region / service)
-        On s'intéresse aussi au groupe auquel appartient le user car certains groupes
-        peuvent tout voir.
+        On s'intéresse aussi au groupe auquel appartient le user car
+        certains groupes peuvent tout voir.
         """
         employe = get_employe_from_user(user)
 
@@ -37,11 +31,12 @@ class SecurityManager(models.Manager):
         # TRAITEMENT NORMAL
         ############################################
         # REGION
-        q = Q(**{ self.prefixe_implantation : employe.implantation.region })
+        q = Q(**{self.prefixe_implantation: employe.implantation.region})
 
         # SERVICE
-        if self.prefixe_service and grp_service_utilisateurs in user.groups.all():
-            q = q | Q(**{ self.prefixe_service : employe.service})
+        if self.prefixe_service \
+           and grp_service_utilisateurs in user.groups.all():
+            q = q | Q(**{self.prefixe_service: employe.service})
 
         liste = self.get_query_set().filter(q)
 
@@ -75,35 +70,55 @@ class SecurityManager(models.Manager):
         return liste
 
 
+class ActifsQuerySet(QuerySet):
+
+    def _actifs(self, debut_field, fin_field, 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(**{fin_field + '__gte': date_min}) |
+                Q(**{fin_field: None})
+            )
+        if date_max:
+            qs = qs.filter(
+                Q(**{debut_field + '__lte': date_max}) |
+                Q(**{debut_field: None})
+            )
+        return qs
+
+    def actifs(self, *args, **kwargs):
+        return self._actifs('date_debut', 'date_fin', *args, **kwargs)
+
+
+class PosteQuerySet(NoDeleteQuerySet, ActifsQuerySet):
+    pass
+
+
 class PosteManager(SecurityManager, NoDeleteManager):
-    """
-    Chargement de tous les objets FK existants sur chaque QuerySet.
-    """
     prefixe_service = "service"
     prefixe_implantation = "implantation__region"
 
-    def actifs(self):
-        q_actif = Q(date_fin__gt=datetime.datetime.now()) | Q(date_fin__isnull=True)
-        return super(PosteManager, self).get_query_set().filter(q_actif)
+    def get_query_set(self):
+        return PosteQuerySet(self.model).filter(supprime=False) \
+                .select_related('type_poste')
+
+    def actifs(self, *args, **kwargs):
+        return self.get_query_set().actifs(*args, **kwargs)
 
     def ma_region_ou_service(self, user):
         return super(PosteManager, self).ma_region_ou_service(user)
 
-    def get_query_set(self):
-        fkeys = (
-            #'id_rh',
-            #'responsable',
-            #'implantation',
-            #'implantation.bureau_rattachement',
-            'type_poste',
-            #'service',
-            #'classement_min',
-            #'classement_max',
-            #'valeur_point_min',
-            #'valeur_point_max',
-        )
-        return super(PosteManager, self).get_query_set() \
-                                        .select_related(*fkeys).all()
+
+class DossierQuerySet(NoDeleteQuerySet, ActifsQuerySet):
+    pass
 
 
 class DossierManager(SecurityManager, NoDeleteManager):
@@ -111,36 +126,40 @@ class DossierManager(SecurityManager, NoDeleteManager):
     prefixe_implantation = "poste__implantation__region"
 
     def get_query_set(self):
-        fkeys = (
-            'poste',
-            'employe',
-        )
-        return super(DossierManager, self).get_query_set() \
-                                        .select_related(*fkeys).all()
+        return DossierQuerySet(self.model) \
+                .filter(supprime=False) \
+                .select_related('poste', 'employe')
 
-    def ma_region_ou_service(self, user):
-        return super(DossierManager, self).ma_region_ou_service(user)
+    def actifs(self, *args, **kwargs):
+        return self.get_query_set().actifs(*args, **kwargs)
+
+
+class RemunerationQuerySet(NoDeleteQuerySet, ActifsQuerySet):
+
+    def actifs(self, *args, **kwargs):
+        return self \
+                ._actifs('date_debut', 'date_fin', *args, **kwargs) \
+                ._actifs(
+                    'dossier__date_debut', 'dossier__date_fin', *args, **kwargs
+                )
+
+
+class RemunerationManager(NoDeleteManager):
+
+    def get_query_set(self):
+        return RemunerationQuerySet(self.model).filter(supprime=False)
+
+    def actifs(self, *args, **kwargs):
+        return self.get_query_set().actifs(*args, **kwargs)
 
 
-class EmployeQuerySet(NoDeleteQuerySet):
+class EmployeQuerySet(NoDeleteQuerySet, ActifsQuerySet):
+
     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()
+        return self \
+                ._actifs('rh_dossiers__date_debut', 'rh_dossiers__date_fin') \
+                .distinct()
+
 
 class EmployeManager(NoDeleteManager):
     def get_query_set(self):
@@ -150,6 +169,7 @@ class EmployeManager(NoDeleteManager):
     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"
@@ -163,8 +183,10 @@ class DossierComparaisonManager(SecurityManager):
 class DeviseManager(NoDeleteManager):
     pass
 
+
 class ServiceManager(NoDeleteManager):
     pass
 
+
 class TypeRemunerationManager(NoDeleteManager):
     pass
diff --git a/project/rh/masse_salariale.py b/project/rh/masse_salariale.py
deleted file mode 100644 (file)
index cf91696..0000000
+++ /dev/null
@@ -1,740 +0,0 @@
-# -*- encoding: utf-8 -*-
-import csv
-import datetime
-import itertools
-import StringIO
-import time
-
-from django.db.models import Q, Count
-
-from auf.django.references import models as ref
-
-from project.rh import ods
-from project.rh import models as rh
-
-
-KEY_DATE_DEBUT = "debut"
-KEY_DATE_FIN = "fin"
-
-TYPE_REMUN_BSTG = (3,)
-TYPE_REMUN_MAD = (2,)
-TYPE_REMUN_BASE = (1,)
-TYPE_REMUN_FONC_RESP = (7, 8)
-TYPE_REMUN_EXPAT = (4,)
-TYPE_REMUN_LOGEMENT = (6,)
-TYPE_REMUN_SCOLARITE = (5,)
-TYPE_REMUN_TRANSP = (9,)
-TYPE_REMUN_13E = (18,)
-TYPE_PRIME_INTERIM = (19,)
-TYPE_REMUN_ALL_INDEMNITES = list(itertools.chain(*(
-        TYPE_REMUN_BSTG, TYPE_REMUN_BASE, TYPE_REMUN_FONC_RESP,
-        TYPE_REMUN_EXPAT, TYPE_REMUN_LOGEMENT, TYPE_REMUN_TRANSP,
-        TYPE_REMUN_13E, TYPE_PRIME_INTERIM, TYPE_REMUN_SCOLARITE)))
-TYPE_PRIME_INSTALLATION = (13,)
-TYPE_PRIME_DEMENAG = (15,)
-TYPE_PRIME_AVION = (14,)
-TYPE_PRIME_ALL = list(itertools.chain(
-            *(TYPE_PRIME_INSTALLATION, TYPE_PRIME_DEMENAG, TYPE_PRIME_AVION)
-        ))
-TYPE_CHARGE_PATRONALE = (17,)
-TYPE_CHARGE_ALL = list(itertools.chain(*(TYPE_CHARGE_PATRONALE,)))
-TYPE_NATURE_INDEMN = u"Indemnité"
-TYPE_NATURE_PAIEMENT = u"Accessoire"
-TYPE_NATURE_CHARGES = u"Charges"
-TYPE_NATURE_TRAITEMENT = u"Traitement"
-HEADER_SEPARATOR = ('sep', ods.Separator(), {'columnwidth': '0.4cm'})
-
-
-class MasseSalariale():
-    """ Rapport de la masse salariale. """
-
-    def __init__(self, date_debut, date_fin, custom_filter=None,
-            ne_pas_grouper=False):
-        """ date_debut: date de début pour les données temporelles
-        date_fin: idem
-        custom_filter: dictionnaire des paramètres à passer au queryset.
-        """
-        if not date_debut and not date_fin:
-            return
-
-        date_debut = datetime.date(
-                *time.strptime(date_debut, "%d-%m-%Y")[0:3]
-        )
-        date_fin = datetime.date(*time.strptime(date_fin, "%d-%m-%Y")[0:3])
-
-        rapport_date_delta = date_fin - date_debut
-        rapport_date_delta += datetime.timedelta(days=1)
-
-        self.annee = date_fin.year
-
-        self.devise_base = rh.Devise.objects.filter(code='EUR')[0]
-        self.taux_change = {}
-
-        q_range = self.build_qs("date_", date_debut, date_fin)
-        q_range_d = self.build_qs("dossier__date_", date_debut, date_fin)
-        remunerations = rh.Remuneration.objects.filter(q_range) \
-                .filter(q_range_d) \
-
-        if custom_filter:
-            remunerations = remunerations.filter(**custom_filter)
-        self.custom_filter = custom_filter
-
-        self.region = None
-        self.implantation = None
-        if 'dossier__poste__implantation__region' in custom_filter:
-            self.region = ref.Region.objects.get(
-                    id=custom_filter['dossier__poste__implantation__region']
-            )
-        if 'dossier__poste__implantation' in custom_filter:
-            self.implantation = ref.Implantation.objects.get(
-                    id=custom_filter['dossier__poste__implantation']
-            )
-
-        remunerations = remunerations.exclude(supprime=True) \
-                .select_related(
-                        "dossier", "dossier_employe", "dossier_poste", "type"
-                        )
-
-        custom_filter = {}
-        for k, v in self.custom_filter.items():
-            custom_filter[k.replace('dossier__', '')] = v
-        count_dossiers_by_employe = dict((d['id'], d['count']) for d in
-                rh.Dossier.objects.filter(q_range).values('id') \
-                .filter(**custom_filter) \
-                .annotate(count=Count('employe')))
-
-        contenu = {}
-
-        lineariser_dossiers = not ne_pas_grouper
-
-        for r in remunerations:
-            if lineariser_dossiers:
-                key = r.dossier.employe_id
-            else:
-                key = r.dossier_id
-
-            if key not in contenu:
-                contenu[key] = {
-                    'dossiers': set(),
-                    'remunerations': []
-                }
-            if lineariser_dossiers:
-                contenu[key]['remunerations'].append(r)
-            else:
-                if r.dossier_id == key:
-                    contenu[key]['remunerations'].append(r)
-            contenu[key]['dossiers'].add(r.dossier)
-
-        self.rapport = []
-
-        pays_list = {}
-        for pays in ref.Pays.objects.all():
-            pays_list[pays.id] = pays
-
-        valeurs_point_par_imp = \
-                dict(
-                    (v.implantation.id, v) for v in \
-                    rh.ValeurPoint.objects.filter(annee=self.annee).all()
-                )
-
-        self.headers = (
-                ('bureau', u"Bureau", {'columnwidth': '2cm'}),
-                ('pays', u"Pays", {'columnwidth': '3.5cm'}),
-                ('implantation', u"Implantation", {'columnwidth': '3cm'}),
-                ('valeur_point', u"Valeur du point",
-                    {'columnwidth': '2.3cm'}),
-                ('numero_employe', u"Numéro d'employé",
-                    {'columnwidth': '2.4cm'}),
-                ('nom', u"Nom", {'columnwidth': '5.4cm'}),
-                ('prenom', u"Prénom", {'columnwidth': '4.8cm'}),
-                ('type_de_poste', u"Type de poste", {'columnwidth': '2.7cm'}),
-                ('intitule_de_poste', u"Intitulé du poste",
-                    {'columnwidth': '7.25cm'}),
-                ('niveau', u"Niveau actel", {'columnwidth': '1.75cm'}),
-                ('point', u"Point", {'columnwidth': '1.75cm'}),
-                ('regime_de_travail', u"Régime de travail annuel",
-                    {'columnwidth': '2cm'}),
-                ('local_expatrie', u"Local / Expatrié",
-                    {'columnwidth': '2.25cm'}),
-                ('statut', u"Statut", {'columnwidth': '1.25cm'}),
-                ('date_fin_contrat', u"Date de fin de contrat",
-                    {'columnwidth': '2cm'}),
-                HEADER_SEPARATOR,
-                ('date_debut', u"Date de début", {'columnwidth': '1.92cm'}),
-                ('date_fin', u"Date de fin", {'columnwidth': '1.92cm'}),
-                ('nb_jours', u"Nombre de jours", {'columnwidth': '2.82cm'}),
-                HEADER_SEPARATOR,
-                ('devise', u"Devise", {'columnwidth': '1.46cm'}),
-                ('salaire_bstg_annuel', u"Salaire BSTG ANNUEL",
-                    {'columnwidth': '2.5cm'}),
-                ('salaire_bstg_euro', u"Salaire BSTG EUR",
-                    {'columnwidth': '2.5cm'}),
-                ('organisme_bstg', u"Organisme BSTG",
-                    {'columnwidth': '2.9cm'}),
-                HEADER_SEPARATOR,
-                ('salaire_theorique', u"Salaire théorique ANNUEL",
-                    {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
-                ('salaire_base_brut', u"Salaire de base brut",
-                    {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
-                ('salaire_complementaire', u"Salaire complémentaire",
-                    {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
-                HEADER_SEPARATOR,
-                ('indemnite_fonctions', u"Indemnités de fonctions",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_expat', u"Indemnités d'expatriation",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_scolarite', u"Indemnités de frais de scolarité",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_logement', u"Indemnités de logement",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_transp', u"Indemnités de transport",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_13e', u"Indemnités 13e mois",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('prime_interim', u"Prime d'intérim",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_autre', u"Autre indemnités",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                ('indemnite_sous_total', u"Sous-total d'indemnités",
-                    {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
-                HEADER_SEPARATOR,
-                ('prime_installation', u"Prime d'installation",
-                    {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
-                ('prime_demenagement', u"Prime de déménagement",
-                    {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
-                ('prime_avion', u"Prime d'avion",
-                    {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
-                ('prime_autre', u"Autre prime",
-                    {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
-                ('prime_sous_total', u"Total des primes",
-                    {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
-                HEADER_SEPARATOR,
-                ('charges_patronales', u"Charges patronales",
-                    {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
-                ('charges_autre', u"Autres charges patronales",
-                    {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
-                ('charges_sous_total', u"Sous-total des charges patronales",
-                    {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
-                HEADER_SEPARATOR,
-                ('sous_total_traitement_annee', u"Total traitements",
-                    {'background-color': '#ecab44'}),
-                ('sous_total_indemnite_annee', u"Total indemnités",
-                    {'background-color': '#fff840'}),
-                ('sous_total_accessoire_annee', u"Total accessoires",
-                    {'background-color': '#d7fb0f'}),
-                ('sous_total_charges_annee', u"Total charges",
-                    {'background-color': '#fb680f'}),
-                HEADER_SEPARATOR,
-                ('masse_salariale', u"Masse salariale ANNUELLE",
-                    {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
-                ('masse_salariale_annee', u"Masse salariale",
-                    {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
-                ('masse_salariale_annee_euro', u"Masse salariale %s EUR" % \
-                        self.annee, {
-                            'columnwidth': '2.5cm',
-                            'background-color': '#e6c6ed'
-                            }
-                ),
-        )
-
-        grand_total = 0.0
-        grand_total_euro = 0.0
-
-        if not lineariser_dossiers:
-            for dossier_id, count in count_dossiers_by_employe.items():
-                if dossier_id not in contenu or \
-                    len(contenu[dossier_id]['dossiers']) != count:
-                    not_in = []
-                    if dossier_id in contenu:
-                        for d in contenu[dossier_id]['dossiers']:
-                            not_in.append(d.id)
-                    custom_filter = {}
-                    for k, v in self.custom_filter.items():
-                        custom_filter[k.replace('dossier__', '')] = v
-
-                    employe_id = rh.Dossier.objects.values('employe').filter(
-                            id=dossier_id).all()[0]['employe']
-                    dossiers = rh.Dossier.objects.filter(q_range) \
-                            .filter(employe=employe_id) \
-                            .filter(**custom_filter) \
-                            .all()
-                    for d in dossiers:
-                        if d.id not in contenu:
-                            contenu[d.id] = {
-                                    'dossiers': set((d,)),
-                                    'remunerations': []
-                            }
-                        else:
-                            contenu[d.id]['dossiers'].add(d)
-
-        postes = rh.Poste.objects
-
-        custom_filter = {}
-        for k, v in self.custom_filter.items():
-            custom_filter[k.replace('dossier__poste__', '')] = v
-
-        if custom_filter:
-            postes = postes.filter(**custom_filter)
-
-        postes_vacants = [p for p in postes.filter(q_range).all()
-                if p.is_vacant()]
-        remuneration_base = rh.TypeRemuneration.objects.get(
-                id=TYPE_REMUN_BASE[0])
-        remuneration_indem = rh.TypeRemuneration(
-                nature_remuneration=TYPE_NATURE_INDEMN)
-        remuneration_charge = rh.TypeRemuneration(
-                nature_remuneration=TYPE_NATURE_CHARGES)
-        for p in postes_vacants:
-            d = rh.Dossier()
-            d.employe = rh.Employe()
-            d.statut = rh.Statut()
-            d.poste = p
-            d.classement = p.classement_max
-            d.point = p.valeur_point_max
-            if p.devise_max:
-                remunerations = [
-                    rh.Remuneration(
-                        montant=p.salaire_max, devise=p.devise_max,
-                        type=remuneration_base
-                    ),
-                    rh.Remuneration(
-                        montant=p.indemn_max, devise=p.devise_max,
-                        type=remuneration_indem
-                    ),
-                    rh.Remuneration(
-                        montant=p.autre_max, devise=p.devise_max,
-                        type=remuneration_charge
-                    )
-                ]
-            else:
-                remunerations = [
-                    rh.Remuneration(
-                        montant=0, devise=self.devise_base, type=type
-                    )
-                    for type in (
-                        remuneration_base, remuneration_indem,
-                        remuneration_charge
-                    )
-                ]
-            contenu['p_%s' % p.id] = {
-                'dossiers': set([d]),
-                'remunerations': remunerations
-            }
-
-        for item in contenu.values():
-            dossiers = item['dossiers']
-            remuns = item['remunerations']
-
-            if not dossiers:
-                continue
-            dossier = list(dossiers)[0]
-            for d in dossiers:
-                if d.principal:
-                    dossier = d
-
-            regime = (float(dossier.regime_travail) / 100)
-
-            if dossier.statut_residence == "expat":
-                statut = "E"
-            else:
-                statut = "L"
-
-            #on détermine la date du début et fin du dossier si année en cours
-            try:
-                d_date_fin = dossier.date_fin \
-                        if dossier.date_fin.year == date_fin.year else None
-            except AttributeError:
-                d_date_fin = None
-            try:
-                d_date_debut = dossier.date_debut \
-                    if dossier.date_debut.year == date_fin.year else None
-            except AttributeError:
-                d_date_debut = None
-
-            pays = \
-                pays_list[dossier.poste.implantation.adresse_physique_pays.id]
-
-            #on détermine si les rémunérations sont tous dans la même devise
-            try:
-                devise = remuns[0].devise
-            except IndexError:
-                devise = self.devise_base
-            meme_devise = True
-            for r in remuns[1:]:
-                if devise != r.devise:
-                    meme_devise = False
-
-            if not meme_devise:
-                for r in remuns:
-                    self.convertir(r)
-                devise = remuns[0].devise
-
-            bstg_dossier = None
-            for d in dossiers:
-                if d.organisme_bstg:
-                    bstg_dossier = d
-
-            bstg_remun = None
-            if bstg_dossier:
-                for r in bstg_dossier.rh_remunerations.all():
-                    if r.type.id in TYPE_REMUN_MAD:
-                        bstg_remun = rh.Remuneration(
-                                montant=float(r.montant),
-                                devise=r.devise
-                        )
-
-            if bstg_remun:
-                bstg_remun_euro = rh.Remuneration(
-                        montant=float(bstg_remun.montant),
-                        devise=bstg_remun.devise
-                )
-                self.convertir(bstg_remun_euro)
-
-            salaire_complement = 0.0
-            salaire_base = 0.0
-            indemnites = {
-                    'fonc_resp': 0.0,
-                    'expat': 0.0,
-                    'scolarite': 0.0,
-                    'logement': 0.0,
-                    'transp': 0.0,
-                    '13e': 0.0,
-                    'autre_recurr': 0.0,
-                    'interim': 0.0,
-            }
-
-            primes = {
-                    'installation': 0.0,
-                    'demenagement': 0.0,
-                    'avion': 0.0,
-                    'autre': 0.0,
-                }
-            charges = {
-                    'patronale': 0.0,
-                    'autre': 0.0,
-                    }
-
-            total_remun_annee = {
-                    'traitement': 0.0,
-                    'indemnite': 0.0,
-                    'accessoire': 0.0,
-                    'charges': 0.0,
-                    }
-
-            #Calcul du nombre de jours pour ce dossier.
-            dossier_date_delta = self.calculer_nombre_jours(
-                    dossier.date_debut, dossier.date_fin,
-                    date_debut, date_fin)
-
-            masse_salariale = 0.0
-            masse_salariale_annee = 0.0
-            for r in remuns:
-                montant = float(r.montant)
-                if r.date_fin is None and dossier.date_fin is not None:
-                    r.date_fin = min(date_fin, dossier.date_fin)
-                facteur = self.calculer_nombre_jours(
-                            r.date_debut, r.date_fin,
-                            date_debut, date_fin).days \
-                        / float(rapport_date_delta.days)
-
-                if r.type_id in TYPE_REMUN_BSTG:
-                    salaire_complement += montant * facteur
-
-                if r.type_id not in TYPE_REMUN_MAD:
-                    masse_salariale += montant
-                    masse_salariale_annee += montant * regime
-
-                if r.type_id in TYPE_REMUN_BASE:
-                    salaire_base += montant * facteur
-
-                if r.type_id in TYPE_REMUN_FONC_RESP:
-                    indemnites['fonc_resp'] += montant * facteur
-
-                if r.type_id in TYPE_REMUN_EXPAT:
-                    indemnites['expat'] += montant * facteur
-
-                if r.type_id in TYPE_REMUN_SCOLARITE:
-                    indemnites['scolarite'] += montant * facteur
-
-                if r.type_id in TYPE_REMUN_LOGEMENT:
-                    indemnites['logement'] += montant * facteur
-
-                if r.type_id in TYPE_REMUN_TRANSP:
-                    indemnites['transp'] += montant * facteur
-
-                if r.type_id in TYPE_REMUN_13E:
-                    indemnites['13e'] += montant * facteur
-
-                if r.type_id in TYPE_PRIME_INTERIM:
-                    indemnites['interim'] += montant * facteur
-
-                if r.type_id not in TYPE_REMUN_ALL_INDEMNITES \
-                        and r.type.nature_remuneration == TYPE_NATURE_INDEMN \
-                        and r.type_id != TYPE_REMUN_MAD:
-                    indemnites['autre_recurr'] += montant * facteur
-
-                if r.type_id in TYPE_PRIME_INSTALLATION:
-                    primes['installation'] += montant * facteur
-
-                if r.type_id in TYPE_PRIME_DEMENAG:
-                    primes['demenagement'] += montant * facteur
-
-                if r.type_id in TYPE_PRIME_AVION:
-                    primes['avion'] += montant * facteur
-
-                if r.type_id not in TYPE_PRIME_ALL and \
-                        r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
-                    primes['autre'] += montant * facteur
-
-                if r.type_id in TYPE_CHARGE_PATRONALE:
-                    charges['patronale'] += montant * facteur
-
-                if r.type_id not in TYPE_CHARGE_ALL and \
-                        r.type.nature_remuneration == TYPE_NATURE_CHARGES:
-                    charges['autre'] += montant * facteur
-
-                if r.type.nature_remuneration == TYPE_NATURE_INDEMN or \
-                        r.type.id in (7,):
-                    total_remun_annee['indemnite'] += montant * facteur
-
-                if r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
-                    total_remun_annee['accessoire'] += montant * facteur
-
-                if r.type.nature_remuneration == TYPE_NATURE_CHARGES:
-                    total_remun_annee['charges'] += montant * facteur
-
-                if (r.type.nature_remuneration == TYPE_NATURE_TRAITEMENT and
-                        r.type.id not in (TYPE_REMUN_MAD, 7)
-                        ) or r.type_id == TYPE_REMUN_BSTG:
-                    total_remun_annee['traitement'] += montant * facteur
-
-            total_indemnites = sum(indemnites.values())
-
-            masse_salariale_euro = rh.Remuneration(
-                    montant=masse_salariale_annee, devise=devise)
-            self.convertir(masse_salariale_euro)
-
-            if dossier.classement and dossier.classement.coefficient:
-                coefficient = dossier.classement.coefficient
-            else:
-                coefficient = ""
-
-            #todo valeur du point si pas présent
-            valeur_point = valeurs_point_par_imp.get(
-                    dossier.poste.implantation_id
-                )
-            if valeur_point:
-                valeur_point_label = "%s %s" % (valeur_point.valeur,
-                        valeur_point.devise.code)
-            else:
-                valeur_point_label = ""
-
-            salaire_theorique = (
-                    round(valeur_point.valeur * int(coefficient) * regime, 2) \
-                    if valeur_point and coefficient and regime else None)
-
-            item_rapport = {
-                    'bureau': dossier.poste.implantation.region.code,
-                    'pays': unicode(pays),
-                    'implantation': dossier.poste.implantation.nom_court,
-                    'type_implantation': dossier.poste.implantation.type,
-                    #'imputation': None,
-                    'valeur_point': valeur_point_label,
-                    'numero_employe': dossier.employe_id,
-                    'nom': dossier.employe.nom.upper(),
-                    'prenom': dossier.employe.prenom,
-                    'type_de_poste': dossier.poste.type_poste.nom,
-                    'intitule_de_poste': dossier.poste.nom_feminin
-                            if dossier.employe.genre == "F" else
-                            dossier.poste.nom,
-                    'niveau': dossier.classement,
-                    'point': coefficient,
-                    'regime_de_travail': "%s %%" % int(regime * 100),
-                    'local_expatrie': statut,
-                    'statut': dossier.statut.code,
-                    'date_fin_contrat': dossier.date_fin or "",
-                    'date_debut': d_date_debut or "",
-                    'date_fin': d_date_fin or "",
-                    'nb_jours': dossier_date_delta.days,
-                    'devise': devise.code,
-                    'salaire_bstg_annuel': bstg_remun.montant \
-                            if bstg_remun else "",
-                    'salaire_bstg_euro': bstg_remun_euro.montant \
-                            if bstg_remun else "",
-                    'organisme_bstg': dossier.organisme_bstg or "",
-                    'salaire_theorique': salaire_theorique,
-                    'salaire_base_brut': \
-                            salaire_base * regime,
-                    'salaire_complementaire': \
-                            salaire_complement * regime,
-                    #'salaire_total': None
-                    'indemnite_fonctions': indemnites['fonc_resp'] * \
-                            regime,
-                    'indemnite_expat': indemnites['expat'] * regime,
-                    'indemnite_scolarite': indemnites['scolarite'] * \
-                            regime,
-                    'indemnite_logement': indemnites['logement'] * \
-                            regime,
-                    'indemnite_transp': indemnites['transp'] * regime,
-                    'indemnite_13e': indemnites['13e'] * regime,
-                    'prime_interim': indemnites['interim'] * regime,
-                    'indemnite_autre': indemnites['autre_recurr'] * \
-                            regime,
-                    'indemnite_sous_total': total_indemnites * regime,
-                    'total_brut': (
-                                total_indemnites + salaire_base +
-                                salaire_complement
-                            ) * regime,
-                    'prime_installation': primes['installation'] * regime,
-                    'prime_demenagement': primes['demenagement'] * regime,
-                    'prime_avion': primes['avion'] * regime,
-                    'prime_autre': primes['autre'] * regime,
-                    'prime_sous_total': sum(primes.values()) * regime,
-                    'charges_patronales': charges['patronale'] * regime,
-                    'charges_autre': charges['autre'] * regime,
-                    'charges_sous_total': sum(charges.values()) * regime,
-                    'sous_total_traitement_annee': \
-                            total_remun_annee['traitement'] * regime,
-                    'sous_total_indemnite_annee': \
-                            total_remun_annee['indemnite'] * regime,
-                    'sous_total_accessoire_annee': \
-                            total_remun_annee['accessoire'] * regime,
-                    'sous_total_charges_annee': \
-                            total_remun_annee['charges'] * regime,
-                    'masse_salariale': masse_salariale * regime,
-                    'masse_salariale_annee': masse_salariale_annee * regime,
-                    'masse_salariale_annee_euro': \
-                            masse_salariale_euro.montant * regime,
-                    'sep': ods.Separator(),
-            }
-
-            grand_total_euro += round(masse_salariale_euro.montant * regime
-                * (
-                        dossier_date_delta.days / rapport_date_delta.days
-                ), 2)
-
-            self.rapport.append(item_rapport)
-
-        self.rapport = sorted(self.rapport, key=lambda r: r['nom'])
-
-        self.grand_totaux = (grand_total, grand_total_euro)
-
-    def calculer_nombre_jours(self, debut, fin, debut_limite, fin_limite):
-        """Calcul le nombre de jours entre fin et debut, sans dépasser
-        les limites. Si debut ou fin set null, on prend debut_limite/fin_limi
-        """
-
-        if not debut:
-            debut = debut_limite
-        if not fin:
-            fin = fin_limite
-
-        if debut < debut_limite:
-            debut = debut_limite
-        if fin > fin_limite:
-            fin = fin_limite
-
-        fin += datetime.timedelta(days=1)
-        return fin - debut
-
-    def build_qs(self, prefix, date_debut, date_fin):
-        date_debut_null = \
-                Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True})
-        date_fin_null = \
-                Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True})
-        date_debut_superieure_ou_egale_a_borne_gauche = \
-                Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut})
-        date_debut_inferieure_ou_egale_a_borne_gauche = \
-                Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut})
-        date_fin_superieure_ou_egale_a_borne_gauche = \
-                Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut})
-        date_fin_inferieure_ou_egale_a_borne_droite = \
-                Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin})
-        date_debut_inferieure_ou_egale_a_borne_droite = \
-                Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin})
-        date_fin_superieure_ou_egale_a_borne_droite = \
-                Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin})
-
-        q_range = \
-            (
-                    date_debut_null & date_fin_null
-            ) | (
-                    date_fin_superieure_ou_egale_a_borne_gauche &
-                    date_fin_inferieure_ou_egale_a_borne_droite &
-                    (
-                        date_debut_inferieure_ou_egale_a_borne_gauche |
-                        date_debut_null
-                    )
-            ) | (
-                    date_debut_superieure_ou_egale_a_borne_gauche &
-                    date_debut_inferieure_ou_egale_a_borne_droite &
-                    (
-                        date_fin_superieure_ou_egale_a_borne_droite |
-                        date_fin_null
-                    )
-            ) | (
-                    date_debut_inferieure_ou_egale_a_borne_gauche &
-                    date_fin_superieure_ou_egale_a_borne_droite
-            ) | (
-                    date_debut_null &
-                    date_fin_superieure_ou_egale_a_borne_droite
-            ) | (
-                    date_debut_inferieure_ou_egale_a_borne_gauche &
-                    date_fin_null
-            )
-        return q_range
-
-    def convertir(self, remuneration):
-        if remuneration.devise != self.devise_base:
-            try:
-                remuneration.montant = float(remuneration.montant) * \
-                    self.trouver_taux(remuneration.devise).taux
-                remuneration.devise = self.devise_base
-            except AttributeError:
-                pass
-
-    def trouver_taux(self, devise):
-        if devise.code not in self.taux_change:
-            try:
-                t = rh.TauxChange.objects.filter(
-                        devise=devise, annee=self.annee
-                )[0]
-            except IndexError:
-                return None
-            self.taux_change[devise.code] = t
-        return self.taux_change[devise.code]
-
-    def csv(self):
-        self.csv_handle = StringIO.StringIO()
-        csv_writer = csv.writer(self.csv_handle, delimiter=",",
-                doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL,
-        )
-        header = [v[0] for v in self.rapport[0]]
-        csv_writer.writerow(header)
-        for row in self.rapport:
-            values = [v[1] for v in row]
-            csv_writer.writerow(
-                    [unicode(r).encode('utf-8') for r in values]
-            )
-
-    def ods(self):
-        self.doc = ods.OpenDocumentSpreadsheet()
-
-        nom = u"Masse salariale %s" % self.annee
-        if self.region:
-            nom += u" %s" % self.region
-        elif self.implantation:
-            nom += u" %s" % self.implantation
-
-        table = self.doc.add_table(name=nom)
-
-        for h in self.headers:
-            if len(h) > 2:
-                table.add_column(**h[2])
-
-        table.add_row([h[1] for h in self.headers], rowheight='2cm')
-
-        for r in self.rapport:
-            table.add_row([r[h[0]] for h in self.headers])
-
-        #a.doc.write('hello_world.ods')
diff --git a/project/rh/migrations/0030_auto__chg_field_postecomparaison_implantation__chg_field_dossiercompar.py b/project/rh/migrations/0030_auto__chg_field_postecomparaison_implantation__chg_field_dossiercompar.py
new file mode 100644 (file)
index 0000000..42ae3d6
--- /dev/null
@@ -0,0 +1,661 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+    
+    def forwards(self, orm):
+        
+        # Changing field 'PosteComparaison.implantation'
+        db.alter_column('rh_postecomparaison', 'implantation_id', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, null=True, to=orm['references.Implantation']))
+
+        # Adding index on 'Contrat', fields ['date_fin']
+        db.create_index('rh_contrat', ['date_fin'])
+
+        # Adding index on 'Contrat', fields ['date_debut']
+        db.create_index('rh_contrat', ['date_debut'])
+
+        # Changing field 'DossierComparaison.implantation'
+        db.alter_column('rh_dossiercomparaison', 'implantation_id', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, null=True, to=orm['references.Implantation']))
+
+        # Adding index on 'Poste', fields ['date_fin']
+        db.create_index('rh_poste', ['date_fin'])
+
+        # Adding index on 'Poste', fields ['date_debut']
+        db.create_index('rh_poste', ['date_debut'])
+
+        # Changing field 'Poste.implantation'
+        db.alter_column('rh_poste', 'implantation', self.gf('django.db.models.fields.related.ForeignKey')(db_column='implantation', to=orm['references.Implantation']))
+
+        # Changing field 'Employe.courriel_perso'
+        db.alter_column('rh_employe', 'courriel_perso', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True))
+
+        # Changing field 'Employe.pays'
+        db.alter_column('rh_employe', 'pays', self.gf('django.db.models.fields.related.ForeignKey')(db_column='pays', to_field='code', to=orm['references.Pays'], blank=True, null=True))
+
+        # Changing field 'Employe.nationalite'
+        db.alter_column('rh_employe', 'nationalite', self.gf('django.db.models.fields.related.ForeignKey')(db_column='nationalite', to_field='code', to=orm['references.Pays'], blank=True, null=True))
+
+        # Changing field 'ResponsableImplantation.implantation'
+        db.alter_column('rh_responsableimplantation', 'implantation', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, db_column='implantation', to=orm['references.Implantation']))
+
+        # Changing field 'ValeurPoint.implantation'
+        db.alter_column('rh_valeurpoint', 'implantation', self.gf('django.db.models.fields.related.ForeignKey')(db_column='implantation', to=orm['references.Implantation']))
+
+        # Adding unique constraint on 'ValeurPoint', fields ['implantation', 'annee']
+        db.create_unique('rh_valeurpoint', ['implantation', 'annee'])
+
+        # Changing field 'AyantDroit.nationalite'
+        db.alter_column('rh_ayantdroit', 'nationalite', self.gf('django.db.models.fields.related.ForeignKey')(db_column='nationalite', to_field='code', to=orm['references.Pays'], blank=True, null=True))
+
+        # Adding index on 'Dossier', fields ['date_fin']
+        db.create_index('rh_dossier', ['date_fin'])
+
+        # Adding index on 'Dossier', fields ['date_debut']
+        db.create_index('rh_dossier', ['date_debut'])
+
+        # Adding unique constraint on 'TauxChange', fields ['devise', 'annee']
+        db.create_unique('rh_tauxchange', ['devise', 'annee'])
+
+        # Changing field 'OrganismeBstg.pays'
+        db.alter_column('rh_organismebstg', 'pays', self.gf('django.db.models.fields.related.ForeignKey')(db_column='pays', to_field='code', to=orm['references.Pays'], blank=True, null=True))
+
+        # Adding index on 'Remuneration', fields ['date_fin']
+        db.create_index('rh_remuneration', ['date_fin'])
+
+        # Adding index on 'Remuneration', fields ['date_debut']
+        db.create_index('rh_remuneration', ['date_debut'])
+    
+    
+    def backwards(self, orm):
+        
+        # Changing field 'PosteComparaison.implantation'
+        db.alter_column('rh_postecomparaison', 'implantation_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['managedref.Implantation'], blank=True))
+
+        # Removing index on 'Contrat', fields ['date_fin']
+        db.delete_index('rh_contrat', ['date_fin'])
+
+        # Removing index on 'Contrat', fields ['date_debut']
+        db.delete_index('rh_contrat', ['date_debut'])
+
+        # Changing field 'DossierComparaison.implantation'
+        db.alter_column('rh_dossiercomparaison', 'implantation_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['managedref.Implantation'], blank=True))
+
+        # Removing index on 'Poste', fields ['date_fin']
+        db.delete_index('rh_poste', ['date_fin'])
+
+        # Removing index on 'Poste', fields ['date_debut']
+        db.delete_index('rh_poste', ['date_debut'])
+
+        # Changing field 'Poste.implantation'
+        db.alter_column('rh_poste', 'implantation', self.gf('django.db.models.fields.related.ForeignKey')(db_column='implantation', to=orm['managedref.Implantation']))
+
+        # Changing field 'Employe.courriel_perso'
+        db.alter_column('rh_employe', 'courriel_perso', self.gf('django.db.models.fields.EmailField')(max_length=75))
+
+        # Changing field 'Employe.pays'
+        db.alter_column('rh_employe', 'pays', self.gf('django.db.models.fields.related.ForeignKey')(db_column='pays', to_field='code', to=orm['managedref.Pays'], blank=True, null=True))
+
+        # Changing field 'Employe.nationalite'
+        db.alter_column('rh_employe', 'nationalite', self.gf('django.db.models.fields.related.ForeignKey')(db_column='nationalite', to_field='code', to=orm['managedref.Pays'], blank=True, null=True))
+
+        # Changing field 'ResponsableImplantation.implantation'
+        db.alter_column('rh_responsableimplantation', 'implantation', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, db_column='implantation', to=orm['managedref.Implantation']))
+
+        # Changing field 'ValeurPoint.implantation'
+        db.alter_column('rh_valeurpoint', 'implantation', self.gf('django.db.models.fields.related.ForeignKey')(db_column='implantation', to=orm['managedref.Implantation']))
+
+        # Removing unique constraint on 'ValeurPoint', fields ['implantation', 'annee']
+        db.delete_unique('rh_valeurpoint', ['implantation', 'annee'])
+
+        # Changing field 'AyantDroit.nationalite'
+        db.alter_column('rh_ayantdroit', 'nationalite', self.gf('django.db.models.fields.related.ForeignKey')(db_column='nationalite', to_field='code', to=orm['managedref.Pays'], blank=True, null=True))
+
+        # Removing index on 'Dossier', fields ['date_fin']
+        db.delete_index('rh_dossier', ['date_fin'])
+
+        # Removing index on 'Dossier', fields ['date_debut']
+        db.delete_index('rh_dossier', ['date_debut'])
+
+        # Removing unique constraint on 'TauxChange', fields ['devise', 'annee']
+        db.delete_unique('rh_tauxchange', ['devise', 'annee'])
+
+        # Changing field 'OrganismeBstg.pays'
+        db.alter_column('rh_organismebstg', 'pays', self.gf('django.db.models.fields.related.ForeignKey')(db_column='pays', to_field='code', to=orm['managedref.Pays'], blank=True, null=True))
+
+        # Removing index on 'Remuneration', fields ['date_fin']
+        db.delete_index('rh_remuneration', ['date_fin'])
+
+        # Removing index on 'Remuneration', fields ['date_debut']
+        db.delete_index('rh_remuneration', ['date_debut'])
+    
+    
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'references.bureau': {
+            'Meta': {'object_name': 'Bureau', 'db_table': "u'ref_bureau'", 'managed': 'False'},
+            'actif': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Implantation']", 'db_column': "'implantation'"}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_court': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'nom_long': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'region': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Region']", 'db_column': "'region'"})
+        },
+        'references.implantation': {
+            'Meta': {'object_name': 'Implantation', 'db_table': "u'ref_implantation'", 'managed': 'False'},
+            'actif': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'adresse_physique_bureau': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'adresse_physique_code_postal': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'adresse_physique_code_postal_avant_ville': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'adresse_physique_no': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'adresse_physique_pays': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'impl_adresse_physique'", 'to_field': "'code'", 'db_column': "'adresse_physique_pays'", 'to': "orm['references.Pays']"}),
+            'adresse_physique_precision': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'adresse_physique_precision_avant': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'adresse_physique_region': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'adresse_physique_rue': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'adresse_physique_ville': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'adresse_postale_boite_postale': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_bureau': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_code_postal': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_code_postal_avant_ville': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'adresse_postale_no': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_pays': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'impl_adresse_postale'", 'to_field': "'code'", 'db_column': "'adresse_postale_pays'", 'to': "orm['references.Pays']"}),
+            'adresse_postale_precision': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_precision_avant': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_region': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_rue': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'adresse_postale_ville': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'bureau_rattachement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Implantation']", 'db_column': "'bureau_rattachement'"}),
+            'code_meteo': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'commentaire': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'courriel': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'courriel_interne': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'date_extension': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'date_fermeture': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'date_inauguration': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'date_ouverture': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'fax': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'fax_interne': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'fuseau_horaire': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'hebergement_convention': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'hebergement_convention_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'hebergement_etablissement': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modif_date': ('django.db.models.fields.DateField', [], {}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_court': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'nom_long': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'region': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Region']", 'db_column': "'region'"}),
+            'remarque': ('django.db.models.fields.TextField', [], {}),
+            'responsable_implantation': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'statut': ('django.db.models.fields.IntegerField', [], {}),
+            'telephone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'telephone_interne': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'})
+        },
+        'references.pays': {
+            'Meta': {'object_name': 'Pays', 'db_table': "u'ref_pays'", 'managed': 'False'},
+            'actif': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2'}),
+            'code_bureau': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Bureau']", 'to_field': "'code'", 'null': 'True', 'db_column': "'code_bureau'", 'blank': 'True'}),
+            'code_iso3': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'}),
+            'developpement': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'monnaie': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nord_sud': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'region': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['references.Region']", 'db_column': "'region'"})
+        },
+        'references.region': {
+            'Meta': {'object_name': 'Region', 'db_table': "u'ref_region'", 'managed': 'False'},
+            'actif': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation_bureau': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'gere_region'", 'null': 'True', 'db_column': "'implantation_bureau'", 'to': "orm['references.Implantation']"}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
+        },
+        'rh.ayantdroit': {
+            'Meta': {'object_name': 'AyantDroit'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_naissance': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'employe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ayantdroits'", 'db_column': "'employe'", 'to': "orm['rh.Employe']"}),
+            'genre': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lien_parente': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+            'nationalite': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ayantdroits_nationalite'", 'db_column': "'nationalite'", 'to_field': "'code'", 'to': "orm['references.Pays']", 'blank': 'True', 'null': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_affichage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'prenom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.ayantdroitcommentaire': {
+            'Meta': {'object_name': 'AyantDroitCommentaire'},
+            'ayant_droit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'ayant_droit'", 'to': "orm['rh.AyantDroit']"}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'owner'", 'to': "orm['auth.User']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'texte': ('django.db.models.fields.TextField', [], {}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.categorieemploi': {
+            'Meta': {'object_name': 'CategorieEmploi'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.classement': {
+            'Meta': {'object_name': 'Classement'},
+            'coefficient': ('django.db.models.fields.FloatField', [], {'default': '0', 'null': 'True'}),
+            'commentaire': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'degre': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
+            'echelon': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.contrat': {
+            'Meta': {'object_name': 'Contrat'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_debut': ('django.db.models.fields.DateField', [], {'db_index': 'True'}),
+            'date_fin': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'dossier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_contrats'", 'db_column': "'dossier'", 'to': "orm['rh.Dossier']"}),
+            'fichier': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type_contrat': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'type_contrat'", 'to': "orm['rh.TypeContrat']"}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.devise': {
+            'Meta': {'object_name': 'Devise'},
+            'archive': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.dossier': {
+            'Meta': {'object_name': 'Dossier'},
+            'classement': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'classement'", 'to': "orm['rh.Classement']"}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_debut': ('django.db.models.fields.DateField', [], {'db_index': 'True'}),
+            'date_fin': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'employe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_dossiers'", 'db_column': "'employe'", 'to': "orm['rh.Employe']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'organisme_bstg': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'organisme_bstg'", 'to': "orm['rh.OrganismeBstg']"}),
+            'poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_dossiers'", 'db_column': "'poste'", 'to': "orm['rh.Poste']"}),
+            'principal': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'regime_travail': ('django.db.models.fields.DecimalField', [], {'default': "'100.00'", 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'regime_travail_nb_heure_semaine': ('django.db.models.fields.DecimalField', [], {'default': "'35.00'", 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'remplacement': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'remplacement_de': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['rh.Dossier']"}),
+            'statut': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': "orm['rh.Statut']"}),
+            'statut_residence': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '10', 'null': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.dossiercommentaire': {
+            'Meta': {'object_name': 'DossierCommentaire'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'dossier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'commentaires'", 'db_column': "'dossier'", 'to': "orm['rh.Dossier']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'owner'", 'to': "orm['auth.User']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'texte': ('django.db.models.fields.TextField', [], {}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.dossiercomparaison': {
+            'Meta': {'object_name': 'DossierComparaison'},
+            'devise': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['rh.Devise']"}),
+            'dossier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_comparaisons'", 'to': "orm['rh.Dossier']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['references.Implantation']"}),
+            'montant': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'personne': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'poste': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        'rh.dossierpiece': {
+            'Meta': {'object_name': 'DossierPiece'},
+            'dossier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_dossierpieces'", 'db_column': "'dossier'", 'to': "orm['rh.Dossier']"}),
+            'fichier': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'rh.employe': {
+            'Meta': {'object_name': 'Employe'},
+            'adresse': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'code_postal': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'courriel_perso': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_entree': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_naissance': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'genre': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nationalite': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'employes_nationalite'", 'db_column': "'nationalite'", 'to_field': "'code'", 'to': "orm['references.Pays']", 'blank': 'True', 'null': 'True'}),
+            'nb_postes': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_affichage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'pays': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'employes'", 'db_column': "'pays'", 'to_field': "'code'", 'to': "orm['references.Pays']", 'blank': 'True', 'null': 'True'}),
+            'prenom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'province': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'situation_famille': ('django.db.models.fields.CharField', [], {'max_length': '1', 'null': 'True', 'blank': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'tel_cellulaire': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'tel_domicile': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"}),
+            'ville': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        'rh.employecommentaire': {
+            'Meta': {'object_name': 'EmployeCommentaire'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'employe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'employe'", 'to': "orm['rh.Employe']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'owner'", 'to': "orm['auth.User']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'texte': ('django.db.models.fields.TextField', [], {}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.employepiece': {
+            'Meta': {'object_name': 'EmployePiece'},
+            'employe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pieces'", 'db_column': "'employe'", 'to': "orm['rh.Employe']"}),
+            'fichier': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'rh.familleprofessionnelle': {
+            'Meta': {'object_name': 'FamilleProfessionnelle'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'rh.organismebstg': {
+            'Meta': {'object_name': 'OrganismeBstg'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'pays': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'organismes_bstg'", 'db_column': "'pays'", 'to_field': "'code'", 'to': "orm['references.Pays']", 'blank': 'True', 'null': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.poste': {
+            'Meta': {'object_name': 'Poste'},
+            'appel': ('django.db.models.fields.CharField', [], {'default': "'interne'", 'max_length': '10', 'null': 'True'}),
+            'autre_max': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'autre_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'classement_max': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'classement_max'", 'to': "orm['rh.Classement']"}),
+            'classement_min': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'classement_min'", 'to': "orm['rh.Classement']"}),
+            'comp_autre_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_autre_min': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_fonctionpub_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_fonctionpub_min': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_locale_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_locale_min': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_ong_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_ong_min': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_universite_max': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'comp_universite_min': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_debut': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_fin': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'devise_comparaison': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'devise_comparaison'", 'to': "orm['rh.Devise']"}),
+            'devise_max': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'db_column': "'devise_max'", 'to': "orm['rh.Devise']"}),
+            'devise_min': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'db_column': "'devise_min'", 'to': "orm['rh.Devise']"}),
+            'expatrie': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'implantation'", 'to': "orm['references.Implantation']"}),
+            'indemn_max': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'indemn_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'justification': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'local': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
+            'mise_a_disposition': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_feminin': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+            'regime_travail': ('django.db.models.fields.DecimalField', [], {'default': "'100.00'", 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'regime_travail_nb_heure_semaine': ('django.db.models.fields.DecimalField', [], {'default': "'35.00'", 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'responsable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'db_column': "'responsable'", 'to': "orm['rh.Poste']"}),
+            'salaire_max': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'salaire_min': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2'}),
+            'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_postes'", 'null': 'True', 'db_column': "'service'", 'to': "orm['rh.Service']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type_poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'db_column': "'type_poste'", 'to': "orm['rh.TypePoste']"}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"}),
+            'vacant': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'valeur_point_max': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'valeur_point_max'", 'to': "orm['rh.ValeurPoint']"}),
+            'valeur_point_min': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'valeur_point_min'", 'to': "orm['rh.ValeurPoint']"})
+        },
+        'rh.postecommentaire': {
+            'Meta': {'object_name': 'PosteCommentaire'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'owner'", 'to': "orm['auth.User']"}),
+            'poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'commentaires'", 'db_column': "'poste'", 'to': "orm['rh.Poste']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'texte': ('django.db.models.fields.TextField', [], {}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.postecomparaison': {
+            'Meta': {'object_name': 'PosteComparaison'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'devise': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['rh.Devise']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['references.Implantation']"}),
+            'montant': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_comparaisons_internes'", 'to': "orm['rh.Poste']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.postefinancement': {
+            'Meta': {'object_name': 'PosteFinancement'},
+            'commentaire': ('django.db.models.fields.TextField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_financements'", 'db_column': "'poste'", 'to': "orm['rh.Poste']"}),
+            'pourcentage': ('django.db.models.fields.DecimalField', [], {'max_digits': '12', 'decimal_places': '2'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+        },
+        'rh.postepiece': {
+            'Meta': {'object_name': 'PostePiece'},
+            'fichier': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'poste': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_pieces'", 'db_column': "'poste'", 'to': "orm['rh.Poste']"})
+        },
+        'rh.remuneration': {
+            'Meta': {'object_name': 'Remuneration'},
+            'commentaire': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_debut': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_fin': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'devise': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'devise'", 'to': "orm['rh.Devise']"}),
+            'dossier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_remunerations'", 'db_column': "'dossier'", 'to': "orm['rh.Dossier']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'montant': ('django.db.models.fields.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '12', 'decimal_places': '2', 'blank': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'type'", 'to': "orm['rh.TypeRemuneration']"}),
+            'type_revalorisation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'type_revalorisation'", 'to': "orm['rh.TypeRevalorisation']"}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.responsableimplantation': {
+            'Meta': {'object_name': 'ResponsableImplantation'},
+            'employe': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'employe'", 'to': "orm['rh.Employe']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'responsable'", 'unique': 'True', 'db_column': "'implantation'", 'to': "orm['references.Implantation']"})
+        },
+        'rh.responsableimplantationproxy': {
+            'Meta': {'object_name': 'ResponsableImplantationProxy', 'db_table': "u'ref_implantation'", '_ormbases': ['references.Implantation']}
+        },
+        'rh.service': {
+            'Meta': {'object_name': 'Service'},
+            'archive': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.statut': {
+            'Meta': {'object_name': 'Statut'},
+            'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.tauxchange': {
+            'Meta': {'unique_together': "(('devise', 'annee'),)", 'object_name': 'TauxChange'},
+            'annee': ('django.db.models.fields.IntegerField', [], {}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'devise': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rh.Devise']", 'db_column': "'devise'"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'taux': ('django.db.models.fields.FloatField', [], {}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.typecontrat': {
+            'Meta': {'object_name': 'TypeContrat'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_long': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.typeposte': {
+            'Meta': {'object_name': 'TypePoste'},
+            'categorie_emploi': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'categorie_emploi'", 'to': "orm['rh.CategorieEmploi']"}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'famille_professionnelle': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'types_de_poste'", 'null': 'True', 'to': "orm['rh.FamilleProfessionnelle']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_responsable': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'nom_feminin': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.typeremuneration': {
+            'Meta': {'object_name': 'TypeRemuneration'},
+            'archive': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nature_remuneration': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'type_paiement': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.typerevalorisation': {
+            'Meta': {'object_name': 'TypeRevalorisation'},
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"})
+        },
+        'rh.valeurpoint': {
+            'Meta': {'unique_together': "(('implantation', 'annee'),)", 'object_name': 'ValeurPoint'},
+            'annee': ('django.db.models.fields.IntegerField', [], {}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_modification': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'devise': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'db_column': "'devise'", 'to': "orm['rh.Devise']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'implantation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rh_valeur_point'", 'db_column': "'implantation'", 'to': "orm['references.Implantation']"}),
+            'supprime': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_creation'", 'to': "orm['auth.User']"}),
+            'user_modification': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'user_modification'", 'to': "orm['auth.User']"}),
+            'valeur': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        }
+    }
+    
+    complete_apps = ['rh']
index f39e795..5ac9044 100644 (file)
@@ -22,7 +22,7 @@ from project.rh.managers import \
         PosteManager, DossierManager, EmployeManager, \
         DossierComparaisonManager, \
         PosteComparaisonManager, DeviseManager, ServiceManager, \
-        TypeRemunerationManager
+        TypeRemunerationManager, RemunerationManager
 from project.rh.validators import validate_date_passee
 
 
@@ -281,10 +281,12 @@ class Poste_(AUFMetadata):
 
     # Autres Metadata
     date_debut = models.DateField(
-        u"date de début", help_text=HELP_TEXT_DATE, null=True, blank=True
+        u"date de début", help_text=HELP_TEXT_DATE, null=True, blank=True,
+        db_index=True
     )
     date_fin = models.DateField(
-        u"date de fin", help_text=HELP_TEXT_DATE, null=True, blank=True
+        u"date de fin", help_text=HELP_TEXT_DATE, null=True, blank=True,
+        db_index=True
     )
 
     class Meta:
@@ -440,7 +442,6 @@ class PosteCommentaire(Commentaire):
     )
 
 
-
 ### EMPLOYÉ/PERSONNE
 
 class Employe(AUFMetadata):
@@ -453,7 +454,7 @@ class Employe(AUFMetadata):
     """
 
     objects = EmployeManager()
-    
+
     # Identification
     nom = models.CharField(max_length=255)
     prenom = models.CharField(u"prénom", max_length=255)
@@ -548,6 +549,18 @@ class Employe(AUFMetadata):
         q = search.get_q_temporel(self.rh_dossiers)
         return self.rh_dossiers.filter(q)
 
+    def dossier_principal(self):
+        """
+        Retourne le dossier principal (ou le plus ancien si il y en a
+        plusieurs)
+        """
+        try:
+            dossier = self.rh_dossiers \
+                    .filter(principal=True).order_by('date_debut')[0]
+        except IndexError, Dossier.DoesNotExist:
+            dossier = None
+        return dossier
+
     def postes_encours(self):
         postes_encours = set()
         for d in self.dossiers_encours():
@@ -560,6 +573,7 @@ class Employe(AUFMetadata):
         Idée derrière :
         si on ajout d'autre Dossiers, c'est pour des Postes secondaires.
         """
+        # DEPRECATED : on a maintenant Dossier.principal
         poste = Poste.objects.none()
         try:
             poste = self.dossiers_encours().order_by('date_debut')[0].poste
@@ -737,9 +751,12 @@ class Dossier_(AUFMetadata, DevisableMixin):
     )
 
     # Occupation du Poste par cet Employe (anciennement "mandat")
-    date_debut = models.DateField(u"date de début d'occupation de poste")
+    date_debut = models.DateField(
+        u"date de début d'occupation de poste", db_index=True
+    )
     date_fin = models.DateField(
-        u"Date de fin d'occupation de poste", null=True, blank=True
+        u"Date de fin d'occupation de poste", null=True, blank=True,
+        db_index=True
     )
 
     # Comptes
@@ -951,6 +968,24 @@ class Dossier_(AUFMetadata, DevisableMixin):
             total += r.montant_euros()
         return total
 
+    def premier_contrat(self):
+        """contrat avec plus petite date de début"""
+        try:
+            contrat = self.rh_contrats.exclude(date_debut=None) \
+                    .order_by('date_debut')[0]
+        except IndexError, Contrat.DoesNotExist:
+            contrat = None
+        return contrat
+
+    def dernier_contrat(self):
+        """contrat avec plus grande date de fin"""
+        try:
+            contrat = self.rh_contrats.exclude(date_debut=None) \
+                    .order_by('-date_debut')[0]
+        except IndexError, Contrat.DoesNotExist:
+            contrat = None
+        return contrat
+
     def actif(self):
         today = date.today()
         return (self.date_debut is None or self.date_debut <= today) \
@@ -1001,7 +1036,6 @@ class DossierPiece(DossierPiece_):
     )
 
 
-
 class DossierCommentaire(Commentaire):
     dossier = models.ForeignKey(
         Dossier, db_column='dossier', related_name='commentaires'
@@ -1061,8 +1095,14 @@ class RemunerationMixin(AUFMetadata):
     commentaire = models.CharField(max_length=255, null=True, blank=True)
 
     # date_debut = anciennement date_effectif
-    date_debut = models.DateField(u"date de début", null=True, blank=True)
-    date_fin = models.DateField(u"date de fin", null=True, blank=True)
+    date_debut = models.DateField(
+        u"date de début", null=True, blank=True, db_index=True
+    )
+    date_fin = models.DateField(
+        u"date de fin", null=True, blank=True, db_index=True
+    )
+
+    objects = RemunerationManager()
 
     class Meta:
         abstract = True
@@ -1126,8 +1166,12 @@ class Contrat_(AUFMetadata):
         'TypeContrat', db_column='type_contrat',
         verbose_name=u'type de contrat', related_name='+'
     )
-    date_debut = models.DateField(u"date de début")
-    date_fin = models.DateField(u"date de fin", null=True, blank=True)
+    date_debut = models.DateField(
+        u"date de début", db_index=True
+    )
+    date_fin = models.DateField(
+        u"date de fin", null=True, blank=True, db_index=True
+    )
     fichier = models.FileField(
         upload_to=contrat_dispatch, storage=storage_prive, null=True,
         blank=True
@@ -1423,6 +1467,7 @@ class TauxChange_(AUFMetadata):
         ordering = ['-annee', 'devise__code']
         verbose_name = u"Taux de change"
         verbose_name_plural = u"Taux de change"
+        unique_together = ('devise', 'annee')
 
     def __unicode__(self):
         return u'%s : %s € (%s)' % (self.devise, self.taux, self.annee)
@@ -1463,6 +1508,7 @@ class ValeurPoint_(AUFMetadata):
         abstract = True
         verbose_name = u"Valeur du point"
         verbose_name_plural = u"Valeurs du point"
+        unique_together = ('implantation', 'annee')
 
     def __unicode__(self):
         return u'%s %s %s [%s] %s' % (
index 07f0976..bb76ae5 100644 (file)
 # encoding: utf-8
 
-from decimal import Decimal
-
-import odf.opendocument
-import odf.style
-import odf.table
-from odf.style import Style, MasterPage, PageLayout, PageLayoutProperties, \
-        TextProperties, GraphicProperties, ParagraphProperties, \
-        DrawingPageProperties
-
-
-class Separator():
-
-    def __unicode__(self):
-        return u""
-
-    def __str__(self):
-        return ""
-
-
-def valuetype(val):
-    valuetype = "string"
-    if isinstance(val, str):
-        valuetype = "string"
-    if isinstance(val, (int, float, Decimal)):
-        valuetype = "float"
-    if isinstance(val, bool):
-        valuetype = "boolean"
-
-    return valuetype
-
-
-class Wrapper(object):
-
-    def __init__(self, *args, **kwargs):
-        self.__wrapped = self._wrapper_constructor(*args, **kwargs)
-
-    def __getattr__(self, attr):
-        return getattr(self.__wrapped, attr)
-
-
-class OpenDocumentSpreadsheet(Wrapper):
-    _wrapper_constructor = staticmethod(
-        odf.opendocument.OpenDocumentSpreadsheet
+import odsgen
+
+
+def masse_salariale(lignes, annee, titres_traitements, titres_indemnites,
+                    titres_primes, titres_charges, masse_salariale_totale):
+    doc = odsgen.Document()
+    doc.add_iso_date_style('iso-date')
+
+    table = doc.add_table(name=u'Masse salariale')
+    for width in (
+        ['1.75cm', '5cm', '4cm', '3cm', '3.5cm', '5cm', '4cm', '6cm',
+         '14cm', '2.5cm', '1.5cm', '4.5cm', '3cm', '1.5cm', '3.75cm',
+         '0.5cm', '2.5cm', '2cm', '3cm', '0.5cm', '1.5cm', '4cm',
+         '3.25cm', '5cm', '0.5cm', '4.25cm'] +
+        ['5cm'] * len(titres_traitements) + ['4cm', '0.5cm'] +
+        ['5cm'] * len(titres_indemnites) + ['4cm', '0.5cm'] +
+        ['5cm'] * len(titres_primes) + ['4cm', '0.5cm'] +
+        ['5cm'] * len(titres_charges) + ['4cm', '0.5cm'] +
+        ['3.75cm'] * 4 + ['0.5cm', '2.75cm', '4cm']
+    ):
+        table.add_column(columnwidth=width)
+
+    row = table.add_row()
+    row.add_cells([
+        u'Bureau', u'Pays', u'Implantation', u'Valeur du point',
+        u"Numéro d'employé", u'Nom', u'Prénom', u'Type de poste',
+        u'Intitulé du poste', u'Niveau actuel', u'Points',
+        u'Régime de travail annuel', u'Local / Expatrié', u'Statut',
+        u'Date de fin de contrat'
+    ], fontweight='bold')
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells([
+        u'Date de début', u'Date de fin', u'Nombre de jours'
+    ], fontweight='bold')
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells([
+        u'Devise', u'Salaire BSTG ANNUEL', u'Salaire BSTG EUR',
+        u'Organisme BSTG'
+    ], fontweight='bold')
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells(
+        [u'Salaire théorique annuel'] + titres_traitements +
+        [u'Total des traitements'],
+        backgroundcolor='#ecab44', fontweight='bold'
+    )
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells(
+        titres_indemnites + [u'Total des indemnités'],
+        backgroundcolor='#fff840', fontweight='bold'
+    )
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells(
+        titres_primes + [u'Total des primes'],
+        backgroundcolor='#d7fb0f', fontweight='bold'
+    )
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells(
+        titres_charges + [u'Total des charges'],
+        backgroundcolor='#fb680f', fontweight='bold'
+    )
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cell(
+        u'Total des traitements', backgroundcolor='#ecab44',
+        fontweight='bold'
+    )
+    row.add_cell(
+        u'Total des indemnités', backgroundcolor='#fff840',
+        fontweight='bold'
+    )
+    row.add_cell(
+        u'Total des primes', backgroundcolor='#d7fb0f',
+        fontweight='bold'
+    )
+    row.add_cell(
+        u'Total des charges', backgroundcolor='#fb680f',
+        fontweight='bold'
+    )
+    row.add_cell(backgroundcolor='#d3d3d3')
+    row.add_cells(
+        [u'Masse salariale', u'Masse salariale EUR'],
+        backgroundcolor='#e6c6ed', fontweight='bold'
     )
 
-    def __init__(self, *args, **kwargs):
-        super(OpenDocumentSpreadsheet, self).__init__(*args, **kwargs)
-        self._automatic_style_idx = 0
-
-    def add_table(self, **kwargs):
-        table = Table(**kwargs)
-        table._doc = self
-        self.spreadsheet.addElement(table)
-        return table
-
-    def add_automatic_style(self, **kwargs):
-        name = 'auto_style_%d' % self._automatic_style_idx
-        style = odf.style.Style(name=name, **kwargs)
-        self.automaticstyles.addElement(style)
-        self._automatic_style_idx += 1
-        return style
-
-
-class Table(Wrapper):
-    _wrapper_constructor = staticmethod(odf.table.Table)
-
-    def add_row(self, values=[], **kwargs):
-         # attributs appartenant à table-column-poperties
-#        props = {}
-#        for attr in ['rowheight']:
-#            if attr in kwargs:
-#                props[attr] = kwargs.pop(attr)
-
-        style = self._doc.add_automatic_style(family='table-row')
-        if 'rowheight' in kwargs:
-            style.addElement(odf.style.TableRowProperties(
-                rowheight=kwargs['rowheight']))
-            kwargs['stylename'] = style.getAttribute('name')
-            del kwargs['rowheight']
-
-        style = {}
-
-        row = TableRow(**kwargs)
-        row._doc = self._doc
-        for value in values:
-            row.add_cell(value, verticalalign='middle', **style)
-        self.addElement(row)
-        return row
-
-    def add_column(self, **kwargs):
-
-        # attributs appartenant à table-column-poperties
-        props = {}
-        for attr in ['columnwidth']:
-            if attr in kwargs:
-                props[attr] = kwargs.pop(attr)
-
-        if props:
-            style = self._doc.add_automatic_style(family='table-column')
-            style.addElement(odf.style.TableColumnProperties(**props))
-            kwargs['stylename'] = style.getAttribute('name')
-        col = odf.table.TableColumn(**kwargs)
-        self.addElement(col)
-        return col
-
-
-class TableRow(Wrapper):
-    _wrapper_constructor = staticmethod(odf.table.TableRow)
-
-    def add_cell(self, value=None, **kwargs):
-        if value:
-            if isinstance(value, (basestring, unicode)):
-                kwargs['stringvalue'] = unicode(value)
-            elif isinstance(value, (int, float, Decimal)):
-                kwargs['valuetype'] = "float"
-                kwargs['value'] = float(value)
-            elif type(value) == type(None) or isinstance(value, Separator):
-                kwargs['stringvalue'] = u""
-            else:
-                kwargs['stringvalue'] = unicode(value)
-
-        style = self._doc.add_automatic_style(family='table-cell')
-        if 'verticalalign' in kwargs:
-            style.addElement(odf.style.TableCellProperties(
-                verticalalign=kwargs['verticalalign'], wrapoption='wrap'))
-            del kwargs['verticalalign']
-
-        if isinstance(value, Separator) or type(value) == type(Separator()):
-            style.addElement(odf.style.TableCellProperties(
-                backgroundcolor='#D3D3D3'))
-
-        kwargs['stylename'] = style.getAttribute('name')
-#        props = {}
-#        if 'fontweight' in kwargs:
-#            props['fontweight'] = kwargs.pop('fontweight')
-#        if 'stringvalue' in kwargs:
-#            props['stringvalue'] = kwargs.pop('stringvalue')
-
-        cell = odf.table.TableCell(**kwargs)
-#        if 'fontweight' in props:
-#            tablecontents = Style(name="Bold", family="paragraph")
-#            tablecontents.addElement(TextProperties(fontweight="bold"))
-#            self._doc.styles.addElement(tablecontents)
-
-#        if 'stringvalue' in props:
-#            p = P(stylename='Bold',text=props['stringvalue'])
-#            cell.addElement(p)
-
-        self.addElement(cell)
-        return cell
+    for ligne in lignes:
+        row = table.add_row()
+        row.add_cells([
+            ligne['poste'].implantation.region.code,
+            ligne['poste'].implantation.adresse_physique_pays.nom,
+            ligne['poste'].implantation.nom_court
+        ])
+        row.add_cell(ligne['valeur_point'], decimalplaces=2)
+        row.add_cells([
+            ligne['dossier'].employe.id or 'VACANT',
+            ligne['dossier'].employe.nom,
+            ligne['dossier'].employe.prenom,
+            ligne['poste'].type_poste.nom,
+            ligne['poste'].nom,
+            unicode(ligne['dossier'].classement),
+            ligne['dossier'].classement
+            and ligne['dossier'].classement.coefficient,
+            ligne['regime_travail'],
+            ligne['local_expatrie'],
+            ligne['dossier'].statut.code,
+        ])
+        row.add_cell(ligne['dossier'].date_fin, datastylename='iso-date')
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells([
+            ligne['date_debut'], ligne['date_fin']
+        ], datastylename='iso-date')
+        row.add_cell(ligne['jours'])
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cell(ligne['devise'])
+        row.add_cells([
+            ligne['salaire_bstg'], ligne['salaire_bstg_eur']
+        ], decimalplaces=2)
+        row.add_cell(
+            ligne['dossier'].organisme_bstg
+            and ligne['dossier'].organisme_bstg.nom,
+        )
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells(
+            [ligne['salaire_theorique']] + ligne['traitements'] +
+            [ligne['total_traitements']],
+            decimalplaces=2
+        )
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells(
+            ligne['indemnites'] + [ligne['total_indemnites']],
+            decimalplaces=2
+        )
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells(
+            ligne['primes'] + [ligne['total_primes']],
+            decimalplaces=2
+        )
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells(
+            ligne['charges'] + [ligne['total_charges']],
+            decimalplaces=2
+        )
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells([
+            ligne['total_traitements'], ligne['total_indemnites'],
+            ligne['total_primes'], ligne['total_charges']
+        ], decimalplaces=2)
+        row.add_cell(backgroundcolor='#d3d3d3')
+        row.add_cells([
+            ligne['masse_salariale'], ligne['masse_salariale_eur']
+        ], decimalplaces=2)
+    return doc
diff --git a/project/rh/static/rh/FixedHeader.min.js b/project/rh/static/rh/FixedHeader.min.js
new file mode 100644 (file)
index 0000000..7bd887f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * File:        FixedHeader.min.js
+ * Version:     2.0.6
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * 
+ * Copyright 2009-2011 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD (3 point) style license, as supplied with this software.
+ * 
+ * This source file is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ */
+var FixedHeader=function(a,c){if("function"!=typeof this.fnInit)alert("FixedHeader warning: FixedHeader must be initialised with the 'new' keyword.");else{var b={aoCache:[],oSides:{top:!0,bottom:!1,left:!1,right:!1},oZIndexes:{top:104,bottom:103,left:102,right:101},oMes:{iTableWidth:0,iTableHeight:0,iTableLeft:0,iTableRight:0,iTableTop:0,iTableBottom:0},oOffset:{top:0},nTable:null,bUseAbsPos:!1,bFooter:!1};this.fnGetSettings=function(){return b};this.fnUpdate=function(){this._fnUpdateClones();this._fnUpdatePositions()};
+this.fnPosition=function(){this._fnUpdatePositions()};this.fnInit(a,c);if("function"==typeof a.fnSettings)a._oPluginFixedHeader=this}};
+FixedHeader.prototype={fnInit:function(a,c){var b=this.fnGetSettings(),d=this;this.fnInitSettings(b,c);if("function"==typeof a.fnSettings){if("functon"==typeof a.fnVersionCheck&&!0!==a.fnVersionCheck("1.6.0")){alert("FixedHeader 2 required DataTables 1.6.0 or later. Please upgrade your DataTables installation");return}var e=a.fnSettings();if(""!=e.oScroll.sX||""!=e.oScroll.sY){alert("FixedHeader 2 is not supported with DataTables' scrolling mode at this time");return}b.nTable=e.nTable;e.aoDrawCallback.push({fn:function(){FixedHeader.fnMeasure();
+d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)},sName:"FixedHeader"})}else b.nTable=a;b.bFooter=0<$(">tfoot",b.nTable).length?!0:!1;b.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version);b.oSides.top&&b.aoCache.push(d._fnCloneTable("fixedHeader","FixedHeader_Header",d._fnCloneThead));b.oSides.bottom&&b.aoCache.push(d._fnCloneTable("fixedFooter","FixedHeader_Footer",d._fnCloneTfoot));b.oSides.left&&b.aoCache.push(d._fnCloneTable("fixedLeft","FixedHeader_Left",
+d._fnCloneTLeft));b.oSides.right&&b.aoCache.push(d._fnCloneTable("fixedRight","FixedHeader_Right",d._fnCloneTRight));FixedHeader.afnScroll.push(function(){d._fnUpdatePositions.call(d)});jQuery(window).resize(function(){FixedHeader.fnMeasure();d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)});FixedHeader.fnMeasure();d._fnUpdateClones();d._fnUpdatePositions()},fnInitSettings:function(a,c){if("undefined"!=typeof c){if("undefined"!=typeof c.top)a.oSides.top=c.top;if("undefined"!=typeof c.bottom)a.oSides.bottom=
+c.bottom;if("undefined"!=typeof c.left)a.oSides.left=c.left;if("undefined"!=typeof c.right)a.oSides.right=c.right;if("undefined"!=typeof c.zTop)a.oZIndexes.top=c.zTop;if("undefined"!=typeof c.zBottom)a.oZIndexes.bottom=c.zBottom;if("undefined"!=typeof c.zLeft)a.oZIndexes.left=c.zLeft;if("undefined"!=typeof c.zRight)a.oZIndexes.right=c.zRight;if("undefined"!=typeof c.offsetTop)a.oOffset.top=c.offsetTop}a.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version)},
+_fnCloneTable:function(a,c,b){var d=this.fnGetSettings(),e;if("absolute"!=jQuery(d.nTable.parentNode).css("position"))d.nTable.parentNode.style.position="relative";e=d.nTable.cloneNode(!1);e.removeAttribute("id");var f=document.createElement("div");f.style.position="absolute";f.style.top="0px";f.style.left="0px";f.className+=" FixedHeader_Cloned "+a+" "+c;if("fixedHeader"==a)f.style.zIndex=d.oZIndexes.top;if("fixedFooter"==a)f.style.zIndex=d.oZIndexes.bottom;if("fixedLeft"==a)f.style.zIndex=d.oZIndexes.left;
+else if("fixedRight"==a)f.style.zIndex=d.oZIndexes.right;e.style.margin="0";f.appendChild(e);document.body.appendChild(f);return{nNode:e,nWrapper:f,sType:a,sPosition:"",sTop:"",sLeft:"",fnClone:b}},_fnMeasure:function(){var a=this.fnGetSettings(),c=a.oMes,b=jQuery(a.nTable),d=b.offset(),e=this._fnSumScroll(a.nTable.parentNode,"scrollTop");this._fnSumScroll(a.nTable.parentNode,"scrollLeft");c.iTableWidth=b.outerWidth();c.iTableHeight=b.outerHeight();c.iTableLeft=d.left+a.nTable.parentNode.scrollLeft;
+c.iTableTop=d.top+e;c.iTableRight=c.iTableLeft+c.iTableWidth;c.iTableRight=FixedHeader.oDoc.iWidth-c.iTableLeft-c.iTableWidth;c.iTableBottom=FixedHeader.oDoc.iHeight-c.iTableTop-c.iTableHeight},_fnSumScroll:function(a,c){for(var b=a[c];(a=a.parentNode)&&!("HTML"==a.nodeName||"BODY"==a.nodeName);)b=a[c];return b},_fnUpdatePositions:function(){var a=this.fnGetSettings();this._fnMeasure();for(var c=0,b=a.aoCache.length;c<b;c++)"fixedHeader"==a.aoCache[c].sType?this._fnScrollFixedHeader(a.aoCache[c]):
+"fixedFooter"==a.aoCache[c].sType?this._fnScrollFixedFooter(a.aoCache[c]):"fixedLeft"==a.aoCache[c].sType?this._fnScrollHorizontalLeft(a.aoCache[c]):this._fnScrollHorizontalRight(a.aoCache[c])},_fnUpdateClones:function(){for(var a=this.fnGetSettings(),c=0,b=a.aoCache.length;c<b;c++)a.aoCache[c].fnClone.call(this,a.aoCache[c])},_fnScrollHorizontalRight:function(a){var c=this.fnGetSettings(),b=c.oMes,d=FixedHeader.oWin,e=FixedHeader.oDoc,f=a.nWrapper,g=jQuery(f).outerWidth();d.iScrollRight<b.iTableRight?
+(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+b.iTableWidth-g+"px","left",f.style)):b.iTableLeft<e.iWidth-d.iScrollRight-g?c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",e.iWidth-d.iScrollRight-g+"px","left",f.style)):(this._fnUpdateCache(a,"sPosition","fixed",
+"position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop-d.iScrollTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",d.iWidth-g+"px","left",f.style)):(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",f.style))},_fnScrollHorizontalLeft:function(a){var c=this.fnGetSettings(),b=c.oMes,d=FixedHeader.oWin,e=a.nWrapper,f=jQuery(e).outerWidth();d.iScrollLeft<b.iTableLeft?
+(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):d.iScrollLeft<b.iTableLeft+b.iTableWidth-f?c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",d.iScrollLeft+"px","left",e.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",e.style),
+this._fnUpdateCache(a,"sTop",b.iTableTop-d.iScrollTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft","0px","left",e.style)):(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+b.iTableWidth-f+"px","left",e.style))},_fnScrollFixedFooter:function(a){var c=this.fnGetSettings(),b=c.oMes,d=FixedHeader.oWin,e=FixedHeader.oDoc,f=a.nWrapper,g=jQuery("thead",c.nTable).outerHeight(),h=jQuery(f).outerHeight();
+d.iScrollBottom<b.iTableBottom?(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+b.iTableHeight-h+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",f.style)):d.iScrollBottom<b.iTableBottom+b.iTableHeight-h-g?c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",e.iHeight-d.iScrollBottom-h+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",
+f.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",f.style),this._fnUpdateCache(a,"sTop",d.iHeight-h+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft-d.iScrollLeft+"px","left",f.style)):(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+h+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",f.style))},_fnScrollFixedHeader:function(a){for(var c=this.fnGetSettings(),b=c.oMes,d=FixedHeader.oWin,e=
+a.nWrapper,f=0,g=c.nTable.getElementsByTagName("tbody"),h=0;h<g.length;++h)f+=g[h].offsetHeight;b.iTableTop>d.iScrollTop+c.oOffset.top?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):d.iScrollTop+c.oOffset.top>b.iTableTop+f?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+f+"px","top",e.style),this._fnUpdateCache(a,
+"sLeft",b.iTableLeft+"px","left",e.style)):c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",d.iScrollTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",e.style),this._fnUpdateCache(a,"sTop",c.oOffset.top+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft-d.iScrollLeft+"px","left",e.style))},_fnUpdateCache:function(a,c,b,d,e){a[c]!=b&&(e[d]=
+b,a[c]=b)},_fnCloneThead:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0<b.childNodes.length;)jQuery("thead th",b).unbind("click"),b.removeChild(b.childNodes[0]);a=jQuery("thead",c.nTable).clone(!0)[0];b.appendChild(a);jQuery("thead>tr th",c.nTable).each(function(a){jQuery("thead>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("thead>tr td",c.nTable).each(function(a){jQuery("thead>tr td:eq("+a+")",b).width(jQuery(this).width())})},
+_fnCloneTfoot:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0<b.childNodes.length;)b.removeChild(b.childNodes[0]);a=jQuery("tfoot",c.nTable).clone(!0)[0];b.appendChild(a);jQuery("tfoot:eq(0)>tr th",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("tfoot:eq(0)>tr td",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b)[0].style.width(jQuery(this).width())})},_fnCloneTLeft:function(a){var c=
+this.fnGetSettings(),b=a.nNode,d=$("tbody",c.nTable)[0];for($("tbody tr:eq(0) td",c.nTable);0<b.childNodes.length;)b.removeChild(b.childNodes[0]);b.appendChild(jQuery("thead",c.nTable).clone(!0)[0]);b.appendChild(jQuery("tbody",c.nTable).clone(!0)[0]);c.bFooter&&b.appendChild(jQuery("tfoot",c.nTable).clone(!0)[0]);$("thead tr",b).each(function(){$("th:gt(0)",this).remove()});$("tfoot tr",b).each(function(){$("th:gt(0)",this).remove()});$("tbody tr",b).each(function(){$("td:gt(0)",this).remove()});
+this.fnEqualiseHeights("tbody",d.parentNode,b);c=jQuery("thead tr th:eq(0)",c.nTable).outerWidth();b.style.width=c+"px";a.nWrapper.style.width=c+"px"},_fnCloneTRight:function(a){for(var c=this.fnGetSettings(),b=$("tbody",c.nTable)[0],d=a.nNode,e=jQuery("tbody tr:eq(0) td",c.nTable).length;0<d.childNodes.length;)d.removeChild(d.childNodes[0]);d.appendChild(jQuery("thead",c.nTable).clone(!0)[0]);d.appendChild(jQuery("tbody",c.nTable).clone(!0)[0]);c.bFooter&&d.appendChild(jQuery("tfoot",c.nTable).clone(!0)[0]);
+jQuery("thead tr th:not(:nth-child("+e+"n))",d).remove();jQuery("tfoot tr th:not(:nth-child("+e+"n))",d).remove();$("tbody tr",d).each(function(){$("td:lt("+(e-1)+")",this).remove()});this.fnEqualiseHeights("tbody",b.parentNode,d);c=jQuery("thead tr th:eq("+(e-1)+")",c.nTable).outerWidth();d.style.width=c+"px";a.nWrapper.style.width=c+"px"},fnEqualiseHeights:function(a,c,b){var d=$(a+" tr:eq(0)",c).children(":eq(0)"),e=d.outerHeight()-d.height(),f=$.browser.msie&&("6.0"==$.browser.version||"7.0"==
+$.browser.version);$(a+" tr",b).each(function(b){$.browser.mozilla||$.browser.opera?$(this).children().height($(a+" tr:eq("+b+")",c).outerHeight()):$(this).children().height($(a+" tr:eq("+b+")",c).outerHeight()-e);f||$(a+" tr:eq("+b+")",c).height($(a+" tr:eq("+b+")",c).outerHeight())})}};FixedHeader.oWin={iScrollTop:0,iScrollRight:0,iScrollBottom:0,iScrollLeft:0,iHeight:0,iWidth:0};FixedHeader.oDoc={iHeight:0,iWidth:0};FixedHeader.afnScroll=[];
+FixedHeader.fnMeasure=function(){var a=jQuery(window),c=jQuery(document),b=FixedHeader.oWin,d=FixedHeader.oDoc;d.iHeight=c.height();d.iWidth=c.width();b.iHeight=a.height();b.iWidth=a.width();b.iScrollTop=a.scrollTop();b.iScrollLeft=a.scrollLeft();b.iScrollRight=d.iWidth-b.iScrollLeft-b.iWidth;b.iScrollBottom=d.iHeight-b.iScrollTop-b.iHeight};FixedHeader.VERSION="2.0.6";FixedHeader.prototype.VERSION=FixedHeader.VERSION;
+jQuery(window).scroll(function(){FixedHeader.fnMeasure();for(var a=0,c=FixedHeader.afnScroll.length;a<c;a++)FixedHeader.afnScroll[a]()});
diff --git a/project/rh/templates/rh/include/rapports_contrat.html b/project/rh/templates/rh/include/rapports_contrat.html
new file mode 100644 (file)
index 0000000..dd94b01
--- /dev/null
@@ -0,0 +1,5 @@
+{% if contrat.fichier %}
+  <a href="{{ contrat.fichier.url }}">{{ contrat.type_contrat.nom }}</a>
+{% else %}
+  {{ contrat.type_contrat.nom }}
+{% endif %}
diff --git a/project/rh/templates/rh/include/rapports_dossier_poste.html b/project/rh/templates/rh/include/rapports_dossier_poste.html
new file mode 100644 (file)
index 0000000..95cc4e4
--- /dev/null
@@ -0,0 +1,8 @@
+<a title="Aperçu du dossier"
+   href="{% url dossier_apercu d.id %}"
+   onclick="return showAddAnotherPopup(this);"
+   title="Aperçu du dossier">
+   <img src="{{ STATIC_URL }}img/dossier-apercu.png" />
+</a>&nbsp;
+<a href="{% url admin:rh_dossier_change d.id %}">Dossier</a> : 
+{{ d.poste.nom }} [{{ d.poste.id|stringformat:"d" }}]
index 3220eb8..294e268 100644 (file)
@@ -2,22 +2,27 @@
 {% load adminmedia rapports i18n %}
 
 {% block extrastyle %}
-{{ block.super }}
-<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
+  {{ block.super }}
+  <link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
 {% endblock %}
 
 {% block bodyclass %}change-list{% endblock %}
 
-{% block breadcrumbs %}{% if not is_popup %}
-<div class="breadcrumbs">
+{% block breadcrumbs %}
+{% if not is_popup %}
+  <div class="breadcrumbs">
     <a href="{% url admin:index %}">{% trans "Home" %}</a> &rsaquo;
     <a href="{% url admin:app_list 'rh' %}">Rh</a> &rsaquo;
-       {% block nomrapport %}{% endblock %}
-</div>
-{% endif %}{% endblock %}
+         {% block nomrapport %}{% endblock %}
+  </div>
+{% endif %}
+{% endblock %}
+
 {% block content %}
-{% block count_elements %}{% endblock %}
-<div id="content-main"><div class="module filtered" id="changelist">
-       {% block contentrapport %}{% endblock %}
-</div></div>
+  {% block count_elements %}{% endblock %}
+  <div id="content-main">
+    <div class="module filtered" id="changelist">
+       {% block contentrapport %}{% endblock %}
+    </div>
+  </div>
 {% endblock %}
index e897205..27afccf 100644 (file)
@@ -9,6 +9,7 @@
 {% block extrahead %}
   <script type="text/javascript" src="/admin/jsi18n"></script>
   <script type="text/javascript" src="{{ STATIC_URL }}/admin/js/core.js"></script>
+  <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js"></script>
   {{ block.super }}
 {% endblock %}
 
   {% for contrat in contrats %}
   <tr class="{% cycle 'row1' 'row2' %}">
     <td style="text-align:right">
-        {{ contrat.dossier.employe.id }}
+        {{ contrat.dossier.employe.id|stringformat:"d" }}
     </td>
     <td>{{ contrat.dossier.employe.nom|upper }} {{ contrat.dossier.employe.prenom|title }}</td>
     <td>
-      <a href="{% url admin:rh_dossier_change contrat.dossier.id %}">
-        Dossier
-      </a> 
-      : {{ contrat.dossier.poste.nom }}
+      {% with contrat.dossier as d %}
+        {% include 'rh/include/rapports_dossier_poste.html' %}
+      {% endwith %}
     </td>
     <td>
-    {% if contrat.fichier %}
-      <a href="{{ contrat.fichier.url }}">{{ contrat.type_contrat.nom }}</a>
-    {% else %}
-      {{ contrat.type_contrat.nom }}
-    {% endif %}
+      {% include 'rh/include/rapports_contrat.html' %}
     </td>
     <td>{{ contrat.date_debut }}</td>
     <td>{{ contrat.date_fin|default:'' }}</td>
index c1b9bbb..813d7af 100644 (file)
@@ -2,15 +2,16 @@
 {% load adminmedia rapports i18n change_list %}
 
 {% block extrastyle %}
-<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>
+  <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js"></script>
+  {{ block.super }}
 {% endblock %}
 
 {% block nomrapport %}Rapport Contrats{% endblock %}
 
 {% block count_elements %}
-<h2>{{ employes.count }} employés sans contrat</h2>
+<h2>{{ employes }} employés sans contrat ou contrat échu</h2>
 {% endblock %}
 
 {% block contentrapport %}
     <tr>{% table_header headers %}</tr>
   </thead>
   <tbody>
-  {% spaceless %}
-    {% for e in employes %}
+  {% spaceless %}   
+    {% for d in dossiers %}
     <tr class="{% cycle 'row1' 'row2' %}">
-      <td style="text-align:right">{{ e.id }}</td>
-      <td>{{ e.nom|upper }} {{ e.prenom }}</td>
+      <td style="text-align:right">{{ d.employe.id|stringformat:"d" }}</td>
+      <td>{{ d.employe.nom|upper }} {{ d.employe.prenom }}</td>
+      <td>{% include 'rh/include/rapports_dossier_poste.html' %}</td>
       <td>
-        {% for d in e.rh_dossiers.all %}
-          {% if d in dossiers_sans_contrat %}
-            <a href="{% url admin:rh_dossier_change d.id %}">Dossier</a> : {{ d.poste.nom }}
-            {% if not forloop.last %}<br />{% endif %}
-          {% endif %}
-        {% endfor %}
-      </td>
-      <td>
-        {% for d in e.rh_dossiers.all %}
-          {% if d in dossiers_sans_contrat %}
-            {{ d.date_debut|default_if_none:"" }}
-            {% if not forloop.last %}<br />{% endif %}
-          {% endif %}
-        {% endfor %}
-      </td>
-      <td>
-        {% for d in e.rh_dossiers.all %}
-          {% if d in dossiers_sans_contrat %}
-            {{ d.date_fin|default_if_none:"" }}
-            {% if not forloop.last %}<br />{% endif %}
-          {% endif %}
-        {% endfor %}
+        {% with d.dernier_contrat as contrat %}
+          {% include 'rh/include/rapports_contrat.html' %}
+        {% endwith %}
       </td>
+      <td>{{ d.dernier_contrat.date_debut|default_if_none:"" }}</td>
+      <td>{{ d.dernier_contrat.date_fin|default_if_none:"" }}</td>
+      <td>{{ d.get_statut_residence_display }}</td>
+      <td>{{ d.poste.implantation.region.code }}</td>
+      <td>{{ d.poste.implantation.nom }}</td>
     </tr>
     {% endfor %}
   {% endspaceless %}
index fb2df81..73c90fa 100644 (file)
-{% extends 'rh/rapports/base.html' %}
+{% extends 'admin/base_site.html' %}
 {% load adminmedia rapports i18n l10n %}
 
-{% block nomrapport %}Rapport de masse salariale{% endblock %}
-{% block count_elements %}<h2>Rapport année {{ request.GET.annee }}</h2>{% endblock %}
+{% block content_title %}<h1>Rapport de masse salariale</h1>{% endblock %}
 
 {% block extrastyle %}
 {{ block.super }}
 <style type="text/css">
-    #changelist .actions .filter {width: auto; float: left;}
-    #changelist .actions .filter h3 {font-size: 11px; margin-left: 0.5em;}
-    #result_list .highlighted {background: #ffff88;}
+table.rapport { border: 1px solid #dddddd; }
+table.rapport th { background: white; }
+table.rapport th.traitements { background: #ecab44; }
+table.rapport th.indemnites { background: #fff840; }
+table.rapport th.primes { background: #d7fb0f; }
+table.rapport th.charges { background: #fb680f; }
+table.rapport .highlighted { background: #ffff88; }
+th.section-end, td.section-end { border-right: 10px solid #dddddd; }
+td.numeric { text-align: right; white-space: nowrap; }
 </style>
 {% endblock %}
 
 {% block extrahead %}
 {{ block.super }}
-<script type="text/javascript" src="{{ STATIC_URL }}js/jquery-1.5.1.min.js"></script>
-<script type="text/javascript" src="{% admin_media_prefix %}js/jquery-stickytableheaders.js"></script>
+<script type="text/javascript"
+        src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+<script type="text/javascript" src="{{ STATIC_URL }}rh/FixedHeader.min.js"></script>
 <script type="text/javascript">
-$(function() {
-    $('#result_list tr').click(function() {
+$(document).ready(function() {
+    new FixedHeader($('table.rapport').get(0));
+    $('table.rapport tr').click(function() {
         $(this).toggleClass('highlighted');
     });
 });
 </script>
 {% endblock %}
 
-{% block contentrapport %}
-{% if url_ods %}
-<ul class="object-tools">
-    <li>
-        <a href="{{ url_ods }}">Exporter en ods</a>
-    </li>
-</ul>
-{% endif %}
-<form method="GET">
-    <input type="hidden" name="ne_pas_grouper" value="True" />
-    <div class="actions">
-        <div class="filter">
-            <h3>Région</h3>
-            {{ form.region }}
-        </div>
-        <div class="filter">
-            <h3>Implantation</h3>
-            {{ form.implantation }}
-        </div>
-        <div class="filter">
-            <h3>Année</h3>
-            {{ form.annee }}
-        </div>
-        <div class="filter" style="margin-left:20px">
-            <h3>&nbsp;</h3>
-            <button type="submit" class="button" title="Exécuter l'action sélectionnée">Rechercher</button>
-        </div>
-        <div class="clear"></div>
-        {% comment %}
-        <label>Plage de dates:
-            {{ form.date_debut }} au {{ form.date_fin }}
-        </label>
-        {% endcomment %}
-    </div>
+{% block content %}
+<form class="module">
+  <table style="width: 100%">
+    {{ form }}
+    <tr>
+      <td></td>
+      <td>
+        <input type="submit" value="Afficher">
+        <input type="submit" name="ods" value="Format Calc">
+      </td>
+    </tr>
+  </table>
 </form>
-<div class="clear"></div>
 
+{% if lignes %}
+<p>
+  <strong>Masse salariale totale: {{ masse_salariale_totale }} EUR</strong>
+</p>
 
-<script type="text/javascript">
-    jQuery(document).ready(function(){
-        $("#result_list").stickyTableHeaders();
-    });
-</script>
-<table id="result_list" class="results">
-<thead>
-<tr>
-    {% table_header headers %}
-</tr>
-</thead>
-{% localize on %}
-{% spaceless %}
-{% for row in rapport %}
-    <tr class="{% cycle 'row1' 'row2' %}">
-        {% for column in header_keys %}
-            {% if column == 'sep' %}
-                <td style="background:gray;">&nbsp;</td>
-            {% else %}
-                {% if row|hash:column|is_float %}
-                <td>
-                    {% comment %}
-                    {% if options.backgroundcolor %}
-                    style="background-color:{{ options.backgroundcolor }}"
-                    {% endif %}
-                    {% endcomment %}
-                    {{ row|hash:column|floatformat:2|localize }}
-                    {% if column != "point" %}
-                        {% if forloop.last or column|contains:"euro" %}
-                            EUR
-                        {% else %}
-                            {{ row.devise }}
-                        {% endif %}
-                    {% endif %}
-                </td>
-                {% else %}
-                    <td>{{ row|hash:column|default:"" }}</td>
-                {% endif %}
-            {% endif %}
-        {% endfor %}
-    </tr>
-{% endfor %}{% endspaceless %}
+<table class="rapport">
+  <thead>
     <tr>
-        <td colspan="{{ colspan }}" style="text-align:right;font-weight:bold;">
-            TOTAL : 
-        </td>
-        <td>{{ total_euro }}</td>
+      <th>Bureau</th>
+      <th>Pays</th>
+      <th>Implantation</th>
+      <th>Valeur du point</th>
+      <th>Numéro d'employé</th>
+      <th>Nom</th>
+      <th>Prénom</th>
+      <th>Type de poste</th>
+      <th>Intitulé du poste</th>
+      <th>Niveau actuel</th>
+      <th>Points</th>
+      <th>Régime de travail annuel</th>
+      <th>Local / Expatrié</th>
+      <th>Statut</th>
+      <th class="section-end">Date de fin de contrat</th>
+      <th>Date de début</th>
+      <th>Date de fin</th>
+      <th class="section-end">Nombre de jours</th>
+      <th>Devise</th>
+      <th>Salaire BSTG ANNUEL</th>
+      <th>Salaire BSTG EUR</th>
+      <th class="section-end">Organisme BSTG</th>
+      <th class="traitements">
+        Salaire théorique annuel
+      </th>
+      {% for titre in titres_traitements %}
+      <th class="traitements">{{ titre }}</th>
+      {% endfor %}
+      <th class="traitements section-end">
+        Total des traitements
+      </th>
+      {% for titre in titres_indemnites %}
+      <th class="indemnites">{{ titre }}</th>
+      {% endfor %}
+      <th class="indemnites section-end">Total des indemnités</th>
+      {% for titre in titres_primes %}
+      <th class="primes">{{ titre }}</th>
+      {% endfor %}
+      <th class="primes section-end">Total des primes</th>
+      {% for titre in titres_charges %}
+      <th class="charges">{{ titre }}</th>
+      {% endfor %}
+      <th class="charges section-end">Total des charges</th>
+      <th class="traitements">Total des traitements</th>
+      <th class="indemnites">Total des indemnités</th>
+      <th class="primes">Total des primes</th>
+      <th class="charges section-end">Total des charges</th>
+      <th>Masse salariale</th>
+      <th>Masse salariale EUR</th>
+    </tr>
+  </thead>
+  <tbody>
+    {% for ligne in lignes %}
+    <tr class="{% cycle 'row1' 'row2' %}">
+      <td>{{ ligne.poste.implantation.region.code }}</td>
+      <td>{{ ligne.poste.implantation.adresse_physique_pays.nom }}</td>
+      <td>{{ ligne.poste.implantation.nom_court }}</td>
+      <td class="numeric">
+        {% if ligne.valeur_point %}
+        {{ ligne.valeur_point }} {{ ligne.valeur_point_devise }}
+        {% endif %}
+      </td>
+      <td>
+        {% if ligne.dossier %}
+        {{ ligne.dossier.employe.id|stringformat:"d" }}
+        {% else %}
+        VACANT
+        {% endif %}
+      </td>
+      <td>
+        {% if ligne.dossier %}
+        <a href="{% url admin:rh_employe_change ligne.dossier.employe.id %}"
+        >{{ ligne.dossier.employe.nom }}</a>
+        {% endif %}
+      </td>
+      <td>
+        {% if ligne.dossier %}
+        <a href="{% url admin:rh_employe_change ligne.dossier.employe.id %}"
+        >{{ ligne.dossier.employe.prenom }}</a>
+        {% endif %}
+      </td>
+      <td>{{ ligne.poste.type_poste.nom }}</td>
+      <td>
+        <a href="{% url admin:rh_poste_change ligne.poste.id %}"
+          >{{ ligne.poste.nom }}</a>
+      </td>
+      <td>{{ ligne.dossier.classement }}</td>
+      <td class="numeric">
+        {{ ligne.dossier.classement.coefficient|floatformat:2 }}
+      </td>
+      <td class="numeric">
+        {{ ligne.regime_travail|floatformat }} %
+      </td>
+      <td>{{ ligne.local_expatrie }}</td>
+      <td>{{ ligne.dossier.statut.code }}</td>
+      <td class="section-end">{{ ligne.dossier.date_fin|date }}</td>
+      <td>
+        {{ ligne.date_debut|date }}
+      </td>
+      <td>
+        {{ ligne.date_fin|date }}
+      </td>
+      <td class="section-end">
+        {{ ligne.jours }}
+      </td>
+      <td>{{ ligne.devise }}</td>
+      <td class="numeric">
+        {% if ligne.salaire_bstg %}
+        {{ ligne.salaire_bstg }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.salaire_bstg_eur %}
+        {{ ligne.salaire_bstg_eur }} EUR
+        {% endif %}
+      </td>
+      <td class="section-end">{{ ligne.dossier.organisme_bstg.nom }}</td>
+      <td class="numeric">
+        {% if ligne.salaire_theorique %}
+        {{ ligne.salaire_theorique }} {{ ligne.valeur_point_devise }}
+        {% endif %}
+      </td>
+      {% for traitement in ligne.traitements %}
+      <td class="numeric">
+        {% if traitement %}
+        {{ traitement }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% endfor %}
+      <td class="section-end numeric">
+        {% if ligne.total_traitements %}
+        {{ ligne.total_traitements }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% for indemnite in ligne.indemnites %}
+      <td class="numeric">
+        {% if indemnite %}
+        {{ indemnite }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% endfor %}
+      <td class="section-end numeric">
+        {% if ligne.total_indemnites %}
+        {{ ligne.total_indemnites }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% for prime in ligne.primes %}
+      <td class="numeric">
+        {% if prime %}
+        {{ prime }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% endfor %}
+      <td class="section-end numeric">
+        {% if ligne.total_primes %}
+        {{ ligne.total_primes }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% for charge in ligne.charges %}
+      <td class="numeric">
+        {% if charge %}
+        {{ charge }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      {% endfor %}
+      <td class="section-end numeric">
+        {% if ligne.total_charges %}
+        {{ ligne.total_charges }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.total_traitements %}
+        {{ ligne.total_traitements }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.total_indemnites %}
+        {{ ligne.total_indemnites }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.total_primes %}
+        {{ ligne.total_primes }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="section-end numeric">
+        {% if ligne.total_charges %}
+        {{ ligne.total_charges }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.masse_salariale %}
+        {{ ligne.masse_salariale }} {{ ligne.devise }}
+        {% endif %}
+      </td>
+      <td class="numeric">
+        {% if ligne.masse_salariale_eur %}
+        {{ ligne.masse_salariale_eur }} EUR
+        {% endif %}
+      </td>
     </tr>
+    {% endfor %}
+  </tbody>
 </table>
-{% endlocalize %}
+{% endif %}
+
 {% endblock %}
index eb9bde6..21e8bf0 100644 (file)
@@ -1,41 +1,37 @@
 # -*- encoding: utf-8 -*-
 
-import urllib
+from collections import defaultdict
 from datetime import date
-from itertools import izip
-import StringIO
+from decimal import Decimal
 
 import pygraphviz as pgv
-
-from django import forms
+from auf.django.references import models as ref
 from django.conf import settings
 from django.contrib.auth.decorators import login_required
-from django.core.servers.basehttp import FileWrapper
 from django.core.urlresolvers import reverse
 from django.db.models import Q
 from django.http import HttpResponse
 from django.shortcuts import render, get_object_or_404
 
-from auf.django.references import models as ref
-
-from project.decorators import redirect_interdiction
 from project.decorators import drh_or_admin_required
 from project.decorators import region_protected
-from project.groups import get_employe_from_user
-from project.groups import grp_drh, grp_correspondants_rh
-
-from project.rh import models as rh
+from project.groups import \
+        get_employe_from_user, grp_drh, grp_correspondants_rh
+from project.rh import ods
 from project.rh import graph as rh_graph
+from project.rh import models as rh
 from project.rh.change_list import RechercheTemporelle
-from project.rh.lib import calc_remun, get_lookup_params
-from project.rh.masse_salariale import MasseSalariale
+from project.rh.forms import MasseSalarialeForm
+from project.rh.lib import get_lookup_params
 from project.rh.templatetags.rapports import SortHeaders
 
+TWOPLACES = Decimal('0.01')
+
 
 @login_required
 def profil(request):
     """Profil personnel de l'employé - éditable"""
-    employe = get_employe_from_user(user)
+    employe = get_employe_from_user(request.user)
     c = {
       'user': request.user,
       'employe': employe,
@@ -106,7 +102,6 @@ def rapports_contrat(request):
 
     # affichage
     employes = set([c.dossier.employe_id for c in contrats])
-
     headers = [
         ("dossier__employe__id", u"#"),
         ("dossier__employe__nom", u"Employé"),
@@ -135,116 +130,12 @@ def rapports_contrat(request):
 
 @login_required
 @drh_or_admin_required
-def rapports_masse_salariale(request):
-
-    class RechercheTemporelle(forms.Form):
-        CHOICE_ANNEES = range(
-            rh.Remuneration.objects.exclude(date_debut=None)
-            .order_by('date_debut')[0].date_debut.year,
-            date.today().year + 1
-        )
-
-        annee = forms.CharField(
-            initial=date.today().year,
-            widget=forms.Select(
-                choices=((a, a) for a in reversed(CHOICE_ANNEES))
-            )
-        )
-
-        region = forms.CharField(
-                widget=forms.Select(choices=[('', '')] +
-                    [(i.id, i) for i in ref.Region.objects.all()]
-                )
-            )
-
-        implantation = forms.CharField(
-                widget=forms.Select(choices=[('', '')] +
-                    [(i.id, i) for i in ref.Implantation.objects.all()]
-                )
-            )
-
-        #date_debut = forms.DateField(widget=adminwidgets.AdminDateWidget)
-        #date_fin = forms.DateField(widget=adminwidgets.AdminDateWidget)
-
-    form = RechercheTemporelle(request.GET)
-    get_filtre = [
-        (k, v) for k, v in request.GET.items()
-        if k not in ('date_debut', 'date_fin', 'implantation')
-    ]
-    query_string = urllib.urlencode(get_filtre)
-
-    date_debut = None
-    date_fin = None
-    if request.GET.get('annee', None):
-        date_debut = "01-01-%s" % request.GET.get('annee', None)
-        date_fin = "31-12-%s" % request.GET.get('annee', None)
-
-    implantation = request.GET.get('implantation')
-    region = request.GET.get('region')
-
-    custom_filter = {}
-    if implantation:
-        custom_filter['dossier__poste__implantation'] = implantation
-    if region:
-        custom_filter['dossier__poste__implantation__region'] = region
-
-    c = {
-            'title': 'Rapport de masse salariale',
-            'form': form,
-            'headers': [],
-            'query_string': query_string,
-    }
-    if date_debut or date_fin:
-        masse = MasseSalariale(date_debut, date_fin, custom_filter,
-                request.GET.get('ne_pas_grouper', False))
-        if masse.rapport:
-            if request.GET.get('ods'):
-                for h in (
-                    h for h in masse.headers if 'background-color' in h[2]
-                ):
-                    del h[2]['background-color']
-                masse.ods()
-                output = StringIO.StringIO()
-                masse.doc.save(output)
-                output.seek(0)
-
-                response = HttpResponse(
-                    FileWrapper(output),
-                    content_type=(
-                        'application/vnd.oasis.opendocument.spreadsheet'
-                    )
-                )
-                response['Content-Disposition'] = \
-                        'attachment; filename=Masse Salariale %s.ods' % \
-                            masse.annee
-                return response
-            else:
-                c['rapport'] = masse.rapport
-                c['header_keys'] = [h[0] for h in masse.headers]
-                #on enleve le background pour le header
-                for h in (
-                    h for h in masse.headers if 'background-color' in h[2]
-                ):
-                    h[2]['background'] = 'none'
-                h = SortHeaders(request, masse.headers, order_field_type="ot",
-                        not_sortable=c['header_keys'], order_field="o")
-                c['headers'] = list(h.headers())
-                for key, nom, opts in masse.headers:
-                    c['headers']
-                c['total'] = masse.grand_totaux[0]
-                c['total_euro'] = masse.grand_totaux[1]
-                c['colspan'] = len(c['header_keys']) - 1
-                get_filtre.append(('ods', True))
-                query_string = urllib.urlencode(get_filtre)
-                c['url_ods'] = "%s?%s" % (
-                        reverse('rhr_masse_salariale'), query_string)
-
-    return render(request, 'rh/rapports/masse_salariale.html', c)
-
-
-@login_required
-@drh_or_admin_required
 def rapports_employes_sans_contrat(request):
+    """
+    Employé sans contrat = a un Dossier qui n'a pas de Contrat associé
+    Employé avec contrat échu = a un Dossier avec un Contrat se terminant hier
+    au plus tard... (aujourd'hui = ok, pas date de fin = illimité donc ok)
+    """
     lookup_params = get_lookup_params(request)
 
     # contrats échus
@@ -254,41 +145,49 @@ def rapports_employes_sans_contrat(request):
             **lookup_params
         )
 
-    # dossiers en cours sans contrat
-    dossiers_sans_contrat = rh.Dossier.objects.filter(
-            Q(date_fin=None) | Q(date_fin__gt=date.today()),
+    # dossiers en cours sans contrat ou contrats échus
+    dossiers = rh.Dossier.objects.filter(
+            Q(date_debut=None) | Q(date_debut__lte=date.today()),
+        ).filter(
+            Q(date_fin=None) | Q(date_fin__gte=date.today()),
         ).exclude(
             date_debut__gt=date.today()
         ).filter(
-            rh_contrats__in=contrats_echus
-        )
-    
-    # employés sans contrat
-    employes = rh.Employe.objects.filter(
-            rh_dossiers__in=dossiers_sans_contrat
+            # sans contrat | contrat échu
+            Q(rh_contrats=None) | Q(rh_contrats__in=contrats_echus)
         ).distinct()
+
+    # employés sans contrat ou contrats échus
+    employes = rh.Employe.objects.filter(rh_dossiers__in=dossiers)  \
+        .distinct().count()
+
+    # tri
     if 'o' in request.GET:
-        employes = employes.order_by(
+        dossiers = dossiers.order_by(
             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
         )
 
     # affichage
     headers = [
-        ("id", u"#"),
-        ("nom", u"Employé"),
+        ("employe__id", u"#"),
+        ("employe__nom", u"Employé"),
         ("dossier", u"Dossier : Poste"),
-        ("dossier_date_debut", u"Début dossier"),
-        ("dossier_date_fin", u"Fin dossier"),
+        ("rh_contrats__type_contrat", u"Contrat"),
+        ("rh_contrats__date_debut", u"Début contrat"),
+        ("rh_contrats__date_fin", u"Fin contrat"),
+        ("statut_residence", u"Statut"),
+        ("poste__implantation__region__code", u"Région"),
+        ("poste__implantation__nom", u"Implantation"),
     ]
     h = SortHeaders(
         request, headers, order_field_type="ot", order_field="o",
-        not_sortable=('dossier','dossier_date_debut','dossier_date_fin',)
+        not_sortable=('dossier',)
     )
 
     c = {
-        'title': u'Rapport des employés sans contrat',
+        'title': u'Rapport des employés sans contrat ou contrat échu',
         'employes': employes,
-        'dossiers_sans_contrat':dossiers_sans_contrat,
+        'dossiers': dossiers,
         'headers': list(h.headers()),
     }
 
@@ -297,6 +196,337 @@ def rapports_employes_sans_contrat(request):
 
 @login_required
 @drh_or_admin_required
+def rapports_masse_salariale(request):
+    form = MasseSalarialeForm(request.user, request.GET)
+    if 'annee' in request.GET and form.is_valid():
+        region = form.cleaned_data['region']
+        implantation = form.cleaned_data['implantation']
+        annee = form.cleaned_data['annee']
+        debut_annee = date(annee, 1, 1)
+        fin_annee = date(annee, 12, 31)
+        jours_annee = (fin_annee - debut_annee).days + 1
+        today = date.today()
+
+        # Récupérer les dossiers actifs
+        dossiers = rh.Dossier.objects \
+                .actifs(annee=annee) \
+                .select_related(
+                    'poste', 'poste__implantation',
+                    'poste__implantation__region',
+                    'poste__implantation__adresse_physique_pays',
+                    'employe', 'poste__type_poste', 'classement',
+                    'statut', 'organisme_bstg'
+                ) \
+                .extra(
+                    select={
+                        'valeur_point': (
+                            'SELECT valeur FROM rh_valeurpoint '
+                            'WHERE annee = %d '
+                            'AND implantation = ref_implantation.id' % annee
+                        ),
+                        'valeur_point_devise': (
+                            'SELECT d.code '
+                            'FROM rh_valeurpoint vp '
+                            'INNER JOIN rh_devise d ON d.id = vp.devise '
+                            'WHERE annee = %d '
+                            'AND implantation = ref_implantation.id' % annee
+                        )
+                    }
+                )
+        if region:
+            dossiers = dossiers.filter(poste__implantation__region=region)
+        if implantation:
+            dossiers = dossiers.filter(poste__implantation=implantation)
+
+        # Récupérer les rémunérations actives
+        remuns = rh.Remuneration.objects \
+                .actifs(annee=annee) \
+                .select_related('devise', 'type') \
+                .extra(
+                    tables=['rh_tauxchange'],
+                    where=[
+                        'rh_tauxchange.annee = %s',
+                        'rh_tauxchange.devise = rh_devise.id'
+                    ],
+                    params=[annee],
+                    select={
+                        'taux_change': 'rh_tauxchange.taux'
+                    }
+                )
+        if region:
+            remuns = remuns.filter(dossier__poste__implantation__region=region)
+        if implantation:
+            remuns = remuns.filter(dossier__poste__implantation=implantation)
+        remuns_par_dossier = defaultdict(list)
+        types_remun = set()
+        for remun in remuns:
+            types_remun.add(remun.type_id)
+            remuns_par_dossier[remun.dossier_id].append(remun)
+
+        # Récupérer les types de rémunération par nature
+        types_remun_par_nature = defaultdict(list)
+        for type in rh.TypeRemuneration.objects.all():
+            if type.id in types_remun:
+                types_remun_par_nature[type.nature_remuneration].append(type)
+        titres_traitements = [
+            t.nom for t in types_remun_par_nature[u'Traitement']
+        ]
+        titres_indemnites = [
+            t.nom for t in types_remun_par_nature[u'Indemnité']
+        ]
+        titres_primes = [
+            t.nom for t in types_remun_par_nature[u'Accessoire']
+        ]
+        titres_charges = [
+            t.nom for t in types_remun_par_nature[u'Charges']
+        ]
+
+        # Boucler sur les dossiers et préprarer les lignes du rapport
+        lignes = []
+        masse_salariale_totale = 0
+        for dossier in dossiers:
+            debut_cette_annee = \
+                    max(dossier.date_debut or debut_annee, debut_annee)
+            fin_cette_annee = \
+                    min(dossier.date_fin or fin_annee, fin_annee)
+            jours = (fin_cette_annee - debut_cette_annee).days + 1
+
+            remuns = remuns_par_dossier[dossier.id]
+            devises = set(remun.devise.code for remun in remuns)
+            if len(devises) == 1:
+                devise = remuns[0].devise.code
+                montant_remun = lambda r: r.montant
+                taux_change = Decimal(str(remuns[0].taux_change))
+            else:
+                devise = 'EUR'
+                montant_remun = lambda r: (
+                    r.montant * Decimal(str(r.taux_change))
+                )
+                taux_change = Decimal(1)
+
+            remuns_par_type = defaultdict(lambda: 0)
+            for remun in remuns:
+                if remun.type.nature_remuneration == u'Accessoire':
+                    remuns_par_type[remun.type_id] += montant_remun(remun)
+                else:
+                    remuns_par_type[remun.type_id] += (
+                        montant_remun(remun) * ((
+                            min(remun.date_fin or fin_annee, fin_annee) -
+                            max(remun.date_debut or debut_annee, debut_annee)
+                        ).days + 1) / jours_annee *
+                        dossier.regime_travail / 100
+                    ).quantize(TWOPLACES)
+            traitements = [
+                remuns_par_type[type.id]
+                for type in types_remun_par_nature[u'Traitement']
+            ]
+            indemnites = [
+                remuns_par_type[type.id]
+                for type in types_remun_par_nature[u'Indemnité']
+            ]
+            primes = [
+                remuns_par_type[type.id]
+                for type in types_remun_par_nature[u'Accessoire']
+            ]
+            charges = [
+                remuns_par_type[type.id]
+                for type in types_remun_par_nature[u'Charges']
+            ]
+            masse_salariale = sum(remuns_par_type.values())
+            masse_salariale_eur = (
+                masse_salariale * taux_change
+            ).quantize(TWOPLACES)
+            masse_salariale_totale += masse_salariale_eur
+
+            if dossier.valeur_point and dossier.classement \
+               and dossier.classement.coefficient and dossier.regime_travail:
+                salaire_theorique = (Decimal(str(
+                    dossier.valeur_point * dossier.classement.coefficient
+                )) * dossier.regime_travail / 100).quantize(TWOPLACES)
+            else:
+                salaire_theorique = None
+
+            lignes.append({
+                'dossier': dossier,
+                'poste': dossier.poste,
+                'date_debut': (
+                    dossier.date_debut
+                    if dossier.date_debut and dossier.date_debut.year == annee
+                    else None
+                ),
+                'date_fin': (
+                    dossier.date_fin
+                    if dossier.date_fin and dossier.date_fin.year == annee
+                    else None
+                ),
+                'jours': jours,
+                'devise': devise,
+                'valeur_point': dossier.valeur_point,
+                'valeur_point_devise': dossier.valeur_point_devise,
+                'regime_travail': dossier.regime_travail,
+                'local_expatrie': {
+                    'local': 'L', 'expat': 'E'
+                }.get(dossier.statut_residence),
+                'salaire_bstg': remuns_par_type[2],
+                'salaire_bstg_eur': (
+                    (remuns_par_type[2] * taux_change).quantize(TWOPLACES)
+                ),
+                'salaire_theorique': salaire_theorique,
+                'traitements': traitements,
+                'total_traitements': sum(traitements),
+                'indemnites': indemnites,
+                'total_indemnites': sum(indemnites),
+                'primes': primes,
+                'total_primes': sum(primes),
+                'charges': charges,
+                'total_charges': sum(charges),
+                'masse_salariale': masse_salariale,
+                'masse_salariale_eur': masse_salariale_eur,
+            })
+
+        # Récupérer les postes actifs pour déterminer le nombre de jours
+        # vacants.
+        postes = rh.Poste.objects.actifs(annee=annee) \
+                .select_related(
+                    'devise_max', 'valeur_point_max', 'classement_max'
+                ) \
+                .extra(
+                    tables=['rh_tauxchange'],
+                    where=[
+                        'rh_tauxchange.annee = %s',
+                        'rh_tauxchange.devise = rh_devise.id'
+                    ],
+                    params=[annee],
+                    select={
+                        'taux_change': 'rh_tauxchange.taux'
+                    }
+                )
+        if region:
+            postes = postes.filter(implantation__region=region)
+        if implantation:
+            postes = postes.filter(implantation=implantation)
+        postes = list(postes)
+        postes_par_id = dict((poste.id, poste) for poste in postes)
+        jours_vacants_date = dict(
+            (poste.id, max(today, poste.date_debut or today))
+            for poste in postes
+        )
+        jours_vacants = defaultdict(lambda: 0)
+        for dossier in rh.Dossier.objects.actifs(annee=annee) \
+                       .order_by('date_debut'):
+            if dossier.poste_id not in jours_vacants_date:
+                continue
+            derniere_date = jours_vacants_date[dossier.poste_id]
+            if dossier.date_debut is not None:
+                jours_vacants[dossier.poste_id] += max((
+                    dossier.date_debut - derniere_date
+                ).days - 1, 0)
+            jours_vacants_date[dossier.poste_id] = max(
+                min(dossier.date_fin or fin_annee, fin_annee),
+                derniere_date
+            )
+        for poste_id, derniere_date in jours_vacants_date.iteritems():
+            jours_vacants[poste_id] += max((
+                min(postes_par_id[poste_id].date_fin or fin_annee, fin_annee) -
+                derniere_date
+            ).days, 0)
+
+        # Ajouter les lignes des postes vacants au rapport
+        for poste_id, jours in jours_vacants.iteritems():
+            if jours == 0:
+                continue
+            poste = postes_par_id[poste_id]
+            if poste.valeur_point_max and poste.classement_max \
+               and poste.classement_max.coefficient and poste.regime_travail:
+                salaire_theorique = (Decimal(str(
+                    poste.valeur_point_max.valeur *
+                    poste.classement_max.coefficient
+                )) * poste.regime_travail / 100).quantize(TWOPLACES)
+            else:
+                salaire_theorique = None
+
+            local_expatrie = '/'.join(
+                (['L'] if poste.local else []) +
+                (['E'] if poste.expatrie else [])
+            )
+
+            salaire = (
+                poste.salaire_max * jours / jours_annee *
+                poste.regime_travail / 100
+            ).quantize(TWOPLACES)
+            indemnites = (
+                poste.indemn_max * jours / jours_annee *
+                poste.regime_travail / 100
+            ).quantize(TWOPLACES)
+            charges = (
+                poste.autre_max * jours / jours_annee *
+                poste.regime_travail / 100
+            ).quantize(TWOPLACES)
+            masse_salariale = salaire + indemnites + charges
+            masse_salariale_eur = (
+                masse_salariale * Decimal(str(poste.taux_change))
+            ).quantize(TWOPLACES)
+            masse_salariale_totale += masse_salariale_eur
+
+            lignes.append({
+                'poste': poste,
+                'regime_travail': poste.regime_travail,
+                'local_expatrie': local_expatrie,
+                'jours': jours,
+                'devise': poste.devise_max and poste.devise_max.code,
+                'valeur_point': (
+                    poste.valeur_point_max and poste.valeur_point_max.valeur
+                ),
+                'valeur_point_devise': (
+                    poste.valeur_point_max and \
+                    poste.valeur_point_max.devise.code
+                ),
+                'salaire_theorique': salaire_theorique,
+                'traitements': [0] * len(titres_traitements),
+                'total_traitements': salaire,
+                'indemnites': [0] * len(titres_indemnites),
+                'total_indemnites': indemnites,
+                'primes': [0] * len(titres_primes),
+                'total_primes': 0,
+                'charges': [0] * len(titres_charges),
+                'total_charges': charges,
+                'masse_salariale': masse_salariale,
+                'masse_salariale_eur': masse_salariale_eur
+            })
+        if 'ods' in request.GET:
+            doc = ods.masse_salariale(
+                lignes=lignes,
+                annee=annee,
+                titres_traitements=titres_traitements,
+                titres_indemnites=titres_indemnites,
+                titres_primes=titres_primes,
+                titres_charges=titres_charges,
+                masse_salariale_totale=masse_salariale_totale
+            )
+            response = HttpResponse(
+                mimetype='vnd.oasis.opendocument.spreadsheet'
+            )
+            response['Content-Disposition'] = 'filename=masse-salariale.ods'
+            doc.write(response)
+            return response
+        else:
+            return render(request, 'rh/rapports/masse_salariale.html', {
+                'form': form,
+                'titres_traitements': titres_traitements,
+                'titres_indemnites': titres_indemnites,
+                'titres_primes': titres_primes,
+                'titres_charges': titres_charges,
+                'masse_salariale_totale': masse_salariale_totale,
+                'lignes': lignes,
+                'annee': annee
+            })
+    return render(request, 'rh/rapports/masse_salariale.html', {
+        'form': form
+    })
+
+
+@login_required
+@drh_or_admin_required
 def rapports_postes_modelisation(request):
     c = {}
     data = []
@@ -359,6 +589,7 @@ def rapports_postes_service(request):
     c['data'] = data
     return render(request, 'rh/rapports/postes_service.html', c)
 
+
 @region_protected(rh.Dossier)
 def dossier_apercu(request, dossier_id):
     d = get_object_or_404(rh.Dossier, pk=dossier_id)
@@ -429,7 +660,6 @@ def employe_apercu(request, employe_id):
 @login_required
 @drh_or_admin_required
 def organigrammes_employe(request, id, level="all"):
-
     poste = get_object_or_404(rh.Poste, pk=id)
     dossiers_by_poste = dict(
         (d.poste_id, d)
@@ -511,7 +741,6 @@ def organigrammes_employe(request, id, level="all"):
 @login_required
 @drh_or_admin_required
 def organigrammes_service(request, id):
-
     service = get_object_or_404(rh.Service, pk=id)
     svg = rh_graph.organigramme_postes_cluster( \
             cluster_filter={"service": service}, \
@@ -522,7 +751,7 @@ def organigrammes_service(request, id):
         'svg': svg
     }
 
-    return render(request, 'rh/organigrammes/vide.html', c, 
+    return render(request, 'rh/organigrammes/vide.html', c,
         content_type="image/svg+xml"
     )
 
@@ -530,7 +759,6 @@ def organigrammes_service(request, id):
 @login_required
 @drh_or_admin_required
 def organigrammes_implantation(request, id):
-
     implantation = get_object_or_404(ref.Implantation, pk=id)
     svg = rh_graph.organigramme_postes_cluster( \
             cluster_filter={"implantation": implantation}, \
@@ -541,7 +769,7 @@ def organigrammes_implantation(request, id):
         'svg': svg
     }
 
-    return render(request, 'rh/organigrammes/vide.html', c, 
+    return render(request, 'rh/organigrammes/vide.html', c,
         content_type="image/svg+xml"
     )
 
@@ -549,7 +777,6 @@ def organigrammes_implantation(request, id):
 @login_required
 @drh_or_admin_required
 def organigrammes_region(request, id):
-
     region = get_object_or_404(ref.Region, pk=id)
     svg = rh_graph.organigramme_postes_cluster( \
             cluster_filter={"implantation__region": region}, \
@@ -560,7 +787,7 @@ def organigrammes_region(request, id):
         'svg': svg
     }
 
-    return render(request, 
-        'rh/organigrammes/vide.html', c, 
+    return render(request,
+        'rh/organigrammes/vide.html', c,
         content_type="image/svg+xml"
     )
index 5d2527f..ef0a311 100644 (file)
@@ -16,18 +16,15 @@ ADMINS = (
 MANAGERS = ADMINS
 
 TIME_ZONE = 'America/Montreal'
+LANGUAGE_CODE = 'fr'
+FORMAT_MODULE_PATH = 'project.formats'
+USE_L10N = True
+USE_THOUSAND_SEPARATOR = True
 DATE_FORMAT = 'd-m-Y'
-DATE_INPUT_FORMATS = (
-    '%d-%m-%Y', '%d/%m/%Y', '%d %m %Y',
-    '%d-%m-%y', '%d/%m/%y', '%d %m %y',
-)
 
 SESSION_SAVE_EVERY_REQUEST = True
 SESSION_EXPIRE_AT_BROWSER_CLOSE = True
 
-SHORT_DATE_FORMAT = 'd-m-Y'
-LANGUAGE_CODE = 'fr-ca'
-
 # Absolute path to the directory that holds media.
 # Example: "/home/media/media.lawrence.com/"
 MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media')
@@ -36,8 +33,6 @@ PRIVE_MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media_prive')
 STATICFILES_DIRS = (
     os.path.join(os.path.dirname(__file__), 'assets'),
 )
-
-
 STATIC_ROOT = os.path.join(os.path.dirname(__file__), 'static')
 STATIC_URL = '/static/'
 
@@ -79,11 +74,12 @@ INSTALLED_APPS = (
     'admin_tools.theming',
     'admin_tools.menu',
     'admin_tools.dashboard',
+    'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
+    'django.contrib.humanize',
     'django.contrib.messages',
     'django.contrib.sessions',
-    'django.contrib.admin',
     'django.contrib.staticfiles',
     'django_qbe',
     'ajax_select',
index cb63f0e..63272ae 100644 (file)
@@ -11,7 +11,6 @@ django-urldecorators = 0.3
 auf.django.auth = 0.5.5dev
 auf.django.metadata = 0.6dev
 auf.django.permissions = 0.1
-auf.django.references = 0.11
 auf.django.skin = 1.5
 auf.django.workflow = 0.15dev
 odfpy = 0.9.4
@@ -62,3 +61,9 @@ django-picklefield = 0.2.1
 
 # Added by Buildout Versions at 2012-06-08 11:15:52.545562
 auf.django.emploi = 1.2dev
+
+# Added by Buildout Versions at 2012-06-15 14:24:42.911205
+odsgen = 0.1
+
+# Added by Buildout Versions at 2012-06-18 15:34:10.516016
+auf.django.references = 0.19