Merge branch 'master' into master

This commit is contained in:
Claude Paroz 2017-12-05 16:18:42 +01:00 committed by GitHub
commit bc033cbcf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 535 additions and 137 deletions

4
.gitignore vendored
View file

@ -1,5 +1,7 @@
*.pyc
database.db
common/local_settings.py
media/
scripts/epcstages.json
.idea/*.*
static/
.idea/

0
candidats/__init__.py Normal file
View file

126
candidats/admin.py Normal file
View file

@ -0,0 +1,126 @@
from collections import OrderedDict
from datetime import date
from django import forms
from django.contrib import admin
from django.core.mail import send_mail
from django.db.models import BooleanField
from django.template import loader
from stages.exports import OpenXMLExport
from .models import Candidate, GENDER_CHOICES
def export_candidates(modeladmin, request, queryset):
"""
Export all candidates fields.
"""
export_fields = OrderedDict(
[(f.verbose_name, f.name) for f in Candidate._meta.get_fields() if f.name != 'ID']
)
boolean_fields = [f.name for f in Candidate._meta.get_fields() if isinstance(f, BooleanField)]
export_fields['Employeur'] = 'corporation__name'
export_fields['Employeur_localite'] = 'corporation__city'
export_fields['FEE/FPP'] = 'instructor__last_name'
export = OpenXMLExport('Exportation')
export.write_line(export_fields.keys(), bold=True)
for cand in queryset.values_list(*export_fields.values()):
values = []
for value, field_name in zip(cand, export_fields.values()):
if field_name == 'gender':
value = dict(GENDER_CHOICES)[value]
if field_name in boolean_fields:
value = 'Oui' if value else ''
values.append(value)
export.write_line(values)
return export.get_http_response('candidats_export')
export_candidates.short_description = "Exporter les candidats sélectionnés"
def send_confirmation_mail(modeladmin, request, queryset):
from_email = request.user.email
subject = "Confirmation de votre inscription à l'Ecole Santé-social Pierre-Coullery"
for candidate in queryset.filter(
deposite_date__isnull=False, date_confirmation_mail__isnull=True, canceled_file=False):
to = [candidate.email]
if candidate.corporation and candidate.corporation.email:
to.append(candidate.corporation.email)
if candidate.instructor and candidate.instructor.email:
to.append(candidate.instructor.email)
context = {
'candidate_civility': candidate.civility,
'candidate_name': " ".join([candidate.civility, candidate.first_name, candidate.last_name]),
'section': candidate.section,
'sender_name': " ".join([request.user.first_name, request.user.last_name]),
'sender_email': from_email,
}
if candidate.section == 'EDE':
body = loader.render_to_string('email/candidate_confirm_EDE.txt', context)
else:
body = loader.render_to_string('email/candidate_confirm_FE.txt', context)
try:
send_mail(subject, body, from_email, to, fail_silently=False)
except Exception as err:
self.message_user(request, "Échec d'envoi pour le candidat {0} ({1})".format(candidate, err))
else:
candidate.date_confirmation_mail = date.today()
candidate.save()
send_confirmation_mail.short_description = "Envoyer email de confirmation"
class CandidateAdminForm(forms.ModelForm):
class Meta:
model = Candidate
widgets = {
'comment': forms.Textarea(attrs={'cols': 100, 'rows': 1}),
'pcode': forms.TextInput(attrs={'size': 10}),
}
fields = '__all__'
class CandidateAdmin(admin.ModelAdmin):
form = CandidateAdminForm
list_display = ('last_name', 'first_name', 'section', 'confirm_mail')
list_filter = ('section', 'option')
readonly_fields = ('total_result_points', 'total_result_mark', 'date_confirmation_mail')
actions = [export_candidates, send_confirmation_mail]
fieldsets = (
(None, {
'fields': (('first_name', 'last_name', 'gender'),
('street', 'pcode', 'city', 'district'),
('mobile', 'email'),
('birth_date', 'avs', 'handicap', 'has_photo'),
('section', 'option'),
('corporation', 'instructor'),
('deposite_date', 'date_confirmation_mail', 'canceled_file'),
'comment',
),
}),
("FE", {
'classes': ('collapse',),
'fields': (('exemption_ecg', 'integration_second_year', 'validation_sfpo'),),
}),
("EDE/EDS", {
'classes': ('collapse',),
'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'),
('examination_result', 'interview_result', 'file_result', 'total_result_points',
'total_result_mark')
),
}),
)
def confirm_mail(self, obj):
return obj.date_confirmation_mail is not None
confirm_mail.boolean = True
admin.site.register(Candidate, CandidateAdmin)

View file

@ -0,0 +1,69 @@
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('stages', '0002_add_student_option_ase'),
]
operations = [
migrations.CreateModel(
name='Candidate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_name', models.CharField(max_length=40, verbose_name='Prénom')),
('last_name', models.CharField(max_length=40, verbose_name='Nom')),
('gender', models.CharField(choices=[('M', 'Masculin'), ('F', 'Féminin'), ('I', 'Inconnu')], max_length=1, verbose_name='Genre')),
('birth_date', models.DateField(blank=True, null=True, verbose_name='Date de naissance')),
('street', models.CharField(blank=True, max_length=150, verbose_name='Rue')),
('pcode', models.CharField(max_length=4, verbose_name='Code postal')),
('city', models.CharField(max_length=40, verbose_name='Localité')),
('district', models.CharField(blank=True, max_length=2, verbose_name='Canton')),
('mobile', models.CharField(blank=True, max_length=40, verbose_name='Portable')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='Courriel')),
('avs', models.CharField(blank=True, max_length=15, verbose_name='No AVS')),
('handicap', models.BooleanField(default=False)),
('section', models.CharField(choices=[('ASA', 'Aide en soin et accompagnement AFP'), ('ASE', 'Assist. socio-éducatif-ve CFC'), ('ASSC', 'Assist. en soin et santé communautaire CFC'), ('EDE', "Educ. de l'enfance, dipl. ES"), ('EDS', 'Educ. social-e, dipl. ES')], max_length=10, verbose_name='Filière')),
('option', models.CharField(blank=True, choices=[('GEN', 'Généraliste'), ('ENF', 'Enfance'), ('PAG', 'Personnes âgées'), ('HAN', 'Handicap'), ('PE-5400h', 'Parcours Emploi 5400h.'), ('PE-3600h', 'Parcours Emploi 3600h.'), ('PS', 'Parcours stage')], max_length=20, verbose_name='Option')),
('exemption_ecg', models.BooleanField(default=False)),
('validation_sfpo', models.DateField(blank=True, null=True, verbose_name='Confirmation SFPO')),
('integration_second_year', models.BooleanField(default=False, verbose_name='Intégration')),
('date_confirmation_mail', models.DateField(blank=True, null=True, verbose_name='Mail de confirmation')),
('canceled_file', models.BooleanField(default=False, verbose_name='Dossier retiré')),
('has_photo', models.BooleanField(default=False, verbose_name='Photo')),
('registration_form', models.BooleanField(default=False, verbose_name="Formulaire d'inscription")),
('certificate_of_payement', models.BooleanField(default=False, verbose_name='Attest. paiement')),
('police_record', models.BooleanField(default=False, verbose_name='Casier judic.')),
('cv', models.BooleanField(default=False, verbose_name='CV')),
('certif_of_cfc', models.BooleanField(default=False, verbose_name='CFC')),
('certif_of_800h', models.BooleanField(default=False, verbose_name='Attest. 800h.')),
('reflexive_text', models.BooleanField(default=False, verbose_name='Texte réflexif')),
('promise', models.BooleanField(default=False, verbose_name="Promesse d'eng.")),
('contract', models.BooleanField(default=False, verbose_name='Contrat valide')),
('comment', models.TextField(blank=True, verbose_name='Remarques')),
('proc_admin_ext', models.BooleanField(default=False, verbose_name='Insc. autre école')),
('work_certificate', models.BooleanField(default=False, verbose_name='Certif. de travail')),
('marks_certificate', models.BooleanField(default=False, verbose_name='Bull. notes')),
('deposite_date', models.DateField(blank=True, null=True, verbose_name='Date dépôt dossier')),
('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Date entretien prof.')),
('interview_room', models.CharField(blank=True, max_length=50, verbose_name="Salle d'entretien prof.")),
('examination_result', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Points examen')),
('interview_result', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Points entretien prof.')),
('file_result', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Points dossier')),
('total_result_points', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Total points')),
('total_result_mark', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Note finale')),
('accepted', models.BooleanField(default=False, verbose_name='Admis')),
('corporation', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='stages.Corporation', verbose_name='Employeur')),
('file_resp', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='stages.Teacher', verbose_name='Exp. dossier')),
('instructor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='stages.CorpContact', verbose_name='FEE/FPP')),
('interview_resp', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='stages.Teacher', verbose_name='Exp. entretien')),
],
options={
'verbose_name': 'Candidat',
},
),
]

View file

108
candidats/models.py Normal file
View file

@ -0,0 +1,108 @@
from django.db import models
GENDER_CHOICES = (
('M', 'Masculin'),
('F', 'Féminin'),
('I', 'Inconnu')
)
SECTION_CHOICES = (
('ASA', 'Aide en soin et accompagnement AFP'),
('ASE', 'Assist. socio-éducatif-ve CFC'),
('ASSC', 'Assist. en soin et santé communautaire CFC'),
('EDE', 'Educ. de l\'enfance, dipl. ES'),
('EDS', 'Educ. social-e, dipl. ES'),
)
OPTION_CHOICES = (
('GEN', 'Généraliste'),
('ENF', 'Enfance'),
('PAG', 'Personnes âgées'),
('HAN', 'Handicap'),
('PE-5400h', 'Parcours Emploi 5400h.'),
('PE-3600h', 'Parcours Emploi 3600h.'),
('PS', 'Parcours stage'),
)
class Candidate(models.Model):
"""
Inscriptions for new students
"""
first_name = models.CharField('Prénom', max_length=40)
last_name = models.CharField('Nom', max_length=40)
gender = models.CharField('Genre', max_length=1, choices=GENDER_CHOICES)
birth_date = models.DateField('Date de naissance', blank=True, null=True)
street = models.CharField('Rue', max_length=150, blank=True)
pcode = models.CharField('Code postal', max_length=4)
city = models.CharField('Localité', max_length=40)
district = models.CharField('Canton', max_length=2, blank=True)
mobile = models.CharField('Portable', max_length=40, blank=True)
email = models.EmailField('Courriel', blank=True)
avs = models.CharField('No AVS', max_length=15, blank=True)
handicap = models.BooleanField(default=False)
section = models.CharField('Filière', max_length=10, choices=SECTION_CHOICES)
option = models.CharField('Option', max_length=20, choices=OPTION_CHOICES, blank=True)
exemption_ecg = models.BooleanField(default=False)
validation_sfpo = models.DateField('Confirmation SFPO', blank=True, null=True)
integration_second_year = models.BooleanField('Intégration', default=False)
date_confirmation_mail = models.DateField('Mail de confirmation', blank=True, null=True)
canceled_file = models.BooleanField('Dossier retiré', default=False)
has_photo = models.BooleanField(default=False, verbose_name='Photo')
corporation = models.ForeignKey(
'stages.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'
)
# Checking for registration file
registration_form = models.BooleanField("Formulaire d'inscription", default=False)
certificate_of_payement = models.BooleanField("Attest. paiement", default=False)
police_record = models.BooleanField("Casier judic.", default=False)
cv = models.BooleanField("CV", default=False)
certif_of_cfc = models.BooleanField("CFC", default=False)
certif_of_800h = models.BooleanField("Attest. 800h.", default=False)
reflexive_text = models.BooleanField("Texte réflexif", default=False)
promise = models.BooleanField("Promesse d'eng.", default=False)
contract = models.BooleanField("Contrat valide", default=False)
comment = models.TextField('Remarques', blank=True)
proc_admin_ext = models.BooleanField("Insc. autre école", default=False)
work_certificate = models.BooleanField("Certif. de travail", default=False)
marks_certificate = models.BooleanField("Bull. notes", default=False)
deposite_date = models.DateField('Date dépôt dossier', blank=True, null=True)
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'
def __str__(self):
return "%s %s" % (self.last_name, self.first_name)
@property
def civility(self):
if self.gender == 'M':
return 'Monsieur'
if self.gender == 'F':
return 'Madame'
else:
return ''

79
candidats/tests.py Normal file
View file

@ -0,0 +1,79 @@
from datetime import date
from django.contrib.auth.models import User
from django.core import mail
from django.test import TestCase
from django.urls import reverse
from stages.models import Section
from .models import Candidate
class CandidateTests(TestCase):
@classmethod
def setUpTestData(cls):
User.objects.create_superuser(
'me', 'me@example.org', 'mepassword', first_name='Hans', last_name='Schmid',
)
def test_send_confirmation_mail(self):
ede = Section.objects.create(name='EDE')
ase = Section.objects.create(name='ASE')
Candidate.objects.bulk_create([
# A mail should NOT be sent for those first 4
Candidate(
first_name='Sara', last_name='Hitz', gender='F', section=ede,
deposite_date=None),
Candidate(
first_name='Jill', last_name='Simth', gender='F', section=ede,
date_confirmation_mail=date.today()),
Candidate(first_name='Hervé', last_name='Bern', gender='M', section=ede,
canceled_file=True),
Candidate(first_name='Frank', last_name='Pit', gender='M', section=ede, email=''),
# Good
Candidate(first_name='Joé', last_name='Glatz', gender='F', section=ase,
email='joe@example.org', deposite_date=date.today()),
Candidate(first_name='Henri', last_name='Dupond', gender='M', section=ede,
email='henri@example.org', deposite_date=date.today()),
])
change_url = reverse('admin:candidats_candidate_changelist')
self.client.login(username='me', password='mepassword')
response = self.client.post(change_url, {
'action': 'send_confirmation_mail',
'_selected_action': Candidate.objects.values_list('pk', flat=True)
}, follow=True)
self.assertEqual(len(mail.outbox), 2)
self.assertEqual(mail.outbox[0].recipients(), ['henri@example.org'])
self.assertEqual(mail.outbox[1].recipients(), ['joe@example.org'])
# Mail content differ depending on the section
self.assertEqual(mail.outbox[0].body, """Monsieur,
Par ce courriel, nous vous confirmons la bonne réception de votre dossier de candidature à la formation ES dEducateur-trice de lenfance et vous remercions de lintérêt que vous portez à notre institution.
Celui-ci sera traité et des nouvelles vous seront communiquées par courriel durant la 2ème quinzaine du mois de février.
Dans lintervalle, nous vous adressons, Monsieur, nos salutations les plus cordiales.
Secrétariat de l'EPC
tél. 032 886 33 00
Hans Schmid
me@example.org
""".format()
)
self.assertEqual(mail.outbox[1].body, """Madame, Monsieur,
Nous vous confirmons la bonne réception de l'inscription de Madame Joé Glatz dans la filière ASE pour l'année scolaire à venir.
Nous nous tenons à votre disposition pour tout renseignement complémentaire et vous prions de recevoir, Madame, Monsieur, nos salutations les plus cordiales.
Secrétariat de l'EPC
tél. 032 886 33 00
Hans Schmid
me@example.org
""".format()
)
# One was already set, 2 new.
self.assertEqual(Candidate.objects.filter(date_confirmation_mail__isnull=False).count(), 3)

View file

@ -108,6 +108,7 @@ INSTALLED_APPS = (
'tabimport',
'stages',
'candidats',
)
FILE_UPLOAD_HANDLERS = ["django.core.files.uploadhandler.TemporaryFileUploadHandler"]

41
stages/exports.py Normal file
View file

@ -0,0 +1,41 @@
from datetime import date
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
from openpyxl.styles import Font, Style
from openpyxl.writer.excel import save_virtual_workbook
from django.http import HttpResponse
openxml_contenttype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
class OpenXMLExport:
def __init__(self, sheet_title):
self.wb = Workbook()
self.ws = self.wb.active
self.ws.title = sheet_title
self.bold = Style(font=Font(bold=True))
self.row_idx = 1
def write_line(self, values, bold=False, col_widths=()):
for col_idx, value in enumerate(values, start=1):
cell = self.ws.cell(row=self.row_idx, column=col_idx)
try:
cell.value = value
except KeyError:
# Ugly workaround for https://bugs.python.org/issue28969
from openpyxl.utils.datetime import to_excel
to_excel.cache_clear()
cell.value = value
if bold:
cell.style = self.bold
if col_widths:
self.ws.column_dimensions[get_column_letter(col_idx)].width = col_widths[col_idx - 1]
self.row_idx += 1
def get_http_response(self, filename_base):
response = HttpResponse(save_virtual_workbook(self.wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s_%s.xlsx' % (
filename_base, date.strftime(date.today(), '%Y-%m-%d'))
return response

View file

@ -143,7 +143,7 @@ class Migration(migrations.Migration):
('ext_id', models.IntegerField(null=True, unique=True, verbose_name='ID externe')),
('first_name', models.CharField(max_length=40, verbose_name='Prénom')),
('last_name', models.CharField(max_length=40, verbose_name='Nom')),
('gender', models.CharField(blank=True, max_length=3, verbose_name='Genre')),
('gender', models.CharField(blank=True, choices=[('M', 'Masculin'), ('F', 'Féminin')], max_length=3, verbose_name='Genre')),
('birth_date', models.DateField(blank=True, verbose_name='Date de naissance')),
('street', models.CharField(blank=True, max_length=150, verbose_name='Rue')),
('pcode', models.CharField(max_length=4, verbose_name='Code postal')),

View file

@ -148,11 +148,16 @@ class Option(models.Model):
return self.name
GENDER_CHOICES = (
('M', 'Masculin'),
('F', 'Féminin'),
)
class Student(models.Model):
ext_id = models.IntegerField(null=True, unique=True, verbose_name='ID externe')
first_name = models.CharField(max_length=40, verbose_name='Prénom')
last_name = models.CharField(max_length=40, verbose_name='Nom')
gender = models.CharField(max_length=3, blank=True, verbose_name='Genre')
gender = models.CharField('Genre', max_length=3, blank=True, choices=GENDER_CHOICES)
birth_date = models.DateField(blank=True, verbose_name='Date de naissance')
street = models.CharField(max_length=150, blank=True, verbose_name='Rue')
pcode = models.CharField(max_length=4, verbose_name='Code postal')
@ -279,7 +284,7 @@ class CorpContact(models.Model):
verbose_name = "Contact"
def __str__(self):
return '%s %s' % (self.last_name, self.first_name)
return '{0} {1}, {2}'.format(self.last_name, self.first_name, self.corporation)
class Domain(models.Model):

View file

@ -34,7 +34,8 @@ class ChargeSheetPDF(SimpleDocTemplate):
def produce(self, activities):
self.story = []
self.story.append(Image(find('img/header.gif'), width=520, height=75))
header = open(find('img/header.gif'), 'rb')
self.story.append(Image(header, width=520, height=75))
self.story.append(Spacer(0, 2*cm))
destinataire = '{0}<br/>{1}'.format(self.teacher.civility, str(self.teacher))
self.story.append(Paragraph(destinataire, style_adress))
@ -80,6 +81,7 @@ class ChargeSheetPDF(SimpleDocTemplate):
self.story.append(Paragraph(d, style_normal))
self.story.append(PageBreak())
self.build(self.story)
header.close()
class UpdateDataFormPDF(SimpleDocTemplate):
@ -100,8 +102,9 @@ class UpdateDataFormPDF(SimpleDocTemplate):
def produce(self, klass):
self.story = []
header = open(find('img/header.gif'), 'rb')
for student in klass.student_set.filter(archived=False):
self.story.append(Image(find('img/header.gif'), width=520, height=75))
self.story.append(Image(header, width=520, height=75))
self.story.append(Spacer(0, 2*cm))
destinataire = '{0}<br/>{1}<br/>{2}'.format(student.civility, student.full_name, student.klass)
self.story.append(Paragraph(destinataire, style_adress))
@ -180,6 +183,7 @@ class UpdateDataFormPDF(SimpleDocTemplate):
self.story.append(Paragraph("Pas d'élèves dans cette classe", style_normal))
self.build(self.story)
header.close()
def is_corp_required(self, klass_name):
return any(el in klass_name for el in ['FE', 'EDS', 'EDEpe'])

View file

@ -274,7 +274,7 @@ class TeacherTests(TestCase):
response = self.client.get(reverse('imputations_export'))
self.assertEqual(
response['Content-Disposition'],
'attachment; filename=Imputations_export%s.xlsx' % date.strftime(date.today(), '%Y-%m-%d')
'attachment; filename=Imputations_export_%s.xlsx' % date.strftime(date.today(), '%Y-%m-%d')
)

View file

@ -6,10 +6,6 @@ from collections import OrderedDict
from datetime import date, datetime, timedelta
from tabimport import CSVImportedFile, FileFactory
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
from openpyxl.styles import Font, Style
from openpyxl.writer.excel import save_virtual_workbook
from django.conf import settings
from django.contrib import messages
@ -21,6 +17,7 @@ from django.urls import reverse
from django.utils.translation import ugettext as _
from django.views.generic import DetailView, FormView, TemplateView, ListView
from .exports import OpenXMLExport
from .forms import PeriodForm, StudentImportForm, UploadHPFileForm
from .models import (
Klass, Section, Option, Student, Teacher, Corporation, CorpContact, Course, Period,
@ -29,8 +26,6 @@ from .models import (
from .pdf import UpdateDataFormPDF
from .utils import is_int
openxml_contenttype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
def school_year_start():
""" Return first official day of current school year """
@ -97,39 +92,26 @@ class KlassView(DetailView):
if self.request.GET.get('format') != 'xls':
return super().render_to_response(context, **response_kwargs)
wb = Workbook()
ws = wb.active
ws.title = self.object.name
bold = Style(font=Font(bold=True))
headers = [
export = OpenXMLExport(self.object.name)
# Headers
export.write_line([
'Nom', 'Prénom', 'Domicile', 'Date de naissance',
'Stage 1', 'Domaine 1', 'Stage 2', 'Domaine 2', 'Stage 3', 'Domaine 3',
]
col_widths = [18, 15, 20, 14, 25, 12, 25, 12, 25, 12]
# Headers
for col_idx, header in enumerate(headers, start=1):
cell = ws.cell(row=1, column=col_idx)
cell.value = header
cell.style = bold
ws.column_dimensions[get_column_letter(col_idx)].width = col_widths[col_idx - 1]
], bold=True, col_widths=[18, 15, 20, 14, 25, 12, 25, 12, 25, 12])
# Data
for row_idx, student in enumerate(context['students'], start=2):
ws.cell(row=row_idx, column=1).value = student.last_name
ws.cell(row=row_idx, column=2).value = student.first_name
ws.cell(row=row_idx, column=3).value = " ".join([student.pcode, student.city])
ws.cell(row=row_idx, column=4).value = student.birth_date
col_idx = 5
for student in context['students']:
values = [
student.last_name, student.first_name,
" ".join([student.pcode, student.city]), student.birth_date,
]
for training in student.training_set.select_related(
'availability', 'availability__corporation', 'availability__domain'
).all():
ws.cell(row=row_idx, column=col_idx).value = training.availability.corporation.name
ws.cell(row=row_idx, column=col_idx + 1).value = training.availability.domain.name
col_idx += 2
values.append(training.availability.corporation.name)
values.append(training.availability.domain.name)
export.write_line(values)
response = HttpResponse(save_virtual_workbook(wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s_export_%s.xlsx' % (
self.object.name.replace(' ', '_'), date.strftime(date.today(), '%Y-%m-%d'))
return response
return export.get_http_response('%s_export' % self.object.name.replace(' ', '_'))
class AttributionView(TemplateView):
@ -629,78 +611,51 @@ def stages_export(request, scope=None):
if not default_contacts[contact.corporation.name][sname]:
default_contacts[contact.corporation.name][sname] = contact
wb = Workbook()
ws = wb.active
ws.title = 'Stages'
bold = Style(font=Font(bold=True))
# Headers
for col_idx, header in enumerate(export_fields.keys(), start=1):
cell = ws.cell(row=1, column=col_idx)
cell.value = header
cell.style = bold
export = OpenXMLExport('Stages')
export.write_line(export_fields.keys(), bold=True) # Headers
# Data
query_keys = [f for f in export_fields.values() if f is not None]
for row_idx, tr in enumerate(query.values(*query_keys), start=2):
for col_idx, field in enumerate(query_keys, start=1):
value = tr[field]
for line in query.values(*query_keys):
values = []
for field in query_keys:
value = line[field]
if 'gender' in field:
value = {'F': 'Madame', 'M': 'Monsieur', '': ''}[value]
ws.cell(row=row_idx, column=col_idx).value = value
if tr[contact_test_field] is None:
values.append(value)
if line[contact_test_field] is None:
# Use default contact
contact = default_contacts.get(tr[corp_name_field], {}).get(tr[export_fields['Filière']])
contact = default_contacts.get(line[corp_name_field], {}).get(line[export_fields['Filière']])
if contact:
contact_col_idx = list(export_fields.keys()).index('Civilité contact') + 1
ws.cell(row=row_idx, column=contact_col_idx).value = contact.title
ws.cell(row=row_idx, column=contact_col_idx + 1).value = contact.first_name
ws.cell(row=row_idx, column=contact_col_idx + 2).value = contact.last_name
ws.cell(row=row_idx, column=contact_col_idx + 3).value = contact.ext_id
ws.cell(row=row_idx, column=contact_col_idx + 4).value = contact.tel
ws.cell(row=row_idx, column=contact_col_idx + 5).value = contact.email
if always_ccs[tr[corp_name_field]].get(tr[export_fields['Filière']]):
ws.cell(row=row_idx, column=col_idx+1).value = "; ".join(
[c.email for c in always_ccs[tr[corp_name_field]].get(tr[export_fields['Filière']])]
)
values = values[:-6] + [
contact.title, contact.first_name, contact.last_name, contact.ext_id,
contact.tel, contact.email
]
if always_ccs[line[corp_name_field]].get(line[export_fields['Filière']]):
values.append("; ".join(
[c.email for c in always_ccs[line[corp_name_field]].get(line[export_fields['Filière']])]
))
export.write_line(values)
response = HttpResponse(save_virtual_workbook(wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s%s.xlsx' % (
'stages_export_', date.strftime(date.today(), '%Y-%m-%d'))
return response
return export.get_http_response('stages_export')
def imputations_export(request):
wb = Workbook()
ws = wb.active
ws.title = 'Imputations'
bold = Style(font=Font(bold=True))
for col_idx, header in enumerate(IMPUTATIONS_EXPORT_FIELDS, start=1):
cell = ws.cell(row=1, column=col_idx)
cell.value = header
cell.style = bold
export = OpenXMLExport('Imputations')
export.write_line(IMPUTATIONS_EXPORT_FIELDS, bold=True) # Headers
for row_idx, teacher in enumerate(Teacher.objects.filter(archived=False), start=2):
for teacher in Teacher.objects.filter(archived=False):
activities, imputations = teacher.calc_imputations()
ws.cell(row=row_idx, column=1).value = teacher.last_name
ws.cell(row=row_idx, column=2).value = teacher.first_name
ws.cell(row=row_idx, column=3).value = teacher.previous_report
ws.cell(row=row_idx, column=4).value = activities['tot_ens']
ws.cell(row=row_idx, column=5).value = 'Ens. prof.'
ws.cell(row=row_idx, column=6).value = activities['tot_mandats'] + activities['tot_formation']
ws.cell(row=row_idx, column=7).value = 'Accompagnement'
ws.cell(row=row_idx, column=8).value = activities['tot_paye']
ws.cell(row=row_idx, column=9).value = 'Charge globale'
ws.cell(row=row_idx, column=10).value = '{0:.2f}'.format(activities['tot_paye']/21.50)
ws.cell(row=row_idx, column=11).value = teacher.next_report
values = [
teacher.last_name, teacher.first_name, teacher.previous_report,
activities['tot_ens'], 'Ens. prof.', activities['tot_mandats'] + activities['tot_formation'],
'Accompagnement', activities['tot_paye'], 'Charge globale',
'{0:.2f}'.format(activities['tot_paye']/21.50),
teacher.next_report,
]
values.extend(imputations.values())
export.write_line(values)
col_idx = 12
for k, v in imputations.items():
ws.cell(row=row_idx, column=col_idx).value = v
col_idx += 1
response = HttpResponse(save_virtual_workbook(wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s%s.xlsx' % (
'Imputations_export', date.strftime(date.today(), '%Y-%m-%d'))
return response
return export.get_http_response('Imputations_export')
def print_update_form(request):
@ -769,33 +724,23 @@ def general_export(request):
Export all current students data
"""
export_fields = OrderedDict(GENERAL_EXPORT_FIELDS)
wb = Workbook()
ws = wb.active
ws.title = 'Exportation'
bold = Style(font=Font(bold=True))
for col_idx, header in enumerate(export_fields.keys(), start=1):
cell = ws.cell(row=1, column=col_idx)
cell.value = header
cell.style = bold
export = OpenXMLExport('Exportation')
export.write_line(export_fields.keys(), bold=True) # Headers
# Data
query_keys = [f for f in export_fields.values() if f is not None]
query = Student.objects.filter(archived=False).order_by('klass__name', 'last_name', 'first_name')
for row_idx, tr in enumerate(query.values(*query_keys), start=2):
for col_idx, field in enumerate(query_keys, start=1):
for line in query.values(*query_keys):
values = []
for field in query_keys:
if field == 'gender':
tr[field] = ('Madame', 'Monsieur')[tr[field] == 'M']
if field == 'dispense_ecg':
tr[field] = ('', 'Oui')[tr[field] == 1]
if field == 'dispense_eps':
tr[field] = ('', 'Oui')[tr[field] == 1]
if field == 'soutien_dys':
tr[field] = ('', 'Oui')[tr[field] == 1]
ws.cell(row=row_idx, column=col_idx).value = tr[field]
values.append(('Madame', 'Monsieur')[line[field] == 'M'])
elif field in ('dispense_ecg', 'dispense_eps', 'soutien_dys'):
values.append('Oui' if line[field] is True else '')
else:
values.append(line[field])
export.write_line(values)
response = HttpResponse(save_virtual_workbook(wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s%s.xlsx' % (
'general_export_', date.strftime(date.today(), '%Y-%m-%d'))
return response
return export.get_http_response('general_export')
ORTRA_EXPORT_FIELDS = [
@ -836,14 +781,8 @@ def ortra_export(request):
Export students data from sections ASAFE, ASEFE and ASSCFE
"""
export_fields = OrderedDict(ORTRA_EXPORT_FIELDS)
wb = Workbook()
ws = wb.active
ws.title = 'Exportation'
bold = Style(font=Font(bold=True))
for col_idx, header in enumerate(export_fields.keys(), start=1):
cell = ws.cell(row=1, column=col_idx)
cell.value = header
cell.style = bold
export = OpenXMLExport('Exportation')
export.write_line(export_fields.keys(), bold=True) # Headers
# Data
query_keys = [f for f in export_fields.values() if f is not None]
query = Student.objects.filter(Q(klass__name__contains='ASAFE') |
@ -853,14 +792,13 @@ def ortra_export(request):
'last_name',
'first_name')
for row_idx, tr in enumerate(query.values(*query_keys), start=2):
for col_idx, field in enumerate(query_keys, start=1):
for line in query.values(*query_keys):
values = []
for field in query_keys:
if field == 'gender':
tr[field] = ('Madame', 'Monsieur')[tr[field] == 'M']
ws.cell(row=row_idx, column=col_idx).value = tr[field]
response = HttpResponse(save_virtual_workbook(wb), content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename=%s%s.xlsx' % (
'ortra_export_', date.strftime(date.today(), '%Y-%m-%d'))
return response
values.append(('Madame', 'Monsieur')[line[field] == 'M'])
else:
values.append(line[field])
export.write_line(values)
return export.get_http_response('ortra_export')

View file

@ -0,0 +1,14 @@
{{ candidate_civility }},
Par ce courriel, nous vous confirmons la bonne réception de votre dossier de candidature à la formation ES dEducateur-trice de lenfance et vous remercions de lintérêt que vous portez à notre institution.
Celui-ci sera traité et des nouvelles vous seront communiquées par courriel durant la 2ème quinzaine du mois de février.
Dans lintervalle, nous vous adressons, {{ candidate_civility }}, nos salutations les plus cordiales.
Secrétariat de l'EPC
tél. 032 886 33 00
{{ sender_name }}
{{ sender_email }}

View file

@ -0,0 +1,11 @@
Madame, Monsieur,
Nous vous confirmons la bonne réception de l'inscription de {{ candidate_name }} dans la filière {{ section }} pour l'année scolaire à venir.
Nous nous tenons à votre disposition pour tout renseignement complémentaire et vous prions de recevoir, Madame, Monsieur, nos salutations les plus cordiales.
Secrétariat de l'EPC
tél. 032 886 33 00
{{ sender_name }}
{{ sender_email }}