| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- """生产完成任务/工单状态级联。"""
- import unittest
- from datetime import datetime
- from unittest.mock import ANY, MagicMock, patch
- from pydantic import ValidationError
- from app.crud import production_task as production_task_svc
- from app.crud import production_work_order as production_work_order_svc
- from app.schemas.production_work_order import ProductionWorkOrderComplete
- class TestProductionWorkOrderCompleteSchema(unittest.TestCase):
- def test_requires_conclusion(self):
- with self.assertRaises(ValidationError):
- ProductionWorkOrderComplete()
- def test_accepts_cg_and_remark(self):
- body = ProductionWorkOrderComplete(conclusion="cg", remark="ok")
- self.assertEqual(body.conclusion, "cg")
- self.assertEqual(body.remark, "ok")
- class TestForceCompleteTaskSteps(unittest.TestCase):
- def test_marks_incomplete_steps_ywc(self):
- db = MagicMock()
- step_dzx = MagicMock(step_status="dzx", completed_by=None, completed_time=None)
- step_jxz = MagicMock(step_status="jxz", completed_by=None, completed_time=None)
- q = MagicMock()
- db.query.return_value = q
- q.filter.return_value = q
- q.all.return_value = [step_dzx, step_jxz]
- now = datetime(2026, 8, 31, 12, 0, 0)
- production_task_svc._force_complete_task_steps(
- db, "task-1", "t1", "user-1", now
- )
- self.assertEqual(step_dzx.step_status, "ywc")
- self.assertEqual(step_dzx.completed_by, "user-1")
- self.assertEqual(step_dzx.completed_time, now)
- self.assertEqual(step_jxz.step_status, "ywc")
- db.add.assert_any_call(step_dzx)
- db.commit.assert_not_called()
- class TestUpdateTaskStatusCascadeSteps(unittest.TestCase):
- @patch("app.crud.production_task._consume_task_input_cell_products")
- @patch("app.crud.production_work_order.sync_production_work_order_status_from_tasks")
- @patch("app.crud.production_task._force_complete_task_steps")
- def test_ywc_no_longer_blocks_on_incomplete_steps(
- self, mock_force, mock_sync, mock_consume
- ):
- db = MagicMock()
- task = MagicMock(
- id="task-1",
- tenant_no="t1",
- del_flag=0,
- task_status="jxz",
- work_order_id="wo-1",
- started_time=None,
- completed_time=None,
- conclusion=None,
- remark=None,
- )
- q = MagicMock()
- db.query.return_value = q
- q.filter.return_value = q
- q.first.return_value = task
- result = production_task_svc.update_task_status(
- db, "task-1", "t1", "user-1", "ywc", conclusion="cg"
- )
- mock_force.assert_called_once()
- self.assertEqual(task.task_status, "ywc")
- self.assertEqual(task.conclusion, "cg")
- mock_consume.assert_called_once()
- mock_sync.assert_called_once()
- db.commit.assert_called_once()
- self.assertIs(result, task)
- class TestCompleteProductionWorkOrderCascade(unittest.TestCase):
- @patch("app.crud.pilot_outbound_status_sync.sync_schedule_from_production_work_order")
- @patch("app.crud.production_task._consume_task_input_cell_products")
- @patch("app.crud.production_task._force_complete_task_steps")
- @patch("app.crud.production_work_order.get_production_work_order")
- def test_cascades_incomplete_tasks_and_steps(
- self, mock_get_wo, mock_force, mock_consume, mock_sync_sched
- ):
- db = MagicMock()
- wo = MagicMock(id="wo-1", work_order_status="jxz", remark=None)
- mock_get_wo.return_value = wo
- task_a = MagicMock(
- id="ta",
- task_status="dzx",
- completed_time=None,
- conclusion=None,
- remark=None,
- )
- q = MagicMock()
- db.query.return_value = q
- q.filter.return_value = q
- q.all.return_value = [task_a]
- body = ProductionWorkOrderComplete(conclusion="sb", remark="batch fail")
- result = production_work_order_svc.complete_production_work_order(
- db, "wo-1", "t1", "user-1", body
- )
- mock_force.assert_called_once_with(db, "ta", "t1", "user-1", ANY)
- self.assertEqual(task_a.task_status, "ywc")
- self.assertEqual(task_a.conclusion, "sb")
- self.assertEqual(task_a.remark, "batch fail")
- mock_consume.assert_called_once()
- self.assertEqual(wo.work_order_status, "ywc")
- self.assertEqual(wo.remark, "batch fail")
- mock_sync_sched.assert_called_once()
- db.commit.assert_called_once()
- self.assertIs(result, wo)
- @patch("app.crud.production_work_order.get_production_work_order")
- def test_rejects_invalid_conclusion(self, mock_get_wo):
- db = MagicMock()
- mock_get_wo.return_value = MagicMock(work_order_status="jxz")
- bad = MagicMock(conclusion="xx", remark=None)
- with self.assertRaises(ValueError):
- production_work_order_svc.complete_production_work_order(
- db, "wo-1", "t1", "user-1", bad
- )
- @patch("app.crud.production_work_order.get_production_work_order")
- def test_rejects_already_completed(self, mock_get_wo):
- db = MagicMock()
- mock_get_wo.return_value = MagicMock(work_order_status="ywc")
- with self.assertRaises(ValueError) as ctx:
- production_work_order_svc.complete_production_work_order(
- db,
- "wo-1",
- "t1",
- "user-1",
- ProductionWorkOrderComplete(conclusion="cg"),
- )
- self.assertIn("已完成", str(ctx.exception))
- if __name__ == "__main__":
- unittest.main()
|