.*.swp
*~
\#*#
-src/*
+# src/*
# DB de dev
*.db
# extra
project/media_prive/*
+src/auf.django.emploi/auf/django/emploi/media_prive/*
http://pypi.auf.org/simple/auf.django.metadata/
http://pypi.auf.org/django-alphafilter/
+develop = src/auf.django.emploi
+
eggs =
django
south
auf.django.skin
auf.django.workflow
auf.django.admingroup
+ auf.django.emploi
datamaster_modeles
auf.django.auth
django-reversion
class Meta:
model = dae.Remuneration
+ def clean_devise(self):
+ devise = self.cleaned_data['devise']
+ liste_taux = devise.tauxchange_set.order_by('-annee').filter(implantation=self.instance.dossier.poste.implantation)
+ if len(liste_taux) == 0:
+ raise forms.ValidationError(u"La devise %s n'a pas de taux pour l'implantation %s" % (devise, self.instance.dossier.poste.implantation))
+ else:
+ return devise
+
+
class RemunForm(inlineformset_factory(dae.Dossier, dae.Remuneration, extra=5, form=FlexibleRemunForm)):
pass
def get_salaire_euros(self):
try:
- tx = rh.TauxChange.objects.filter(implantation=self.poste.implantation, devise=self.devise)[0].taux
+ tx = self.devise.tauxchange_set.order_by('-annee').filter(implantation=self.poste.implantation)[0].taux
except:
- tx = 1
+ tx = 0
return (float)(tx) * (float)(self.salaire)
def get_remunerations_brutes(self):
return round(self.montant / 12, 2)
def taux_devise(self):
- return self.devise.tauxchange_set.order_by('-annee').all()[0].taux
+ liste_taux = self.devise.tauxchange_set.order_by('-annee').filter(implantation=self.dossier.poste.implantation)
+ if len(liste_taux) == 0:
+ raise Exception(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise, self.dossier.poste.implantation))
+ else:
+ return liste_taux[0].taux
def montant_euro(self):
return round(float(self.montant) * float(self.taux_devise()), 2)
from django.http import HttpResponseRedirect
from django.contrib import admin
from django.shortcuts import get_object_or_404
+from django.core.files.storage import default_storage
from reversion.admin import VersionAdmin
from datamaster_modeles.models import Employe, Implantation, Region
+from django.forms.models import BaseInlineFormSet
+from project.rh import models as rh
from recrutement.models import *
from recrutement.workflow import grp_administrateurs_recrutement,\
grp_evaluateurs_recrutement, grp_drh_recrutement
+from recrutement.forms import *
+
+"""
+class MetaAdmin(VersionAdmin):
+ def get_actions(self, request):
+
+Pour refactoring
+"""
+
+class ProxyEvaluateur(Evaluateur.offres_emploi.through):
+ """
+ Ce proxy sert uniquement dans l'admin à disposer d'un libellé
+ plus ergonomique.
+ """
+ class Meta:
+ proxy = True
+ verbose_name = "évaluateur"
+
+class EvaluateurInline(admin.TabularInline):
+ model = ProxyEvaluateur
+ fields = ('evaluateur',)
+ extra = 1
class OffreEmploiAdmin(VersionAdmin):
date_hierarchy = 'date_creation'
list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
- 'est_affiche', '_candidatsList')
+ 'est_affiche', '_candidatsList', )
+ exclude = ('poste_nom',)
list_filter = ('statut', 'est_affiche', )
actions = ['affecter_evaluateurs_offre_emploi', ]
+ form = OffreEmploiForm
+ inlines = [EvaluateurInline, ]
+
+ def get_actions(self, request):
+ actions = super(OffreEmploiAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
+
# Affecter un évaluateurs à des offres d'emploi
def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
_candidatsList.allow_tags = True
_candidatsList.short_description = "Afficher la liste des candidats"
-
def queryset(self, request):
qs = self.model._default_manager.get_query_set()
# Si user est superuser afficher toutes les offres d'emploi
user_groupes = request.user.groups.all()
- if not grp_drh_recrutement in user_groupes:
+ if not grp_drh_recrutement in user_groupes and \
+ not request.user.is_superuser:
"""
Si le user n'est ni un évaluateur ni un administrateur régional,
retourner none
def has_change_permission(self, request, obj=None):
user_groupes = request.user.groups.all()
if grp_drh_recrutement in user_groupes or \
- grp_administrateurs_recrutement in user_groupes:
+ grp_administrateurs_recrutement in user_groupes or \
+ request.user.is_superuser:
return True
return False
class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
'est_affiche')
- readonly_fields = ('description', 'poste', 'bureau',
+ readonly_fields = ('description', 'bureau',
'duree_affectation', 'renumeration',
'debut_affectation', 'lieu_affectation', 'nom',
'resume', 'date_limite', 'region')
'fields': ('nom', )
}),
('Description générale', {
- 'fields': ('poste', 'resume','description', 'date_limite', )
+ 'fields': ('resume','description', 'date_limite', )
}),
('Coordonnées', {
'fields': ('lieu_affectation', 'bureau', 'region', )
'renumeration', )
}),
)
+
+ def get_actions(self, request):
+ actions = super(ProxyOffreEmploiAdmin, self).get_actions(request)
+ del actions['affecter_evaluateurs_offre_emploi']
+ return actions
+
+ def response_change(self, request, obj):
+ response = super(ProxyOffreEmploiAdmin, self).response_change(request, obj)
+ user_groupes = request.user.groups.all()
+ if grp_drh_recrutement in user_groupes or \
+ request.user.is_superuser:
+ return HttpResponseRedirect(reverse('admin:recrutement_offreemploi_changelist'))
+ return HttpResponseRedirect(reverse('admin:recrutement_proxyoffreemploi_changelist'))
+
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
user_groupes = request.user.groups.all()
if grp_evaluateurs_recrutement in user_groupes or \
- grp_drh_recrutement in user_groupes:
+ grp_drh_recrutement in user_groupes or \
+ request.user.is_superuser:
return True
return False
-class ProxyCandidatPiece(CandidatPiece):
- """
- Ce proxy sert uniquement dans l'admin à disposer d'un libellé
- plus ergonomique.
- """
- class Meta:
- proxy = True
- verbose_name = "pièce jointe"
- verbose_name_plural = "pièces jointes"
-
class CandidatPieceInline(admin.TabularInline):
- model = ProxyCandidatPiece
- fields = ('candidat', 'nom', 'path', )
+ model = CandidatPiece
+ fields = ('candidat', 'nom', 'path',)
extra = 1
+ max_num = 3
-class ProxyEvaluateur(Evaluateur.candidats.through):
+class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
"""
- Ce proxy sert uniquement dans l'admin à disposer d'un libellé
- plus ergonomique.
+ Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
"""
- class Meta:
- proxy = True
- verbose_name = "évaluateur"
-
-class EvaluateurInline(admin.TabularInline):
- model = ProxyEvaluateur
- fields = ('evaluateur',)
- extra = 1
+ def __init__(self, *args, **kwargs):
+ super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
+ self.can_delete = False
+
+class CandidatEvaluationInline(admin.TabularInline):
+ model = CandidatEvaluation
+ fields = ('evaluateur', 'note', 'commentaire')
+ max_num = 0
+ extra = 0
+ formset = CandidatEvaluationInlineFormSet
+
+ def get_readonly_fields(self, request, obj=None):
+ """
+ Empêche la modification des évaluations
+ """
+ if obj:
+ return self.readonly_fields+('evaluateur', 'note', 'commentaire')
+ return self.readonly_fields
class CandidatAdmin(VersionAdmin):
date_hierarchy = 'date_creation'
)
inlines = [
CandidatPieceInline,
- EvaluateurInline,
+ CandidatEvaluationInline,
]
- actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
- # Affecter un évaluateurs à des candidats
- def affecter_candidats_evaluateur(modeladmin, obj, candidats):
- selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
+ actions = ['envoyer_courriel_candidats']
- return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
- "?ids=%s" % (",".join(selected)))
- affecter_candidats_evaluateur.short_description = u'Affecter évaluateur(s)'
+ def get_actions(self, request):
+ actions = super(CandidatAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
# Envoyer un courriel à des candidats
def envoyer_courriel_candidats(modeladmin, obj, candidats):
return "<a href='%s'>Voir le candidat</a>" % \
(reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
afficher_candidat.allow_tags = True
- afficher_candidat.short_description = u'Afficher les détails du candidat'
+ afficher_candidat.short_description = u'Détails du candidat'
# Voir l'offre d'emploi
def voir_offre_emploi(self, obj):
def add_delete_permission(self, request, obj=None) :
user_groupes = request.user.groups.all()
if grp_drh_recrutement in user_groupes or \
- grp_administrateurs_recrutement in user_groupes:
+ grp_administrateurs_recrutement in user_groupes or \
+ request.user.is_superuser:
return True
return False
def has_change_permission(self, request, obj=None):
user_groupes = request.user.groups.all()
if grp_drh_recrutement in user_groupes or \
- grp_administrateurs_recrutement in user_groupes:
+ grp_administrateurs_recrutement in user_groupes or \
+ request.user.is_superuser:
return True
return False
- def queryset(self, obj):
+ def queryset(self, request):
"""
Spécifie un queryset limité, autrement Django exécute un
select_related() sans paramètre, ce qui a pour effet de charger tous
"""
qs = self.model._default_manager.get_query_set()
# Si user est superuser afficher tous les candidats
- user_groupes = obj.user.groups.all()
- if not grp_drh_recrutement in user_groupes:
+ user_groupes = request.user.groups.all()
+ if not grp_drh_recrutement in user_groupes and \
+ not request.user.is_superuser:
# Si le user n'est ni un évaluateur ni un administrateur régional,
# retourner none
# Vérifier groupes
if grp_evaluateurs_recrutement in user_groupes:
try:
- user = Evaluateur.objects.get(user=obj.user)
+ user = Evaluateur.objects.get(user=request.user)
except Evaluateur.DoesNotExist:
return qs.none()
"""
'nombre_dependant', 'telephone', 'email', 'adresse',
'ville', 'etat_province', 'code_postal', 'pays',
'niveau_diplome', 'employeur_actuel', 'poste_actuel',
- 'domaine_professionnel',)
+ 'domaine_professionnel', 'pieces_jointes',)
fieldsets = (
("Offre d'emploi", {
'fields': ('offre_emploi', )
('Informations professionnelles', {
'fields': ('niveau_diplome','employeur_actuel',
'poste_actuel', 'domaine_professionnel',)
- }),
+ }),
)
inlines = []
+ def response_change(self, request, obj):
+ response = super(ProxyCandidatAdmin, self).response_change(request, obj)
+ user_groupes = request.user.groups.all()
+ if grp_drh_recrutement in user_groupes or \
+ request.user.is_superuser:
+ return HttpResponseRedirect(reverse('admin:recrutement_candidat_changelist'))
+ return HttpResponseRedirect(reverse('admin:recrutement_proxycandidat_changelist'))
+
def has_add_permission(self, request):
return False
user_groupes = request.user.groups.all()
if grp_drh_recrutement in user_groupes or \
grp_administrateurs_recrutement in user_groupes or \
- grp_evaluateurs_recrutement in user_groupes:
+ grp_evaluateurs_recrutement in user_groupes or \
+ request.user.is_superuser:
return True
return False
class EvaluateurAdmin(VersionAdmin):
fieldsets = (
- (None, {'fields': ('user', )}),
- #(None, {'fields': ('candidats',)}),
+ ("Utilisateur", {
+ 'fields': ('user',)
+ }),
+ ("Offres d'emploi à évaluer", {
+ 'fields': ('offres_emploi',)
+ }),
)
+ def get_actions(self, request):
+ actions = super(EvaluateurAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
+
class AdministrateurRegionalAdmin(VersionAdmin):
pass
class CandidatEvaluationAdmin(VersionAdmin):
- list_display = ('_offre_emploi', '_candidat', 'evaluateur', '_note',
+ list_display = ('_candidat', '_offre_emploi', 'evaluateur', '_note',
'_commentaire', )
readonly_fields = ('candidat', 'evaluateur')
fieldsets = (
}),
)
+ def get_actions(self, request):
+ actions = super(CandidatEvaluationAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
+
def _note(self, obj):
"""
Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
_offre_emploi.allow_tags = True
_offre_emploi.short_description = "Voir offre d'emploi"
- _offre_emploi.admin_order_field = 'offre_emploi'
def has_change_permission(self, request, obj=None):
"""
"""
qs = self.model._default_manager.get_query_set()
user_groupes = request.user.groups.all()
- if grp_drh_recrutement in user_groupes:
+ if grp_drh_recrutement in user_groupes or \
+ request.user.is_superuser:
return qs.select_related('offre_emploi')
try:
filter(id__in=candidats_evaluations_ids)
class CourrielTemplateAdmin(VersionAdmin):
- pass
+ def get_actions(self, request):
+ actions = super(CourrielTemplateAdmin, self).get_actions(request)
+ del actions['delete_selected']
+ return actions
admin.site.register(OffreEmploi, OffreEmploiAdmin)
admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
--- /dev/null
+# -*- encoding: utf-8 -*
+from django.http import HttpResponse
+from django.template import RequestContext, Template
+from django.shortcuts import render_to_response, redirect, get_object_or_404
+from django.utils import simplejson
+from django.contrib import messages
+
+from auf.django.emploi import models as emploi
+from auf.django.emploi import forms as emploiForms
+from project.recrutement.models import Evaluateur, CandidatEvaluation, \
+ CourrielTemplate
+from project.recrutement.views import *
+
+STATUS_OK = 200
+
+STATUS_ERROR = 400
+STATUS_ERROR_NOT_FOUND = 404
+STATUS_ERROR_PERMISSIONS = 403
+STATUS_ERROR_BADMETHOD = 405
+
+def api(request, method):
+ # TODO: Sécurité :
+ # L'échange d'information doit être possible qu'avec les HOST désirés.
+
+ #if request.method != 'POST':
+ # return api_return(STATUS_ERROR_BADMETHOD)
+
+ api = API(request)
+ if hasattr(api, 'api_%s' % method):
+ return getattr(api, 'api_%s' % method)()
+
+ return api_return(STATUS_ERROR)
+
+def api_return(status, text='', json=False):
+ content_type = 'text/html'
+ if status == STATUS_OK and json:
+ content_type = 'text/json'
+ if text is None:
+ if status == STATUS_ERROR:
+ text = 'Error'
+ elif status == STATUS_ERROR_NOT_FOUND:
+ text = 'Resource Not Found'
+ elif status == STATUS_ERROR_PERMISSIONS:
+ text = 'Invalid username or password'
+ elif status == STATUS_ERROR_BADMETHOD:
+ text = 'Invalid request method'
+ elif status == STATUS_OK:
+ text = 'OK'
+
+ r = HttpResponse(status=status, content=text, content_type=content_type)
+
+ if status == STATUS_ERROR_BADMETHOD:
+ r.Allow = 'POST'
+
+ return r
+
+
+class API:
+ def __init__(self, request):
+ self.request = request
+
+ def api_candidat_add(self):
+ vars = dict()
+ offre_emploi = get_object_or_404(emploi.OffreEmploi, id=self.request.GET.get('id'))
+ cand = emploi.Candidat()
+ cand.offre_emploi = offre_emploi
+
+ if self.request.method == "POST":
+ form = emploiForms.PostulerOffreEmploiForm(self.request.POST,
+ instance=cand, offre_emploi=offre_emploi)
+ piecesForm = emploiForms.CandidatPieceForm(self.request.POST, self.request.FILES,
+ instance=cand)
+
+ if form.is_valid() and piecesForm.is_valid():
+ offre = form.save()
+ piecesForm.instance = offre
+ piecesForm.save()
+
+ """courriel_template = CourrielTemplate.objects.\
+ get(id=1)
+ send_templated_email(cand, courriel_template)
+ """
+ evaluateurs = offre_emploi.evaluateurs.all()
+ for evaluateur in evaluateurs:
+ candidat_evaluation = CandidatEvaluation()
+ candidat_evaluation.candidat = cand
+ candidat_evaluation.evaluateur = evaluateur
+ candidat_evaluation.save()
+
+ return api_return(STATUS_OK)
+ else:
+ messages.add_message(self.request, messages.ERROR,
+ 'Il y a des erreurs dans le formulaire.')
+ else:
+ form = emploiForms.PostulerOffreEmploiForm(instance=cand,
+ offre_emploi=offre_emploi)
+ piecesForm = emploiForms.CandidatPieceForm(instance=cand)
+
+ vars.update(dict(form=form, candidat=cand, piecesForm=piecesForm, ))
+
+ return render_to_response('recrutement/postuler_appel_offre.html', vars,
+ RequestContext(self.request))
+
+
+ def api_offre_emploi_liste(self):
+ return api_return(STATUS_OK, simplejson.dumps(
+ [{"id": "%s" % offre.id,
+ "est_affiche": "%s" % offre.est_affiche,
+ "statut": "%s" % offre.statut,
+ "nom": "%s" % offre.nom,
+ "resume": "%s" % offre.resume,
+ "description": "%s" % offre.description,
+ "poste_nom": "%s" % offre.poste_nom,
+ "region": "%s" % offre.region.id,
+ "bureau": "%s" % offre.bureau.id,
+ "date_limite": "%s" % offre.date_limite,
+ "duree_affectation": "%s" % offre.duree_affectation,
+ "renumeration": "%s" % offre.renumeration,
+ "debut_affectation": "%s" % offre.debut_affectation,
+ "lieu_affectation": "%s" % offre.lieu_affectation.id}
+ for offre in emploi.OffreEmploi.objects.all()]), json=True)
+
+ def api_offre_emploi(self):
+ try:
+ offre = emploi.OffreEmploi.objects.get(id=self.request.GET.get('id'))
+ except emploi.OffreEmploi.DoesNotExist:
+ return api_return(STATUS_ERROR, "ID d'offre d'emploi invalide")
+ return api_return(STATUS_OK, simplejson.dumps(
+ {"id": "%s" % offre.id,
+ "est_affiche": "%s" % offre.est_affiche,
+ "statut": "%s" % offre.statut,
+ "nom": "%s" % offre.nom,
+ "resume": "%s" % offre.resume,
+ "description": "%s" % offre.description,
+ "poste_nom": "%s" % offre.poste_nom,
+ "region": "%s" % offre.region.id,
+ "bureau": "%s" % offre.bureau.id,
+ "date_limite": "%s" % offre.date_limite,
+ "duree_affectation": "%s" % offre.duree_affectation,
+ "renumeration": "%s" % offre.renumeration,
+ "debut_affectation": "%s" % offre.debut_affectation,
+ "lieu_affectation": "%s" % offre.lieu_affectation.id} ), json=True)
+
from django.forms.widgets import CheckboxSelectMultiple
from django.contrib.admin import widgets as admin_widgets
from form_utils.forms import BetterModelForm
-from django.forms import ModelForm
+from django.forms import ModelForm, ModelChoiceField, HiddenInput, CharField
from django.forms.models import BaseInlineFormSet
+from django.core.mail import send_mail
from tinymce.widgets import TinyMCE
from captcha.fields import CaptchaField
from recrutement import models as recr
-from django.core.mail import send_mail
-#from recrutement.lib import send_templated_mail
+from auf.django.emploi import forms as emploi
+from project.rh import models as rh
################################################################################
# EVALUATION
recr.Evaluateur.objects.all())
def __init__(self, *args, **kwargs):
- self.candidats = kwargs.pop('candidats')
+ self.offres_emploi = kwargs.pop('offres_emploi')
super(EvaluateurForm, self).__init__(*args, **kwargs)
def save(self):
- for candidat in self.candidats:
+ candidats = recr.Candidat.objects.\
+ filter(offre_emploi__in=self.offres_emploi)
+ for candidat in candidats:
for evaluateur in self.cleaned_data.get('evaluateurs', []):
candidat_evaluation = recr.CandidatEvaluation()
candidat_evaluation.candidat = candidat
candidat_evaluation.evaluateur = evaluateur
candidat_evaluation.save()
+
################################################################################
# OFFRE EMPLOI
################################################################################
-class CandidatPieceForm(inlineformset_factory(recr.Candidat,
- recr.CandidatPiece)):
- nom = forms.MultipleChoiceField(choices=recr.TYPE_PIECE_CHOICES,
- widget=CheckboxSelectMultiple)
+class CandidatPieceForm(emploi.CandidatPieceForm):
+ pass
-class PostulerOffreEmploiForm(ModelForm):
- captcha = CaptchaField()
+class PostulerOffreEmploiForm(emploi.PostulerOffreEmploiForm):
+ pass
- def __init__(self, *args, **kwargs):
- self.offre_emploi = kwargs.pop('offre_emploi')
- super(PostulerOffreEmploiForm, self).__init__(*args, **kwargs)
+class OffreEmploiForm(ModelForm):
+ poste = ModelChoiceField(queryset=rh.Poste.objects.all())
- def save(self, *args, **kwargs):
+ class Meta:
+ model = recr.OffreEmploi
+
+ def save(self, *args, **kwargs):
kwargs2 = kwargs.copy()
kwargs2['commit'] = False
- postulation = super(PostulerOffreEmploiForm, self).save(*args, **kwargs2)
+ offre = super(OffreEmploiForm, self).save(*args, **kwargs2)
+ offre.poste = self.cleaned_data.get("poste")
+ offre.poste_nom = self.cleaned_data.get("poste").nom
if 'commit' not in kwargs or kwargs['commit']:
- postulation.save()
- return postulation
-
- class Meta:
- model = recr.Candidat
- exclude = ('actif', 'offre_emploi',)
- fields = ('nom', 'prenom', 'genre', 'nationalite', 'situation_famille',
- 'nombre_dependant', 'niveau_diplome', 'employeur_actuel',
- 'poste_actuel', 'domaine_professionnel', 'telephone',
- 'email', 'adresse', 'ville', 'code_postal', 'etat_province',
- 'pays', 'captcha', )
+ offre.save()
+ return offre
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ date_limite = cleaned_data.get("date_limite")
+ debut_affectation = cleaned_data.get("debut_affectation")
+
+ if date_limite and debut_affectation:
+ if date_limite > debut_affectation:
+ raise forms.ValidationError("La date limite ne peut pas être \
+ supérieure à la date d'affection.")
+
+ """if date_limite < datetime.date.today() or \
+ debut_affectation < datetime.date.today():
+ raise forms.ValidationError("La date limite et/ou la date \
+ d'affection doivent être supérieures à la date d'aujourdhui.")
+ """
+ return cleaned_data
################################################################################
# TEMPLATE COURRIEL
from tinymce import models as tinymce_models
from django.db import models
import settings
-#from private_files import PrivateFileField
import datamaster_modeles.models as ref
-from project.rh.models import Poste
+from recrutement.workflow import grp_evaluateurs_recrutement
+from auf.django.emploi import models as emploi
+from auf.django.emploi.models import TYPE_PIECE_CHOICES
+
+from recrutement.workflow import grp_evaluateurs_recrutement
### CONSTANTES
#NOTES
HELP_TEXT_FORMAT_DATE = "Le format de la date est AAAA-MM-JJ"
HELP_TEXT_TAGS_ACCEPTES = "Pour le texte, les variables disponibles sont : \
{{ nom_candidat }} {{ prenom_candidat }} \
- {{ offre_emploi }}. Ces champs seront \
+ {{ offre_emploi }} et {{ genre_candidat }} \
+ (Pour Monsieur/Madame). Ces champs seront \
automatiquement remplacés par les informations de \
chaque candidat."
class Meta:
abstract = True
-class OffreEmploiManager(models.Manager):
- def get_query_set(self):
- fkeys = ('region',)
- return super(OffreEmploiManager, self).get_query_set().\
- select_related(*fkeys).all()
-
-class ProxyPoste(Poste):
+class Candidat(emploi.Candidat):
class Meta:
proxy = True
- def __unicode__(self):
- return '%s [%s]' % (self.nom, self.id)
-
-STATUT_OFFRE_EMPLOI_CHOICES = (
- ('NOUV', 'Nouveau'),
- ('AFFI', 'Offre d\'emploi en affichage'),
- ('EVAL', 'En évaluation des candidatures'),
- ('ENTR', 'En entrevue'),
- ('TERM', 'Terminé'),
-)
+class OffreEmploi(emploi.OffreEmploi):
+ class Meta:
+ proxy = True
-class OffreEmploi(Metadata):
- #objects = OffreEmploiManager()
- est_affiche = models.BooleanField(default=False,
- verbose_name="En affichage sur le site")
- statut = models.CharField(max_length=4, choices=STATUT_OFFRE_EMPLOI_CHOICES,
- default='NOUV')
- nom = models.CharField(max_length=255)
- resume = models.TextField(verbose_name="Résumé")
- description = tinymce_models.HTMLField()
- poste = models.ForeignKey(ProxyPoste, db_column='poste')
- date_limite = models.DateField(verbose_name="Date limite",
- help_text=HELP_TEXT_FORMAT_DATE,)
- region = models.ForeignKey(ref.Region, db_column='region',
- verbose_name="Région")
- bureau = models.ForeignKey(ref.Bureau, db_column='bureau', )
- duree_affectation = models.CharField(max_length=255,
- verbose_name="Durée de l'affectation")
- renumeration = models.CharField(max_length=255,
- verbose_name='Rénumération')
- debut_affectation = models.DateField(verbose_name="Début de l'affectation",
- help_text=HELP_TEXT_FORMAT_DATE,)
- lieu_affectation = models.ForeignKey(ref.Implantation,
- db_column='implantation',
- verbose_name="Lieu d'affectation")
+class CandidatPiece(emploi.CandidatPiece):
class Meta:
- verbose_name_plural = "offres d'emploi"
+ proxy = True
- def __unicode__(self):
- return '%s [%s]' % (self.nom, self.id)
-
-class ProxyOffreEmploi(OffreEmploi):
+class OffreEmploiManager(models.Manager):
+ def get_query_set(self):
+ fkeys = ('region',)
+ return super(OffreEmploiManager, self).get_query_set().\
+ select_related(*fkeys).all()
+
+class ProxyOffreEmploi(emploi.OffreEmploi):
class Meta:
proxy = True
verbose_name = "Offre d'emploi (visualisation)"
def __unicode__(self):
return '%s [%s] - View' % (self.nom, self.id)
-
-### CANDIDAT
-
-GENRE_CHOICES = (
- ('M', 'Homme'),
- ('F', 'Femme'),
-)
-SITUATION_CHOICES = (
- ('C', 'Célibataire'),
- ('F', 'Conjoint de fait'),
- ('M', 'Marié'),
- ('D', 'Divorcé'),
-)
-STATUT_CHOICES = (
- ('NOUV', 'Nouveau'),
- ('REC', 'Recevable'),
- ('SEL', 'Sélectionné'),
- ('REF', 'Refusé'),
- ('ACC', 'Accepté'),
-)
-class Candidat(Metadata):
- statut = models.CharField(max_length=4, choices=STATUT_CHOICES,
- default='NOUV')
- offre_emploi = models.ForeignKey('OffreEmploi', db_column='offre_emploi',
- related_name='+')
- prenom = models.CharField(max_length=255, verbose_name='Prénom', )
- nom = models.CharField(max_length=255)
- genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
- nationalite = models.ForeignKey(ref.Pays,
- db_column='nationalite', related_name='+',
- verbose_name='Nationalité')
- situation_famille = models.CharField(max_length=1,
- choices=SITUATION_CHOICES,
- verbose_name='Situation familiale', )
- nombre_dependant = models.IntegerField(verbose_name='Nombre de dépendant',
- help_text=HELP_TEXT_NB_DEPENDANT, )
- niveau_diplome = models.CharField(max_length=255,
- verbose_name='Niveau du diplôme')
- employeur_actuel = models.CharField(max_length=255, )
- poste_actuel = models.CharField(max_length=255, )
- domaine_professionnel = models.CharField(max_length=255, )
- telephone = models.CharField(max_length=255, verbose_name='Téléphone', )
- email = models.EmailField(max_length=255, verbose_name = 'Courriel', )
-
- # Adresse
- adresse = models.CharField(max_length=255)
- ville = models.CharField(max_length=255)
- etat_province = models.CharField(max_length=255,
- verbose_name="État/Province")
- code_postal = models.CharField(max_length=255, blank=True)
- pays = models.ForeignKey(ref.Pays, db_column='pays',
- related_name='+')
-
- def __unicode__(self):
- return '%s %s [%s]' % (self.prenom, self.nom, self.id)
-
-class ProxyCandidat(Candidat):
+class ProxyCandidat(emploi.Candidat):
class Meta:
proxy = True
verbose_name = "Candidat (visualisation)"
def __unicode__(self):
return '%s %s [%s]' % (self.prenom, self.nom, self.id)
-### PIECE CANDIDAT
-
-TYPE_PIECE_CHOICES = (
- ('CV','CV'),
- ('LET','Lettre'),
- ('AUT','Autre'),
-)
-# Upload de fichiers
-storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT,
- base_url=settings.PRIVE_MEDIA_URL)
-
-def candidat_piece_dispatch(instance, filename):
- path = "offre_emploi/%s_%s/%s/%s_%s" % (instance.candidat.nom,
- instance.candidat.prenom, instance.nom, instance.candidat.id,
- filename)
- return path
-
-class CandidatPiece(models.Model):
- candidat = models.ForeignKey(Candidat, db_column='candidat',
- related_name='candidat_piece')
- nom = models.CharField(max_length=3, choices=TYPE_PIECE_CHOICES)
- #path = PrivateFileField("file", upload_to=candidat_piece_dispatch)
- path = models.FileField(verbose_name="Fichier",
- upload_to=candidat_piece_dispatch,
- storage=storage_prive, )
-
- class Meta:
- verbose_name = "pièce jointe"
- verbose_name_plural = "pièces jointes"
-
- def __unicode__(self):
- return '%s' % (self.nom)
-
class Evaluateur(models.Model):
user = models.ForeignKey(User, unique=True, verbose_name="Évaluateur")
- candidats = models.ManyToManyField(Candidat, through='CandidatEvaluation',
- related_name="evaluateurs")
-
+ offres_emploi = models.ManyToManyField(emploi.OffreEmploi,
+ related_name="evaluateurs", blank=True)
+
+ def save(self, *args, **kwargs):
+ """
+ Assigner automatiquement l'évaluateurs d'une offre d'emploi à un
+ nouveau candidat.
+ """
+ self.user.groups.add(grp_evaluateurs_recrutement)
+ super(Evaluateur, self).save(*args, **kwargs)
+
class Meta:
verbose_name = "évaluateur"
return '%s %s' % (self.user.first_name, self.user.last_name)
class CandidatEvaluation(models.Model):
- candidat = models.ForeignKey(Candidat, db_column='candidat',
+ candidat = models.ForeignKey(emploi.Candidat, db_column='candidat',
related_name='+',)
evaluateur = models.ForeignKey(Evaluateur, db_column='evaluateur',
related_name='+', verbose_name='Évaluateur')
note = models.IntegerField(choices=NOTES, blank=True, null=True)
- commentaire = models.TextField(null=True, blank=True)
+ commentaire = models.TextField(null=True, blank=True, default='Aucun')
date = models.DateField(auto_now_add=True,
help_text=HELP_TEXT_FORMAT_DATE, )
def __unicode__(self):
return '%s' % (self.titre)
+
+ class Meta:
+ verbose_name = "modèle de courriel"
+ verbose_name_plural = "modèles de courriel"
--- /dev/null
+{% extends "admin/base_site.html" %}
+{% load i18n admin_modify adminmedia %}
+
+{% block extrahead %}{{ block.super }}
+{% url admin:jsi18n as jsi18nurl %}
+<script type="text/javascript" src="{{ jsi18nurl|default:"../../../jsi18n/" }}"></script>
+{{ media }}
+{% endblock %}
+
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
+
+{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %}
+
+{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
+
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="../../../">{% trans "Home" %}</a> ›
+ <a href="../../">{{ app_label|capfirst|escape }}</a> ›
+ {% if has_change_permission %}<a href="../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} ›
+ {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
+</div>
+{% endif %}{% endblock %}
+
+{% block content %}<div id="content-main">
+{% block object-tools %}
+{% if change %}{% if not is_popup %}
+ <ul class="object-tools"><li><a href="history/" class="historylink">{% trans "History" %}</a></li>
+ {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
+ </ul>
+{% endif %}{% endif %}
+{% endblock %}
+<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
+<div>
+{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
+{% if save_on_top %}{% submit_row %}{% endif %}
+{% if errors %}
+ <p class="errornote">
+ {% blocktrans count errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+ {{ adminform.form.non_field_errors }}
+{% endif %}
+
+{% for fieldset in adminform %}
+ {% include "admin/includes/fieldset.html" %}
+{% endfor %}
+
+{% block after_field_sets %}{% endblock %}
+
+{% for inline_admin_formset in inline_admin_formsets %}
+ {% include inline_admin_formset.opts.template %}
+{% endfor %}
+
+<fieldset class="module aligned ">
+ <h2>Pièces jointes</h2>
+ {% for p in original.pieces_jointes %}
+ <div class="form-row">
+ <label>{{ p.get_nom_display }}:</label>
+ <p><a href="{{ p.path.url }}">{{ p.path.url }}</a></p>
+ </div>
+ {% endfor %}
+</fieldset>
+
+{% block after_related_objects %}{% endblock %}
+
+{% submit_row %}
+
+{% if adminform and add %}
+ <script type="text/javascript">document.getElementById("{{ adminform.first_field.id_for_label }}").focus();</script>
+{% endif %}
+
+{# JavaScript for prepopulated fields #}
+{% prepopulated_fields_js %}
+
+</div>
+</form></div>
+{% endblock %}
# -*- encoding: utf-8 -*
from django.conf.urls.defaults import patterns, url
-urlpatterns = patterns(
- 'project.recrutement.views',
+
+
+
+urlpatterns = patterns('',
url(r'^$', 'index', name='index'),
+
+ url(r'^affecter_evaluateurs_offre_emploi/$',
+ 'recrutement.views.affecter_evaluateurs_offre_emploi',
+ name='affecter_evaluateurs_offre_emploi'),
+
+ url(r'^envoyer_courriel_candidats/$',
+ 'recrutement.views.envoyer_courriel_candidats',
+ name='envoyer_courriel_candidats'),
+
+ url(r'^selectionner_template/$',
+ 'recrutement.views.selectionner_template',
+ name='selectionner_template'),
+
+ url(r'^pieces/$', 'recrutement.views.postuler_appel_offre',
+ name='pieces'),
+
+ url(r'^postuler_appel_offre/$',
+ 'recrutement.views.postuler_appel_offre', name='postuler_appel_offre'),
)
from forms import *
from models import *
-from project.recrutement import models as recr
from recrutement.workflow import grp_evaluateurs_recrutement
+from views import *
def index(request):
return render_to_response('recrutement/index.html', {},
RequestContext(request))
-def affecter_evaluateurs_candidats(request):
- candidat_ids = request.GET.get('ids').split(',')
- candidats = Candidat.objects.filter(id__in=candidat_ids)
- if request.method == "POST":
- form = EvaluateurForm(request.POST, candidats=candidats)
- if form.is_valid():
- form.save()
- messages.add_message(request, messages.SUCCESS,
- "Les évaluateurs ont été affectés aux candidats.")
- return redirect("admin:recrutement_candidat_changelist")
- else:
- form = EvaluateurForm(candidats=candidats)
-
- c = {'form' : form}
- return render_to_response("recrutement/affecter_evaluateurs.html",
- Context(c), context_instance = RequestContext(request))
-
def selectionner_template(request):
candidat_ids = request.GET.get('ids')
if request.method == "POST":
courriel_template = CourrielTemplate.objects.\
get(nom_modele='Confirmation postulation (automatique)')
- send_templated_email(candidat, courriel_template)
+ emp.send_templated_email(candidat, courriel_template)
messages.add_message(request, messages.SUCCESS,
"Votre application à l'appel d'offre d'emploi a \
def affecter_evaluateurs_offre_emploi(request):
offre_emploi_ids = request.GET.get('ids').split(',')
offres_emploi = OffreEmploi.objects.filter(id__in=offre_emploi_ids)
- candidats = Candidat.objects.filter(offre_emploi__in=offres_emploi)
if request.method == "POST":
- form = EvaluateurForm(request.POST, candidats=candidats)
+ form = EvaluateurForm(request.POST, offres_emploi=offres_emploi)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS,
- "Les évaluateurs ont été affectés aux candidats.")
+ "Les évaluateurs ont été affectés aux offres d'emploi.")
return redirect("admin:recrutement_offreemploi_changelist")
else:
- form = EvaluateurForm(candidats=candidats)
+ form = EvaluateurForm(offres_emploi=offres_emploi)
c = {'form' : form}
return render_to_response("recrutement/affecter_evaluateurs.html",
texte_template = Template(template.plain_text)
dict_texte = {"nom_candidat": candidat.nom,
"prenom_candidat": candidat.prenom,
- "offre_emploi": candidat.offre_emploi.nom,}
+ "offre_emploi": candidat.offre_emploi.nom,
+ "genre_candidat": "Monsieur" if candidat.genre == "M" \
+ else "Madame",
+ }
texte = Context(dict_texte)
# HTML text
html_template = Template(template.html)
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.admin',
+ 'auf.django.emploi',
'auf.django.admingroup',
'ajax_select',
'south',
<script type="text/javascript">
jQuery(document).ready(function($){{% block script %}
$("#{{html_id}}_text").autocomplete('{{lookup_url}}', {
+ max: 100,
width: 320,
formatItem: function(row) { return row[2]; },
formatResult: function(row) { return row[1]; },
from django.conf.urls.defaults import patterns, include, handler500, url
from django.conf import settings
from django.contrib import admin
+from auf.django.emploi import settings as sett
admin.autodiscover()
urlpatterns = patterns(
'',
(r'^$', 'project.views.index'),
- #url(r'^private_files/', include('private_files.urls')),
url(r'^captcha/', include('captcha.urls')),
url(r'^admin_tools/', include('admin_tools.urls')),
(r'^admin/', include(admin.site.urls)),
+ url(r'^api/(?P<method>[a-z_-]+)/$', 'recrutement.api.api',
+ name='recrutement_api'),
(r'^connexion/$', 'django.contrib.auth.views.login'),
(r'^deconnexion/$', 'django.contrib.auth.views.logout'),
(r'^dae/', include('project.dae.urls')),
- (r'^recrutement/', include('project.recrutement.urls')),
- url(r'^recrutement/affecter_evaluateurs_candidats/$',
- 'recrutement.views.affecter_evaluateurs_candidats',
- name='affecter_evaluateurs_candidats'),
- url(r'^recrutement/affecter_evaluateurs_offre_emploi/$',
- 'recrutement.views.affecter_evaluateurs_offre_emploi',
- name='affecter_evaluateurs_offre_emploi'),
- url(r'^recrutement/envoyer_courriel_candidats/$',
- 'recrutement.views.envoyer_courriel_candidats',
- name='envoyer_courriel_candidats'),
- url(r'^recrutement/selectionner_template/$',
- 'recrutement.views.selectionner_template',
- name='selectionner_template'),
- url(r'^recrutement/pieces/$', 'recrutement.views.postuler_appel_offre',
- name='pieces'),
- url(r'^recrutement/postuler_appel_offre/$',
- 'recrutement.views.postuler_appel_offre', name='postuler_appel_offre'),
+ (r'^recrutement/', include('recrutement.urls')),
(r'^tinymce/', include('tinymce.urls')),
(r'^', include('project.rh.urls')),
(r'^prive/(?P<path>.*)$', 'django.views.static.serve',
- {'document_root': settings.PRIVE_MEDIA_ROOT}),
+ {'document_root': sett.PRIVE_MEDIA_ROOT}),
)
if settings.DEBUG:
--- /dev/null
+*.pyc
+*egg-info
+build
+dist
--- /dev/null
+auf.django.emploi
+===================
+
+0.1
+---
+
+* Création du module :
--- /dev/null
+auf.django.emploi
+===================
+
--- /dev/null
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except:
+ # bootstrapping
+ pass
--- /dev/null
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except:
+ # bootstrapping
+ pass
--- /dev/null
+# -*- encoding: utf-8 -*
+from django.shortcuts import render_to_response, redirect, get_object_or_404
+from django.template import Context, RequestContext
+
+from django.utils import simplejson
+from auf.django.emploi import models as emploi
+from auf.django.emploi import forms as emploiForms
+from restkit import request as req
+import datamaster_modeles.models as ref
+
+class API:
+ def __init__(self, request):
+ self.request = request
+
+ def offre_emploi_liste(self):
+ url = "http://127.0.0.1:8000/api/offre_emploi_liste/"
+ r = req(url)
+ liste_json = r.body_string()
+ liste_offres = simplejson.loads(liste_json)
+ obj_offres_emploi = []
+
+ for offre_dict in liste_offres:
+ offre = emploi.OffreEmploi()
+ offre.est_affiche = offre_dict['est_affiche']
+ offre.statut = offre_dict['statut']
+ offre.nom = offre_dict['nom']
+ offre.resume = offre_dict['resume']
+ offre.description = offre_dict['description']
+ offre.poste_nom = offre_dict['poste_nom']
+ offre.date_limite = offre_dict['date_limite']
+ offre.region = ref.Region.objects.get(id=offre_dict['region'])
+ offre.bureau = ref.Bureau.objects.get(id=offre_dict['bureau'])
+ offre.duree_affectation = offre_dict['duree_affectation']
+ offre.renumeration = offre_dict['renumeration']
+ offre.debut_affectation = offre_dict['debut_affectation']
+ offre.lieu_affectation = ref.Implantation.objects.get(id=offre_dict['lieu_affectation'])
+ obj_offres_emploi.append(offre)
+ return obj_offres_emploi
+
+ def offre_emploi(self, offre_id):
+ url = "http://127.0.0.1:8000/api/offre_emploi/?id=%s"
+ r = req(url % (offre_id))
+ offre_json = r.body_string()
+ offre_dict = simplejson.loads(offre_json)
+ obj_offres_emploi = []
+
+ offre = emploi.OffreEmploi()
+ offre.est_affiche = offre_dict['est_affiche']
+ offre.statut = offre_dict['statut']
+ offre.nom = offre_dict['nom']
+ offre.resume = offre_dict['resume']
+ offre.description = offre_dict['description']
+ offre.poste_nom = offre_dict['poste_nom']
+ offre.date_limite = offre_dict['date_limite']
+ offre.region = ref.Region.objects.get(id=offre_dict['region'])
+ offre.bureau = ref.Bureau.objects.get(id=offre_dict['bureau'])
+ offre.duree_affectation = offre_dict['duree_affectation']
+ offre.renumeration = offre_dict['renumeration']
+ offre.debut_affectation = offre_dict['debut_affectation']
+ offre.lieu_affectation = ref.Implantation.objects.get(id=offre_dict['lieu_affectation'])
+ obj_offres_emploi.append(offre)
+ return obj_offres_emploi
+
+ def candidat_add(self, offre_id):
+ url = "http://127.0.0.1:8000/api/candidat_add/?id=%s" % (offre_id)
+ return redirect(url)
+
+
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from django import forms
+from django.forms.models import inlineformset_factory
+from django.forms.widgets import CheckboxSelectMultiple
+from django.forms import ModelForm
+
+from captcha.fields import CaptchaField
+
+from auf.django.emploi import models as emploi
+
+################################################################################
+# OFFRE EMPLOI
+################################################################################
+class CandidatPieceForm(inlineformset_factory(emploi.Candidat,
+ emploi.CandidatPiece)):
+ nom = forms.MultipleChoiceField(choices=emploi.TYPE_PIECE_CHOICES,
+ widget=CheckboxSelectMultiple)
+
+class PostulerOffreEmploiForm(ModelForm):
+ captcha = CaptchaField()
+
+ def __init__(self, *args, **kwargs):
+ self.offre_emploi = kwargs.pop('offre_emploi')
+ super(PostulerOffreEmploiForm, self).__init__(*args, **kwargs)
+
+ def save(self, *args, **kwargs):
+ kwargs2 = kwargs.copy()
+ kwargs2['commit'] = False
+ postulation = super(PostulerOffreEmploiForm, self).save(*args, **kwargs2)
+ if 'commit' not in kwargs or kwargs['commit']:
+ postulation.save()
+ return postulation
+
+ class Meta:
+ model = emploi.Candidat
+ exclude = ('actif', 'offre_emploi',)
+ fields = ('nom', 'prenom', 'genre', 'nationalite', 'situation_famille',
+ 'nombre_dependant', 'niveau_diplome', 'employeur_actuel',
+ 'poste_actuel', 'domaine_professionnel', 'telephone',
+ 'email', 'adresse', 'ville', 'code_postal', 'etat_province',
+ 'pays', 'captcha', )
--- /dev/null
+# -*- encoding: utf-8 -*
+
+import datetime
+from django.core.files.storage import FileSystemStorage
+from tinymce import models as tinymce_models
+from django.db import models
+import settings
+
+import datamaster_modeles.models as ref
+
+### CONSTANTES ###
+# HELP_TEXT
+HELP_TEXT_NB_DEPENDANT = "Le nombre de personnes à charge"
+HELP_TEXT_FORMAT_DATE = "Le format de la date est AAAA-MM-JJ"
+HELP_TEXT_TAGS_ACCEPTES = "Pour le texte, les variables disponibles sont : \
+ {{ nom_candidat }} {{ prenom_candidat }} \
+ {{ offre_emploi }}. Ces champs seront \
+ automatiquement remplacés par les informations de \
+ chaque candidat."
+
+
+STATUT_OFFRE_EMPLOI_CHOICES = (
+ ('NOUV', 'Nouveau'),
+ ('AFFI', 'Offre d\'emploi en affichage'),
+ ('EVAL', 'En évaluation des candidatures'),
+ ('ENTR', 'En entrevue'),
+ ('TERM', 'Terminé'),
+)
+
+# CANDIDAT
+GENRE_CHOICES = (
+ ('M', 'Homme'),
+ ('F', 'Femme'),
+)
+SITUATION_CHOICES = (
+ ('C', 'Célibataire'),
+ ('F', 'Conjoint de fait'),
+ ('M', 'Marié'),
+ ('D', 'Divorcé'),
+)
+STATUT_CHOICES = (
+ ('NOUV', 'Nouveau'),
+ ('REC', 'Recevable'),
+ ('SEL', 'Sélectionné'),
+ ('REF', 'Refusé'),
+ ('ACC', 'Accepté'),
+)
+
+# PIECE CANDIDAT
+TYPE_PIECE_CHOICES = (
+ ('CV','CV'),
+ ('LET','Lettre'),
+ ('AUT','Autre'),
+)
+
+# Abstracts
+class Metadata(models.Model):
+ """
+ Méta-données AUF.
+ Metadata.actif = flag remplaçant la suppression.
+ actif == False : objet réputé supprimé.
+ """
+ actif = models.BooleanField(default=True)
+ date_creation = models.DateField(auto_now_add=True,
+ help_text=HELP_TEXT_FORMAT_DATE, )
+
+ class Meta:
+ abstract = True
+
+class OffreEmploi(Metadata):
+ est_affiche = models.BooleanField(default=False,
+ verbose_name="En affichage sur le site")
+ statut = models.CharField(max_length=4, choices=STATUT_OFFRE_EMPLOI_CHOICES,
+ default='NOUV')
+ nom = models.CharField(max_length=255)
+ resume = models.TextField(verbose_name="Résumé")
+ description = models.TextField()
+ poste = models.CharField(max_length=255)
+ poste_nom = models.CharField(max_length=255)
+ date_limite = models.DateField(verbose_name="Date limite",
+ help_text=HELP_TEXT_FORMAT_DATE,)
+ region = models.ForeignKey(ref.Region, db_column='region',
+ verbose_name="Région")
+ bureau = models.ForeignKey(ref.Bureau, db_column='bureau', )
+ duree_affectation = models.CharField(max_length=255,
+ verbose_name="Durée de l'affectation")
+ renumeration = models.CharField(max_length=255,
+ verbose_name='Rénumération')
+ debut_affectation = models.DateField(verbose_name="Début de l'affectation",
+ help_text=HELP_TEXT_FORMAT_DATE,)
+ lieu_affectation = models.ForeignKey(ref.Implantation,
+ db_column='implantation',
+ verbose_name="Lieu d'affectation")
+
+ class Meta:
+ db_table = 'emploi_offreemploi'
+ verbose_name_plural = "offres d'emploi"
+
+ def __unicode__(self):
+ return '%s [%s]' % (self.nom, self.id)
+
+class Candidat(Metadata):
+ statut = models.CharField(max_length=4, choices=STATUT_CHOICES,
+ default='NOUV')
+ offre_emploi = models.ForeignKey('OffreEmploi', db_column='offre_emploi',
+ related_name='+')
+ prenom = models.CharField(max_length=255, verbose_name='Prénom', )
+ nom = models.CharField(max_length=255)
+ genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
+ nationalite = models.ForeignKey(ref.Pays,
+ db_column='nationalite', related_name='+',
+ verbose_name='Nationalité')
+ situation_famille = models.CharField(max_length=1,
+ choices=SITUATION_CHOICES,
+ verbose_name='Situation familiale', )
+ nombre_dependant = models.IntegerField(verbose_name='Nombre de dépendant',
+ help_text=HELP_TEXT_NB_DEPENDANT, )
+ niveau_diplome = models.CharField(max_length=255,
+ verbose_name='Niveau du diplôme')
+ employeur_actuel = models.CharField(max_length=255, )
+ poste_actuel = models.CharField(max_length=255, )
+ domaine_professionnel = models.CharField(max_length=255, )
+ telephone = models.CharField(max_length=255, verbose_name='Téléphone', )
+ email = models.EmailField(max_length=255, verbose_name = 'Courriel', )
+
+ # Adresse
+ adresse = models.CharField(max_length=255)
+ ville = models.CharField(max_length=255)
+ etat_province = models.CharField(max_length=255,
+ verbose_name="État/Province")
+ code_postal = models.CharField(max_length=255, blank=True)
+ pays = models.ForeignKey(ref.Pays, db_column='pays',
+ related_name='+')
+
+ class Meta:
+ db_table = 'emploi_candidat'
+
+ def pieces_jointes(self):
+ return CandidatPiece.objects.filter(candidat=self)
+ pieces_jointes.allow_tags = True
+
+ def __unicode__(self):
+ return '%s %s [%s]' % (self.nom, self.prenom, self.id)
+
+
+# Upload de fichiers
+storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT,
+ base_url=settings.PRIVE_MEDIA_URL)
+
+def candidat_piece_dispatch(instance, filename):
+ path = u'%s/%s/%s_%s_%s/%s/%s' % ('emplois', instance.candidat.offre_emploi.id,
+ instance.candidat.nom, instance.candidat.prenom, instance.candidat.id,
+ instance.nom, filename)
+ return path
+
+class CandidatPiece(models.Model):
+ candidat = models.ForeignKey(Candidat, db_column='candidat',
+ related_name='candidat_piece')
+ nom = models.CharField(max_length=3, choices=TYPE_PIECE_CHOICES)
+ path = models.FileField(verbose_name="Fichier",
+ upload_to=candidat_piece_dispatch, storage=storage_prive)
+
+ class Meta:
+ db_table = 'emploi_pieces'
+ verbose_name = "pièce jointe"
+ verbose_name_plural = "pièces jointes"
+
+ def __unicode__(self):
+ return '%s' % (self.nom)
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+import os
+from django.conf import settings
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = getattr(settings, 'OE_MEDIA_ROOT',
+ os.path.join(os.path.dirname(__file__), 'media'))
+PRIVE_MEDIA_ROOT = getattr(settings, 'OE_PRIV_MEDIA_ROOT',
+ os.path.join(os.path.dirname(__file__), 'media_prive'))
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = '/media/'
+PRIVE_MEDIA_URL = '/prive/'
--- /dev/null
+<table>
+ {% for f in piecesForm.management_form %}
+ {{ f }}
+ {% endfor %}
+ <tr>
+ <th></th>
+ {% for field in piecesForm.forms.0 %}
+ {% if not field.is_hidden %}
+ <th>{{ field.label }}</th>
+ {% endif %}
+ {% endfor %}
+ </tr>
+ {% for f in piecesForm.forms %}
+ <tr>
+ <td>
+ {{ f.errors }}
+ {% if f.initial.fichier %}
+ <a href="{{ f.initial.fichier.url }}" target="_blank">Télécharger</a>
+ {% endif %}
+ </td>
+ {% for field in f %}
+ {% if not field.is_hidden %}
+ <td>{{ field }}</td>
+ {% else %}
+ {{ field }}
+ {% endif %}
+ {% endfor %}
+ </tr>
+ {% endfor %}
+</table>
--- /dev/null
+{% extends 'base.html' %}
+{% load adminmedia %}
+
+{% block title %}RH{% endblock %}
+{% block titre %}Ressources humaines{% endblock %}
+{% block sous_titre %}Accueil{% endblock %}
+
+{% block main %}
+<div id="content-main">
+ {% block object-tools %}{% endblock %}
+
+
+
+
+ <div class="module">
+ <h2>Poster pour un appel d'offre d'emploi</h2>
+ </div>
+
+ <form action="" method="post" enctype="multipart/form-data">
+ <fieldset>
+ <h2>Informations personnelles</h2>
+ <table id="informations_personnelles">
+ <tbody>
+ <tr>
+ <td>{{ form.prenom.label }}</td>
+ <td>{{ form.prenom }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.nom.label }}</td>
+ <td>{{ form.nom }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.genre.label }}</td>
+ <td>{{ form.genre }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.nationalite.label }}</td>
+ <td>{{ form.nationalite }}</td>
+ <tr>
+ <td>{{ form.situation_famille.label }}</td>
+ <td>{{ form.situation_famille }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.nombre_dependant.label }}</td>
+ <td>{{ form.nombre_dependant }}<br />
+ <span class="info">{{ form.nombre_dependant.help_text }}
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </fieldset>
+ <fieldset>
+ <h2>Coordonnées</h2>
+ <table id="coordonnees">
+ <tbody>
+ <tr>
+ <td>{{ form.telephone.label }}</td>
+ <td>{{ form.telephone }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.email.label }}</td>
+ <td>{{ form.email }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.adresse.label }}</td>
+ <td>{{ form.adresse }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.ville.label }}</td>
+ <td>{{ form.ville }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.etat_province.label }}</td>
+ <td>{{ form.etat_province }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.code_postal.label }}</td>
+ <td>{{ form.code_postal }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.pays.label }}</td>
+ <td>{{ form.pays }}</td>
+ </tr>
+ </tbody>
+ </table>
+ </fieldset>
+ <fieldset>
+ <h2>Informations professionnelles</h2>
+ <table id="informations_professionnelles">
+ <tbody>
+ <tr>
+ <td>{{ form.niveau_diplome.label }}</td>
+ <td>{{ form.niveau_diplome }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.employeur_actuel.label }}</td>
+ <td>{{ form.employeur_actuel }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.poste_actuel.label }}</td>
+ <td>{{ form.poste_actuel }}</td>
+ </tr>
+ <tr>
+ <td>{{ form.domaine_professionnel.label }}</td>
+ <td>{{ form.domaine_professionnel }}</td>
+ </tr>
+ </tbody>
+ </table>
+ </fieldset>
+ <fieldset>
+ <h2>Pièces jointes</h2>
+ <p class="info">CV, lettre de motivation...</p>
+ {% include "recrutement/pieces.html" %}
+ </fieldset>
+ <fieldset>
+ <h2>Vérification CAPTCHA</h2>
+ <p class="info">Entrez les caractères figurant dans l'image ci-dessous.</p>
+ <tr>
+ <td>
+ {{ form.captcha }}
+ {{ form.captcha.errors }}
+ </td>
+ </tr>
+ </fieldset>
+ <div class="submit-row">
+ <input type="submit" name="save" value="Enregistrer" />
+ </div>
+ </form>
+
+
+
+</div>
+
+{% endblock %}
--- /dev/null
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from setuptools import setup, find_packages
+import sys, os
+
+name = 'auf.django.emploi'
+version = '0.1'
+
+setup(name=name,
+ version=version,
+ description="Outils nécessaires pour la diffusion des offres d'emploi et \
+ la soumissions des candidatures, dans l'application de \
+ recrutement du système SGRH.",
+ long_description="""\
+""",
+ classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ keywords='',
+ author='Nilovna Bascunan-Vasquez',
+ author_email='contact@nilovna.com',
+ url='http://pypi.auf.org/%s' % name,
+ license='GPL',
+ packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )