eds/cms/pdf.py
2018-05-18 15:53:28 +02:00

397 lines
18 KiB
Python

import os
import tempfile
from django.contrib.staticfiles.finders import find
from django.conf import settings
from reportlab.lib import colors
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import cm
from reportlab.lib.styles import ParagraphStyle as ps
from reportlab.pdfgen import canvas
from reportlab.platypus import (Frame, FrameBreak, Flowable, NextPageTemplate,
Paragraph, PageTemplate, Preformatted, Spacer,
SimpleDocTemplate, Table, TableStyle
)
style_normal = ps(name='CORPS', fontName='Helvetica', fontSize=9, alignment=TA_LEFT)
style_bold = ps(name='CORPS', fontName='Helvetica-Bold', fontSize=10, alignment=TA_LEFT)
style_footer = ps(name='CORPS', fontName='Helvetica', fontSize=7, alignment=TA_CENTER)
LOGO_EPC = find('img/logo_EPC.png')
LOGO_ESNE = find('img/logo_ESNE.png')
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
def __init__(self, filename, section='', title='', orientation=A4):
path = os.path.join(tempfile.gettempdir(), filename)
self.section = section
self.title = title
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 = []
#self.title = title
def header(self, canvas, doc):
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
)
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)
canvas.drawRightString(x + doc.width, y, self.title)
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)
footer.drawOn(canvas, doc.leftMargin, h )
canvas.restoreState()
def later_header(self, canvas, doc):
# 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)
footer.drawOn(canvas, doc.leftMargin, h)
canvas.restoreState()
def formating(self, text):
return Preformatted(text, style_normal, maxLineLength=25)
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)
later_pages_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width + 1 * cm, self.height - 2 * cm,
id='later_table', showBoundary=0, leftPadding=0 * cm)
# Page template
first_page = PageTemplate(id='FirstPage', frames=[first_page_table_frame], onPage=self.header)
later_pages = PageTemplate(id='LaterPages', frames=[later_pages_table_frame], onPage=self.later_header)
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)
frame_size = (7 * cm, 6 * cm,)
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))
frames.insert(0,frame_title)
# Page template
frame_page = PageTemplate(id='FirstPage', frames=frames, onPage=self.header)
self.addPageTemplates(frame_page)
class NumberedCanvas(canvas.Canvas):
"""
Page number and pages counter
"""
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)
self.drawString(self._pagesize[0] / 2, 1 * cm, "Page {0} de {1}".format(self._pageNumber, page_count))
"""
class EpcBaseDocTemplate(SimpleDocTemplate):
def __init__(self, filename, title='', pagesize=A4):
super().__init__(filename, pagesize=pagesize, _pageBreakQuick=0, lefMargin=1.5 * cm, bottomMargin=1.5 * cm,
topMargin=1.5 * cm, rightMargin=1.5 * cm)
self.story = []
self.title = title
def header(self, canvas, doc):
canvas.saveState()
canvas.drawImage(LOGO_EPC, doc.leftMargin, doc.height - 0.5 * cm, 5 * cm, 3 * cm, preserveAspectRatio=True)
canvas.drawImage(LOGO_ESNE, doc.width - 2 * cm, doc.height - 0.5 * cm, 5 * cm, 3 * cm,
preserveAspectRatio=True)
canvas.line(doc.leftMargin, doc.height - 0.5 * cm, doc.width + doc.leftMargin, doc.height - 0.5 * cm)
canvas.drawString(doc.leftMargin, doc.height - 1.1 * cm, FILIERE)
canvas.drawRightString(doc.width + doc.leftMargin, doc.height - 1.1 * cm, self.title)
canvas.line(doc.leftMargin, doc.height - 1.3 * cm, doc.width + doc.leftMargin, doc.height - 1.3 * cm)
canvas.restoreState()
def later_header(self, canvas, doc):
canvas.saveState()
canvas.line(doc.leftMargin, doc.height + 1 * cm, doc.width + doc.leftMargin, doc.height + 1 * cm)
canvas.drawString(doc.leftMargin, doc.height + 0.5 * cm, FILIERE)
canvas.drawRightString(doc.width + doc.leftMargin, doc.height + 0.5 * cm, self.title)
canvas.line(doc.leftMargin, doc.height + 0.2 * cm, doc.width + doc.leftMargin, doc.height + 0.2 * cm)
canvas.restoreState()
def normal_template_page(self):
first_page_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width + 1 * cm, self.height - 4 * cm,
id='first_table', showBoundary=0, leftPadding=0 * cm)
later_pages_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width + 1 * cm, self.height - 2 * cm,
id='later_table', showBoundary=0, leftPadding=0 * cm)
# Page template
first_page = PageTemplate(id='FirstPage', frames=[first_page_table_frame], onPage=self.header)
later_pages = PageTemplate(id='LaterPages', frames=[later_pages_table_frame], onPage=self.later_header)
self.addPageTemplates([first_page, later_pages])
self.story = [NextPageTemplate(['*', 'LaterPages'])]
def six_semester_template_page(self):
frame_size = (8 * cm, 6.5 * cm,)
w, h = frame_size
x = [self.leftMargin, 12 * 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))
# Page template
frame_page = PageTemplate(id='FirstPage', frames=frames, onPage=self.header)
self.addPageTemplates(frame_page)
"""
class ModuleDescriptionPdf(EpcBaseDocTemplate):
"""
PDF for module description
"""
def __init__(self, filename):
super().__init__(filename, 'Filière EDS', 'Module de formation')
self.normal_template_page()
def produce(self, module):
str_competence = ' \n'.join(['- {0} ({1})'.format(c.nom, c.code) for c in module.competence_set.all()])
str_sous_competence = ''
for c in module.competence_set.all():
for sc in c.souscompetence_set.all():
str_sous_competence += '- {0} (voir {1})\n'.format(sc.nom, c.code)
str_res = ' \n'.join(['- {0}'.format(c.nom) for c in module.ressource_set.all()])
str_objectif = ' \n'.join(['- {0}'.format(c.nom) for c in module.objectif_set.all()])
self.story.append(Paragraph(module.__str__(), style_bold))
self.story.append(Spacer(0, 0.5 * cm))
data = [
['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()]
]
formated_data = []
for foo in data:
formated_data.append(
[
Preformatted(foo[0], style_normal, maxLineLength=15),
Preformatted(foo[1], style_normal, maxLineLength=97),
]
)
t = Table(data=formated_data, colWidths=[4 * cm, 13 * cm])
t.hAlign = TA_LEFT
t.setStyle(
TableStyle(
[
('SIZE', (0, 0), (-1, -1), 7),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('LEFTPADDING', (0, 0), (-1, -1), 0),
]
)
)
self.story.append(t)
self.build(self.story)
class FormationPlanPdf(EpcBaseDocTemplate):
"""
PDF for formation plan
"""
def __init__(self, filename):
super().__init__(filename, 'Filière EDS','Plan de formation', landscape(A4))
self.normal_template_page()
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', '', '', '', '', ''],
[self.formating(''), self.formating(process[1], 60), '', '', '', 'M03', '', ''],
[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', ''],
[self.formating(domain[2]), self.formating(process[4], 60), '', '', 'M10', '', 'M12'],
[self.formating(''), self.formating(process[5], 60), '', '', 'M11', '', ''],
[self.formating(domain[3]), self.formating(process[6], 60), '', '', 'M13', '', 'M14', ''],
[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', '', '', '', '', ''],
]
t = Table(
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],
spaceBefore=0.5 * cm, spaceAfter=1 * cm
)
t.setStyle(
TableStyle(
[
('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']),
('BACKGROUND', (5, 3), (5, 3), settings.DOMAINE_COULEURS['D1']),
('BACKGROUND', (3, 4), (3, 4), settings.DOMAINE_COULEURS['D1']),
# Domaine 2
('SPAN', (0, 5), (0, 7)),
('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
('SPAN', (0, 8), (0, 9)),
('SPAN', (1, 6), (1, 7)),
('SPAN', (4, 8), (5, 8)),
('SPAN', (4, 9), (5, 9)),
('BACKGROUND', (0, 8), (1, 9), settings.DOMAINE_COULEURS['D3']),
('BACKGROUND', (4, 8), (6, 8), settings.DOMAINE_COULEURS['D3']),
('BACKGROUND', (4, 9), (5, 9), settings.DOMAINE_COULEURS['D3']),
# Domaine 4
('BACKGROUND', (0, 10), (1, 10), settings.DOMAINE_COULEURS['D4']),
('BACKGROUND', (4, 10), (4, 10), settings.DOMAINE_COULEURS['D4']),
('BACKGROUND', (6, 10), (6, 10), settings.DOMAINE_COULEURS['D4']),
# Domaine 5
('SPAN', (2, 11), (-1, 11)),
('BACKGROUND', (0, 11), (-1, 11), settings.DOMAINE_COULEURS['D5']),
# Domaine 6
('SPAN', (2, 12), (3, 12)),
('SPAN', (4, 12), (5, 12)),
('SPAN', (6, 12), (7, 12)),
('BACKGROUND', (0, 12), (-1, 12), settings.DOMAINE_COULEURS['D6']),
# Domaine 7
('SPAN', (2, 13), (3, 13)),
('SPAN', (4, 13), (5, 13)),
('SPAN', (6, 13), (7, 13)),
('BACKGROUND', (0, 13), (-1, 13), settings.DOMAINE_COULEURS['D7']),
# Domaine 8
('SPAN', (2, 14), (-1, 14)),
('BACKGROUND', (0, 14), (-1, 14), settings.DOMAINE_COULEURS['D8']),
]
)
)
t.hAlign = TA_LEFT
self.story.append(t)
self.build(self.story)
class PeriodSemesterPdf(EpcBaseDocTemplate):
"""
PDF for periods during semesters
"""
def __init__(self, filename):
super().__init__(filename, 'Filière EDS','Périodes de formation')
self.six_semester_template_page()
def produce(self, context):
for sem in range(1, 7):
modules = context['sem{0}'.format(str(sem))]
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)])
t = Table(data=data, colWidths=[6 * cm, 1 * cm], spaceBefore=0 * cm, spaceAfter=0.5 * cm, hAlign=TA_LEFT,
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'),
]
)
self.story.append(t)
self.story.append(FrameBreak())
self.story.append(Paragraph('Total de la formation: {0} heures'.format(context['tot']), style_bold))
self.build(self.story)