125 lines
5.0 KiB
Python
125 lines
5.0 KiB
Python
"""Unit-тесты пересчёта весов при замене компонента в плане."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from app.models import Component, Ingredient, Recipe
|
|
from app.services.daily_plan.ingredient_weights import resolve_plan_ingredient_weights
|
|
|
|
|
|
class PlanIngredientWeightsTests(unittest.TestCase):
|
|
def _make(self, *, locked: bool, wph: float, dm_pct: float, repl_dm: float, dm_ph=None):
|
|
recipe = Recipe(id="r1", name="R", dry_matter_locked=locked, content_hash="")
|
|
ing = Ingredient(
|
|
id="i1",
|
|
name="Ing",
|
|
weight_per_head=wph,
|
|
amount=0.0,
|
|
dry_matter=dm_pct,
|
|
dry_matter_per_head=dm_ph,
|
|
order=1,
|
|
recipe_id="r1",
|
|
component_id="c1",
|
|
created_by="system",
|
|
updated_by="system",
|
|
)
|
|
components = {
|
|
"c1": Component(id="c1", name="A", type="grain", dry_matter=dm_pct),
|
|
"c2": Component(id="c2", name="B", type="silage", dry_matter=repl_dm),
|
|
}
|
|
return ing, recipe, components
|
|
|
|
def test_weight_mode_keeps_kg_per_head(self) -> None:
|
|
ing, recipe, components = self._make(locked=False, wph=2.0, dm_pct=55.0, repl_dm=35.0)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing, recipe, heads=10, components_by_id=components, replacement_component_id="c2"
|
|
)
|
|
self.assertEqual(out["recalculationMode"], "weight")
|
|
self.assertEqual(out["weightPerHead"], 2.0)
|
|
self.assertEqual(out["totalKg"], 20.0)
|
|
self.assertEqual(out["dryMatterPct"], 35.0)
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 0.7, places=4)
|
|
|
|
def test_dry_matter_mode_keeps_dm_per_head(self) -> None:
|
|
ing, recipe, components = self._make(
|
|
locked=True, wph=1.0, dm_pct=55.0, repl_dm=35.0, dm_ph=0.55
|
|
)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing, recipe, heads=20, components_by_id=components, replacement_component_id="c2"
|
|
)
|
|
self.assertEqual(out["recalculationMode"], "dry_matter")
|
|
self.assertAlmostEqual(out["weightPerHead"], 1.57, places=2)
|
|
self.assertAlmostEqual(out["totalKg"], 31.4, places=1)
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 0.55, places=4)
|
|
|
|
def test_dry_matter_pct_adjustment_locked(self) -> None:
|
|
ing, recipe, components = self._make(
|
|
locked=True, wph=1.0, dm_pct=55.0, repl_dm=35.0, dm_ph=0.55
|
|
)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing,
|
|
recipe,
|
|
heads=10,
|
|
components_by_id=components,
|
|
component_adjustment={
|
|
"dry_matter": 40.0,
|
|
"dry_matter_locked": True,
|
|
"weight_per_head": None,
|
|
"dry_matter_per_head": None,
|
|
},
|
|
)
|
|
self.assertTrue(out["adjustedToday"])
|
|
self.assertEqual(out["dryMatterPct"], 40.0)
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 0.55, places=4)
|
|
self.assertAlmostEqual(out["weightPerHead"], 1.38, places=2)
|
|
|
|
def test_dry_matter_pct_adjustment(self) -> None:
|
|
ing, recipe, components = self._make(locked=False, wph=2.0, dm_pct=55.0, repl_dm=35.0)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing,
|
|
recipe,
|
|
heads=10,
|
|
components_by_id=components,
|
|
component_adjustment={"dry_matter": 40.0, "weight_per_head": None, "dry_matter_per_head": None},
|
|
)
|
|
self.assertTrue(out["adjustedToday"])
|
|
self.assertEqual(out["weightPerHead"], 2.0)
|
|
self.assertEqual(out["dryMatterPct"], 40.0)
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 0.8, places=4)
|
|
self.assertEqual(out["originalWeightPerHead"], 2.0)
|
|
self.assertEqual(out["originalDryMatterPct"], 55.0)
|
|
|
|
def test_weight_mode_adjustment(self) -> None:
|
|
ing, recipe, components = self._make(locked=False, wph=2.0, dm_pct=55.0, repl_dm=35.0)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing,
|
|
recipe,
|
|
heads=10,
|
|
components_by_id=components,
|
|
component_adjustment={"weight_per_head": 3.0, "dry_matter_per_head": None},
|
|
)
|
|
self.assertTrue(out["adjustedToday"])
|
|
self.assertEqual(out["weightPerHead"], 3.0)
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 1.65, places=4)
|
|
self.assertEqual(out["originalWeightPerHead"], 2.0)
|
|
|
|
def test_dry_matter_mode_adjustment(self) -> None:
|
|
ing, recipe, components = self._make(
|
|
locked=True, wph=1.0, dm_pct=55.0, repl_dm=35.0, dm_ph=0.55
|
|
)
|
|
out = resolve_plan_ingredient_weights(
|
|
ing,
|
|
recipe,
|
|
heads=20,
|
|
components_by_id=components,
|
|
component_adjustment={"weight_per_head": None, "dry_matter_per_head": 0.7},
|
|
)
|
|
self.assertTrue(out["adjustedToday"])
|
|
self.assertAlmostEqual(out["dryMatterPerHead"], 0.7, places=4)
|
|
self.assertAlmostEqual(out["weightPerHead"], 1.27, places=2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|