@@ -0,0 +1,163 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user