76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
"""PDD 采购演练适配层的稳定边界。
|
|
|
|
应用服务只依赖本文件中的小接口,不直接认识 uiautomator2。接口故意不提供
|
|
“提交订单”或“付款”方法,因此演练代码没有可误调用的真实下单入口。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass, field
|
|
from typing import Mapping
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PurchasePageState:
|
|
"""一次重新读取页面后得到的采购相关事实。"""
|
|
|
|
page_kind: str
|
|
goods_id: str
|
|
selected_options: Mapping[str, str] = field(default_factory=dict)
|
|
quantity: int = 0
|
|
price_cent: int = 0
|
|
candidate_count: int = 1
|
|
|
|
|
|
class PddPurchaseError(RuntimeError):
|
|
"""适配层失败,包含稳定代码、步骤和是否可安全重试。"""
|
|
|
|
def __init__(
|
|
self,
|
|
code: str,
|
|
message: str,
|
|
*,
|
|
step: str,
|
|
retryable: bool = False,
|
|
diagnostics: Mapping[str, object] | None = None,
|
|
) -> None:
|
|
super().__init__(message)
|
|
self.code = str(code or "PURCHASE_ADAPTER_ERROR")
|
|
self.message = str(message or "PDD 采购演练失败")
|
|
self.step = str(step or "purchase_prepare")
|
|
self.retryable = bool(retryable)
|
|
self.diagnostics = dict(diagnostics or {})
|
|
|
|
|
|
class PddPurchaseAdapter(ABC):
|
|
"""一台设备的一次采购演练会话;只能由创建它的工作线程使用。"""
|
|
|
|
@abstractmethod
|
|
def open_goods(self, goods_url: str) -> None:
|
|
"""通过商品链接打开 PDD 商品页。"""
|
|
|
|
@abstractmethod
|
|
def read_state(self) -> PurchasePageState:
|
|
"""重新读取当前页面,不返回缓存状态。"""
|
|
|
|
@abstractmethod
|
|
def select_options(self, options: Mapping[str, str]) -> None:
|
|
"""按完整动态规格对象精确选择,不做相似匹配。"""
|
|
|
|
@abstractmethod
|
|
def set_quantity(self, quantity: int) -> None:
|
|
"""设置采购数量。"""
|
|
|
|
@abstractmethod
|
|
def enter_confirmation(self) -> None:
|
|
"""进入最终提交前确认页,但不得提交订单。"""
|
|
|
|
@abstractmethod
|
|
def stop_before_submit(self) -> None:
|
|
"""在提交订单按钮之前停止并保持页面可供人工核对。"""
|
|
|
|
@abstractmethod
|
|
def close(self) -> None:
|
|
"""释放设备会话;不得在此方法中产生页面点击。"""
|