Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
@@ -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()