Allow different compensation forms (experts/mentors)

This commit is contained in:
Claude Paroz 2020-04-23 12:08:18 +02:00
parent fa519cddff
commit 95a30d6731
5 changed files with 105 additions and 48 deletions

View file

@ -42,19 +42,22 @@ urlpatterns = [
name='candidate-validation'),
path('candidate/<int:pk>/summary/', candidats_views.inscription_summary, name='candidate-summary'),
path('student/<int:pk>/examination/mentor/', views.PrintCompensationForm.as_view(), {'typ': 'mentor'},
name='print-mentor-compens-form'),
path('exam/<int:pk>/indemn/<slug:typ>/', views.PrintCompensationForm.as_view(),
name='print-compens-form'),
# Qualification EDE
path('student_ede/<int:pk>/send_convocation/', views.StudentConvocationExaminationView.as_view(),
name='student-ede-convocation'),
path('student_ede/<int:pk>/examination/expert/', views.PrintExpertEDECompensationForm.as_view(),
name='print-expert-compens-ede'),
path('student_ede/<int:pk>/examination/mentor/', views.PrintMentorEDECompensationForm.as_view(),
name='print-mentor-compens-ede'),
name='print-expert-letter-ede'),
# Qualification EDS
path('student_eds/<int:pk>/send_convocation/', views.StudentConvocationEDSView.as_view(),
name='student-eds-convocation'),
path('student_eds/<int:pk>/examination/expert/', views.PrintExpertEDSCompensationForm.as_view(),
name='print-expert-compens-eds'),
name='print-expert-letter-eds'),
path('student/export_qualif/<slug:section>/', views.export.export_qualification,
name='export-qualif'),

View file

@ -130,10 +130,12 @@ class ExaminationInline(admin.StackedInline):
return format_html(
'<a class="button" href="{}">Courrier pour lexpert</a>&nbsp;'
'<a class="button" href="{}">Mail convocation soutenance</a>&nbsp;'
'<a class="button" href="{}">Indemnité au mentor</a>',
reverse('print-expert-compens-ede', args=[obj.pk]),
'<a class="button" href="{}">Indemnité EP</a>&nbsp;'
'<a class="button" href="{}">Indemnité soutenance</a>',
reverse('print-expert-letter-ede', args=[obj.pk]),
reverse('student-ede-convocation', args=[obj.pk]),
reverse('print-mentor-compens-ede', args=[obj.student.pk]),
reverse('print-compens-form', args=[obj.pk, 'ep']),
reverse('print-compens-form', args=[obj.pk, 'sout']),
)
elif obj and obj.student.is_eds_3():
if obj.missing_examination_data():
@ -142,10 +144,12 @@ class ExaminationInline(admin.StackedInline):
return format_html(
'<a class="button" href="{}">Courrier pour lexpert</a>&nbsp;'
'<a class="button" href="{}">Mail convocation soutenance</a>&nbsp;'
'<a class="button" href="{}">Indemnité au mentor</a>',
reverse('print-expert-compens-eds', args=[obj.pk]),
'<a class="button" href="{}">Indemnité EP</a>&nbsp;'
'<a class="button" href="{}">Indemnité soutenance</a>',
reverse('print-expert-letter-eds', args=[obj.pk]),
reverse('student-eds-convocation', args=[obj.pk]),
reverse('print-mentor-compens-ede', args=[obj.student.pk]),
reverse('print-compens-form', args=[obj.pk, 'ep']),
reverse('print-compens-form', args=[obj.pk, 'sout']),
)
else:
return missing_message
@ -158,7 +162,7 @@ class StudentAdmin(admin.ModelAdmin):
list_filter = (('archived', ArchivedListFilter), ('klass', KlassRelatedListFilter))
search_fields = ('last_name', 'first_name', 'pcode', 'city', 'klass__name')
autocomplete_fields = ('corporation', 'instructor', 'supervisor', 'mentor')
readonly_fields = ('report_sem1_sent', 'report_sem2_sent')
readonly_fields = ('report_sem1_sent', 'report_sem2_sent', 'mentor_indemn')
fieldsets = [
(None, {
'fields': (
@ -176,13 +180,23 @@ class StudentAdmin(admin.ModelAdmin):
'fields': (
('supervisor', 'supervision_attest_received'),
('subject', 'title'),
('training_referent', 'referent', 'mentor'),
('training_referent', 'referent'),
('mentor', 'mentor_indemn'),
)
}),
]
actions = ['archive']
inlines = [ExaminationInline, SupervisionBillInline]
def mentor_indemn(self, obj):
if obj is None or not obj.mentor:
return '-'
return format_html(
'<a class="button" href="{}">Indemnité au mentor</a>',
reverse('print-mentor-compens-form', args=[obj.pk]),
)
mentor_indemn.short_description = 'Indemnité'
def get_inlines(self, request, obj=None):
if obj is None:
return []

View file

@ -286,6 +286,7 @@ class UpdateDataFormPDF(EpcBaseDocTemplate):
class CompensationForm:
"""Mixin class to host paiement formdata."""
AMOUNT = ''
EXPERT_MANDAT = 'EXPERT'
MENTOR_MANDAT = 'MENTOR'
EXPERT_ACCOUNT = MENTOR_ACCOUNT = "3'130'0003"
@ -336,12 +337,12 @@ class CompensationForm:
self.story.append(Spacer(0, 0.5 * cm))
def add_accounting_stamp(self, student, mandat=None):
account = otp = total = ''
account = otp = ''
total = self.AMOUNT
if mandat == self.EXPERT_MANDAT:
account = self.EXPERT_ACCOUNT
elif mandat == self.MENTOR_MANDAT:
account = self.MENTOR_ACCOUNT
total = '500.-'
if student.klass.is_Ede_pe():
otp = self.OTP_EDE_PE_OTP
@ -535,32 +536,59 @@ class ExpertEdsLetterPdf(ExpertEdeLetterPdf):
"""
class MentorCompensationPdfForm(CompensationForm, EpcBaseDocTemplate):
def __init__(self, out, student):
self.student = student
super().__init__(out)
class CompensationPDFForm(CompensationForm, EpcBaseDocTemplate):
def __init__(self, out, *args, **kwargs):
super().__init__(out, *args, **kwargs)
self.addPageTemplates([
PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header_iso)
])
def produce(self):
self.add_private_data(self.student.mentor)
self.add_private_data(self.expert)
self.story.append(Paragraph(
"Mandat : Mentoring de {0} {1}, classe {2}".format(
self.mandat_template.format(
self.student.civility, self.student.full_name, self.student.klass
), style_normal_center
))
self.story.append(Paragraph(
"Montant forfaitaire de Fr 500.- payable à la fin de la session d'examen", style_normal_center
))
self.story.append(Paragraph(self.montant_template, style_normal_center))
self.story.append(Spacer(0, 3 * cm))
self.add_accounting_stamp(self.student, self.MENTOR_MANDAT)
self.add_accounting_stamp(self.student, self.mandat_type)
self.build(self.story)
class MentorCompensationPdfForm(CompensationPDFForm):
mandat_type = CompensationPDFForm.MENTOR_MANDAT
mandat_template = "Mandat : Mentoring de {0} {1}, classe {2}"
montant_template = "Montant forfaitaire de Fr 500.- payable à la fin de la session dexamen"
AMOUNT = '500.-'
def __init__(self, out, student):
self.student = student
self.expert = student.mentor
super().__init__(out)
class EntretienProfCompensationPdfForm(CompensationPDFForm):
mandat_type = CompensationPDFForm.EXPERT_MANDAT
mandat_template = "Mandat : Entretien professionnel pour {0} {1}, classe {2}"
montant_template = "Montant forfaitaire de Fr 200.- payable à la fin de la session dexamen"
AMOUNT = '200.-'
def __init__(self, out, exam):
self.student = exam.student
self.expert = exam.external_expert
super().__init__(out)
class SoutenanceCompensationPdfForm(EntretienProfCompensationPdfForm):
mandat_template = "Mandat : Soutenance pour {0} {1}, classe {2}"
montant_template = "Montant forfaitaire de Fr 200.- payable à la fin de la session dexamen"
AMOUNT = '200.-'
class KlassListPDF(EpcBaseDocTemplate):
"""
Génération des rôles de classes en pdf.

View file

@ -334,7 +334,7 @@ tél. 032 886 33 00
def test_print_ede_compensation_forms(self):
st = Student.objects.get(first_name="Albin")
exam = Examination.objects.create(student=st, session=ExamEDESession.objects.create(year=2020, season='1'))
url = reverse('print-expert-compens-ede', args=[exam.pk])
url = reverse('print-expert-letter-ede', args=[exam.pk])
self.client.login(username='me', password='mepassword')
response = self.client.get(url, follow=True)
self.assertContains(response, "Toutes les informations ne sont pas disponibles")
@ -361,7 +361,7 @@ tél. 032 886 33 00
# Mentor form
st.mentor = CorpContact.objects.get(last_name="Horner")
st.save()
response = self.client.get(reverse('print-mentor-compens-ede', args=[st.pk]), follow=True)
response = self.client.get(reverse('print-mentor-compens-form', args=[st.pk]), follow=True)
self.assertEqual(
response['Content-Disposition'],
'attachment; filename="dupond_albin_Indemn_mentor.pdf"'
@ -378,7 +378,7 @@ tél. 032 886 33 00
pcode="2000", city="Neuchâtel", klass=klass
)
exam = Examination.objects.create(student=st, session=ExamEDESession.objects.create(year=2020, season='1'))
url = reverse('print-expert-compens-eds', args=[exam.pk])
url = reverse('print-expert-letter-eds', args=[exam.pk])
self.client.login(username='me', password='mepassword')
response = self.client.get(url, follow=True)
self.assertContains(response, "Toutes les informations ne sont pas disponibles")

View file

@ -26,10 +26,7 @@ from ..models import (
Klass, Section, Student, Teacher, Corporation, CorpContact, Period,
Training, Availability, Examination,
)
from ..pdf import (
ChargeSheetPDF, ExpertEdeLetterPdf, ExpertEdsLetterPdf, UpdateDataFormPDF,
MentorCompensationPdfForm, KlassListPDF,
)
from .. import pdf
from ..utils import school_year_start
@ -501,8 +498,8 @@ class PrintUpdateForm(ZippedFilesBaseView):
for klass in Klass.objects.filter(level__gte=2
).exclude(section__name='MP_ASSC').exclude(section__name='MP_ASE'):
buff = io.BytesIO()
pdf = UpdateDataFormPDF(buff, self.return_date)
pdf.produce(klass)
pdf_doc = pdf.UpdateDataFormPDF(buff, self.return_date)
pdf_doc.produce(klass)
yield ('{0}.pdf'.format(klass.name), buff.getvalue())
@ -511,7 +508,7 @@ class PrintExpertEDECompensationForm(PDFBaseView):
Imprime le PDF à envoyer à l'expert EDE en accompagnement du
travail de diplôme
"""
pdf_class = ExpertEdeLetterPdf
pdf_class = pdf.ExpertEdeLetterPdf
def filename(self, exam):
return slugify('{0}_{1}'.format(exam.student.last_name, exam.student.first_name)) + '_Expert.pdf'
@ -536,25 +533,40 @@ class PrintExpertEDECompensationForm(PDFBaseView):
return super().get(request, *args, **kwargs)
class PrintMentorEDECompensationForm(PDFBaseView):
class PrintCompensationForm(PDFBaseView):
"""
Imprime le PDF à envoyer au mentor EDE pour le mentoring
"""
pdf_class = MentorCompensationPdfForm
@property
def pdf_class(self):
return {
'mentor': pdf.MentorCompensationPdfForm,
'ep': pdf.EntretienProfCompensationPdfForm,
'sout': pdf.SoutenanceCompensationPdfForm,
}.get(self.typ)
def filename(self, student):
def filename(self, obj):
student = obj if self.typ == 'mentor' else obj.student
return slugify(
'{0}_{1}'.format(student.last_name, student.first_name)
) + '_Indemn_mentor.pdf'
) + f'_Indemn_{self.typ}.pdf'
def get_object(self):
return Student.objects.get(pk=self.kwargs['pk'])
model = Student if self.typ == 'mentor' else Examination
return model.objects.get(pk=self.kwargs['pk'])
def get(self, request, *args, **kwargs):
student = self.get_object()
if not student.mentor:
messages.error(request, "Aucun mentor n'est attribué à cet étudiant")
return redirect(reverse("admin:stages_student_change", args=(student.pk,)))
self.typ = self.kwargs['typ']
if self.typ == 'mentor':
student = self.get_object()
if not student.mentor:
messages.error(request, "Aucun mentor nest attribué à cet étudiant")
return redirect(reverse("admin:stages_student_change", args=(student.pk,)))
else:
exam = self.get_object()
if not exam.external_expert:
messages.error(request, "Aucun expert nest attribué à cet examen")
return redirect(reverse("admin:stages_student_change", args=(exam.student.pk,)))
return super().get(request, *args, **kwargs)
@ -563,7 +575,7 @@ class PrintExpertEDSCompensationForm(PrintExpertEDECompensationForm):
Imprime le PDF à envoyer à l'expert EDS en accompagnement du
travail final.
"""
pdf_class = ExpertEdsLetterPdf
pdf_class = pdf.ExpertEdsLetterPdf
def check_object(self, exam):
missing = exam.missing_examination_data()
@ -581,8 +593,8 @@ class PrintKlassList(ZippedFilesBaseView):
def generate_files(self):
for klass in Klass.active.order_by('section', 'name'):
buff = io.BytesIO()
pdf = KlassListPDF(buff, klass)
pdf.produce(klass)
pdf_doc = pdf.KlassListPDF(buff, klass)
pdf_doc.produce(klass)
filename = slugify(klass.name + '.pdf')
yield (filename, buff.getvalue())
@ -599,7 +611,7 @@ class PrintChargeSheet(ZippedFilesBaseView):
for teacher in queryset:
activities = teacher.calc_activity()
buff = io.BytesIO()
pdf = ChargeSheetPDF(buff, teacher)
pdf.produce(activities)
pdf_doc = pdf.ChargeSheetPDF(buff, teacher)
pdf_doc.produce(activities)
filename = slugify('{0}_{1}'.format(teacher.last_name, teacher.first_name)) + '.pdf'
yield (filename, buff.getvalue())