70 lines
2.4 KiB
Python
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
|