aemo_fr/aemo/export.py

213 lines
8.2 KiB
Python
Raw Permalink Normal View History

2024-06-03 16:49:01 +02:00
from datetime import timedelta
from tempfile import NamedTemporaryFile
from django.http import HttpResponse
from openpyxl import Workbook
from openpyxl.styles import Font
from openpyxl.utils import get_column_letter
from .utils import format_d_m_Y
openxml_contenttype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
class OpenXMLExport:
def __init__(self, sheet_title=None):
self.wb = Workbook()
self.ws = self.wb.active
if sheet_title:
self.ws.title = sheet_title
self.bold = Font(name='Calibri', bold=True)
self.row_idx = 1
def write_line(self, values, bold=False, col_widths=()):
# A values item can be an object with a `value` attribute
for col_idx, value in enumerate(values, start=1):
cell = self.ws.cell(row=self.row_idx, column=col_idx)
if isinstance(value, timedelta):
cell.number_format = '[h]:mm;@'
elif hasattr(value, 'number_format'):
cell.number_format = value.number_format
cell.value = getattr(value, 'value', value)
if bold:
cell.font = self.bold
if col_widths and len(col_widths) >= col_idx:
self.ws.column_dimensions[get_column_letter(col_idx)].width = col_widths[col_idx - 1]
self.row_idx += 1
def add_sheet(self, title):
self.wb.create_sheet(title)
self.ws = self.wb[title]
self.row_idx = 1
def get_http_response(self, filename):
with NamedTemporaryFile() as tmp:
self.wb.save(tmp.name)
tmp.seek(0)
response = HttpResponse(tmp, content_type=openxml_contenttype)
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response
class ExportReporting(OpenXMLExport):
def __init__(self):
super().__init__('temp')
self.first_sheet = True
# Totaux pour vérification interne dans les tests.
self._total_spe = {'eval': timedelta(0), 'suivi': timedelta(0), 'gen': timedelta(0)}
def setup_sheet(self, title):
if not self.first_sheet:
self.add_sheet(title)
else:
self.ws.title = title
self.first_sheet = False
def produce_suivis(self, sheet_title, query, mois):
self.setup_sheet(sheet_title)
SuiviSheet(self, mois).produce(query)
def produce_nouveaux(self, sheet_title, query):
self.setup_sheet(sheet_title)
NouveauxSheet(self).produce(query)
def produce_termines(self, sheet_title, query):
self.setup_sheet(sheet_title)
TerminesSheet(self).produce(query)
def produce_totaux(self, sheet_title):
self.setup_sheet(sheet_title)
self.write_line(['Évaluation', self._total_spe['eval']], col_widths=[25, 10])
self.write_line(['Accompagnement', self._total_spe['suivi']])
self.write_line(['Intervention générale', self._total_spe['gen']])
self.write_line(['Total', self._total_spe['eval'] + self._total_spe['suivi'] + self._total_spe['gen']])
class BaseFamilleSheet:
en_tetes = [
('Institution', 12), ('Prestation', 10), ('Nom', 25), ('Prenom', 15), ('Genre', 8),
('Date de naissance', 17), ('Adresse', 20), ('NPA', 8), ('Localité', 20), ('Canton', 8),
('OPE', 25), ('Nom mère', 20), ('Prénom mère', 20), ('Nom père', 20), ('Prénom père', 20),
('Autorité parentale', 18), ('Statut marital', 15), ('Statut financier', 15),
('Fam. monopar.', 15), ('Nbre enfants', 12),
('Date demande', 15), ('Provenance', 15), ('Motif demande', 40), ('Début suivi', 15),
]
def __init__(self, exp):
self.exp = exp
def _set_col_dimensions(self):
for col_idx, (_, size) in enumerate(self.en_tetes, start=1):
self.exp.ws.column_dimensions[get_column_letter(col_idx)].width = size
def produce(self, query):
self._set_col_dimensions()
self.exp.write_line([et[0] for et in self.en_tetes], bold=True)
for famille in query:
self.produce_famille(famille)
self.exp.ws.freeze_panes = self.exp.ws['A2']
def produce_famille(self, famille):
membres_suivis = famille.membres_suivis()
if membres_suivis:
for pers in famille.membres_suivis():
data = self.collect_pers_data(famille, pers)
self.exp.write_line(data)
else:
data = self.collect_pers_data(famille, None)
self.exp.write_line(data)
def collect_pers_data(self, famille, pers):
parents = famille.parents()
mere = next((par for par in parents if par.role.nom == 'Mère'), None)
pere = next((par for par in parents if par.role.nom == 'Père'), None)
return [
'Fondation Transit',
'AEMO',
pers.nom if pers else famille.nom,
pers.prenom if pers else "-",
pers.genre if pers else "-",
format_d_m_Y(pers.date_naissance) if pers else "-",
pers.rue if pers else famille.rue,
pers.npa if pers else famille.npa,
pers.localite if pers else famille.localite,
'NE',
famille.suivi.ope_referent.nom_prenom if famille.suivi.ope_referent else '',
mere.nom if mere else '',
mere.prenom if mere else '',
pere.nom if pere else '',
pere.prenom if pere else '',
famille.get_autorite_parentale_display(),
famille.get_statut_marital_display(),
famille.get_statut_financier_display(),
{True: 'OUI', False: 'NON', None: ''}[famille.monoparentale],
len(famille.membres_suivis()) + len(famille.enfants_non_suivis()),
format_d_m_Y(famille.suivi.date_demande),
famille.get_provenance_display(),
famille.suivi.get_motif_demande_display(),
format_d_m_Y(famille.suivi.date_debut_suivi),
]
class SuiviSheet(BaseFamilleSheet):
en_tetes = BaseFamilleSheet.en_tetes + [('H. Évaluation', 12), ('H. Suivi', 12), ('H. Prest. gén.', 12)]
def __init__(self, exp, date_debut_mois):
self.date_debut_mois = date_debut_mois
super().__init__(exp)
def produce_famille(self, famille):
# Prepare some data common to famille
nb_membres_suivis = len(famille.membres_suivis()) or 1
famille._h_evaluation_par_pers = famille.total_mensuel_evaluation(self.date_debut_mois) // nb_membres_suivis
famille._h_suivi_par_pers = famille.total_mensuel_suivi(self.date_debut_mois) // nb_membres_suivis
super().produce_famille(famille)
def collect_pers_data(self, famille, pers):
data = super().collect_pers_data(famille, pers)
h_evaluation = famille._h_evaluation_par_pers
h_suivi = famille._h_suivi_par_pers
h_prest_gen = famille.prest_gen # Annotation from the view.
data.extend([h_evaluation, h_suivi, h_prest_gen])
# Variables des totaux
self.exp._total_spe['eval'] += h_evaluation
self.exp._total_spe['suivi'] += h_suivi
self.exp._total_spe['gen'] += h_prest_gen
return data
class NouveauxSheet(BaseFamilleSheet):
pass
class TerminesSheet(BaseFamilleSheet):
en_tetes = BaseFamilleSheet.en_tetes + [
('Date fin suivi', 15), ('Motif fin suivi', 15), ('Destination', 15), ('Total heures', 12),
]
def collect_pers_data(self, famille, pers):
data = super().collect_pers_data(famille, pers)
suivi = famille.suivi
data.extend([
format_d_m_Y(suivi.date_fin_suivi),
famille.suivi.get_motif_fin_suivi_display(),
famille.get_destination_display(),
famille.temps_total_prestations_reparti(),
])
return data
class ExportStatistique(OpenXMLExport):
def __init__(self, *args, col_widths=None, **kwargs):
self.col_widths = col_widths
super().__init__(*args, **kwargs)
def fill_data(self, generator):
for row in generator:
if row and row[0] == 'BOLD':
self.write_line(row[1:], bold=True, col_widths=self.col_widths)
else:
self.write_line(row, col_widths=self.col_widths)