@@ -0,0 +1,105 @@
|
||||
"""Excel: отчёт «Потребление корма» (3 листа)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
|
||||
from flask import Flask
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
from app.services.feed_accounting.consumption_report_builder import build_consumption_report
|
||||
|
||||
|
||||
def _header_font() -> Font:
|
||||
return Font(bold=True)
|
||||
|
||||
|
||||
def build_consumption_xlsx(app: Flask, date_from: str, date_to: str) -> bytes:
|
||||
report = build_consumption_report(app, date_from, date_to)
|
||||
wb = Workbook()
|
||||
|
||||
ws_sum = wb.active
|
||||
ws_sum.title = "Сводка"
|
||||
ws_sum.append([f"Потребление корма · {date_from} — {date_to}"])
|
||||
ws_sum.append([])
|
||||
sum_headers = [
|
||||
"Компонент",
|
||||
"Осталось, кг",
|
||||
"Расход за период (факт), кг",
|
||||
"Расход /24ч (план), кг",
|
||||
"Осталось дней",
|
||||
"Поступление, кг",
|
||||
"Всего на складе, кг",
|
||||
]
|
||||
ws_sum.append(sum_headers)
|
||||
header_row = ws_sum.max_row
|
||||
for col in range(1, len(sum_headers) + 1):
|
||||
ws_sum.cell(row=header_row, column=col).font = _header_font()
|
||||
for row in report.summary:
|
||||
ws_sum.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"],
|
||||
]
|
||||
)
|
||||
for col in range(1, len(sum_headers) + 1):
|
||||
ws_sum.column_dimensions[get_column_letter(col)].width = 18
|
||||
|
||||
ws_det = wb.create_sheet("Детализация")
|
||||
det_headers = [
|
||||
"Дата/время начала",
|
||||
"Дата/время окончания",
|
||||
"Рецепт",
|
||||
"Кормораздатчик",
|
||||
"Компонент",
|
||||
"Целевой вес, кг",
|
||||
"Фактический вес, кг",
|
||||
"Перегруз, кг",
|
||||
"Порядок загрузки",
|
||||
]
|
||||
ws_det.append(det_headers)
|
||||
for col in range(1, len(det_headers) + 1):
|
||||
ws_det.cell(row=1, column=col).font = _header_font()
|
||||
for row in report.detail:
|
||||
ws_det.append(
|
||||
[
|
||||
row["start"],
|
||||
row["end"],
|
||||
row["recipe"],
|
||||
row["dispenser"],
|
||||
row["component"],
|
||||
row["target_kg"],
|
||||
row["actual_kg"],
|
||||
row["overload_kg"],
|
||||
row["loading_order"],
|
||||
]
|
||||
)
|
||||
for col in range(1, len(det_headers) + 1):
|
||||
ws_det.column_dimensions[get_column_letter(col)].width = 16
|
||||
|
||||
ws_daily = wb.create_sheet("Расход по дням")
|
||||
day_headers = ["Компонент"] + [d.strftime("%d.%m.%Y") for d in report.days] + ["Итого за период"]
|
||||
ws_daily.append(day_headers)
|
||||
for col in range(1, len(day_headers) + 1):
|
||||
ws_daily.cell(row=1, column=col).font = _header_font()
|
||||
for row in report.daily:
|
||||
values = [row["name"]]
|
||||
for d in report.days:
|
||||
v = row["days"].get(d, 0)
|
||||
values.append(v if v else 0)
|
||||
values.append(row["total_kg"])
|
||||
ws_daily.append(values)
|
||||
ws_daily.column_dimensions["A"].width = 22
|
||||
for col in range(2, len(day_headers) + 1):
|
||||
ws_daily.column_dimensions[get_column_letter(col)].width = 11
|
||||
|
||||
buf = io.BytesIO()
|
||||
wb.save(buf)
|
||||
return buf.getvalue()
|
||||
Reference in New Issue
Block a user