@@ -0,0 +1,193 @@
|
||||
"""Перенос рейса между периодами (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()
|
||||
Reference in New Issue
Block a user