Files
site/WESP_REL/tests/test_recipe_dry_matter_locked.py
2026-07-17 12:57:18 +03:00

164 lines
5.4 KiB
Python

"""dry_matter_locked: серверный пересчёт весов при сохранении рецепта."""
from __future__ import annotations
import os
import tempfile
import unittest
from app import create_app, db
from app.models import Ingredient, Recipe
from app.services.recipe_calculator import calculate_recipe
from app.services.recipe_update_service import RecipeUpdateError, update_recipe_from_payload
from config import TestingConfig
from tests.helpers.mill_recipe_fixtures import (
create_component,
create_recipe_with_children,
ingredient_payload_from_row,
recipe_update_payload,
)
class RecipeDryMatterLockedConfig(TestingConfig):
_TMP_DIR = tempfile.mkdtemp(prefix="wesp-dm-lock-")
SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(_TMP_DIR, 'dm_lock_test.db')}"
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{os.path.join(_TMP_DIR, 'reports_test.db')}"}
AUTH_LOGIN = "dm-lock-admin"
AUTH_PASSWORD = "dm-lock-secret"
SCENARIO_SAVE_DRY_MATTER_LOCKED = "SAVE_DRY_MATTER_LOCKED"
class RecipeDryMatterLockedTests(unittest.TestCase):
def setUp(self) -> None:
self.app = create_app(RecipeDryMatterLockedConfig)
self.client = self.app.test_client()
self.ctx = self.app.app_context()
self.ctx.push()
db.create_all()
self.client.post(
"/api/auth/login",
json={"login": "dm-lock-admin", "password": "dm-lock-secret"},
)
def tearDown(self) -> None:
db.session.remove()
db.drop_all()
self.ctx.pop()
def test_update_recipe_from_payload_recalculates_when_locked(self) -> None:
comp_id = create_component(dry_matter=50.0)
recipe_id, ing_ids, _ = create_recipe_with_children(
component_ids=[comp_id], heads=10, with_groups=False
)
recipe = db.session.get(Recipe, recipe_id)
recipe.dry_matter_locked = True
db.session.commit()
ing = db.session.get(Ingredient, ing_ids[0])
payload = recipe_update_payload(
recipe,
ingredients=[
{
"id": ing_ids[0],
"component_id": comp_id,
"dry_matter": 50.0,
"dry_matter_per_head": 1.0,
"order": 1,
}
],
groups=[],
)
payload["dry_matter_locked"] = True
payload["heads_count"] = 10
payload["trip_percent"] = 100.0
update_recipe_from_payload(recipe_id, payload)
db.session.commit()
db.session.refresh(ing)
self.assertEqual(ing.weight_per_head, 2.0)
self.assertEqual(ing.amount, 20.0)
def test_locked_save_matches_calculate_api_math(self) -> None:
comp_id = create_component(dry_matter=60.0)
recipe_id, ing_ids, _ = create_recipe_with_children(
component_ids=[comp_id], heads=20, with_groups=False
)
recipe = db.session.get(Recipe, recipe_id)
recipe.dry_matter_locked = True
db.session.commit()
dm_per_head = 0.6
expected = calculate_recipe(
ingredients=[{"dryMatterPerHead": dm_per_head, "dryMatter": 60.0}],
heads_count=20,
trip_percent=100.0,
calculate_from_dry_matter=True,
)
resp = self.client.put(
f"/api/recipes/{recipe_id}",
json={
"name": recipe.name,
"heads_count": 20,
"trip_percent": 100.0,
"mixing_time": recipe.mixing_time,
"target_component_id": comp_id,
"dry_matter_locked": True,
"unloading_link_broken": False,
"ingredients": [
{
"id": ing_ids[0],
"component_id": comp_id,
"dry_matter": 60.0,
"dry_matter_per_head": dm_per_head,
"order": 1,
}
],
"unloading_groups": [],
},
)
self.assertEqual(resp.status_code, 200, resp.get_data(as_text=True))
get_resp = self.client.get(f"/api/recipes/{recipe_id}")
self.assertEqual(get_resp.status_code, 200)
ing = get_resp.get_json()["ingredients"][0]
self.assertEqual(
float(ing["weight_per_head"]),
expected["ingredients"][0]["weightPerHead"],
)
def test_locked_raises_when_dm_percent_missing(self) -> None:
comp_id = create_component(dry_matter=0.0)
recipe_id, ing_ids, _ = create_recipe_with_children(
component_ids=[comp_id], with_groups=False
)
recipe = db.session.get(Recipe, recipe_id)
recipe.dry_matter_locked = True
db.session.commit()
payload = recipe_update_payload(
recipe,
ingredients=[
{
"id": ing_ids[0],
"component_id": comp_id,
"dry_matter": 0,
"dry_matter_per_head": 1.0,
"order": 1,
}
],
groups=[],
)
payload["dry_matter_locked"] = True
with self.assertRaises(RecipeUpdateError) as ctx:
update_recipe_from_payload(recipe_id, payload)
self.assertEqual(ctx.exception.status_code, 400)
if __name__ == "__main__":
unittest.main()