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

194 lines
7.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Перенос рейса между периодами (POST .../transfer)."""
import os
import tempfile
import unittest
from datetime import datetime
from app import create_app, db
from app.models import FeedDispenser, FeedingPeriod, PeriodRecipe, Recipe
from config import TestingConfig
class RecipeTransferConfig(TestingConfig):
_TMP_DIR = tempfile.mkdtemp(prefix="wesp-recipe-transfer-")
SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(_TMP_DIR, 'test.db')}"
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{os.path.join(_TMP_DIR, 'reports.db')}"}
AUTH_LOGIN = "xfer-admin"
AUTH_PASSWORD = "xfer-secret"
class RecipePeriodTransferTests(unittest.TestCase):
def setUp(self) -> None:
self.app = create_app(RecipeTransferConfig)
self.client = self.app.test_client()
self.ctx = self.app.app_context()
self.ctx.push()
db.create_all()
login = self.client.post(
"/api/auth/login", json={"login": "xfer-admin", "password": "xfer-secret"}
)
self.assertEqual(login.status_code, 200)
def tearDown(self) -> None:
db.session.remove()
db.drop_all()
self.ctx.pop()
def _seed_two_periods(self) -> tuple[str, str, str, str, str]:
d1 = FeedDispenser(
id="d-xfer-1", name="D1", farm="F", operator="O", type="dispenser"
)
d2 = FeedDispenser(
id="d-xfer-2", name="D2", farm="F", operator="O", type="dispenser"
)
p1 = FeedingPeriod(id="p-xfer-1", name="P1", dispenser_id=d1.id)
p2 = FeedingPeriod(id="p-xfer-2", name="P2", dispenser_id=d2.id)
r_a = Recipe(id="r-xfer-a", name="A", heads_per_trip=1, mixing_time=0)
r_b = Recipe(id="r-xfer-b", name="B", heads_per_trip=1, mixing_time=0)
r_move = Recipe(id="r-xfer-move", name="Move", heads_per_trip=1, mixing_time=0)
db.session.add_all([d1, d2, p1, p2, r_a, r_b, r_move])
db.session.flush()
now = datetime.now()
for pid, rid, ord_ in (
("p-xfer-1", "r-xfer-a", 1),
("p-xfer-1", "r-xfer-move", 2),
("p-xfer-2", "r-xfer-b", 1),
):
db.session.add(
PeriodRecipe(
period_id=pid,
recipe_id=rid,
order=ord_,
created_at=now,
created_by="system",
updated_by="system",
)
)
db.session.commit()
return "d-xfer-1", "p-xfer-1", "d-xfer-2", "p-xfer-2", "r-xfer-move"
def test_transfer_inserts_at_index_and_removes_from_source(self) -> None:
d1, p1, d2, p2, r_move = self._seed_two_periods()
resp = self.client.post(
f"/api/feed_dispensers/{d2}/periods/{p2}/recipes/{r_move}/transfer",
json={"from_dispenser_id": d1, "from_period_id": p1, "to_index": 0},
)
self.assertEqual(resp.status_code, 200, resp.get_json())
self.assertTrue(resp.get_json().get("success"))
p1_list = self.client.get(f"/api/periods/{p1}/recipes").get_json()
p2_list = self.client.get(f"/api/periods/{p2}/recipes").get_json()
self.assertEqual([x["id"] for x in p1_list], ["r-xfer-a"])
self.assertEqual([x["id"] for x in p2_list], ["r-xfer-move", "r-xfer-b"])
def test_transfer_same_period_rejected(self) -> None:
d1, p1, _, _, r_move = self._seed_two_periods()
resp = self.client.post(
f"/api/feed_dispensers/{d1}/periods/{p1}/recipes/{r_move}/transfer",
json={"from_dispenser_id": d1, "from_period_id": p1, "to_index": 0},
)
self.assertEqual(resp.status_code, 400)
def test_transfer_duplicate_in_target_409(self) -> None:
d1, p1, d2, p2, r_move = self._seed_two_periods()
# Тот же рейс уже привязан к p2 (дубликат цели)
db.session.add(
PeriodRecipe(
period_id=p2,
recipe_id=r_move,
order=2,
created_at=datetime.now(),
created_by="system",
updated_by="system",
)
)
db.session.commit()
resp = self.client.post(
f"/api/feed_dispensers/{d2}/periods/{p2}/recipes/{r_move}/transfer",
json={"from_dispenser_id": d1, "from_period_id": p1, "to_index": 0},
)
self.assertEqual(resp.status_code, 409)
def test_transfer_revives_soft_deleted_row_same_dispenser(self) -> None:
"""Раньше в целевом периоде удалили рейс (строка period_recipes с is_deleted) — INSERT давал UNIQUE."""
d = FeedDispenser(
id="d-xfer-sd", name="D", farm="F", operator="O", type="dispenser"
)
p1 = FeedingPeriod(id="p-xfer-sd-1", name="P1", dispenser_id=d.id)
p2 = FeedingPeriod(id="p-xfer-sd-2", name="P2", dispenser_id=d.id)
r_keep = Recipe(id="r-xfer-sd-k", name="K", heads_per_trip=1, mixing_time=0)
r_move = Recipe(id="r-xfer-sd-m", name="M", heads_per_trip=1, mixing_time=0)
db.session.add_all([d, p1, p2, r_keep, r_move])
db.session.flush()
now = datetime.now()
db.session.add(
PeriodRecipe(
period_id=p1.id,
recipe_id=r_move.id,
order=1,
created_at=now,
created_by="system",
updated_by="system",
)
)
db.session.add(
PeriodRecipe(
period_id=p2.id,
recipe_id=r_move.id,
order=1,
created_at=now,
created_by="system",
updated_by="system",
is_deleted=True,
deleted_at=now,
deleted_by="test",
)
)
db.session.add(
PeriodRecipe(
period_id=p2.id,
recipe_id=r_keep.id,
order=2,
created_at=now,
created_by="system",
updated_by="system",
)
)
db.session.commit()
resp = self.client.post(
f"/api/feed_dispensers/{d.id}/periods/{p2.id}/recipes/{r_move.id}/transfer",
json={
"from_dispenser_id": d.id,
"from_period_id": p1.id,
"to_index": 0,
},
)
self.assertEqual(resp.status_code, 200, resp.get_json())
p1_list = self.client.get(f"/api/periods/{p1.id}/recipes").get_json()
p2_list = self.client.get(f"/api/periods/{p2.id}/recipes").get_json()
self.assertEqual(p1_list, [])
self.assertEqual([x["id"] for x in p2_list], [r_move.id, r_keep.id])
def test_transfer_to_mill_rejected(self) -> None:
d1, p1, _, _, r_move = self._seed_two_periods()
mill = FeedDispenser(
id="d-mill-xfer", name="Mill", farm="F", operator="O", type="mill"
)
pm = FeedingPeriod(id="p-mill-xfer", name="Px", dispenser_id=mill.id)
db.session.add_all([mill, pm])
db.session.commit()
resp = self.client.post(
f"/api/feed_dispensers/d-mill-xfer/periods/p-mill-xfer/recipes/{r_move}/transfer",
json={"from_dispenser_id": d1, "from_period_id": p1, "to_index": 0},
)
self.assertEqual(resp.status_code, 400)
if __name__ == "__main__":
unittest.main()