eds/cms/pdf.py

346 lines
15 KiB
Python
Raw Permalink Normal View History

2018-05-18 15:53:28 +02:00
import os
import tempfile
2017-11-02 14:56:11 +01:00
2018-05-18 15:53:28 +02:00
from django.conf import settings
2018-05-22 16:04:39 +02:00
from django.contrib.staticfiles.finders import find
2018-05-18 15:53:28 +02:00
from reportlab.lib import colors
from reportlab.lib.enums import TA_LEFT, TA_CENTER
2017-08-13 22:58:46 +02:00
from reportlab.lib.pagesizes import A4, landscape
2018-05-22 16:04:39 +02:00
from reportlab.lib.styles import ParagraphStyle
2017-08-13 22:58:46 +02:00
from reportlab.lib.units import cm
2017-10-30 14:31:02 +01:00
from reportlab.pdfgen import canvas
2018-05-18 15:53:28 +02:00
from reportlab.platypus import (Frame, FrameBreak, Flowable, NextPageTemplate,
Paragraph, PageTemplate, Preformatted, Spacer,
SimpleDocTemplate, Table, TableStyle
)
2017-10-30 14:31:02 +01:00
2018-05-22 16:04:39 +02:00
style_normal = ParagraphStyle(name='CORPS', fontName='Helvetica', fontSize=9, alignment=TA_LEFT)
style_bold = ParagraphStyle(name='CORPS', fontName='Helvetica-Bold', fontSize=10, alignment=TA_LEFT)
style_footer = ParagraphStyle(name='CORPS', fontName='Helvetica', fontSize=7, alignment=TA_CENTER)
2017-10-30 14:31:02 +01:00
2018-02-16 11:14:31 +01:00
LOGO_EPC = find('img/logo_EPC.png')
LOGO_ESNE = find('img/logo_ESNE.png')
2018-05-18 15:53:28 +02:00
LOGO_EPC_LONG = find('img/header.gif')
class HorLine(Flowable):
"""Horizontal Line flowable --- draws a line in a flowable"""
def __init__(self, width):
Flowable.__init__(self)
self.width = width
def __repr__(self):
return "Line(w=%s)" % self.width
def draw(self):
self.canv.line(0, 0, self.width, 0)
class EpcBaseDocTemplate(SimpleDocTemplate):
points = '.' * 93
2018-05-22 16:04:39 +02:00
def __init__(self, filename, section='', subject='', orientation=A4):
2018-05-18 15:53:28 +02:00
path = os.path.join(tempfile.gettempdir(), filename)
super().__init__(
path,
pagesize=orientation,
lefMargin=2.5 * cm, bottomMargin=1 * cm, topMargin=1 * cm, rightMargin=2.5 * cm
)
self.page_frame = Frame(
self.leftMargin, self.bottomMargin, self.width - 2.5, self.height - 4 * cm,
id='first_table', showBoundary=0, leftPadding=0 * cm
)
self.story = []
2018-05-22 16:04:39 +02:00
self.section = section
self.subject = subject
2018-05-18 15:53:28 +02:00
def header(self, canvas, doc):
2018-05-22 16:04:39 +02:00
# Logos
2018-05-18 15:53:28 +02:00
canvas.saveState()
canvas.drawImage(
LOGO_EPC, doc.leftMargin, doc.height - 1.5 * cm, 5 * cm, 3 * cm, preserveAspectRatio=True
)
canvas.drawImage(
LOGO_ESNE, doc.width - 2.5 * cm, doc.height - 1.2 * cm, 5 * cm, 3 * cm, preserveAspectRatio=True
)
2018-05-22 16:04:39 +02:00
# Section and subject
2018-05-18 15:53:28 +02:00
x = doc.leftMargin
y = doc.height - 2.5 * cm
canvas.setFont('Helvetica-Bold', 10)
canvas.line(x, y, x + doc.width, y)
y -= 0.4 * cm
canvas.drawString(x, y, self.section)
2018-05-22 16:04:39 +02:00
canvas.drawRightString(x + doc.width, y, self.subject)
2018-05-18 15:53:28 +02:00
y -= 0.2 * cm
canvas.line(x, y, x + doc.width, y)
# Footer
canvas.line(doc.leftMargin, 1 * cm, doc.width + doc.leftMargin, 1 * cm)
footer = Paragraph(settings.PDF_FOOTER_TEXT, style_footer)
w, h = footer.wrap(doc.width, doc.bottomMargin)
2018-05-22 16:04:39 +02:00
footer.drawOn(canvas, doc.leftMargin, h)
2018-05-18 15:53:28 +02:00
canvas.restoreState()
def later_header(self, canvas, doc):
# Footer
2018-05-22 16:04:39 +02:00
canvas.saveState()
2018-05-18 15:53:28 +02:00
canvas.line(doc.leftMargin, 1 * cm, doc.width + doc.leftMargin, 1 * cm)
footer = Paragraph(settings.PDF_FOOTER_TEXT, style_footer)
w, h = footer.wrap(doc.width, doc.bottomMargin)
footer.drawOn(canvas, doc.leftMargin, h)
canvas.restoreState()
2018-05-22 16:04:39 +02:00
def formating(self, text, len=25):
return Preformatted(text, style_normal, maxLineLength=len)
2018-05-18 15:53:28 +02:00
def normal_template_page(self):
first_page_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width + 1 * cm, self.height - 5 * cm,
id='first_table', showBoundary=0, leftPadding=0 * cm)
2018-05-22 16:04:39 +02:00
later_pages_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width + 1 * cm, self.height - 5 * cm,
2018-05-18 15:53:28 +02:00
id='later_table', showBoundary=0, leftPadding=0 * cm)
# Page template
first_page = PageTemplate(id='FirstPage', frames=[first_page_table_frame], onPage=self.header)
2018-05-22 16:04:39 +02:00
later_pages = PageTemplate(id='LaterPages', frames=[later_pages_table_frame], onPage=self.header)
2018-05-18 15:53:28 +02:00
self.addPageTemplates([first_page, later_pages])
self.story = [NextPageTemplate(['*', 'LaterPages'])]
def six_semester_template_page(self):
frame_title = Frame(self.leftMargin, 24*cm, self.width, 1*cm, showBoundary=0, leftPadding=0)
w, h = (7.5 * cm, 6.5 * cm,)
x = [self.leftMargin, 11 * cm] * 3
y = [17 * cm, 17 * cm, 10 * cm, 10 * cm, 3 * cm, 3 * cm]
frames = [Frame(x[f], y[f], width=w, height=h, showBoundary=0, leftPadding=0) for f in range(6)]
# Frame for total periods
frames.append(Frame(self.leftMargin, self.bottomMargin, self.width, 1.5 * cm, leftPadding=0))
2018-05-22 16:04:39 +02:00
frames.insert(0, frame_title)
2018-05-18 15:53:28 +02:00
# Page template
frame_page = PageTemplate(id='FirstPage', frames=frames, onPage=self.header)
self.addPageTemplates(frame_page)
2017-11-01 22:14:10 +01:00
2018-02-16 14:52:26 +01:00
2017-11-01 22:14:10 +01:00
class NumberedCanvas(canvas.Canvas):
2017-11-02 14:56:11 +01:00
"""
2018-02-05 08:15:47 +01:00
Page number and pages counter
2017-11-02 14:56:11 +01:00
"""
2017-11-01 22:14:10 +01:00
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
"""add page info to each page (page x of y)"""
num_pages = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_page_number(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_page_number(self, page_count):
self.setFont("Helvetica", 7)
2017-11-02 14:56:11 +01:00
self.drawString(self._pagesize[0] / 2, 1 * cm, "Page {0} de {1}".format(self._pageNumber, page_count))
2017-10-30 14:31:02 +01:00
2017-11-02 14:56:11 +01:00
class ModuleDescriptionPdf(EpcBaseDocTemplate):
"""
PDF for module description
"""
2017-10-30 14:31:02 +01:00
def __init__(self, filename):
2018-05-18 15:53:28 +02:00
super().__init__(filename, 'Filière EDS', 'Module de formation')
2018-02-16 14:52:26 +01:00
self.normal_template_page()
2017-10-30 14:31:02 +01:00
def produce(self, module):
2018-05-18 15:53:28 +02:00
str_competence = ' \n'.join(['- {0} ({1})'.format(c.nom, c.code) for c in module.competence_set.all()])
2017-11-02 14:56:11 +01:00
str_sous_competence = ''
2017-10-30 14:31:02 +01:00
for c in module.competence_set.all():
for sc in c.souscompetence_set.all():
2017-11-02 14:56:11 +01:00
str_sous_competence += '- {0} (voir {1})\n'.format(sc.nom, c.code)
2017-10-30 14:31:02 +01:00
2018-05-22 16:04:39 +02:00
str_res = ' \n'.join(['- {0}'.format(c.nom) for c in module.ressource_set.all()]) # for future use
2017-10-30 14:31:02 +01:00
2018-05-18 15:53:28 +02:00
str_objectif = ' \n'.join(['- {0}'.format(c.nom) for c in module.objectif_set.all()])
2017-08-13 22:58:46 +02:00
2017-11-01 22:14:10 +01:00
self.story.append(Paragraph(module.__str__(), style_bold))
2017-11-01 16:10:31 +01:00
self.story.append(Spacer(0, 0.5 * cm))
2017-10-30 14:31:02 +01:00
data = [
2018-05-18 15:53:28 +02:00
['Domaine', module.processus.domaine.__str__()],
['Processus', module.processus.__str__()],
['Situation emblématique', module.situation],
['Compétences visées', str_competence],
['Plus-value sur le CFC ASE', str_sous_competence],
['Objectifs', str_objectif],
['Didactique', module.didactique],
['Evaluation', module.evaluation],
['Type', '{0}, obligatoire'.format(module.type)],
['Semestre', 'Sem. {0}'.format(module.semestre)],
['Présentiel', '{0} heures'.format(module.total_presentiel)],
['Travail personnel', '{0} heures'.format(module.travail_perso)],
['Responsable', module.processus.domaine.responsable.descr_pdf()]
]
2017-11-01 06:33:55 +01:00
2017-11-01 22:14:10 +01:00
formated_data = []
for foo in data:
formated_data.append(
2018-05-18 15:53:28 +02:00
[
Preformatted(foo[0], style_normal, maxLineLength=15),
2018-05-22 16:04:39 +02:00
Preformatted(foo[1], style_normal, maxLineLength=85),
2018-05-18 15:53:28 +02:00
]
2017-11-01 22:14:10 +01:00
)
2017-11-01 16:10:31 +01:00
2018-05-18 15:53:28 +02:00
t = Table(data=formated_data, colWidths=[4 * cm, 13 * cm])
2017-11-01 22:14:10 +01:00
t.hAlign = TA_LEFT
2018-05-22 16:04:39 +02:00
t.setStyle(tblstyle=TableStyle(
2017-11-02 14:56:11 +01:00
[
('SIZE', (0, 0), (-1, -1), 7),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('LEFTPADDING', (0, 0), (-1, -1), 0),
]
2017-10-30 14:31:02 +01:00
)
)
2017-11-01 16:10:31 +01:00
self.story.append(t)
2018-05-18 15:53:28 +02:00
self.build(self.story)
2017-10-30 14:31:02 +01:00
2017-11-02 14:56:11 +01:00
class FormationPlanPdf(EpcBaseDocTemplate):
"""
PDF for formation plan
"""
2017-10-30 14:31:02 +01:00
def __init__(self, filename):
2018-05-22 16:04:39 +02:00
super().__init__(filename, 'Filière EDS', 'Plan de formation', landscape(A4))
2018-02-16 14:52:26 +01:00
self.normal_template_page()
2017-10-30 14:31:02 +01:00
def formating(self, el1='', length=40):
el1 = '' if el1 == '' else el1.__str__()
return Preformatted(el1, style_normal, maxLineLength=length)
def produce(self, domain, process):
data = [
['Domaines', 'Processus', 'Sem1', 'Sem2', 'Sem3', 'Sem4', 'Sem5', 'Sem6'],
[self.formating(domain[0]), self.formating(process[0], 60), 'M01', '', '', '', '', ''],
[self.formating(''), self.formating('', 60), 'M02', '', '', '', '', ''],
2018-08-14 13:51:04 +02:00
[self.formating(''), self.formating(process[1], 60), '', '', '', '', 'M03', ''],
2017-10-30 14:31:02 +01:00
[self.formating(''), self.formating('', 60), '', 'M04', '', '', '', ''],
[self.formating(domain[1]), self.formating(process[2], 60), 'M05', '', 'M06', '', '', ''],
[self.formating(''), self.formating(process[3], 60), '', '', '', '', 'M07', 'M09'],
[self.formating(''), self.formating('', 60), '', '', '', '', 'M08', ''],
2018-08-14 13:51:04 +02:00
[self.formating(domain[2]), self.formating(process[4], 60), '', '', 'M10', '', ''],
2017-10-30 14:31:02 +01:00
[self.formating(''), self.formating(process[5], 60), '', '', 'M11', '', ''],
2018-08-14 13:51:04 +02:00
[self.formating(''), self.formating('', 60), '', '', '', 'M12', '', ''],
2018-02-05 08:28:07 +01:00
[self.formating(domain[3]), self.formating(process[6], 60), '', '', 'M13', '', 'M14', ''],
2017-10-30 14:31:02 +01:00
[self.formating(domain[4]), self.formating(process[7], 60), 'M15', '', '', '', '', ''],
[self.formating(domain[5]), self.formating(process[8], 60), 'M16_1', '', 'M16_2', '', 'M16_3', ''],
[self.formating(domain[6]), self.formating(process[9], 60), 'M17_1', '', 'M17_2', '', 'M17_3', ''],
[self.formating(domain[7]), self.formating(process[10], 60), 'Macc', '', '', '', '', ''],
]
2018-02-16 14:52:26 +01:00
t = Table(
2018-05-18 15:53:28 +02:00
data=data, colWidths=[7 * cm, 9 * cm, 1.5 * cm, 1.5 * cm, 1.5 * cm, 1.5 * cm, 1.5 * cm, 1.5 * cm],
2018-02-16 14:52:26 +01:00
spaceBefore=0.5 * cm, spaceAfter=1 * cm
)
2018-05-22 16:04:39 +02:00
t.setStyle(tblstyle=TableStyle(
2018-02-16 14:52:26 +01:00
[
('SIZE', (0, 0), (-1, -1), 8),
('FONT', (0, 0), (-1, 0), 'Helvetica-Bold'),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('ALIGN', (2, 0), (-1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 0.25, colors.black),
# Domaine 1
('SPAN', (0, 1), (0, 4)),
('SPAN', (1, 1), (1, 2)),
('SPAN', (1, 3), (1, 4)),
('BACKGROUND', (0, 1), (1, 4), settings.DOMAINE_COULEURS['D1']),
('BACKGROUND', (2, 1), (2, 2), settings.DOMAINE_COULEURS['D1']),
2018-08-14 13:51:04 +02:00
('BACKGROUND', (6, 3), (6, 3), settings.DOMAINE_COULEURS['D1']),
2018-02-16 14:52:26 +01:00
('BACKGROUND', (3, 4), (3, 4), settings.DOMAINE_COULEURS['D1']),
# Domaine 2
('SPAN', (0, 5), (0, 7)),
2018-08-14 13:51:04 +02:00
('SPAN', (1, 6), (1, 7)),
2018-02-16 14:52:26 +01:00
('BACKGROUND', (0, 5), (1, 7), settings.DOMAINE_COULEURS['D2']),
('BACKGROUND', (2, 5), (2, 5), settings.DOMAINE_COULEURS['D2']),
('BACKGROUND', (4, 5), (4, 5), settings.DOMAINE_COULEURS['D2']),
('BACKGROUND', (6, 6), (6, 6), settings.DOMAINE_COULEURS['D2']),
('BACKGROUND', (7, 6), (7, 6), settings.DOMAINE_COULEURS['D2']),
('BACKGROUND', (6, 7), (6, 7), settings.DOMAINE_COULEURS['D2']),
# Domaine 3
2018-08-14 13:51:04 +02:00
('SPAN', (0, 8), (0, 10)),
('SPAN', (1, 9), (1, 10)),
2018-02-16 14:52:26 +01:00
('SPAN', (4, 8), (5, 8)),
('SPAN', (4, 9), (5, 9)),
2018-08-14 13:51:04 +02:00
('BACKGROUND', (0, 8), (1, 10), settings.DOMAINE_COULEURS['D3']),
('BACKGROUND', (4, 8), (5, 8), settings.DOMAINE_COULEURS['D3']),
2018-02-16 14:52:26 +01:00
('BACKGROUND', (4, 9), (5, 9), settings.DOMAINE_COULEURS['D3']),
2018-08-14 13:51:04 +02:00
('BACKGROUND', (5, 10), (5, 10), settings.DOMAINE_COULEURS['D3']),
2018-02-16 14:52:26 +01:00
# Domaine 4
2018-08-14 13:51:04 +02:00
('BACKGROUND', (0, 11), (1, 11), settings.DOMAINE_COULEURS['D4']),
('BACKGROUND', (4, 11), (4, 11), settings.DOMAINE_COULEURS['D4']),
('BACKGROUND', (6, 11), (6, 11), settings.DOMAINE_COULEURS['D4']),
2018-02-16 14:52:26 +01:00
# Domaine 5
2018-08-14 13:51:04 +02:00
('SPAN', (2, 12), (-1, 12)),
('BACKGROUND', (0, 12), (-1, 12), settings.DOMAINE_COULEURS['D5']),
2018-02-16 14:52:26 +01:00
# Domaine 6
('SPAN', (2, 13), (3, 13)),
('SPAN', (4, 13), (5, 13)),
('SPAN', (6, 13), (7, 13)),
2018-08-14 13:51:04 +02:00
('BACKGROUND', (0, 13), (-1, 13), settings.DOMAINE_COULEURS['D6']),
# Domaine 7
('SPAN', (2, 14), (3, 14)),
('SPAN', (4, 14), (5, 14)),
('SPAN', (6, 14), (7, 14)),
('BACKGROUND', (0, 14), (-1, 14), settings.DOMAINE_COULEURS['D7']),
2018-02-16 14:52:26 +01:00
# Domaine 8
2018-08-14 13:51:04 +02:00
('SPAN', (2, 15), (-1, 15)),
('BACKGROUND', (0, 15), (-1, 15), settings.DOMAINE_COULEURS['D8']),
2018-02-16 14:52:26 +01:00
]
)
)
2017-08-13 22:58:46 +02:00
t.hAlign = TA_LEFT
self.story.append(t)
2018-05-18 15:53:28 +02:00
self.build(self.story)
2017-08-13 22:58:46 +02:00
2017-11-01 22:14:10 +01:00
2018-05-23 21:16:25 +02:00
class PeriodeSemestrePdf(EpcBaseDocTemplate):
2017-11-02 14:56:11 +01:00
"""
PDF for periods during semesters
"""
2017-08-13 22:58:46 +02:00
def __init__(self, filename):
2018-05-22 16:04:39 +02:00
super().__init__(filename, 'Filière EDS', 'Périodes de formation')
2018-02-16 14:52:26 +01:00
self.six_semester_template_page()
2017-11-01 16:10:31 +01:00
def produce(self, context):
2018-05-18 15:53:28 +02:00
2017-11-01 22:14:10 +01:00
for sem in range(1, 7):
2018-05-23 21:16:25 +02:00
modules = [m for m in context['modules'] if getattr(m, 'sem{0}'.format(sem))]
2017-11-01 16:10:31 +01:00
total = context['tot{0}'.format(str(sem))]
data = [['Semestre {0}'.format(sem), '{0} h.'.format(total)]]
for line in modules:
value = getattr(line, 'sem{0}'.format(sem))
data.append([line.nom, '{0} h.'.format(value)])
2018-05-18 15:53:28 +02:00
t = Table(data=data, colWidths=[6 * cm, 1 * cm], spaceBefore=0 * cm, spaceAfter=0.5 * cm, hAlign=TA_LEFT,
2018-05-22 16:04:39 +02:00
style=[
('ALIGN', (0, 0), (0, -1), 'LEFT'),
('ALIGN', (1, 0), (1, -1), 'RIGHT'),
('LINEBELOW', (0, 0), (1, 0), 1, colors.black),
('SIZE', (0, 0), (-1, -1), 8),
('FONT', (0, 0), (-1, 0), 'Helvetica-Bold'),
]
)
2017-11-01 22:14:10 +01:00
self.story.append(t)
self.story.append(FrameBreak())
2017-11-02 14:56:11 +01:00
2017-11-01 22:14:10 +01:00
self.story.append(Paragraph('Total de la formation: {0} heures'.format(context['tot']), style_bold))
2018-05-18 15:53:28 +02:00
self.build(self.story)