"""PDF-экспорт учётных документов (reportlab).""" from __future__ import annotations import io from pathlib import Path from typing import List from flask import Flask from reportlab.lib import colors from reportlab.lib.pagesizes import A4, landscape from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.units import mm from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle from app.services.feed_accounting.sp20_report_builder import build_journal_rows, build_sp20_report from app.services.org_settings import get_org_settings, signature_path from app.services.pdf_cyrillic_fonts import ( register_cyrillic_font as _register_cyrillic_font, register_cyrillic_font_bold as _register_cyrillic_font_bold, ) def _styles(): font = _register_cyrillic_font() styles = getSampleStyleSheet() styles["Title"].fontName = font styles["Normal"].fontName = font return styles, font def _signature_image_flowable(role: str, width=40 * mm, height=15 * mm): try: from reportlab.platypus import Image p = signature_path(role) if p.is_file(): return Image(str(p), width=width, height=height) except Exception: pass return None def build_sp20_pdf(app: Flask, year: int, month: int) -> bytes: report = build_sp20_report(app, year, month) org = report.org buf = io.BytesIO() doc = SimpleDocTemplate(buf, pagesize=landscape(A4), leftMargin=12 * mm, rightMargin=12 * mm) styles, font = _styles() story = [] story.append(Paragraph("Ведомость учёта расхода кормов (форма СП-20)", styles["Title"])) story.append(Paragraph(f"ОКУД 0325020 · {month:02d}.{year}", styles["Normal"])) story.append(Spacer(1, 6)) meta = [ ["Организация", org.get("organization_name") or "—", "ОКПО", org.get("okpo") or "—"], ["Ферма", org.get("farm_name") or "—", "Бригада", org.get("brigade") or "—"], ["Вид скота", report.animal_type, "Ответственный", org.get("responsible_person") or "—"], ] mt = Table(meta, colWidths=[35 * mm, 70 * mm, 35 * mm, 70 * mm]) mt.setStyle( TableStyle( [ ("FONTNAME", (0, 0), (-1, -1), font), ("FONTSIZE", (0, 0), (-1, -1), 9), ("GRID", (0, 0), (-1, -1), 0.25, colors.grey), ] ) ) story.append(mt) story.append(Spacer(1, 8)) data = [["Дата", "Корм", "Голов", "Кг"]] for line in report.lines[:120]: data.append( [ f"{line.day:02d}.{month:02d}.{year}", line.feed_name, str(line.heads or ""), str(line.quantity_kg), ] ) if len(data) == 1: data.append(["—", "Нет данных за период", "", ""]) tbl = Table(data, repeatRows=1) tbl.setStyle( TableStyle( [ ("FONTNAME", (0, 0), (-1, -1), font), ("FONTSIZE", (0, 0), (-1, -1), 8), ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("GRID", (0, 0), (-1, -1), 0.25, colors.grey), ] ) ) story.append(tbl) story.append(Spacer(1, 12)) sig_row = [] for role, label in ( ("zootechnician", org.get("zootechnician") or "Зоотехник"), ("warehouse_keeper", org.get("warehouse_keeper") or "Кладовщик"), ): img = _signature_image_flowable(role) sig_row.append([label, img if img else ""]) sig_tbl = Table(sig_row, colWidths=[100 * mm, 100 * mm]) sig_tbl.setStyle(TableStyle([("FONTNAME", (0, 0), (-1, -1), font), ("FONTSIZE", (0, 0), (-1, -1), 9)])) story.append(sig_tbl) doc.build(story) return buf.getvalue() def build_journal_pdf(app: Flask, year: int, month: int) -> bytes: org = get_org_settings(app) rows = build_journal_rows(app, year, month) buf = io.BytesIO() doc = SimpleDocTemplate(buf, pagesize=A4) styles, font = _styles() story = [ Paragraph("Журнал учёта расхода кормов", styles["Title"]), Paragraph(org.get("organization_name") or "", styles["Normal"]), Paragraph(f"Период: {month:02d}.{year}", styles["Normal"]), Spacer(1, 8), ] data = [["Вид корма", "Ед.", "За месяц, кг", "С начала года, кг"]] for r in rows: data.append([r["name"], r["unit"], r["month_kg"], r["ytd_kg"]]) if len(data) == 1: data.append(["—", "кг", 0, 0]) tbl = Table(data, repeatRows=1) tbl.setStyle( TableStyle( [ ("FONTNAME", (0, 0), (-1, -1), font), ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("GRID", (0, 0), (-1, -1), 0.25, colors.grey), ] ) ) story.append(tbl) doc.build(story) return buf.getvalue()