feat: 安全领取并分派采购任务 (#72)
This commit is contained in:
@@ -20,6 +20,7 @@ from src.pdd_ui_event import (
|
||||
summary_to_row,
|
||||
)
|
||||
from src.mock_admin_gateway import MockAdminGateway
|
||||
from src.pdd_purchase_adapter import PddPurchaseAdapter, PurchasePageState
|
||||
from src.settings_repository import SettingsRepository
|
||||
from src.task_models import NewClaimedTask, TaskStatus, TaskSummary, TaskType
|
||||
from src.task_repository import TaskRepository
|
||||
@@ -45,6 +46,12 @@ class BrokenSaveRepository(BrokenRepository):
|
||||
def next_collect_task(self):
|
||||
return None
|
||||
|
||||
def next_runnable_task(self, *, include_purchase):
|
||||
return None
|
||||
|
||||
def next_purchase_task(self):
|
||||
return None
|
||||
|
||||
|
||||
class RecordingClaimGateway:
|
||||
"""记录领取参数并返回预设结果。"""
|
||||
@@ -148,6 +155,63 @@ def collect_admin_task(task_id="COL-001"):
|
||||
)
|
||||
|
||||
|
||||
def purchase_admin_task(task_id="PUR-001"):
|
||||
return AdminTask(
|
||||
task_id=task_id,
|
||||
task_type=TaskType.PURCHASE,
|
||||
version=1,
|
||||
priority=10,
|
||||
payload={
|
||||
"goods_id": "737116531267",
|
||||
"goods_url": "https://example.test/737116531267",
|
||||
"options": {"color": "黑色", "size": "L"},
|
||||
"quantity": 2,
|
||||
"max_price_cent": 1200,
|
||||
},
|
||||
created_at="2026-08-09T08:00:00Z",
|
||||
updated_at="2026-08-09T08:00:00Z",
|
||||
)
|
||||
|
||||
|
||||
class FakePurchaseAdapter(PddPurchaseAdapter):
|
||||
def __init__(self):
|
||||
self.options = {}
|
||||
self.quantity = 0
|
||||
self.page_kind = "goods"
|
||||
|
||||
def open_goods(self, _goods_url):
|
||||
pass
|
||||
|
||||
def read_state(self):
|
||||
return PurchasePageState(
|
||||
self.page_kind,
|
||||
"737116531267",
|
||||
dict(self.options),
|
||||
self.quantity,
|
||||
990,
|
||||
1,
|
||||
)
|
||||
|
||||
def select_options(self, options):
|
||||
self.options = dict(options)
|
||||
|
||||
def set_quantity(self, quantity):
|
||||
self.quantity = quantity
|
||||
|
||||
def enter_confirmation(self):
|
||||
self.page_kind = "order_confirmation"
|
||||
|
||||
def stop_before_submit(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
def fake_purchase_factory(_address, _cancelled):
|
||||
return FakePurchaseAdapter()
|
||||
|
||||
|
||||
def wait_until(application, predicate, timeout=3.0):
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
@@ -442,6 +506,35 @@ class PDDTaskPageEventTest(unittest.TestCase):
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_ready_runtime_claims_and_dispatches_purchase_in_worker(self):
|
||||
gateway = RecordingClaimGateway(purchase_admin_task())
|
||||
page = PDDTaskPage()
|
||||
events = PDDTaskPageEvent(
|
||||
page,
|
||||
self.repository,
|
||||
claim_gateway=gateway,
|
||||
settings_repository=self._saved_settings(),
|
||||
collect_service_factory=fake_collect_factory,
|
||||
purchase_adapter_factory=fake_purchase_factory,
|
||||
)
|
||||
|
||||
page.autoFetchRequested.emit()
|
||||
|
||||
self.assertTrue(wait_until(self.app, lambda: not events._claim_busy))
|
||||
_, capabilities = gateway.calls[0]
|
||||
self.assertEqual(
|
||||
capabilities.supported_types,
|
||||
(TaskType.COLLECT, TaskType.PURCHASE),
|
||||
)
|
||||
self.assertEqual(capabilities.purchase_mode, "dry_run")
|
||||
detail = self.repository.get_task("PUR-001")
|
||||
assert detail is not None
|
||||
self.assertEqual(detail.task_type, TaskType.PURCHASE)
|
||||
self.assertEqual(detail.status, TaskStatus.SUCCEEDED)
|
||||
self.assertIn("演练完成", page.statusLabel.text())
|
||||
events.shutdown()
|
||||
page.deleteLater()
|
||||
|
||||
def test_no_task_schedules_next_claim_and_stop_cancels_timer(self):
|
||||
gateway = RecordingClaimGateway(None)
|
||||
page = PDDTaskPage()
|
||||
|
||||
Reference in New Issue
Block a user