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