test_pl_io_order_site_feedback_status.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. from datetime import datetime
  2. from decimal import Decimal
  3. from types import SimpleNamespace
  4. from unittest.mock import MagicMock
  5. import pytest
  6. from app.services.pl_io_order_service import apply_site_feedback
  7. def _header(**kwargs):
  8. defaults = dict(
  9. status="in_progress",
  10. site_feedback_remark=None,
  11. site_feedback_images=None,
  12. site_feedback_time=None,
  13. site_first_submitted_at=None,
  14. update_by=None,
  15. )
  16. defaults.update(kwargs)
  17. return SimpleNamespace(**defaults)
  18. def _item(item_id="item-1"):
  19. return SimpleNamespace(
  20. id=item_id,
  21. actual_qty=None,
  22. qty_source=None,
  23. update_by=None,
  24. )
  25. def test_apply_site_feedback_sets_status_completed():
  26. header = _header()
  27. item = _item()
  28. db = MagicMock()
  29. apply_site_feedback(
  30. db,
  31. header=header,
  32. items=[item],
  33. item_qty={"item-1": Decimal("12.5")},
  34. remark="ok",
  35. images=["a.jpg"],
  36. status="completed",
  37. )
  38. assert header.status == "completed"
  39. assert item.actual_qty == Decimal("12.5")
  40. assert header.site_first_submitted_at is not None
  41. assert header.site_feedback_remark == "ok"
  42. db.flush.assert_called_once()
  43. def test_apply_site_feedback_sets_status_voided():
  44. header = _header()
  45. apply_site_feedback(
  46. MagicMock(),
  47. header=header,
  48. items=[_item()],
  49. item_qty={"item-1": Decimal("1")},
  50. remark=None,
  51. images=[],
  52. status="voided",
  53. )
  54. assert header.status == "voided"
  55. def test_apply_site_feedback_keeps_in_progress_when_requested():
  56. """首次提交选进行中时,不得隐式改成已完成。"""
  57. header = _header(status="in_progress")
  58. apply_site_feedback(
  59. MagicMock(),
  60. header=header,
  61. items=[_item()],
  62. item_qty={"item-1": Decimal("1")},
  63. remark=None,
  64. images=[],
  65. status="in_progress",
  66. )
  67. assert header.status == "in_progress"
  68. assert header.site_first_submitted_at is not None
  69. def test_apply_site_feedback_rejects_invalid_status():
  70. header = _header()
  71. with pytest.raises(ValueError, match="无效状态"):
  72. apply_site_feedback(
  73. MagicMock(),
  74. header=header,
  75. items=[_item()],
  76. item_qty={},
  77. remark=None,
  78. images=[],
  79. status="done",
  80. )
  81. def test_apply_site_feedback_rejects_already_voided():
  82. header = _header(status="voided")
  83. with pytest.raises(ValueError, match="单据已作废"):
  84. apply_site_feedback(
  85. MagicMock(),
  86. header=header,
  87. items=[_item()],
  88. item_qty={},
  89. remark=None,
  90. images=[],
  91. status="completed",
  92. )
  93. def test_apply_site_feedback_does_not_reset_first_submitted_at():
  94. first = datetime(2026, 1, 1, 12, 0, 0)
  95. header = _header(
  96. status="completed",
  97. site_first_submitted_at=first,
  98. )
  99. apply_site_feedback(
  100. MagicMock(),
  101. header=header,
  102. items=[_item()],
  103. item_qty={"item-1": Decimal("2")},
  104. remark="二改",
  105. images=[],
  106. status="in_progress",
  107. )
  108. assert header.status == "in_progress"
  109. assert header.site_first_submitted_at == first