@@ -0,0 +1,188 @@
|
||||
"""Временная правка СВ% компонентов в плане на день."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from app import create_app, db
|
||||
from app.models import Component, Ingredient, Recipe
|
||||
from app.services.daily_plan.adjustments import (
|
||||
adjust_component_norm,
|
||||
get_component_adjustment_map,
|
||||
list_component_norms_for_plan,
|
||||
undo_component_norm_adjustment,
|
||||
)
|
||||
from app.services.daily_plan.builder import build_daily_plan
|
||||
from app.services.daily_plan.replacements import replace_ingredient
|
||||
from app.services.setup_state import mark_setup_complete
|
||||
from tests.helpers.dispenser_recipe_fixtures import (
|
||||
E2E_DISP_COMP,
|
||||
E2E_DISP_ID,
|
||||
E2E_DISP_RECIPE_1,
|
||||
E2E_DISP_RECIPE_2,
|
||||
seed_dispenser_period_recipes,
|
||||
)
|
||||
from tests.helpers.zootech_test_helpers import ZootechTestConfig
|
||||
|
||||
|
||||
class DailyPlanAdjustmentsTests(unittest.TestCase):
|
||||
PLAN_DATE = "2026-06-07"
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.app = create_app(ZootechTestConfig)
|
||||
self.client = self.app.test_client()
|
||||
self.ctx = self.app.app_context()
|
||||
self.ctx.push()
|
||||
db.create_all()
|
||||
mark_setup_complete(self.app)
|
||||
seed_dispenser_period_recipes()
|
||||
alt = Component(
|
||||
id="e2e-disp-comp-alt",
|
||||
name="Alt Silo",
|
||||
type="silage",
|
||||
dry_matter=35.0,
|
||||
protein=3.0,
|
||||
energy=6.0,
|
||||
price=0.0,
|
||||
)
|
||||
db.session.add(alt)
|
||||
db.session.commit()
|
||||
self.client.post(
|
||||
"/api/auth/login",
|
||||
json={"login": "zootech-test-admin", "password": "zootech-test-secret"},
|
||||
)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
db.session.remove()
|
||||
db.drop_all()
|
||||
self.ctx.pop()
|
||||
|
||||
def test_adjustment_applies_to_all_trips_with_component(self) -> None:
|
||||
adjust_component_norm(
|
||||
E2E_DISP_COMP,
|
||||
self.PLAN_DATE,
|
||||
dry_matter=50.0,
|
||||
)
|
||||
plan = build_daily_plan(dispenser_id=E2E_DISP_ID, plan_date=self.PLAN_DATE)
|
||||
trips = plan["periods"][0]["trips"]
|
||||
self.assertEqual(len(trips), 2)
|
||||
for trip in trips:
|
||||
ing = trip["ingredients"][0]
|
||||
self.assertTrue(ing["adjustedToday"])
|
||||
self.assertEqual(ing["dryMatterPct"], 50.0)
|
||||
master_wph = 1.0 if trip["recipeId"] == E2E_DISP_RECIPE_1 else 2.0
|
||||
self.assertEqual(ing["weightPerHead"], master_wph)
|
||||
self.assertAlmostEqual(ing["dryMatterPerHead"], master_wph * 0.5, places=4)
|
||||
self.assertEqual(ing["originalWeightPerHead"], master_wph)
|
||||
|
||||
def test_master_ingredient_unchanged_after_adjustment(self) -> None:
|
||||
adjust_component_norm(
|
||||
E2E_DISP_COMP,
|
||||
self.PLAN_DATE,
|
||||
dry_matter=45.0,
|
||||
)
|
||||
ing = db.session.get(Ingredient, "e2e-disp-ing-1")
|
||||
self.assertEqual(float(ing.weight_per_head), 1.0)
|
||||
|
||||
master = self.client.get(f"/api/recipes/{E2E_DISP_RECIPE_1}").get_json()
|
||||
self.assertEqual(master["ingredients"][0]["weightPerHead"], 1.0)
|
||||
self.assertNotIn("adjustedToday", master["ingredients"][0])
|
||||
|
||||
overlay = self.client.get(
|
||||
f"/api/recipes/{E2E_DISP_RECIPE_1}?date={self.PLAN_DATE}"
|
||||
).get_json()
|
||||
self.assertTrue(overlay["ingredients"][0]["adjustedToday"])
|
||||
self.assertEqual(overlay["ingredients"][0]["weightPerHead"], 1.0)
|
||||
self.assertEqual(overlay["ingredients"][0]["dry_matter"], 45.0)
|
||||
self.assertAlmostEqual(overlay["ingredients"][0]["dry_matter_per_head"], 0.45, places=4)
|
||||
self.assertEqual(overlay["ingredients"][0]["originalWeightPerHead"], 1.0)
|
||||
|
||||
def test_component_norms_api_and_undo(self) -> None:
|
||||
created = self.client.post(
|
||||
"/api/daily-plan/adjustments/components",
|
||||
json={
|
||||
"componentId": E2E_DISP_COMP,
|
||||
"dryMatter": 40.0,
|
||||
"dryMatterLocked": True,
|
||||
"date": self.PLAN_DATE,
|
||||
"duration": "today",
|
||||
},
|
||||
)
|
||||
self.assertEqual(created.status_code, 200, created.get_data(as_text=True))
|
||||
|
||||
listed = self.client.get(
|
||||
f"/api/daily-plan/component-norms?dispenser_id={E2E_DISP_ID}&date={self.PLAN_DATE}"
|
||||
).get_json()
|
||||
self.assertEqual(len(listed["items"]), 1)
|
||||
item = listed["items"][0]
|
||||
self.assertEqual(item["componentId"], E2E_DISP_COMP)
|
||||
self.assertTrue(item["adjustedToday"])
|
||||
self.assertEqual(item["planDryMatterPct"], 40.0)
|
||||
self.assertTrue(item["planDryMatterLocked"])
|
||||
self.assertEqual(item["usageCount"], 2)
|
||||
|
||||
deleted = self.client.delete(
|
||||
f"/api/daily-plan/adjustments/components?component_id={E2E_DISP_COMP}&date={self.PLAN_DATE}"
|
||||
)
|
||||
self.assertEqual(deleted.status_code, 200)
|
||||
self.assertEqual(get_component_adjustment_map(self.PLAN_DATE), {})
|
||||
plan = build_daily_plan(dispenser_id=E2E_DISP_ID, plan_date=self.PLAN_DATE)
|
||||
ing = plan["periods"][0]["trips"][0]["ingredients"][0]
|
||||
self.assertFalse(ing["adjustedToday"])
|
||||
|
||||
def test_adjustment_before_replacement_on_same_ingredient(self) -> None:
|
||||
adjust_component_norm(
|
||||
E2E_DISP_COMP,
|
||||
self.PLAN_DATE,
|
||||
dry_matter=50.0,
|
||||
)
|
||||
replace_ingredient(
|
||||
E2E_DISP_RECIPE_1,
|
||||
"e2e-disp-ing-1",
|
||||
"e2e-disp-comp-alt",
|
||||
self.PLAN_DATE,
|
||||
)
|
||||
|
||||
plan = build_daily_plan(dispenser_id=E2E_DISP_ID, plan_date=self.PLAN_DATE)
|
||||
ing = plan["periods"][0]["trips"][0]["ingredients"][0]
|
||||
self.assertTrue(ing["replacedToday"])
|
||||
self.assertTrue(ing["adjustedToday"])
|
||||
self.assertEqual(ing["weightPerHead"], 1.0)
|
||||
self.assertEqual(ing["dryMatterPct"], 35.0)
|
||||
|
||||
def test_locked_mode_adjustment_keeps_dry_matter_per_head(self) -> None:
|
||||
recipe = db.session.get(Recipe, E2E_DISP_RECIPE_1)
|
||||
self.assertIsNotNone(recipe)
|
||||
recipe.dry_matter_locked = True
|
||||
db.session.commit()
|
||||
|
||||
adjust_component_norm(
|
||||
E2E_DISP_COMP,
|
||||
self.PLAN_DATE,
|
||||
dry_matter=40.0,
|
||||
)
|
||||
plan = build_daily_plan(dispenser_id=E2E_DISP_ID, plan_date=self.PLAN_DATE)
|
||||
ing = plan["periods"][0]["trips"][0]["ingredients"][0]
|
||||
self.assertAlmostEqual(ing["dryMatterPerHead"], 0.55, places=4)
|
||||
self.assertAlmostEqual(ing["weightPerHead"], 1.38, places=2)
|
||||
self.assertEqual(ing["dryMatterPct"], 40.0)
|
||||
|
||||
def test_undo_service(self) -> None:
|
||||
adjust_component_norm(E2E_DISP_COMP, self.PLAN_DATE, dry_matter=42.0)
|
||||
self.assertTrue(
|
||||
undo_component_norm_adjustment(E2E_DISP_COMP, self.PLAN_DATE)
|
||||
)
|
||||
self.assertEqual(get_component_adjustment_map(self.PLAN_DATE), {})
|
||||
|
||||
def test_list_component_norms_for_plan(self) -> None:
|
||||
rows = list_component_norms_for_plan(self.PLAN_DATE, dispenser_id=E2E_DISP_ID)
|
||||
self.assertEqual(len(rows), 1)
|
||||
self.assertEqual(rows[0]["usageCount"], 2)
|
||||
adjust_component_norm(E2E_DISP_COMP, self.PLAN_DATE, dry_matter=48.0)
|
||||
rows2 = list_component_norms_for_plan(self.PLAN_DATE, dispenser_id=E2E_DISP_ID)
|
||||
self.assertTrue(rows2[0]["adjustedToday"])
|
||||
self.assertEqual(rows2[0]["planDryMatterPct"], 48.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user