131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
"""PDF: отчёт «Потребление корма»."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
|
|
from flask import Flask
|
|
from reportlab.lib import colors
|
|
from reportlab.lib.pagesizes import A4, landscape
|
|
from reportlab.lib.units import mm
|
|
from reportlab.platypus import PageBreak, Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
|
|
|
|
from app.services.feed_accounting.consumption_report_builder import build_consumption_report
|
|
from app.services.feed_accounting.pdf_feed_accounting import _styles
|
|
|
|
|
|
def _table(data: list, font: str, *, font_size: int = 8, repeat_rows: int = 1) -> Table:
|
|
tbl = Table(data, repeatRows=repeat_rows)
|
|
tbl.setStyle(
|
|
TableStyle(
|
|
[
|
|
("FONTNAME", (0, 0), (-1, -1), font),
|
|
("FONTSIZE", (0, 0), (-1, -1), font_size),
|
|
("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
|
|
("GRID", (0, 0), (-1, -1), 0.25, colors.grey),
|
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
|
]
|
|
)
|
|
)
|
|
return tbl
|
|
|
|
|
|
def build_consumption_pdf(app: Flask, date_from: str, date_to: str) -> bytes:
|
|
report = build_consumption_report(app, date_from, date_to)
|
|
buf = io.BytesIO()
|
|
doc = SimpleDocTemplate(
|
|
buf,
|
|
pagesize=landscape(A4),
|
|
leftMargin=10 * mm,
|
|
rightMargin=10 * mm,
|
|
topMargin=10 * mm,
|
|
bottomMargin=10 * mm,
|
|
)
|
|
styles, font = _styles()
|
|
story = [
|
|
Paragraph("Потребление корма", styles["Title"]),
|
|
Paragraph(f"Период: {date_from} — {date_to}", styles["Normal"]),
|
|
Spacer(1, 6),
|
|
Paragraph("Сводка", styles["Normal"]),
|
|
Spacer(1, 4),
|
|
]
|
|
|
|
sum_data = [
|
|
[
|
|
"Компонент",
|
|
"Осталось, кг",
|
|
"Расход за период, кг",
|
|
"План кг/сут",
|
|
"Осталось дней",
|
|
"Поступление, кг",
|
|
"Всего, кг",
|
|
]
|
|
]
|
|
for row in report.summary:
|
|
sum_data.append(
|
|
[
|
|
row["name"],
|
|
row["remaining_kg"],
|
|
row["consumed_kg"],
|
|
row["planned_per_day_kg"] or "",
|
|
row["days_left"] if row["days_left"] is not None else "",
|
|
row["inflow_kg"],
|
|
row["total_kg"],
|
|
]
|
|
)
|
|
if len(sum_data) == 1:
|
|
sum_data.append(["—", "", "", "", "", "", ""])
|
|
story.append(_table(sum_data, font))
|
|
story.append(PageBreak())
|
|
|
|
story.append(Paragraph("Расход по дням", styles["Normal"]))
|
|
story.append(Spacer(1, 4))
|
|
day_labels = [d.strftime("%d.%m") for d in report.days]
|
|
daily_data = [["Компонент"] + day_labels + ["Итого"]]
|
|
for row in report.daily:
|
|
daily_data.append(
|
|
[row["name"]]
|
|
+ [row["days"].get(d, 0) or "" for d in report.days]
|
|
+ [row["total_kg"]]
|
|
)
|
|
if len(daily_data) == 1:
|
|
daily_data.append(["—"] + [""] * (len(report.days) + 1))
|
|
story.append(_table(daily_data, font, font_size=6))
|
|
story.append(PageBreak())
|
|
|
|
story.append(Paragraph("Детализация загрузок", styles["Normal"]))
|
|
story.append(Spacer(1, 4))
|
|
det_data = [
|
|
[
|
|
"Начало",
|
|
"Окончание",
|
|
"Рецепт",
|
|
"Кормораздатчик",
|
|
"Компонент",
|
|
"План, кг",
|
|
"Факт, кг",
|
|
"Перегруз, кг",
|
|
"№",
|
|
]
|
|
]
|
|
for row in report.detail:
|
|
det_data.append(
|
|
[
|
|
row["start"],
|
|
row["end"],
|
|
row["recipe"],
|
|
row["dispenser"],
|
|
row["component"],
|
|
row["target_kg"],
|
|
row["actual_kg"],
|
|
row["overload_kg"],
|
|
row["loading_order"],
|
|
]
|
|
)
|
|
if len(det_data) == 1:
|
|
det_data.append(["—", "", "", "", "", "", "", "", ""])
|
|
story.append(_table(det_data, font, font_size=7))
|
|
|
|
doc.build(story)
|
|
return buf.getvalue()
|