Stabilize patrol delete automation against delayed Amazon UI

The patrol-delete flow now waits for country and listing-status controls before acting, uses the dedicated PatrolDeleteTask entry point, and includes the browser helper scripts required by the bulk-delete path. Tests cover delayed dropdown readiness, payload rejection/retry behavior, complete-draft normalization, filtered bulk deletion, and asset fallback lookup.

Constraint: Amazon listing UI exposes status controls through dynamic KAT components and delayed option rendering

Rejected: Keep row-by-row delete flow | bulk selection is the current implemented path and is covered by the added helper scripts

Confidence: high

Scope-risk: moderate

Directive: Do not remove the patrol_delete JS helper files without checking app/amazon/patrol_delete.py script loading

Tested: uv run --group dev pytest tests\\test_amazon_base.py tests\\test_patrol_delete.py

Tested: uv run python -m py_compile amazon\\base.py amazon\\main.py blueprints\\main.py

Not-tested: Real Amazon Seller Central browser session
This commit is contained in:
koko
2026-04-28 20:46:50 +08:00
parent 4ff4d8cfdc
commit 1be28f10e9
14 changed files with 1062 additions and 170 deletions

View File

@@ -36,6 +36,8 @@ COUNTRY_INITIAL_LOAD_TIMEOUT = 120
COUNTRY_LOOKUP_TIMEOUT = 20
COUNTRY_CLICK_TIMEOUT = 10
COUNTRY_DROPDOWN_DELAY = 1
COUNTRY_DROPDOWN_READY_TIMEOUT = 20
COUNTRY_DROPDOWN_RETRY_INTERVAL = 0.5
IP_CHECK_TIMEOUT = 60
LOGIN_ATTEMPTS = 4
@@ -585,18 +587,36 @@ class AmamzonBase(ZiniaoDriver):
if not dropdown_header:
logger.warning("找不到国家切换下拉框")
return False
dropdown_header.click()
time.sleep(COUNTRY_DROPDOWN_DELAY)
logger.info("正在展开国家列表")
first_item = self.tab.ele(COUNTRY_LIST_ITEM_XPATH, timeout=COUNTRY_CLICK_TIMEOUT)
if not first_item:
first_item = self._wait_country_list_item(dropdown_header)
if first_item is None:
logger.warning("找不到国家列表项")
return False
first_item.click()
time.sleep(COUNTRY_DROPDOWN_DELAY)
return True
def _wait_country_list_item(self, dropdown_header):
deadline = time.time() + COUNTRY_DROPDOWN_READY_TIMEOUT
attempt = 0
while time.time() < deadline:
attempt += 1
try:
dropdown_header.click()
except Exception as exc:
logger.info("点击国家切换下拉框失败, attempt={}, error={}", attempt, exc)
time.sleep(COUNTRY_DROPDOWN_DELAY)
first_item = self.tab.ele(COUNTRY_LIST_ITEM_XPATH, timeout=COUNTRY_DROPDOWN_RETRY_INTERVAL)
if first_item:
return first_item
self.tab.wait.doc_loaded(timeout=COUNTRY_CLICK_TIMEOUT, raise_err=False)
time.sleep(COUNTRY_DROPDOWN_RETRY_INTERVAL)
return None
def _select_country(self, country_name: str) -> bool:
logger.info("正在切换到国家:{}", country_name)
target_country = self.tab.ele(self._country_option_xpath(country_name), timeout=COUNTRY_CLICK_TIMEOUT)