@@ -0,0 +1,174 @@
|
||||
"""Фабрики данных для тестов кормоцеха и рецептов."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import func, select
|
||||
|
||||
from app import db
|
||||
from app.models import Component, Ingredient, Recipe, SyncQueue, UnloadingGroup
|
||||
|
||||
|
||||
def create_component(*, name: str = "Компонент А", dry_matter: float = 50.0) -> str:
|
||||
comp_id = str(uuid.uuid4())
|
||||
db.session.add(
|
||||
Component(
|
||||
id=comp_id,
|
||||
name=name,
|
||||
type="grain",
|
||||
dry_matter=dry_matter,
|
||||
protein=0.0,
|
||||
energy=0.0,
|
||||
price=0.0,
|
||||
)
|
||||
)
|
||||
db.session.flush()
|
||||
return comp_id
|
||||
|
||||
|
||||
def create_recipe_with_children(
|
||||
*,
|
||||
name: str = "Тестовый рецепт",
|
||||
heads: int = 10,
|
||||
component_ids: Optional[List[str]] = None,
|
||||
with_groups: bool = True,
|
||||
) -> Tuple[str, List[str], List[str]]:
|
||||
"""Рецепт + ингредиенты (+ опционально группы). Возвращает recipe_id, ingredient_ids, group_ids."""
|
||||
if component_ids is None:
|
||||
component_ids = [create_component(name=f"К{i + 1}") for i in range(2)]
|
||||
|
||||
recipe_id = str(uuid.uuid4())
|
||||
recipe = Recipe(
|
||||
id=recipe_id,
|
||||
name=name,
|
||||
heads_per_trip=heads,
|
||||
mixing_time=5,
|
||||
trip_percent=100.0,
|
||||
target_component_id=component_ids[0],
|
||||
content_hash="",
|
||||
)
|
||||
db.session.add(recipe)
|
||||
db.session.flush()
|
||||
|
||||
ingredient_ids: List[str] = []
|
||||
for idx, comp_id in enumerate(component_ids, 1):
|
||||
ing = Ingredient(
|
||||
name=f"Ing {idx}",
|
||||
weight_per_head=float(idx),
|
||||
amount=float(idx * heads),
|
||||
dry_matter=50.0 + idx,
|
||||
component_id=comp_id,
|
||||
order=idx,
|
||||
recipe_id=recipe_id,
|
||||
created_by="system",
|
||||
updated_by="system",
|
||||
)
|
||||
db.session.add(ing)
|
||||
db.session.flush()
|
||||
ingredient_ids.append(str(ing.id))
|
||||
|
||||
group_ids: List[str] = []
|
||||
if with_groups:
|
||||
for idx in range(1, 3):
|
||||
grp = UnloadingGroup(
|
||||
name=f"Г{idx}",
|
||||
distribution_type="percent",
|
||||
value=50.0,
|
||||
weight=float(idx * 10),
|
||||
order=idx,
|
||||
recipe_id=recipe_id,
|
||||
created_by="system",
|
||||
updated_by="system",
|
||||
)
|
||||
db.session.add(grp)
|
||||
db.session.flush()
|
||||
group_ids.append(str(grp.id))
|
||||
|
||||
db.session.commit()
|
||||
return recipe_id, ingredient_ids, group_ids
|
||||
|
||||
|
||||
def recipe_update_payload(
|
||||
recipe: Recipe,
|
||||
*,
|
||||
ingredients: List[Dict[str, Any]],
|
||||
groups: Optional[List[Dict[str, Any]]] = None,
|
||||
deleted_ingredient_ids: Optional[List[str]] = None,
|
||||
deleted_group_ids: Optional[List[str]] = None,
|
||||
target_component_id: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
payload: Dict[str, Any] = {
|
||||
"name": recipe.name,
|
||||
"heads_count": recipe.heads_per_trip,
|
||||
"mixing_time": recipe.mixing_time,
|
||||
"trip_percent": recipe.trip_percent,
|
||||
"target_component_id": target_component_id or recipe.target_component_id,
|
||||
"dry_matter_locked": False,
|
||||
"unloading_link_broken": False,
|
||||
"ingredients": ingredients,
|
||||
"unloading_groups": groups or [],
|
||||
}
|
||||
if deleted_ingredient_ids:
|
||||
payload["deleted_ingredient_ids"] = deleted_ingredient_ids
|
||||
if deleted_group_ids:
|
||||
payload["deleted_unloading_group_ids"] = deleted_group_ids
|
||||
return payload
|
||||
|
||||
|
||||
def sync_task_exists(
|
||||
table_name: str,
|
||||
record_id: str,
|
||||
action: str,
|
||||
) -> bool:
|
||||
row = db.session.execute(
|
||||
select(SyncQueue).where(
|
||||
SyncQueue.table_name == table_name,
|
||||
SyncQueue.record_id == record_id,
|
||||
SyncQueue.action == action,
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
return row is not None
|
||||
|
||||
|
||||
def count_sync_tasks(
|
||||
table_name: str,
|
||||
record_id: str,
|
||||
action: str,
|
||||
) -> int:
|
||||
return int(
|
||||
db.session.scalar(
|
||||
select(func.count())
|
||||
.select_from(SyncQueue)
|
||||
.where(
|
||||
SyncQueue.table_name == table_name,
|
||||
SyncQueue.record_id == record_id,
|
||||
SyncQueue.action == action,
|
||||
)
|
||||
)
|
||||
or 0
|
||||
)
|
||||
|
||||
|
||||
def ingredient_payload_from_row(ing: Ingredient, *, order: Optional[int] = None) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": str(ing.id),
|
||||
"component_id": str(ing.component_id),
|
||||
"weight_per_head": ing.weight_per_head,
|
||||
"amount": ing.amount,
|
||||
"dry_matter": ing.dry_matter,
|
||||
"order": order if order is not None else ing.order,
|
||||
}
|
||||
|
||||
|
||||
def group_payload_from_row(grp: UnloadingGroup, *, order: Optional[int] = None) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": str(grp.id),
|
||||
"name": grp.name,
|
||||
"distribution_type": grp.distribution_type,
|
||||
"value": grp.value,
|
||||
"weight": grp.weight,
|
||||
"order": order if order is not None else grp.order,
|
||||
}
|
||||
Reference in New Issue
Block a user