637 lines
25 KiB
Python
637 lines
25 KiB
Python
from io import BytesIO
|
||
|
||
import extract_msg
|
||
import nh3
|
||
|
||
from bs4 import BeautifulSoup
|
||
from pypdf import PdfWriter
|
||
|
||
from functools import partial
|
||
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
|
||
from reportlab.lib.pagesizes import A4
|
||
from reportlab.lib import colors
|
||
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
||
from reportlab.lib.units import cm
|
||
from reportlab.pdfgen import canvas
|
||
from reportlab.platypus import (
|
||
PageBreak, Paragraph, Preformatted, SimpleDocTemplate, Spacer, Table, TableStyle
|
||
)
|
||
|
||
from django.contrib.staticfiles.finders import find
|
||
from django.utils.text import slugify
|
||
|
||
from .utils import format_d_m_Y, format_duree, format_Ymd
|
||
|
||
|
||
def format_booleen(val):
|
||
return '?' if val is None else ('oui' if val else 'non')
|
||
|
||
|
||
class PageNumCanvas(canvas.Canvas):
|
||
"""A special canvas to be able to draw the total page number in the footer."""
|
||
def __init__(self, *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
self._pages = []
|
||
|
||
def showPage(self):
|
||
self._pages.append(dict(self.__dict__))
|
||
self._startPage()
|
||
|
||
def save(self):
|
||
page_count = len(self._pages)
|
||
for page in self._pages:
|
||
self.__dict__.update(page)
|
||
self.draw_page_number(page_count)
|
||
canvas.Canvas.showPage(self)
|
||
super().save()
|
||
|
||
def draw_page_number(self, page_count):
|
||
self.setFont("Helvetica", 9)
|
||
self.drawRightString(self._pagesize[0] - 1.6*cm, 2.3*cm, "p. %s/%s" % (self._pageNumber, page_count))
|
||
|
||
|
||
class CleanParagraph(Paragraph):
|
||
"""If the (HTML) text cannot be parsed, try to clean it."""
|
||
def __init__(self, text, *args, **kwargs):
|
||
if text:
|
||
text = text.replace('</p>', '</p><br/>')
|
||
if '<ul>' in text:
|
||
text = text.replace('<li>', ' • ').replace('</ul>','<br>').replace('</li>', '<br>')
|
||
try:
|
||
super().__init__(text, *args, **kwargs)
|
||
except ValueError:
|
||
text = nh3.clean(
|
||
text, tags={'p', 'br', 'b', 'strong', 'u', 'i', 'em', 'ul', 'li'}
|
||
).replace('<br>', '<br/>')
|
||
super().__init__(text, *args, **kwargs)
|
||
|
||
|
||
class RawParagraph(Paragraph):
|
||
"""Raw text, replace new lines by <br/>."""
|
||
def __init__(self, text='', *args, **kwargs):
|
||
if text:
|
||
text = text.replace('\r\n', '\n').replace('\n', '\n<br/>')
|
||
super().__init__(text, *args, **kwargs)
|
||
|
||
|
||
class StyleMixin:
|
||
FONTSIZE = 9
|
||
MAXLINELENGTH = 120
|
||
|
||
def __init__(self, base_font='Helvetica', **kwargs):
|
||
self.styles = getSampleStyleSheet()
|
||
self.style_title = ParagraphStyle(
|
||
name='title', fontName='Helvetica-Bold', fontSize=self.FONTSIZE + 4,
|
||
leading=self.FONTSIZE + 5, alignment=TA_CENTER
|
||
)
|
||
self.style_normal = ParagraphStyle(
|
||
name='normal', fontName='Helvetica', fontSize=self.FONTSIZE, alignment=TA_LEFT,
|
||
leading=self.FONTSIZE + 1, spaceAfter=0
|
||
)
|
||
self.style_justifie = ParagraphStyle(
|
||
name='justifie', parent=self.style_normal, alignment=TA_JUSTIFY, spaceAfter=0.2 * cm
|
||
)
|
||
self.style_sub_title = ParagraphStyle(
|
||
name='sous_titre', fontName='Helvetica-Bold', fontSize=self.FONTSIZE + 2,
|
||
alignment=TA_LEFT, spaceBefore=0.5 * cm, spaceAfter=0.1 * cm
|
||
)
|
||
self.style_inter_title = ParagraphStyle(
|
||
name='inter_titre', fontName='Helvetica-Bold', fontSize=self.FONTSIZE + 1,
|
||
alignment=TA_LEFT, spaceBefore=0.3 * cm, spaceAfter=0
|
||
)
|
||
self.style_bold = ParagraphStyle(
|
||
name='bold', fontName='Helvetica-Bold', fontSize=self.FONTSIZE, leading=self.FONTSIZE + 1
|
||
)
|
||
self.style_italic = ParagraphStyle(
|
||
name='italic', fontName='Helvetica-Oblique', fontSize=self.FONTSIZE - 1, leading=self.FONTSIZE
|
||
)
|
||
self.style_indent = ParagraphStyle(
|
||
name='indent', fontName='Helvetica', fontSize=self.FONTSIZE, alignment=TA_LEFT,
|
||
leftIndent=1 * cm
|
||
)
|
||
super().__init__(**kwargs)
|
||
|
||
|
||
class HeaderFooterMixin:
|
||
LOGO = find('img/logo-cr.png')
|
||
EDUQUA = find('img/eduqua.png')
|
||
DON = find('img/logo-zewo.png')
|
||
|
||
def draw_header(self, canvas, doc):
|
||
canvas.saveState()
|
||
canvas.drawImage(
|
||
self.LOGO, doc.leftMargin + 316, doc.height+60, 7 * cm, 1.6 * cm, preserveAspectRatio=True, mask='auto'
|
||
)
|
||
canvas.restoreState()
|
||
|
||
def draw_footer(self, canvas, doc):
|
||
canvas.saveState()
|
||
canvas.drawImage(
|
||
self.EDUQUA, doc.leftMargin, doc.height - 670, 1.8 * cm, 0.8 * cm, preserveAspectRatio=True
|
||
)
|
||
canvas.drawImage(
|
||
self.DON, doc.leftMargin + 60, doc.height - 670, 2.5 * cm, 0.8 * cm, preserveAspectRatio=True, mask='auto'
|
||
)
|
||
tab = [220, 365]
|
||
line = [658, 667, 676, 685]
|
||
|
||
canvas.setFont("Helvetica", 8)
|
||
canvas.drawRightString(doc.leftMargin + tab[0], doc.height - line[2], "CCP ?")
|
||
canvas.drawRightString(doc.leftMargin + tab[0], doc.height - line[3], "IBAN ?")
|
||
canvas.setLineWidth(0.5)
|
||
canvas.line(doc.leftMargin + 230, 2.2 * cm, doc.leftMargin + 230, 1.0 * cm)
|
||
|
||
canvas.drawRightString(doc.leftMargin + tab[1], doc.height - line[0], "Rte d’Englisberg 3")
|
||
canvas.setFont("Helvetica-Bold", 8)
|
||
canvas.drawRightString(doc.leftMargin + tab[1], doc.height - line[1], "1763 Granges-Paccot")
|
||
canvas.setFont("Helvetica", 8)
|
||
canvas.line(doc.leftMargin + 375, 2.2 * cm, doc.leftMargin + 375, 1.0 * cm)
|
||
canvas.drawRightString(doc.leftMargin + doc.width, doc.height - line[0], "+41 26 407 70 44")
|
||
canvas.drawRightString(doc.leftMargin + doc.width, doc.height - line[1], "secretariat@fondation-transit.ch")
|
||
canvas.drawRightString(doc.leftMargin + doc.width, doc.height - line[2], "fondation-transit.ch/aemo")
|
||
canvas.restoreState()
|
||
|
||
|
||
class BasePDF(HeaderFooterMixin, StyleMixin):
|
||
|
||
def __init__(self, tampon, instance, **kwargs):
|
||
self.instance = instance
|
||
self.kwargs = kwargs
|
||
self.doc = SimpleDocTemplate(
|
||
tampon, title=self.title, pagesize=A4,
|
||
leftMargin=1.5 * cm, rightMargin=1.5 * cm, topMargin=2 * cm, bottomMargin=2.5 * cm
|
||
)
|
||
self.story = []
|
||
super().__init__(**kwargs)
|
||
|
||
def draw_header_footer(self, canvas, doc):
|
||
self.draw_header(canvas, doc)
|
||
self.draw_footer(canvas, doc)
|
||
|
||
def produce(self):
|
||
# subclass should call self.doc.build(self.story, onFirstPage=self.draw_header_footer)
|
||
raise NotImplementedError
|
||
|
||
def get_filename(self):
|
||
raise NotImplementedError
|
||
|
||
@staticmethod
|
||
def format_note(note, length=StyleMixin.MAXLINELENGTH):
|
||
return Preformatted(note.replace('\r\n', '\n'), maxLineLength=length)
|
||
|
||
def set_title(self, title=''):
|
||
self.story.append(Spacer(0, 1 * cm))
|
||
self.story.append(Paragraph(title, self.style_title))
|
||
self.story.append(Spacer(0, 1.2 * cm))
|
||
|
||
def parent_data(self, person):
|
||
"""Return parent data ready to be used in a 2-column table."""
|
||
parents = person.parents()
|
||
par1 = parents[0] if len(parents) > 0 else None
|
||
par2 = parents[1] if len(parents) > 1 else None
|
||
data = [
|
||
[('Parent 1 (%s)' % par1.role.nom) if par1 else '-',
|
||
('Parent 2 (%s)' % par2.role.nom) if par2 else '-'],
|
||
[par1.contact.nom_prenom if par1 else '', par2.contact.nom_prenom if par2 else ''],
|
||
[par1.contact.adresse if par1 else '', par2.contact.adresse if par2 else ''],
|
||
[par1.contact.contact if par1 else '', par2.contact.contact if par2 else ''],
|
||
|
||
['Autorité parentale: {}'.format(format_booleen(par1.contact.autorite_parentale)) if par1 else '',
|
||
'Autorité parentale: {}'.format(format_booleen(par2.contact.autorite_parentale)) if par2 else ''],
|
||
]
|
||
return data
|
||
|
||
def formate_persons(self, parents_list):
|
||
labels = (
|
||
("Nom", "nom"), ("Prénom", "prenom"), ("Adresse", "rue"),
|
||
("Localité", 'localite_display'), ("Profession", 'profession'), ("Tél.", 'telephone'),
|
||
("Courriel", 'email'), ('Remarque', 'remarque'),
|
||
)
|
||
P = partial(Paragraph, style=self.style_normal)
|
||
Pbold = partial(Paragraph, style=self.style_bold)
|
||
data = []
|
||
parents = [parent for parent in parents_list if parent is not None]
|
||
if len(parents) == 0:
|
||
pass
|
||
elif len(parents) == 1:
|
||
data.append([Pbold('Rôle:'), Pbold(parents[0].role.nom), '', ''])
|
||
for label in labels:
|
||
data.append([
|
||
label[0], P(getattr(parents[0], label[1])), '', ''
|
||
])
|
||
elif len(parents) == 2:
|
||
data.append([
|
||
Pbold('Rôle:'), Pbold(parents[0].role.nom),
|
||
Pbold('Rôle:'), Pbold(parents[1].role.nom)
|
||
])
|
||
for label in labels:
|
||
data.append([
|
||
label[0], P(getattr(parents[0], label[1]) if parents[0] else ''),
|
||
label[0], P(getattr(parents[1], label[1]) if parents[1] else '')
|
||
])
|
||
return data
|
||
|
||
def get_table(self, data, columns, before=0.0, after=0.0, inter=None):
|
||
"""Prepare a Table instance with data and columns, with a common style."""
|
||
if inter:
|
||
inter = inter * cm
|
||
cols = [c * cm for c in columns]
|
||
|
||
t = Table(
|
||
data=data, colWidths=cols, hAlign=TA_LEFT,
|
||
spaceBefore=before * cm, spaceAfter=after * cm
|
||
)
|
||
t.hAlign = 0
|
||
t.setStyle(tblstyle=TableStyle([
|
||
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
|
||
('FONTSIZE', (0, 0), (-1, -1), self.FONTSIZE),
|
||
('VALIGN', (0, 0), (-1, -1), "TOP"),
|
||
('LEFTPADDING', (0, 0), (0, -1), 1),
|
||
('LEADING', (0, 0), (-1, -1), 7),
|
||
]))
|
||
return t
|
||
|
||
def _add_subtitle(self, data):
|
||
t = Table(
|
||
data=[data], colWidths=[18 * cm / len(data)] * len(data),
|
||
hAlign=TA_LEFT,
|
||
spaceBefore=0.2 * cm, spaceAfter=0.5 * cm
|
||
)
|
||
t.hAlign = 0
|
||
t.setStyle(tblstyle=TableStyle([
|
||
('FONT', (0, 0), (-1, -1), "Helvetica-Bold"),
|
||
('FONTSIZE', (0, 0), (-1, -1), self.FONTSIZE + 2),
|
||
('LINEBELOW', (0, -1), (-1, -1), 0.25, colors.black),
|
||
('ALIGN', (-1, -1), (-1, -1), 'RIGHT'),
|
||
]))
|
||
self.story.append(t)
|
||
|
||
def write_paragraph(self, title, text, html=False, justifie=False):
|
||
if title:
|
||
self.story.append(Paragraph(title, self.style_sub_title))
|
||
style = self.style_justifie if justifie else self.style_normal
|
||
if html:
|
||
if text.startswith('<p>') and text.endswith('</p>'):
|
||
soup = BeautifulSoup(text, features="html5lib")
|
||
for tag in soup.find_all(['p', 'ul']):
|
||
self.story.append(CleanParagraph(str(tag), style))
|
||
else:
|
||
self.story.append(CleanParagraph(text, style))
|
||
else:
|
||
self.story.append(RawParagraph(text, style))
|
||
|
||
def enfant_data(self, enfant):
|
||
labels = [('Tél.', enfant.telephone)]
|
||
if hasattr(enfant, 'formation'):
|
||
labels.extend([
|
||
('Statut scol', enfant.formation.get_statut_display()),
|
||
('Centre', enfant.formation.cercle_scolaire),
|
||
('Collège', enfant.formation.college),
|
||
('Classe', enfant.formation.classe),
|
||
('Struct. extra-fam.', enfant.formation.creche),
|
||
('Ens.', enfant.formation.enseignant),
|
||
])
|
||
labels.extend([
|
||
('Permis de séjour', enfant.permis),
|
||
('Validité', enfant.validite),
|
||
])
|
||
row = [f"{enfant.nom_prenom} (*{format_d_m_Y(enfant.date_naissance)})"]
|
||
for label in labels:
|
||
if label[1]:
|
||
row.append(f"{label[0]}: {label[1]}")
|
||
return '; '.join(row)
|
||
|
||
|
||
class DemandeAccompagnement(BasePDF):
|
||
title = None
|
||
|
||
def produce(self):
|
||
famille = self.instance
|
||
suivi = famille.suivi
|
||
self.set_title("Famille {} - {}".format(famille.nom, self.title))
|
||
|
||
self.story.append(Paragraph("<strong>Motif(s) de la demande:</strong> {}".format(
|
||
suivi.get_motif_demande_display()), self.style_normal
|
||
))
|
||
self.story.append(Paragraph('_' * 90, self.style_normal))
|
||
|
||
self.write_paragraph("Dates", suivi.dates_demande)
|
||
self.write_paragraph(
|
||
"Difficultés",
|
||
"{}<br/>{}<br/><br/>{}".format(
|
||
"<em>Quelles sont les difficultés éducatives que vous rencontrez et depuis combien de "
|
||
"temps ?",
|
||
"Fonctionnement familial: règles, coucher, lever, repas, jeux, relations "
|
||
"parent-enfants, rapport au sein de la fratrie, … (exemple)</em>",
|
||
suivi.difficultes
|
||
),
|
||
html=True
|
||
)
|
||
self.write_paragraph(
|
||
"Autres services",
|
||
"<em>{}</em><br/>{}".format(
|
||
"Avez-vous fait appel à d'autres services ? Si oui, avec quels vécus ?",
|
||
suivi.autres_contacts
|
||
),
|
||
html=True
|
||
)
|
||
self.write_paragraph("Aides souhaitées", suivi.aides, html=True)
|
||
self.write_paragraph("Ressources/Compétences", suivi.competences, html=True)
|
||
self.write_paragraph("Disponibilités", suivi.disponibilites, html=True)
|
||
self.write_paragraph("Remarques", suivi.remarque)
|
||
|
||
self.doc.build(self.story, onFirstPage=self.draw_header_footer)
|
||
|
||
|
||
class JournalPdf(BasePDF):
|
||
title = "Journal de bord"
|
||
|
||
def get_filename(self):
|
||
return '{}_journal.pdf'.format(slugify(self.instance.nom))
|
||
|
||
def get_title(self):
|
||
return 'Famille {} - {}'.format(self.instance.nom, self.title)
|
||
|
||
def produce(self):
|
||
famille = self.instance
|
||
self.set_title(self.get_title())
|
||
|
||
self.style_bold.spaceAfter = 0.2*cm
|
||
self.style_italic.spaceBefore = 0.2 * cm
|
||
self.style_italic.spaceAfter = 0.7 * cm
|
||
for prest in famille.prestations.all().prefetch_related('intervenants'):
|
||
self.story.append(CleanParagraph(prest.texte, self.style_normal))
|
||
self.story.append(
|
||
Paragraph('{} - {} ({})'.format(
|
||
'/'.join(interv.sigle for interv in prest.intervenants.all()),
|
||
format_d_m_Y(prest.date_prestation),
|
||
format_duree(prest.duree)
|
||
), self.style_italic)
|
||
)
|
||
|
||
self.doc.build(
|
||
self.story,
|
||
onFirstPage=self.draw_header_footer, onLaterPages=self.draw_footer,
|
||
canvasmaker=PageNumCanvas
|
||
)
|
||
|
||
|
||
class RapportPdf(BasePDF):
|
||
title = None
|
||
|
||
def get_filename(self):
|
||
return "{}_resume_{}.pdf".format(
|
||
slugify(self.instance.famille.nom),
|
||
format_Ymd(self.instance.date)
|
||
)
|
||
|
||
def produce(self):
|
||
rapport = self.instance
|
||
self.style_normal.fontSize += 2
|
||
self.style_normal.leading += 2
|
||
self.style_justifie.fontSize += 2
|
||
self.style_justifie.leading += 2
|
||
self.doc.title = 'Résumé "AEMO"'
|
||
self.set_title('Famille {} - {}'.format(rapport.famille.nom, self.doc.title))
|
||
self._add_subtitle([f"Date: {format_d_m_Y(rapport.date)}"])
|
||
|
||
data = [
|
||
("Enfant(s)", '<br/>'.join(
|
||
[f"{enfant.nom_prenom} (*{format_d_m_Y(enfant.date_naissance)})"
|
||
for enfant in rapport.famille.membres_suivis()]), False),
|
||
("Intervenant-e-s", ', '.join([i.nom_prenom for i in rapport.intervenants()]), False),
|
||
("Début du suivi", format_d_m_Y(rapport.famille.suivi.date_debut_suivi), False),
|
||
("Situation / contexte familial", rapport.situation, True),
|
||
]
|
||
data.append(("Observations", rapport.observations, True))
|
||
data.append(("Perspectives d'avenir", rapport.projet, True))
|
||
|
||
for title, text, html in data:
|
||
self.write_paragraph(title, text, html=html, justifie=True)
|
||
|
||
if hasattr(rapport, 'sig_interv'):
|
||
self.story.append(Spacer(0, 0.5 * cm))
|
||
|
||
for idx, interv in enumerate(rapport.sig_interv.all()):
|
||
if idx == 0:
|
||
self.write_paragraph("Signature des intervenant-e-s :", '')
|
||
self.story.append(Spacer(0, 0.2 * cm))
|
||
self.write_paragraph('', interv.nom_prenom + (f', {interv.profession}' if interv.profession else ''))
|
||
self.story.append(Spacer(0, 1 * cm))
|
||
|
||
secret_style = ParagraphStyle(
|
||
name='italic', fontName='Helvetica-Oblique', fontSize=self.FONTSIZE - 1, leading=self.FONTSIZE + 1,
|
||
backColor=colors.Color(0.96, 0.96, 0.96, 1), borderRadius=12,
|
||
)
|
||
self.story.append(Paragraph(
|
||
"Le présent résumé comporte des éléments <b>couverts par le secret professionnel au sens "
|
||
"de la LPSy et du Code pénal</b>. Seuls les propriétaires des données, à savoir les membres "
|
||
"de la famille faisant l’objet du résumé, peuvent <b>ensemble</b> lever ce secret ou "
|
||
"accepter la divulgation des données. Si cette autorisation n’est pas donnée, l’autorité "
|
||
"compétente en matière de levée du secret professionnel doit impérativement être saisie.",
|
||
secret_style
|
||
))
|
||
|
||
self.doc.build(self.story, onFirstPage=self.draw_header_footer, onLaterPages=self.draw_footer)
|
||
|
||
|
||
class MessagePdf(BasePDF):
|
||
title = 'Message'
|
||
|
||
def get_filename(self):
|
||
return '{}_message.pdf'.format(slugify(self.instance.subject))
|
||
|
||
def produce(self):
|
||
doc = self.instance
|
||
self.set_title('{} - Famille {}'.format(self.title, doc.famille.nom))
|
||
with extract_msg.Message(doc.fichier.path) as msg:
|
||
P = partial(Paragraph, style=self.style_normal)
|
||
Pbold = partial(Paragraph, style=self.style_bold)
|
||
|
||
msg_headers = [
|
||
[Pbold('De:'), P(msg.sender)],
|
||
[Pbold('À:'), P(msg.to)],
|
||
]
|
||
if msg.cc:
|
||
msg_headers.append([Pbold('CC:'), P(msg.cc)])
|
||
if msg.date:
|
||
msg_headers.append([Pbold('Date:'), P(msg.date)])
|
||
msg_headers.append([Pbold('Sujet:'), P(msg.subject)])
|
||
self.story.append(self.get_table(msg_headers, [3, 15]))
|
||
self.story.append(Pbold('Message:'))
|
||
self.story.append(RawParagraph(msg.body, style=self.style_normal))
|
||
return self.doc.build(
|
||
self.story,
|
||
onFirstPage=self.draw_header_footer, onLaterPages=self.draw_footer,
|
||
canvasmaker=PageNumCanvas
|
||
)
|
||
|
||
|
||
class EvaluationPdf:
|
||
def __init__(self, tampon, famille):
|
||
self.tampon = tampon
|
||
self.famille = famille
|
||
self.merger = PdfWriter()
|
||
|
||
def append_pdf(self, PDFClass):
|
||
tampon = BytesIO()
|
||
pdf = PDFClass(tampon, self.famille)
|
||
pdf.produce()
|
||
self.merger.append(tampon)
|
||
|
||
def produce(self):
|
||
|
||
self.append_pdf(CoordonneesPagePdf)
|
||
self.append_pdf(DemandeAccompagnementPagePdf)
|
||
self.merger.write(self.tampon)
|
||
|
||
def get_filename(self):
|
||
return '{}_aemo_evaluation.pdf'.format(slugify(self.famille.nom))
|
||
|
||
|
||
class CoordonneesFamillePdf(BasePDF):
|
||
title = "Informations"
|
||
|
||
def get_filename(self):
|
||
return '{}_coordonnees.pdf'.format(slugify(self.instance.nom))
|
||
|
||
def produce(self):
|
||
famille = self.instance
|
||
suivi = famille.suivi
|
||
self.set_title('Famille {} - {}'.format(famille.nom, self.title))
|
||
|
||
# Parents
|
||
self.story.append(Paragraph('Parents', self.style_sub_title))
|
||
data = self.formate_persons(famille.parents())
|
||
if data:
|
||
self.story.append(self.get_table(data, columns=[2, 7, 2, 7], before=0, after=0))
|
||
else:
|
||
self.story.append(Paragraph('-', self.style_normal))
|
||
|
||
# Situation matrimoniale
|
||
data = [
|
||
['Situation matrimoniale: {}'.format(famille.get_statut_marital_display()),
|
||
'Autorité parentale: {}'.format(famille.get_autorite_parentale_display())],
|
||
]
|
||
self.story.append(self.get_table(data, columns=[9, 9], before=0, after=0))
|
||
|
||
# Personnes significatives
|
||
autres_parents = list(famille.autres_parents())
|
||
if autres_parents:
|
||
self.story.append(Paragraph('Personne-s significative-s', self.style_sub_title))
|
||
data = self.formate_persons(autres_parents)
|
||
self.story.append(self.get_table(data, columns=[2, 7, 3, 6], before=0, after=0))
|
||
if len(autres_parents) > 2:
|
||
self.story.append(PageBreak())
|
||
|
||
# Enfants suivis
|
||
self.write_paragraph(
|
||
"Enfant(s)",
|
||
'<br/>'.join(self.enfant_data(enfant) for enfant in famille.membres_suivis())
|
||
)
|
||
# Réseau
|
||
self.story.append(Paragraph("Réseau", self.style_sub_title))
|
||
data = [
|
||
['AS OPE', '{} - (Mandat: {})'.format(
|
||
', '.join(ope.nom_prenom for ope in suivi.ope_referents),
|
||
suivi.get_mandat_ope_display()
|
||
)],
|
||
['Interv. CRNE', '{}'.format(
|
||
', '.join('{}'.format(i.nom_prenom) for i in suivi.intervenants.all().distinct())
|
||
)]
|
||
]
|
||
for enfant in famille.membres_suivis():
|
||
for contact in enfant.reseaux.all():
|
||
data.append([
|
||
enfant.prenom,
|
||
'{} ({})'.format(contact, contact.contact)
|
||
])
|
||
self.story.append(self.get_table(data, columns=[2, 16], before=0, after=0))
|
||
|
||
self.write_paragraph("Motif de la demande", famille.suivi.motif_detail)
|
||
self.write_paragraph("Collaborations", famille.suivi.collaboration)
|
||
|
||
# Historique
|
||
self.story.append(Paragraph('Historique', self.style_sub_title))
|
||
P = partial(Paragraph, style=self.style_normal)
|
||
Pbold = partial(Paragraph, style=self.style_bold)
|
||
fields = ['date_demande', 'date_debut_evaluation', 'date_fin_evaluation',
|
||
'date_debut_suivi', 'date_fin_suivi']
|
||
data = []
|
||
for field_name in fields:
|
||
field = famille.suivi._meta.get_field(field_name)
|
||
if getattr(famille.suivi, field_name):
|
||
data.append(
|
||
[Pbold(f"{field.verbose_name} :"), P(format_d_m_Y(getattr(famille.suivi, field_name)))]
|
||
)
|
||
if famille.suivi.motif_fin_suivi:
|
||
data.append([Pbold("Motif de fin de suivi :"), famille.suivi.get_motif_fin_suivi_display()])
|
||
if famille.destination:
|
||
data.append([Pbold("Destination :"), famille.get_destination_display()])
|
||
if famille.archived_at:
|
||
data.append([Pbold("Date d'archivage :"), format_d_m_Y(famille.archived_at)])
|
||
|
||
self.story.append(self.get_table(data, [4, 5]))
|
||
self.doc.build(self.story, onFirstPage=self.draw_header_footer)
|
||
|
||
|
||
class DemandeAccompagnementPagePdf(DemandeAccompagnement):
|
||
title = "Évaluation AEMO"
|
||
|
||
|
||
class BilanPdf(BasePDF):
|
||
title = "Bilan AEMO"
|
||
|
||
def get_filename(self):
|
||
return "{}_bilan_{}.pdf".format(
|
||
slugify(self.instance.famille.nom),
|
||
format_Ymd(self.instance.date)
|
||
)
|
||
|
||
def produce(self):
|
||
bilan = self.instance
|
||
self.style_normal.fontSize += 2
|
||
self.style_normal.leading += 2
|
||
self.style_justifie.fontSize += 2
|
||
self.style_justifie.leading += 2
|
||
self.set_title('Famille {} - {}'.format(bilan.famille.nom, self.title))
|
||
self._add_subtitle([f"Date: {format_d_m_Y(bilan.date)}"])
|
||
|
||
for title, text, html in (
|
||
("Enfant(s)", '<br/>'.join(
|
||
[f"{enfant.nom_prenom} (*{format_d_m_Y(enfant.date_naissance)})"
|
||
for enfant in bilan.famille.membres_suivis()]), False),
|
||
("Intervenant-e-s", ', '.join(
|
||
[i.intervenant.nom_prenom for i in bilan.famille.interventions_actives(bilan.date)]
|
||
), False),
|
||
("Début du suivi", format_d_m_Y(bilan.famille.suivi.date_debut_suivi), False),
|
||
("Besoins et objectifs", bilan.objectifs, True),
|
||
("Rythme et fréquence", bilan.rythme, True),
|
||
):
|
||
self.write_paragraph(title, text, html=html, justifie=True)
|
||
|
||
self.story.append(Spacer(0, 0.5 * cm))
|
||
|
||
for idx, interv in enumerate(bilan.sig_interv.all()):
|
||
if idx == 0:
|
||
self.write_paragraph("Signature des intervenant-e-s AEMO :", '')
|
||
self.story.append(Spacer(0, 0.2 * cm))
|
||
self.write_paragraph('', interv.nom_prenom + (f', {interv.profession}' if interv.profession else ''))
|
||
self.story.append(Spacer(0, 1 * cm))
|
||
|
||
if bilan.sig_famille:
|
||
self.write_paragraph("Signature de la famille :", '')
|
||
|
||
self.doc.build(self.story, onFirstPage=self.draw_header_footer, onLaterPages=self.draw_footer)
|
||
|
||
|
||
class CoordonneesPagePdf(CoordonneesFamillePdf):
|
||
title = "Informations"
|
||
|
||
def get_filename(self, famille):
|
||
return '{}_aemo_evaluation.pdf'.format(slugify(famille.nom))
|
||
|
||
|
||
def str_or_empty(value):
|
||
return '' if not value else str(value)
|