# -*- encoding: utf-8 -*-
-from django.contrib import admin
from django import forms
+
+from django.core.urlresolvers import reverse
+from django.core.mail import mail_admins
+from django.contrib import admin
+from django.contrib import messages
+from django.shortcuts import redirect
from reversion.admin import VersionAdmin
from auf.django.workflow.models import WorkflowCommentaire
-from models import Poste, Dossier
+from models import Poste, Dossier, DossierFinalise, PosteFinalise
class PosteAdmin(VersionAdmin):
list_display = ('nom', 'implantation', 'etat', )
return obj.poste.implantation
-
class PosteStatutAdmin(StatutAdmin):
search_fields = ('nom', )
list_display = ('nom', 'implantation', '_etat', )
form = StatutPosteForm
+class ImportAdmin(admin.ModelAdmin,):
+
+ def has_delete_permission(self, request, obj=None):
+ return False
+
+ def has_add_permission(self, request):
+ return False
+
+ def has_change_permission(self, request, obj=None):
+ if obj is None:
+ return True
+ else:
+ return False
+
+ def get_actions(self, request):
+ actions = super(ImportAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
+
+
+class ImportDossierAdmin(ImportAdmin):
+ list_display = ('_poste', '_employe', '_dae', )
+ actions = ['importer_dans_RH', ]
+
+ def _employe(self, obj):
+ return obj.employe
+
+ def _poste(self, obj):
+ rh = obj.poste.rh_importation()
+ if rh is not None:
+ extra = u"<a href='%s' style='color: red;'> (déjà importé)</a>" % \
+ reverse('admin:rh_poste_change', args=(rh.id,))
+ else:
+ extra = u""
+
+ return u"%s%s" % (obj.poste.nom, extra)
+ _poste.allow_tags = True
+
+
+
+ def _dae(self, obj):
+ url = reverse('embauche_consulter', args=(obj.id, ))
+ return "<a href='%s'>voir la DAE</a>" % url
+ _dae.allow_tags = True
+
+ def importer_dans_RH(self, request, data):
+ selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
+ dae = [d for d in Dossier.objects.filter(id__in=selected)]
+ for d in dae:
+ try:
+ d.importer(dry_run=True)
+ copie = d.importer()
+ messages.add_message(request, messages.SUCCESS, u"%s importé dans\
+ RH" % d)
+ url = reverse('admin:rh_dossier_change', args=(copie.id, ))
+ except Exception, e:
+ mail_admins('DAE import', unicode(e))
+ messages.add_message(request, messages.ERROR, u"%s ne peut pas\
+ être importé" % d)
+ url = reverse('admin:dae_dossierfinalise_changelist')
+ return redirect(url)
+
+
+class ImportPosteAdmin(ImportAdmin):
+ list_display = ('nom', '_implantation', '_dae', )
+ actions = ['importer_dans_RH', ]
+
+ def _implantation(self, obj):
+ return obj.implantation
+
+ def _dae(self, obj):
+ url = reverse('poste_consulter', args=(obj.id, ))
+ return "<a href='%s'>voir le poste dans DAE</a>" % url
+ _dae.allow_tags = True
+
+ def importer_dans_RH(self, request, data):
+ selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
+ dae = [d for d in Poste.objects.filter(id__in=selected)]
+ for p in dae:
+ try:
+ p.importer(dry_run=True)
+ copie = p.importer()
+ messages.add_message(request, messages.SUCCESS, u"%s importé dans\
+ RH" % d)
+ url = reverse('admin:rh_poste_change', args=(copie.id, ))
+ except Exception, e:
+ mail_admins('DAE import', unicode(e))
+ messages.add_message(request, messages.ERROR, u"%s ne peut pas\
+ être importé" % p)
+ url = reverse('admin:dae_postefinalise_changelist')
+ return redirect(url)
+
+
admin.site.register(Poste, PosteAdmin)
admin.site.register(Dossier, DossierAdmin)
admin.site.register(ProxyDossierStatut, DossierStatutAdmin)
admin.site.register(ProxyPosteStatut, PosteStatutAdmin)
+admin.site.register(DossierFinalise, ImportDossierAdmin)
+admin.site.register(PosteFinalise, ImportPosteAdmin)
--- /dev/null
+# -*- coding: utf-8 -*-
+
+import sys
+import codecs
+import os
+import shutil
+
+from django.conf import settings
+from project.rh import models as rh
+import models as dae
+
+SKIP = "** SKIP **"
+
+class SuperCopier(object):
+ """
+ Classe abstraite pour faire de la copie profonde sur des objets en BD.
+ Elle prévoit des hooks pour traiter des propriétés en particulier.
+ """
+ dry_run = True
+ verbosity = 0
+ stdout = codecs.getwriter('utf8')(sys.stdout)
+
+ def __init__(self, dry_run=True, verbosity=0):
+ self.verbosity = verbosity
+ self.dry_run = dry_run
+
+ def out(self, txt, level=0):
+ if self.verbosity >= level:
+ self.stdout.write(txt)
+
+ def clean_id(self, source, copy, parent, field, value):
+ self.out(SKIP, 2)
+ return []
+
+ def parent(self, parent, child):
+ if not self.dry_run:
+ parent.save()
+ klass = parent.__class__.__name__.lower()
+ k = "%s_id" % klass
+ setattr(child, k, parent.id)
+
+ def duplicate(self, obj, parent=None, level=0):
+ klass = getattr(rh, obj.__class__.__name__)
+ copy = klass()
+
+ indent = " "*level*4
+ self.out(u"\n%s [%s] %s" % (indent, str(obj.__class__),
+ obj), 1)
+
+ for f in obj._meta.fields:
+ value = getattr(obj, f.name)
+
+ self.out(u"\n%s * %s: %s " % (indent, f.name, value), 2)
+
+ cleanup_fct = "clean_%s" % f.name
+ if hasattr(self, cleanup_fct):
+ cleaner = getattr(self, cleanup_fct)
+ cleaner(obj, copy, parent, f, value)
+ else:
+ setattr(copy, f.name, value)
+
+ for obj_composition in obj._meta._related_objects_cache:
+ app_label, dummy = obj_composition.name.split(':')
+ field_name = obj_composition.field.rel.related_name
+ if field_name == '+':
+ continue
+ self.out(u"\n%s + [%s] %s " % (indent, app_label, field_name), 1)
+ try:
+ cleanup_fct = "clean_%s" % field_name
+ if hasattr(self, cleanup_fct):
+ cleaner = getattr(self, cleanup_fct)
+ children = cleaner(obj, copy, parent, f, value)
+ else:
+ children = getattr(obj, field_name).all()
+ except Exception, e:
+ # no reverse relation
+ self.out(" %s %s" % (field_name, str(e)), 1)
+ continue
+
+ for child in children:
+ child_copy = self.duplicate(child, parent=copy, level=level+1,)
+ parentship_fct = "parent_%s" % (field_name)
+ if hasattr(self,parentship_fct):
+ parentship = getattr(self, parentship_fct)
+ else:
+ parentship = getattr(self, "parent")
+ parentship(copy, child_copy)
+ if not self.dry_run:
+ child_copy.save()
+
+ return copy
+
+ def copy(self, obj):
+ return self.duplicate(obj)
+
+
+class PosteCopier(SuperCopier):
+
+ def copy(self, obj):
+ copy = super(PosteCopier, self).copy(obj)
+ if not self.dry_run:
+ dae.ImportPoste(dae=obj, rh=copy).save()
+ return copy
+
+ def clean_rh_dossiers(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_comparaisons_internes(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_financements(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_pieces(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_dae_dossiers(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_poste(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_fichier(self, source, copy, parent, field, value):
+ if not self.dry_run and parent.id is None:
+ parent.save()
+ filename = value.path.split('/')[-1]
+ copy.poste_id = parent.id
+ new_value = rh.poste_piece_dispatch(copy, filename)
+
+ app, model, id, f = new_value.split('/')
+ app_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app)
+ model_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app, model)
+ id_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app, model, id)
+ if not os.path.exists(app_path):
+ os.mkdir(app_path)
+ if not os.path.exists(model_path):
+ os.mkdir(model_path)
+ if not os.path.exists(id_path):
+ os.mkdir(id_path)
+ src = value.path
+ dst = os.path.join(settings.PRIVE_MEDIA_ROOT, new_value)
+ shutil.copy(src, dst)
+ setattr(copy, field.name, new_value)
+
+
+class DossierCopier(SuperCopier):
+
+ def copy(self, obj):
+ copy = super(DossierCopier, self).copy(obj)
+ if not self.dry_run:
+ dae.ImportDossier(dae=obj, rh=copy).save()
+ return copy
+
+ def clean_rh_contrats(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_dossierpieces(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_comparaisons(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_rh_remunerations(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+ def clean_dossier(self, source, copy, parent, field, value):
+ self.out(SKIP, 1)
+ return []
+
+
+ def clean_employe(self, source, copy, parent, field, value):
+ if source.employe.id_rh is not None:
+ copy.employe = source.employe.id_rh
+ else:
+ nouvel_employe = rh.Employe()
+ nouvel_employe.nom = source.employe.nom
+ nouvel_employe.prenom = source.employe.prenom
+ nouvel_employe.genre = source.employe.genre
+ nouvel_employe.save()
+ copy.employe = nouvel_employe
+
+ def clean_poste(self, source, copy, parent, field, value):
+ # poste comparaison a un champs nommé poste
+ if isinstance(value, unicode):
+ setattr(copy, field.name, value)
+ return
+
+ if dae.ImportPoste.objects.filter(dae=value).exists():
+ poste = dae.ImportPoste.objects.get(dae=value).rh
+ else:
+ copier = PosteCopier(verbosity=self.verbosity,
+ dry_run=self.dry_run)
+ poste = copier.copy(value)
+ copy.poste_id = poste.id
+
+ def clean_fichier(self, source, copy, parent, field, value):
+ if not self.dry_run and parent.id is None:
+ parent.save()
+ filename = value.path.split('/')[-1]
+ copy.dossier_id = parent.id
+
+ ct = copy.__class__.__name__.lower()
+ if ct == 'contrat':
+ new_value = rh.contrat_dispatch(copy, filename)
+ elif ct == 'dossierpiece':
+ new_value = rh.dossier_piece_dispatch(copy, filename)
+ else:
+ raise Exception('fichier %s à mapper!' % ct)
+
+ app, model, id, f = new_value.split('/')
+ app_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app)
+ model_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app, model)
+ id_path = os.path.join(settings.PRIVE_MEDIA_ROOT, app, model, id)
+ if not os.path.exists(app_path):
+ os.mkdir(app_path)
+ if not os.path.exists(model_path):
+ os.mkdir(model_path)
+ if not os.path.exists(id_path):
+ os.mkdir(id_path)
+ src = value.path
+ dst = os.path.join(settings.PRIVE_MEDIA_ROOT, new_value)
+ shutil.copy(src, dst)
+ setattr(copy, field.name, new_value)
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from django.core.management.base import BaseCommand
+
+from project.dae import models as dae
+
+class Command(BaseCommand):
+
+
+ def handle(self, *args, **options):
+
+ if len(args) < 2:
+ print len(args)
+ self.stdout.write("dae <modele> <id> <run>\n")
+ return
+
+ classname = args[0]
+ klass = getattr(dae, classname, None)
+ if klass is None:
+ self.stdout.write("Le modèle %s n'existe pas dans DAE.\n" % classname)
+
+ id = int(args[1])
+ try:
+ obj = klass.objects.get(id=id)
+ except:
+ self.stdout.write("L'id %s n'existe pas pour le modèle %s dans DAE.\n" % \
+ (id, classname))
+ return
+
+
+ copy = obj.importer()
+ self.stdout.write(u"\n[%s] DAE:%s => RH:%s\n" %
+ (obj.__class__.__name__, obj.id, copy.id))
+
from django.db import models
from django.db.models import Q
from utils import get_employe_from_user
-from workflow import MAP_GROUPE_ETATS_A_FAIRE
-from workflow import dae_groupes, \
- grp_administrateurs, \
- grp_directeurs_bureau, \
- grp_drh, \
+from workflow import MAP_GROUPE_ETATS_A_FAIRE, DOSSIER_ETAT_FINALISE, \
+ POSTE_ETAT_FINALISE
+from workflow import grp_drh, \
grp_drh2, \
grp_accior, \
grp_abf, \
grp_haute_direction, \
- grp_service_utilisateurs, \
- grp_correspondants_rh
+ grp_service_utilisateurs
from rh.managers import DossierManager as RHDossierManager
from rh.managers import PosteManager as RHPosteManager
class DossierComparaisonManager(RHDossierComparaisonManager, TodoManagerMixin):
pass
+class DossierFinaliseManager(models.Manager):
+ """
+ Dossiers finalisés, qui ne sont pas encore importés
+ """
+ def get_query_set(self):
+ from dae.models import ImportDossier
+ dae_importees = [str(i.dae_id) for i in ImportDossier.objects.all()]
+ qs = super(DossierFinaliseManager, self).get_query_set().filter(etat=DOSSIER_ETAT_FINALISE,)
+ if len(dae_importees) > 0:
+ qs = qs.extra(where=['id NOT IN (%s)' % ", ".join(dae_importees)])
+ return qs
+
+
+class PosteFinaliseManager(models.Manager):
+ """
+ Dossiers finalisés, qui ne sont pas encore importés
+ """
+ def get_query_set(self):
+ from dae.models import ImportPoste
+ dae_importees = [str(i.dae_id) for i in ImportPoste.objects.all()]
+
+ qs = super(PosteFinaliseManager, self).get_query_set().filter(etat=POSTE_ETAT_FINALISE,)
+ if len(dae_importees) > 0:
+ qs = qs.extra(where=['id NOT IN (%s)' % ", ".join(dae_importees)])
+ return qs
+
+
from auf.django.metadata.models import AUFMetadata
from managers import *
from rh.models import HELP_TEXT_DATE
-
+from exporter import DossierCopier, PosteCopier
# Upload de fichiers
UPLOAD_STORAGE = FileSystemStorage(settings.PRIVE_MEDIA_ROOT)
# Managers
objects = PosteManager()
-
- def est_importe(self):
- """Test si le poste a déjà été importé"""
- return ImportPoste.objects.filter(dae=self).exists()
-
- def importer(self):
- from django.db.models import AutoField
- if self.est_importe():
- return ImportPoste.objects.get(dae=self)
- rh_poste = rh.Poste()
- # Faire une copie profonde de l'objet.
- # PosteFinancement, PosteComparaison, Remun modele a ajuster...
-
- def copy_model(src, dst, exclude=[]):
- keys = [f.name for f in src._meta.fields if f.name not in ['id', ] + exclude]
- for k in keys:
- setattr(dst, k, getattr(src, k))
- return dst
-
- rh_poste = copy_model(self, rh_poste)
- rh_poste.save()
- print rh_poste.id
-
- for o in self.dae_financements.all():
- rh_financement = rh.PosteFinancement()
- rh_financement = copy_model(o, rh_financement, exclude=['poste',])
- rh_financement.poste = rh_poste
- rh_financement.save()
-
- for o in self.dae_pieces.all():
- rh_piece = rh.PostePiece()
- rh_piece = copy_model(o, rh_piece, exclude=['poste',])
- rh_piece.poste = rh_poste
- rh_piece.save()
-
- for o in self.dae_comparaisons_internes.all():
- rh_comp = rh.PosteComparaison()
- rh_comp = copy_model(o, rh_financement, exclude=['poste',])
- rh_comp.poste = rh_poste
- rh_comp.save()
-
- return rh_poste
-
def _get_key(self):
"""
Les vues sont montées selon une clef spéciale
return []
return self.id_rh.rh_dossiers.all()
+ def rh_importation(self):
+ if ImportPoste.objects.filter(dae=self).exists():
+ return ImportPoste.objects.get(dae=self).rh
+ else:
+ return None
+
+ def importer(self, verbosity=0, dry_run=False):
+ copieur = PosteCopier(verbosity=verbosity, dry_run=dry_run)
+ return copieur.copy(self)
def get_employe(self):
"""
def __unicode__(self):
return u'[%s] %s - %s' % (self.poste.implantation, self.poste.nom, self.employe)
- def est_importe(self):
- """Test si le dossier a déjà été importé"""
- return dae.ImportDossier.objects.filter(dae=self).exists()
-
- def importer(self):
- if not self.poste.est_importe():
- raise Exception('Le poste de cette DAE doît être importé')
- return True
+ def importer(self, verbosity=0, dry_run=False):
+ copieur = DossierCopier(verbosity=verbosity, dry_run=dry_run)
+ return copieur.copy(self)
def get_salaire_anterieur_euros(self):
if self.devise_anterieur is None:
class Contrat(rh.Contrat_):
pass
+
+class DossierFinalise(Dossier):
+
+ objects = DossierFinaliseManager()
+
+ class Meta:
+ proxy = True
+ verbose_name = "Import d'un dossier finalisé"
+ verbose_name_plural = "Import des dossiers finalisés"
+
+class PosteFinalise(Poste):
+
+ objects = PosteFinaliseManager()
+
+ class Meta:
+ proxy = True
+ verbose_name = "Import d'un poste finalisé"
+ verbose_name_plural = "Import des postes finalisés"
+
# modèle de liaison entre les systèmes
class ImportDossier(models.Model):
AUF_METADATA_READONLY_FIELDS
from forms import ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect, \
DossierForm
+from dae import models as dae
from dae.utils import get_employe_from_user
from change_list import ChangeList
from groups import grp_correspondants_rh
'_date_fin',
'_date_modification',
'user_modification',
+ '_dae',
)
list_display_links = ('_nom',)
list_filter = (
_apercu.allow_tags = True
_apercu.short_description = u""
+ def _dae(self, d):
+ apercu_link = ""
+ if dae.ImportDossier.objects.filter(rh=d).exists():
+ dae_id = dae.ImportDossier.objects.get(rh=d).dae_id
+ 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=(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_fin',
'_date_modification',
'user_modification',
+ '_dae',
)
list_filter = (
'implantation__region',
_apercu.allow_tags = True
_apercu.short_description = ''
+ def _dae(self, poste):
+ apercu_link = ""
+ if dae.ImportPoste.objects.filter(rh=poste).exists():
+ dae_id = dae.ImportPoste.objects.get(rh=poste).dae_id
+ apercu_link = u"""<a title="Aperçu du dossier"
+ onclick="return showAddAnotherPopup(this);"
+ href='%s'>
+ <img src="%simg/loupe.png" />
+ </a>""" % \
+ (reverse('poste_consulter', args=("dae-%s" % dae_id,)),
+ settings.STATIC_URL,
+ )
+ return apercu_link
+ _dae.allow_tags = True
+ _dae.short_description = u"DAE"
+
def _id(self, obj):
return "%s" % obj.id
_id.short_description = '#'
class Meta:
abstract = True
+ def __unicode__(self):
+ return "%s (%s)" % (self.poste, self.personne)
+
class DossierComparaison(DossierComparaison_):
pass