Files
site/WESP_REL/app/services/feed_accounting/pdf_feed_accounting.py
T
2026-07-17 12:57:18 +03:00

140 lines
5.0 KiB
Python

"""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()