Add convocation email functionality for EDS section
This commit is contained in:
parent
35e5c84933
commit
067f6f96ac
6 changed files with 194 additions and 24 deletions
|
|
@ -107,7 +107,8 @@ class StudentAdmin(admin.ModelAdmin):
|
|||
search_fields = ('last_name', 'first_name', 'pcode', 'city', 'klass__name')
|
||||
autocomplete_fields = ('corporation', 'instructor', 'supervisor', 'mentor', 'expert')
|
||||
readonly_fields = (
|
||||
'report_sem1_sent', 'report_sem2_sent', 'examination_actions',
|
||||
'report_sem1_sent', 'report_sem2_sent',
|
||||
'examination_actions', 'examination_ep_actions',
|
||||
'date_soutenance_mailed', 'date_soutenance_ep_mailed'
|
||||
)
|
||||
fieldsets = (
|
||||
|
|
@ -140,7 +141,7 @@ class StudentAdmin(admin.ModelAdmin):
|
|||
('session_ep', 'date_exam_ep', 'room_ep', 'mark_ep'),
|
||||
('internal_expert_ep', 'expert_ep'),
|
||||
('date_soutenance_ep_mailed', 'date_confirm_ep_received'),
|
||||
#('examination_actions',)
|
||||
('examination_ep_actions',)
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
|
@ -174,6 +175,18 @@ class StudentAdmin(admin.ModelAdmin):
|
|||
return ''
|
||||
examination_actions.short_description = 'Actions pour les examens ES'
|
||||
|
||||
def examination_ep_actions(self, obj):
|
||||
if obj.klass and obj.klass.section.name == 'EDS' and obj.klass.level.name == "3":
|
||||
return format_html(
|
||||
'<a class="button" href="{}">Courrier pour l’expert</a> '
|
||||
'<a class="button" href="{}">Mail convocation soutenance</a> ',
|
||||
'', #reverse('print-expert-compens-eds', args=[obj.pk]),
|
||||
reverse('student-eds-convocation', args=[obj.pk]),
|
||||
)
|
||||
else:
|
||||
return ''
|
||||
examination_ep_actions.short_description = 'Actions pour les examens ES'
|
||||
|
||||
|
||||
class CorpContactAdmin(admin.ModelAdmin):
|
||||
list_display = ('__str__', 'corporation', 'role')
|
||||
|
|
|
|||
|
|
@ -407,6 +407,18 @@ class Student(models.Model):
|
|||
missing.append("L’expert interne n’est pas défini")
|
||||
return missing
|
||||
|
||||
def missing_examination_ep_data(self):
|
||||
missing = []
|
||||
if not self.date_exam_ep:
|
||||
missing.append("La date d’examen est manquante")
|
||||
if not self.room_ep:
|
||||
missing.append("La salle d’examen n’est pas définie")
|
||||
if not self.expert_ep:
|
||||
missing.append("L’expert externe n’est pas défini")
|
||||
if not self.internal_expert_ep:
|
||||
missing.append("L’expert interne n’est pas défini")
|
||||
return missing
|
||||
|
||||
|
||||
class StudentFile(models.Model):
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class StagesTests(TestCase):
|
|||
sect_ase = Section.objects.get(name='MP_ASE')
|
||||
lev1 = Level.objects.create(name='1')
|
||||
lev2 = Level.objects.create(name='2')
|
||||
lev3 = Level.objects.create(name='3')
|
||||
klass1 = Klass.objects.create(name="1ASE3", section=sect_ase, level=lev1)
|
||||
klass2 = Klass.objects.create(name="2ASE3", section=sect_ase, level=lev2)
|
||||
klass3 = Klass.objects.create(name="2EDS", section=Section.objects.get(name='EDS'), level=lev2)
|
||||
|
|
@ -261,6 +262,70 @@ tél. 032 886 33 00
|
|||
st.refresh_from_db()
|
||||
self.assertIsNotNone(st.date_soutenance_mailed)
|
||||
|
||||
def test_send_eds_convocation(self):
|
||||
klass = Klass.objects.create(
|
||||
name="3EDS", section=Section.objects.get(name='EDS'), level=Level.objects.get(name='3')
|
||||
)
|
||||
st = Student.objects.create(
|
||||
first_name="Laurent", last_name="Hots", birth_date="1994-07-12",
|
||||
pcode="2000", city="Neuchâtel", klass=klass
|
||||
)
|
||||
|
||||
self.client.login(username='me', password='mepassword')
|
||||
url = reverse('student-eds-convocation', args=[st.pk])
|
||||
response = self.client.get(url, follow=True)
|
||||
for err in ("L’étudiant-e n’a pas de courriel valide",
|
||||
"La date d’examen est manquante",
|
||||
"La salle d’examen n’est pas définie",
|
||||
"L’expert externe n’est pas défini",
|
||||
"L’expert interne n’est pas défini"):
|
||||
self.assertContains(response, err)
|
||||
st.email = 'hots@example.org'
|
||||
st.date_exam_ep = datetime(2018, 6, 28, 12, 00)
|
||||
st.room_ep = "B123"
|
||||
st.expert_ep = CorpContact.objects.get(last_name="Horner")
|
||||
st.internal_expert_ep = Teacher.objects.get(last_name="Caux")
|
||||
st.save()
|
||||
response = self.client.get(url, follow=True)
|
||||
self.assertContains(response, "L’expert externe n’a pas de courriel valide !")
|
||||
st.expert_ep.email = "horner@example.org"
|
||||
st.expert_ep.save()
|
||||
response = self.client.get(url)
|
||||
expected_message = """ Laurent Hots,
|
||||
Madame Julie Caux,
|
||||
Monsieur Jean Horner,
|
||||
|
||||
|
||||
Nous vous informons que la soutenance du travail final de Laurent Hots aura lieu dans les locaux de l’Ecole Santé-social Pierre-Coullery, rue Sophie-Mairet 29-31, 2300 La Chaux-de-Fonds en date du:
|
||||
|
||||
- jeudi 28 juin 2018 à 12h00 en salle B123
|
||||
|
||||
|
||||
Nous informons également Monsieur Horner que le mémoire lui est adressé ce jour par courrier postal.
|
||||
|
||||
|
||||
Nous vous remercions de nous confirmer par retour de courriel que vous avez bien reçu ce message et dans l’attente du plaisir de vous rencontrer prochainement, nous vous prions d’agréer, Madame, Messieurs, nos salutations les meilleures.
|
||||
|
||||
|
||||
|
||||
Secrétariat de la filière Education sociale, dipl. ES
|
||||
Jean Valjean
|
||||
me@example.org
|
||||
tél. 032 886 33 00
|
||||
"""
|
||||
self.assertEqual(response.context['form'].initial['message'], expected_message)
|
||||
# Now send the message
|
||||
response = self.client.post(url, data={
|
||||
'cci': 'me@example.org',
|
||||
'to': st.email,
|
||||
'subject': "Convocation",
|
||||
'message': "Monsieur Albin, ...",
|
||||
'sender': 'me@example.org',
|
||||
})
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
st.refresh_from_db()
|
||||
self.assertIsNotNone(st.date_soutenance_ep_mailed)
|
||||
|
||||
def test_print_ede_compensation_forms(self):
|
||||
st = Student.objects.get(first_name="Albin")
|
||||
url = reverse('print-expert-compens-ede', args=[st.pk])
|
||||
|
|
|
|||
|
|
@ -398,36 +398,55 @@ class EmailConfirmationView(EmailConfirmationBaseView):
|
|||
class StudentConvocationExaminationView(EmailConfirmationView):
|
||||
success_message = "Le message de convocation a été envoyé pour l’étudiant {person}"
|
||||
title = "Convocation à la soutenance du travail de diplôme"
|
||||
email_template = 'email/student_convocation_EDE.txt'
|
||||
|
||||
@property
|
||||
def expert(self):
|
||||
return self.student.expert
|
||||
|
||||
@property
|
||||
def internal_expert(self):
|
||||
return self.student.internal_expert
|
||||
|
||||
@property
|
||||
def date_soutenance_mailed(self):
|
||||
return self.student.date_soutenance_mailed
|
||||
|
||||
def missing_examination_data(self):
|
||||
return self.student.missing_examination_data()
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.student = Student.objects.get(pk=self.kwargs['pk'])
|
||||
errors = self.student.missing_examination_data()
|
||||
if self.student.expert and not self.student.expert.email:
|
||||
errors.append("L’expert externe n’a pas de courriel valide !")
|
||||
if self.student.internal_expert and not self.student.internal_expert.email:
|
||||
errors.append("L’expert interne n'a pas de courriel valide !")
|
||||
if self.student.date_soutenance_mailed is not None:
|
||||
errors.append("Une convocation a déjà été envoyée !")
|
||||
errors = self.missing_examination_data()
|
||||
errors.extend(self.check_errors())
|
||||
if errors:
|
||||
messages.error(request, "\n".join(errors))
|
||||
return redirect(reverse("admin:stages_student_change", args=(self.student.pk,)))
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
initial = super().get_initial()
|
||||
to = [self.student.email, self.student.expert.email, self.student.internal_expert.email]
|
||||
src_email = 'email/student_convocation_EDE.txt'
|
||||
def check_errors(self):
|
||||
errors = []
|
||||
if not self.student.email:
|
||||
errors.append("L’étudiant-e n’a pas de courriel valide !")
|
||||
if self.expert and not self.expert.email:
|
||||
errors.append("L’expert externe n’a pas de courriel valide !")
|
||||
if self.internal_expert and not self.internal_expert.email:
|
||||
errors.append("L’expert interne n'a pas de courriel valide !")
|
||||
if self.date_soutenance_mailed is not None:
|
||||
errors.append("Une convocation a déjà été envoyée !")
|
||||
return errors
|
||||
|
||||
def msg_context(self):
|
||||
# Recipients with ladies first!
|
||||
recip_names = sorted([
|
||||
self.student.civility_full_name,
|
||||
self.student.expert.civility_full_name,
|
||||
self.student.internal_expert.civility_full_name,
|
||||
self.expert.civility_full_name,
|
||||
self.internal_expert.civility_full_name,
|
||||
])
|
||||
titles = [
|
||||
self.student.civility,
|
||||
self.student.expert.civility,
|
||||
self.student.internal_expert.civility,
|
||||
self.expert.civility,
|
||||
self.internal_expert.civility,
|
||||
]
|
||||
mme_count = titles.count('Madame')
|
||||
# Civilities, with ladies first!
|
||||
|
|
@ -439,29 +458,65 @@ class StudentConvocationExaminationView(EmailConfirmationView):
|
|||
civilities = 'Mesdames, Monsieur'
|
||||
else:
|
||||
civilities = 'Mesdames'
|
||||
|
||||
msg_context = {
|
||||
return {
|
||||
'recipient1': recip_names[0],
|
||||
'recipient2': recip_names[1],
|
||||
'recipient3': recip_names[2],
|
||||
'student': self.student,
|
||||
'sender': self.request.user,
|
||||
'global_civilities': civilities,
|
||||
'date_examen': django_format(self.student.date_exam, 'l j F Y à H\hi'),
|
||||
'date_examen': django_format(self.student.date_exam, 'l j F Y à H\hi') if self.student.date_exam else '-',
|
||||
'salle': self.student.room,
|
||||
}
|
||||
|
||||
def get_initial(self):
|
||||
initial = super().get_initial()
|
||||
to = [self.student.email, self.expert.email, self.internal_expert.email]
|
||||
|
||||
initial.update({
|
||||
'cci': self.request.user.email,
|
||||
'to': '; '.join(to),
|
||||
'subject': "Convocation à la soutenance de travail de diplôme",
|
||||
'message': loader.render_to_string(src_email, msg_context),
|
||||
'subject': self.title,
|
||||
'message': loader.render_to_string(self.email_template, self.msg_context()),
|
||||
'sender': self.request.user.email,
|
||||
})
|
||||
return initial
|
||||
|
||||
def on_success(self, student):
|
||||
student.date_soutenance_mailed = timezone.now()
|
||||
student.save()
|
||||
self.student.date_soutenance_mailed = timezone.now()
|
||||
self.student.save()
|
||||
|
||||
|
||||
class StudentConvocationEDSView(StudentConvocationExaminationView):
|
||||
title = "Convocation à la soutenance du travail final"
|
||||
email_template = 'email/student_convocation_EDS.txt'
|
||||
|
||||
@property
|
||||
def expert(self):
|
||||
return self.student.expert_ep
|
||||
|
||||
@property
|
||||
def internal_expert(self):
|
||||
return self.student.internal_expert_ep
|
||||
|
||||
@property
|
||||
def date_soutenance_mailed(self):
|
||||
return self.student.date_soutenance_ep_mailed
|
||||
|
||||
def missing_examination_data(self):
|
||||
return self.student.missing_examination_ep_data()
|
||||
|
||||
def msg_context(self):
|
||||
context = super().msg_context()
|
||||
context.update({
|
||||
'date_examen': django_format(self.student.date_exam_ep, 'l j F Y à H\hi'),
|
||||
'salle': self.student.room_ep,
|
||||
})
|
||||
return context
|
||||
|
||||
def on_success(self, student):
|
||||
self.student.date_soutenance_ep_mailed = timezone.now()
|
||||
self.student.save()
|
||||
|
||||
|
||||
class PrintUpdateForm(ZippedFilesBaseView):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue