fix: 下单后自动进入只读核单 (#119)
This commit is contained in:
@@ -112,6 +112,7 @@ ERROR_FEEDBACK_MIN_WIDTH = 520
|
||||
ERROR_FEEDBACK_MIN_HEIGHT = 112
|
||||
ERROR_FEEDBACK_BUTTON_MIN_WIDTH = 120
|
||||
ERROR_FEEDBACK_BUTTON_MIN_HEIGHT = 40
|
||||
PURCHASE_RECONCILE_DELAY_MS = 5_000
|
||||
|
||||
|
||||
class ClaimTaskWorker(QObject):
|
||||
@@ -1203,6 +1204,16 @@ class PDDTaskPageEvent(QObject):
|
||||
)
|
||||
elif kind == "result_pending":
|
||||
self._on_claim_retryable_failed(message)
|
||||
elif kind == "reconcile_pending":
|
||||
self._retry_count = 0
|
||||
seconds = PURCHASE_RECONCILE_DELAY_MS / 1000
|
||||
self._continue_after(
|
||||
PURCHASE_RECONCILE_DELAY_MS,
|
||||
(
|
||||
f"自动获取:运行中 · {message};"
|
||||
f"{seconds:g} 秒后自动核对订单"
|
||||
),
|
||||
)
|
||||
elif kind == "failed" and self._is_retry_wait_task(task_id):
|
||||
content = (
|
||||
f"自动获取:已停止 · 任务 {task_id} 重试已暂停;"
|
||||
|
||||
@@ -272,7 +272,7 @@ class PurchaseTaskService:
|
||||
remote_task_id,
|
||||
)
|
||||
return PurchaseTaskOutcome(
|
||||
"manual_review",
|
||||
"reconcile_pending",
|
||||
f"任务 {remote_task_id} {message}",
|
||||
remote_task_id,
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ from src.pdd_ui_event import (
|
||||
ERROR_FEEDBACK_DURATION_MS,
|
||||
ERROR_FEEDBACK_MIN_HEIGHT,
|
||||
ERROR_FEEDBACK_MIN_WIDTH,
|
||||
PURCHASE_RECONCILE_DELAY_MS,
|
||||
PDDTaskPageEvent,
|
||||
admin_task_to_new_claimed_task,
|
||||
summary_to_row,
|
||||
@@ -1474,6 +1475,56 @@ class PDDTaskPageEventTest(unittest.TestCase):
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_live_submit_schedules_read_only_reconcile_after_five_seconds(self):
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(
|
||||
page,
|
||||
self.repository,
|
||||
claim_gateway=RecordingClaimGateway(None),
|
||||
settings_repository=self._saved_settings(),
|
||||
)
|
||||
events._auto_fetch_running = True
|
||||
|
||||
events._on_collect_outcome(
|
||||
"reconcile_pending",
|
||||
"任务 PUR-001 订单提交点击已执行,结果待只读核对",
|
||||
"PUR-001",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
events._cycle_next_delay_ms, PURCHASE_RECONCILE_DELAY_MS
|
||||
)
|
||||
self.assertTrue(events._auto_fetch_running)
|
||||
self.assertFalse(events._stop_requested)
|
||||
self.assertIn("5 秒后自动核对订单", page.statusLabel.text())
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_stop_during_reconcile_wait_cancels_next_cycle(self):
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(
|
||||
page,
|
||||
self.repository,
|
||||
claim_gateway=RecordingClaimGateway(None),
|
||||
settings_repository=self._saved_settings(),
|
||||
)
|
||||
events._auto_fetch_running = True
|
||||
events._on_collect_outcome(
|
||||
"reconcile_pending", "等待只读核对", "PUR-001"
|
||||
)
|
||||
events._on_claim_thread_finished()
|
||||
self.assertTrue(events._next_cycle_timer.isActive())
|
||||
self.assertEqual(
|
||||
events._next_cycle_timer.interval(), PURCHASE_RECONCILE_DELAY_MS
|
||||
)
|
||||
|
||||
events._request_stop_auto_fetch()
|
||||
|
||||
self.assertFalse(events._next_cycle_timer.isActive())
|
||||
self.assertFalse(events._auto_fetch_running)
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_duplicate_task_is_normal_status(self):
|
||||
task = collect_admin_task()
|
||||
self.repository.add_claimed_task(admin_task_to_new_claimed_task(task))
|
||||
|
||||
@@ -304,7 +304,7 @@ class PurchaseTaskServiceTest(unittest.TestCase):
|
||||
|
||||
outcome = self._service(adapter).execute_one_local()
|
||||
|
||||
self.assertEqual(outcome.kind, "manual_review")
|
||||
self.assertEqual(outcome.kind, "reconcile_pending")
|
||||
self.assertEqual(adapter.submit_count, 1)
|
||||
detail = self.repository.get_task("PUR-001")
|
||||
run = self.repository.latest_task_run("PUR-001")
|
||||
@@ -332,7 +332,7 @@ class PurchaseTaskServiceTest(unittest.TestCase):
|
||||
|
||||
outcome = self._service(adapter).execute_one_local()
|
||||
|
||||
self.assertEqual(outcome.kind, "manual_review")
|
||||
self.assertEqual(outcome.kind, "reconcile_pending")
|
||||
self.assertEqual(adapter.submit_count, 1)
|
||||
run = self.repository.latest_task_run("PUR-001")
|
||||
self.assertIsNotNone(run.irreversible_action_at)
|
||||
|
||||
@@ -249,7 +249,7 @@ class TaskDispatcherTest(unittest.TestCase):
|
||||
).execute_one()
|
||||
|
||||
self.assertEqual(dry_outcome.kind, "no_task")
|
||||
self.assertEqual(live_outcome.kind, "manual_review")
|
||||
self.assertEqual(live_outcome.kind, "reconcile_pending")
|
||||
self.assertEqual(
|
||||
self.repository.get_task(task.task_id).execution_mode,
|
||||
"live",
|
||||
|
||||
@@ -95,6 +95,9 @@ Client 不保存或读取 `purchase.live_*` 手工授权设置。`purchase_mode`
|
||||
- `execution_mode=live` 只允许采购任务,且 Client 不得自行升级 Admin 下发的模式。
|
||||
- 最终点击前重新读取页面并核对规格、数量、价格、库存和唯一提交目标。
|
||||
- `irreversible_action_at` 必须在点击前以事务提交;点击最多一次,返回或抛错后均只进入核单。
|
||||
- 下单点击完成或结果不确定后,任务先保存为 `reconcile_purchase`。持续自动获取
|
||||
等待 5 秒后自动开始下一轮;Dispatcher 必须优先执行当前任务的只读核单,不能
|
||||
重新打开商品、重新下单或先领取其他任务。5 秒只用于页面跳转缓冲,不代表下单成功。
|
||||
- 正式 uiautomator2 采购 Adapter 只点击商品页采购入口和目标规格,
|
||||
演练的 `enter_confirmation` 与 `stop_before_submit` 均为只读检查。
|
||||
- 单元测试必须断言演练没有最终点击、live 只有一次最终点击,且模糊目标不会点击。
|
||||
|
||||
Reference in New Issue
Block a user