diff --git a/candidats/admin.py b/candidats/admin.py index 10219fd..7448465 100644 --- a/candidats/admin.py +++ b/candidats/admin.py @@ -8,7 +8,7 @@ from django.db.models import BooleanField from django.template import loader from stages.exports import OpenXMLExport -from .models import Candidate, GENDER_CHOICES +from .models import Candidate, Interview, GENDER_CHOICES def export_candidates(modeladmin, request, queryset): @@ -88,6 +88,8 @@ send_confirmation_mail.short_description = "Envoyer email de confirmation" class CandidateAdminForm(forms.ModelForm): + interview = forms.ModelChoiceField(queryset=Interview.objects.all(), required=False) + class Meta: model = Candidate widgets = { @@ -96,6 +98,24 @@ class CandidateAdminForm(forms.ModelForm): } fields = '__all__' + def __init__(self, *args, **kwargs): + try: + kwargs['initial'] = {'interview': kwargs['instance'].interview} + except Interview.DoesNotExist: + pass + return super().__init__(*args, **kwargs) + + def save(self, **kwargs): + obj = super().save(**kwargs) + if 'interview' in self.changed_data: + if self.cleaned_data['interview'] is None: + self.initial['interview'].candidat = None + self.initial['interview'].save() + else: + self.cleaned_data['interview'].candidat = obj + self.cleaned_data['interview'].save() + return obj + class CandidateAdmin(admin.ModelAdmin): form = CandidateAdminForm @@ -124,7 +144,7 @@ class CandidateAdmin(admin.ModelAdmin): 'fields': (('registration_form', 'certificate_of_payement', 'cv', 'certif_of_cfc', 'police_record', 'certif_of_800h', 'reflexive_text', 'work_certificate', 'marks_certificate', 'proc_admin_ext', 'promise', 'contract'), - ('interview_date', 'interview_room'), + ('interview',), ('examination_result', 'interview_result', 'file_result', 'total_result_points', 'total_result_mark') ), @@ -135,4 +155,10 @@ class CandidateAdmin(admin.ModelAdmin): return obj.date_confirmation_mail is not None confirm_mail.boolean = True + +class InterviewAdmin(admin.ModelAdmin): + pass + + admin.site.register(Candidate, CandidateAdmin) +admin.site.register(Interview, InterviewAdmin) diff --git a/candidats/migrations/0003_add_interview_model.py b/candidats/migrations/0003_add_interview_model.py new file mode 100644 index 0000000..776a706 --- /dev/null +++ b/candidats/migrations/0003_add_interview_model.py @@ -0,0 +1,58 @@ +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('stages', '__latest__'), + ('candidats', '0002_deposit_date_non_null'), + ] + + operations = [ + migrations.CreateModel( + name='Interview', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(verbose_name='Date')), + ('room', models.CharField(max_length=20, verbose_name="Salle d'entretien")), + ('status', models.CharField(choices=[('N', 'Normal'), ('R', 'Réserve'), ('X', 'Attente confirmation enseignants')], default='N', max_length=1, verbose_name='Statut')), + ], + options={ + 'ordering': ('date',), + 'verbose_name': "Entretien d'admission", + 'verbose_name_plural': "Entretiens d'admission", + }, + ), + migrations.RemoveField( + model_name='candidate', + name='file_resp', + ), + migrations.RemoveField( + model_name='candidate', + name='interview_date', + ), + migrations.RemoveField( + model_name='candidate', + name='interview_resp', + ), + migrations.RemoveField( + model_name='candidate', + name='interview_room', + ), + migrations.AddField( + model_name='interview', + name='candidat', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='candidats.Candidate'), + ), + migrations.AddField( + model_name='interview', + name='teacher_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='stages.Teacher', verbose_name='Ens. dossier'), + ), + migrations.AddField( + model_name='interview', + name='teacher_int', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='stages.Teacher', verbose_name='Ens. entretien'), + ), + ] diff --git a/candidats/models.py b/candidats/models.py index 66c833a..cbd5f4b 100644 --- a/candidats/models.py +++ b/candidats/models.py @@ -1,5 +1,7 @@ from django.db import models +from django.utils.dateformat import format as django_format +from stages.models import Corporation, CorpContact, Teacher GENDER_CHOICES = ( ('M', 'Masculin'), @@ -53,10 +55,10 @@ class Candidate(models.Model): has_photo = models.BooleanField(default=False, verbose_name='Photo passeport') corporation = models.ForeignKey( - 'stages.Corporation', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='Employeur' + Corporation, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='Employeur' ) instructor = models.ForeignKey( - 'stages.CorpContact', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='FEE/FPP' + CorpContact, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='FEE/FPP' ) # Checking for registration file @@ -75,23 +77,12 @@ class Candidate(models.Model): work_certificate = models.BooleanField("Certif. de travail", default=False) marks_certificate = models.BooleanField("Bull. de notes", default=False) deposite_date = models.DateField('Date dépôt dossier') - interview_date = models.DateTimeField('Date entretien prof.', blank=True, null=True) - interview_room = models.CharField("Salle d'entretien prof.", max_length=50, blank=True) examination_result = models.PositiveSmallIntegerField('Points examen', blank=True, null=True) interview_result = models.PositiveSmallIntegerField('Points entretien prof.', blank=True, null=True) file_result = models.PositiveSmallIntegerField('Points dossier', blank=True, null=True) total_result_points = models.PositiveSmallIntegerField('Total points', blank=True, null=True) total_result_mark = models.PositiveSmallIntegerField('Note finale', blank=True, null=True) - accepted = models.BooleanField('Admis', default=False) - interview_resp = models.ForeignKey( - 'stages.Teacher', null=True, blank=True, related_name='+', verbose_name='Exp. entretien', - on_delete=models.SET_NULL - ) - file_resp = models.ForeignKey( - 'stages.Teacher', null=True, blank=True, related_name='+', verbose_name='Exp. dossier', - on_delete=models.SET_NULL - ) class Meta: verbose_name = 'Candidat' @@ -107,3 +98,36 @@ class Candidate(models.Model): return 'Madame' else: return '' + + +INTERVIEW_CHOICES = ( + ('N', 'Normal'), + ('R', 'Réserve'), + ('X', 'Attente confirmation enseignants'), +) + +class Interview(models.Model): + date = models.DateTimeField('Date') + room = models.CharField("Salle d'entretien", max_length=20) + candidat = models.OneToOneField(Candidate, null=True, blank=True, on_delete=models.SET_NULL) + teacher_int = models.ForeignKey( + Teacher, null=True, blank=True, on_delete=models.SET_NULL, related_name='+', + verbose_name='Ens. entretien' + ) + teacher_file = models.ForeignKey( + Teacher, null=True, blank=True, on_delete=models.SET_NULL, related_name='+', + verbose_name='Ens. dossier' + ) + status = models.CharField('Statut', max_length=1, choices=INTERVIEW_CHOICES, default='N') + + class Meta: + verbose_name = "Entretien d'admission" + verbose_name_plural = "Entretiens d'admission" + ordering = ('date',) + + def __str__(self): + return '{0} : {1}/{2} - ({3}) -salle:{4}-{5}'.format( + django_format(self.date, "l j F Y à H\hi"), + self.teacher_int or '?', self.teacher_file or '?', + self.status, self.room, self.candidat or '???' + ) diff --git a/candidats/tests.py b/candidats/tests.py index ef28922..4a000a8 100644 --- a/candidats/tests.py +++ b/candidats/tests.py @@ -1,4 +1,4 @@ -from datetime import date +from datetime import date, datetime from unittest import mock from django.contrib.auth.models import User @@ -6,8 +6,8 @@ from django.core import mail from django.test import TestCase from django.urls import reverse -from stages.models import Section -from .models import Candidate +from stages.models import Section, Teacher +from .models import Candidate, Interview class CandidateTests(TestCase): @@ -17,6 +17,26 @@ class CandidateTests(TestCase): 'me', 'me@example.org', 'mepassword', first_name='Hans', last_name='Schmid', ) + def test_interview(self): + inter = Interview.objects.create(date=datetime(2018, 3, 10, 10, 30), room='B103') + self.assertEqual(str(inter), 'samedi 10 mars 2018 à 10h30 : ?/? - (N) -salle:B103-???') + ede = Section.objects.create(name='EDE') + cand = Candidate.objects.create( + first_name='Henri', last_name='Dupond', gender='M', section=ede, + email='henri@example.org', deposite_date=date.today() + ) + t1 = Teacher.objects.create(first_name="Julie", last_name="Caux", abrev="JCA") + t2 = Teacher.objects.create(first_name='Jeanne', last_name='Dubois') + inter.teacher_int = t1 + inter.teacher_file = t2 + inter.candidat = cand + inter.save() + self.assertEqual( + str(inter), + 'samedi 10 mars 2018 à 10h30 : Caux Julie/Dubois Jeanne - (N) -salle:B103-Dupond Henri' + ) + self.assertEqual(cand.interview, inter) + def test_send_confirmation_mail(self): ede = Section.objects.create(name='EDE') ase = Section.objects.create(name='ASE')