Files
2026-07-17 12:57:18 +03:00

70 lines
2.4 KiB
Python

from __future__ import annotations
import time
from app import db
from app.lab.calc.engine import calculate_ration
from app.lab.commands.write_audit import write_audit, write_calculation_run
from app.lab.db_guard import retry_locked
from app.lab.commands.seed_demo_component_nutrients import (
ensure_component_nutrients_if_empty,
supplement_component_nutrients_if_sparse,
)
from app.lab.loaders.ration_loader import load_ration, ration_to_calc_lines
from app.lab.models import LabAnimalProfile, LabRecipeRation
from app.lab.services.ration_calc_store import save_calc_result
@retry_locked
def recalculate_ration(recipe_id: str, user_id: str = "system") -> dict:
snapshot = load_ration(recipe_id)
if not snapshot.lines:
raise ValueError("Пустой мастер — добавьте строки рациона")
seeded_any = False
for line in snapshot.lines:
if not line.component_id:
continue
if ensure_component_nutrients_if_empty(line.component_id, user_id=user_id):
seeded_any = True
elif supplement_component_nutrients_if_sparse(line.component_id, user_id=user_id):
seeded_any = True
if seeded_any:
db.session.commit()
snapshot = load_ration(recipe_id)
profile_mass_kg = None
if snapshot.animal_profile_id:
prof = LabAnimalProfile.query.get(snapshot.animal_profile_id)
if prof is not None:
profile_mass_kg = prof.mass_kg
started = time.perf_counter()
result = calculate_ration(
snapshot.ration_type,
ration_to_calc_lines(snapshot),
snapshot.norms,
heads_per_trip=snapshot.heads_per_trip,
profile_mass_kg=profile_mass_kg,
)
duration_ms = int((time.perf_counter() - started) * 1000)
header = LabRecipeRation.query.filter_by(recipe_id=recipe_id).first()
if header is None:
header = LabRecipeRation(recipe_id=recipe_id, created_by=user_id, updated_by=user_id)
db.session.add(header)
save_calc_result(recipe_id, result, header)
header.updated_by = user_id
status = "FAILED" if result.get("errors") else "COMPLETED"
write_calculation_run(
recipe_id,
status,
{"indicators": result.get("indicators", [])},
duration_ms=duration_ms,
error_message="; ".join(result.get("errors") or []) or None,
)
write_audit("RECALCULATE", "lab_recipe_ration", recipe_id, user_id)
db.session.commit()
return result