feat: patrol delete
This commit is contained in:
@@ -106,15 +106,19 @@ def test_kill_process_uses_ziniao_driver(monkeypatch):
|
||||
assert calls == [("init", {}), ("kill_process", "v6")]
|
||||
|
||||
|
||||
def test_get_zinaio_exe_returns_none_when_winreg_unavailable(monkeypatch, caplog):
|
||||
def test_get_zinaio_exe_returns_none_when_winreg_unavailable(monkeypatch):
|
||||
driver = base.ZiniaoDriver({})
|
||||
monkeypatch.setattr(base, "winreg", None)
|
||||
messages = []
|
||||
sink_id = base.logger.add(messages.append, level="ERROR", format="{message}")
|
||||
|
||||
with caplog.at_level("ERROR", logger=base.logger.name):
|
||||
try:
|
||||
result = driver.get_zinaio_exe()
|
||||
finally:
|
||||
base.logger.remove(sink_id)
|
||||
|
||||
assert result is None
|
||||
assert any("winreg" in message for message in caplog.messages)
|
||||
assert any("winreg" in message for message in messages)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -250,7 +254,7 @@ def test_switching_countries_returns_true_when_already_current():
|
||||
}
|
||||
)
|
||||
|
||||
assert driver.SwitchingCountries("西班牙") is True
|
||||
assert driver.switch_to_country("西班牙") is True
|
||||
|
||||
|
||||
def test_switching_countries_returns_false_when_target_missing(monkeypatch):
|
||||
@@ -268,7 +272,7 @@ def test_switching_countries_returns_false_when_target_missing(monkeypatch):
|
||||
}
|
||||
)
|
||||
|
||||
assert driver.SwitchingCountries("西班牙") is False
|
||||
assert driver.switch_to_country("西班牙") is False
|
||||
|
||||
|
||||
def test_switching_countries_clicks_and_verifies_target(monkeypatch):
|
||||
@@ -292,7 +296,7 @@ def test_switching_countries_clicks_and_verifies_target(monkeypatch):
|
||||
}
|
||||
)
|
||||
|
||||
assert driver.SwitchingCountries("西班牙") is True
|
||||
assert driver.switch_to_country("西班牙") is True
|
||||
assert dropdown.clicks == 1
|
||||
assert first_item.clicks == 1
|
||||
assert target.clicks == 1
|
||||
|
||||
834
app/tests/test_product.py
Normal file
834
app/tests/test_product.py
Normal file
@@ -0,0 +1,834 @@
|
||||
from amazon.product import InventoryManage, ProductTask
|
||||
|
||||
|
||||
def test_product_task_post_result_builds_patrol_delete_payload(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
class Response:
|
||||
status_code = 200
|
||||
text = '{"success":true}'
|
||||
|
||||
def fake_post(url, **kwargs):
|
||||
captured["url"] = url
|
||||
captured["kwargs"] = kwargs
|
||||
return Response()
|
||||
|
||||
monkeypatch.setattr("config.DELETE_BRAND_API_BASE", "http://java.example")
|
||||
monkeypatch.setattr("amazon.product.requests.post", fake_post)
|
||||
|
||||
country_sections = [
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [{"status": "正常", "quantity": "12", "deleteQuantity": "3", "processStatus": "处理中"}],
|
||||
}
|
||||
]
|
||||
cart_ratios = [{"country": "德国", "ratio": "25%"}]
|
||||
|
||||
ProductTask().post_result(
|
||||
task_id=3089,
|
||||
shop_name="郭亚芳",
|
||||
country_sections=country_sections,
|
||||
cart_ratios=cart_ratios,
|
||||
shop_done=True,
|
||||
)
|
||||
|
||||
assert captured["url"] == "http://java.example/api/patrol-delete/tasks/3089/result"
|
||||
assert captured["kwargs"]["headers"] == {"Content-Type": "application/json"}
|
||||
assert captured["kwargs"]["timeout"] == 30
|
||||
assert captured["kwargs"]["verify"] is False
|
||||
assert captured["kwargs"]["json"]["shops"] == [
|
||||
{
|
||||
"shopName": "郭亚芳",
|
||||
"shopDone": True,
|
||||
"submissionId": captured["kwargs"]["json"]["shops"][0]["submissionId"],
|
||||
"chunkIndex": 1,
|
||||
"chunkTotal": 1,
|
||||
"countrySections": country_sections,
|
||||
"cartRatios": cart_ratios,
|
||||
}
|
||||
]
|
||||
assert captured["kwargs"]["json"]["shops"][0]["submissionId"].startswith("patrol-delete:3089:郭亚芳:")
|
||||
|
||||
|
||||
def test_product_task_process_task_aggregates_country_results(monkeypatch):
|
||||
from config import runing_shop, runing_task
|
||||
|
||||
runing_task.clear()
|
||||
runing_shop.clear()
|
||||
calls = []
|
||||
|
||||
class Driver:
|
||||
def close_store(self):
|
||||
return None
|
||||
|
||||
def fake_post_result(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
def fake_open_shop(self, **kwargs):
|
||||
return Driver()
|
||||
|
||||
def fake_process_country(self, driver, task_id, shop_name, country_name):
|
||||
if country_name == "德国":
|
||||
return {
|
||||
"success": True,
|
||||
"countrySection": {
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{
|
||||
"status": "商品信息草稿",
|
||||
"quantity": "0",
|
||||
"deleteQuantity": "2",
|
||||
"processStatus": "已完成",
|
||||
}
|
||||
],
|
||||
},
|
||||
"cartRatio": {"country": "德国", "ratio": "25%"},
|
||||
"deletedCount": 2,
|
||||
"reopenRequired": False,
|
||||
}
|
||||
return {
|
||||
"success": False,
|
||||
"countrySection": {
|
||||
"country": "英国",
|
||||
"rows": [
|
||||
{
|
||||
"status": "全部",
|
||||
"quantity": "",
|
||||
"deleteQuantity": "",
|
||||
"processStatus": "处理失败: 切换国家失败",
|
||||
}
|
||||
],
|
||||
},
|
||||
"cartRatio": {"country": "英国", "ratio": ""},
|
||||
"deletedCount": 0,
|
||||
"reopenRequired": True,
|
||||
}
|
||||
|
||||
monkeypatch.setattr(ProductTask, "open_shop", fake_open_shop)
|
||||
monkeypatch.setattr(ProductTask, "process_country", fake_process_country)
|
||||
monkeypatch.setattr(ProductTask, "post_result", fake_post_result)
|
||||
|
||||
country_sections = [
|
||||
{"country": "德国", "rows": [{"status": "全部", "quantity": "", "deleteQuantity": "", "processStatus": ""}]},
|
||||
{"country": "英国", "rows": [{"status": "全部", "quantity": "", "deleteQuantity": "", "processStatus": ""}]},
|
||||
]
|
||||
cart_ratios = [{"country": "德国", "ratio": ""}, {"country": "英国", "ratio": ""}]
|
||||
ProductTask().process_task(
|
||||
{
|
||||
"type": "patrol-delete-run",
|
||||
"data": {
|
||||
"taskId": 1,
|
||||
"items": [{"shopName": "郭亚芳", "companyName": "rongchuang123"}],
|
||||
"country_sections": country_sections,
|
||||
"cart_ratios": cart_ratios,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
assert runing_task[1]["status"] == "completed"
|
||||
assert runing_task[1]["processed_shops"] == 1
|
||||
assert runing_task[1]["processed_countries"] == 2
|
||||
assert runing_task[1]["success_count"] == 1
|
||||
assert runing_task[1]["failed_count"] == 0
|
||||
assert runing_task[1]["failed_countries"] == 1
|
||||
assert runing_task[1]["deleted_listings_count"] == 2
|
||||
assert "郭亚芳" not in runing_shop
|
||||
assert calls == [
|
||||
{
|
||||
"task_id": 1,
|
||||
"shop_name": "郭亚芳",
|
||||
"country_sections": [
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{
|
||||
"status": "商品信息草稿",
|
||||
"quantity": "0",
|
||||
"deleteQuantity": "2",
|
||||
"processStatus": "已完成",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"country": "英国",
|
||||
"rows": [
|
||||
{
|
||||
"status": "全部",
|
||||
"quantity": "",
|
||||
"deleteQuantity": "",
|
||||
"processStatus": "处理失败: 切换国家失败",
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
"cart_ratios": [{"country": "德国", "ratio": "25%"}, {"country": "英国", "ratio": ""}],
|
||||
"shop_done": True,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_product_task_process_task_skips_missing_required_data(monkeypatch):
|
||||
calls = []
|
||||
|
||||
def fake_post_result(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
monkeypatch.setattr(ProductTask, "post_result", fake_post_result)
|
||||
|
||||
ProductTask().process_task({"type": "patrol-delete-run", "data": {"items": [{"shopName": "郭亚芳"}]}})
|
||||
ProductTask().process_task({"type": "patrol-delete-run", "data": {"taskId": 1, "items": []}})
|
||||
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_product_task_reports_shop_error(monkeypatch):
|
||||
from config import runing_shop, runing_task
|
||||
|
||||
runing_task.clear()
|
||||
runing_shop.clear()
|
||||
calls = []
|
||||
|
||||
def fake_post_result(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
def fake_open_shop(self, **kwargs):
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(ProductTask, "open_shop", fake_open_shop)
|
||||
monkeypatch.setattr(ProductTask, "post_result", fake_post_result)
|
||||
|
||||
ProductTask().process_task(
|
||||
{
|
||||
"type": "patrol-delete-run",
|
||||
"data": {
|
||||
"taskId": 2,
|
||||
"items": [{"shopName": "郭亚芳", "companyName": "rongchuang123"}],
|
||||
"country_sections": [{"country": "德国", "rows": [{"status": "全部"}]}],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
assert runing_task[2]["status"] == "completed"
|
||||
assert runing_task[2]["processed_shops"] == 1
|
||||
assert runing_task[2]["success_count"] == 0
|
||||
assert runing_task[2]["failed_count"] == 1
|
||||
assert "郭亚芳" not in runing_shop
|
||||
assert calls == [{"task_id": 2, "shop_name": "郭亚芳", "error": "店铺 郭亚芳 打开失败", "shop_done": True}]
|
||||
|
||||
|
||||
def test_delete_all_listings_from_non_whitelisted_statuses_loops_until_no_candidates(monkeypatch):
|
||||
driver = InventoryManage({})
|
||||
sections = [
|
||||
[
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{"status": "商品信息草稿", "quantity": "2", "deleteQuantity": "", "processStatus": ""},
|
||||
{"status": "全部", "quantity": "9", "deleteQuantity": "", "processStatus": ""},
|
||||
],
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{"status": "商品信息草稿", "quantity": "1", "deleteQuantity": "", "processStatus": ""},
|
||||
{"status": "全部", "quantity": "8", "deleteQuantity": "", "processStatus": ""},
|
||||
],
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{"status": "全部", "quantity": "7", "deleteQuantity": "", "processStatus": ""},
|
||||
],
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"country": "德国",
|
||||
"rows": [
|
||||
{"status": "全部", "quantity": "7", "deleteQuantity": "", "processStatus": ""},
|
||||
],
|
||||
}
|
||||
],
|
||||
]
|
||||
state = {"index": 0, "selected": [], "deleted": 0}
|
||||
|
||||
def fake_get_listing_status_country_sections(shop_name, country):
|
||||
current = sections[state["index"]]
|
||||
state["index"] += 1
|
||||
return current
|
||||
|
||||
def fake_select_listing_status(status):
|
||||
state["selected"].append(status)
|
||||
|
||||
def fake_get_first_inventory_row(status):
|
||||
return {"sku": f"sku-{state['deleted'] + 1}"}
|
||||
|
||||
def fake_summarize_inventory_row(row):
|
||||
return {"sku": row["sku"], "rawText": row["sku"]}
|
||||
|
||||
def fake_delete_inventory_row(row, status):
|
||||
state["deleted"] += 1
|
||||
return f"{status} 删除成功"
|
||||
|
||||
monkeypatch.setattr(driver, "get_listing_status_country_sections", fake_get_listing_status_country_sections)
|
||||
monkeypatch.setattr(driver, "select_listing_status", fake_select_listing_status)
|
||||
monkeypatch.setattr(driver, "_get_first_inventory_row", fake_get_first_inventory_row)
|
||||
monkeypatch.setattr(driver, "_summarize_inventory_row", fake_summarize_inventory_row)
|
||||
monkeypatch.setattr(driver, "_delete_inventory_row", fake_delete_inventory_row)
|
||||
monkeypatch.setattr(driver, "_wait_inventory_loader", lambda timeout=5: None)
|
||||
|
||||
result = driver.delete_all_listings_from_non_whitelisted_statuses("郭亚芳", "德国")
|
||||
|
||||
assert state["selected"] == ["商品信息草稿", "商品信息草稿"]
|
||||
assert state["deleted"] == 2
|
||||
assert result["deleteCounts"] == {"商品信息草稿": 2}
|
||||
assert result["totalDeleted"] == 2
|
||||
assert result["stopReason"] == "no-candidates"
|
||||
assert result["statusRows"] == [{"status": "全部", "quantity": "7", "deleteQuantity": "", "processStatus": ""}]
|
||||
assert [item["target"]["sku"] for item in result["results"]] == ["sku-1", "sku-2"]
|
||||
|
||||
|
||||
def test_extract_country_cart_ratio_prefers_ratio2daysago_only():
|
||||
ratio = ProductTask._extract_country_cart_ratio(
|
||||
[
|
||||
{"country": "德国", "ratio2DaysAgo": "25%", "ratio30DaysAgo": "19%"},
|
||||
{"country": "英国", "ratio30DaysAgo": "40%"},
|
||||
],
|
||||
"德国",
|
||||
)
|
||||
missing_ratio2 = ProductTask._extract_country_cart_ratio(
|
||||
[{"country": "英国", "ratio30DaysAgo": "40%"}],
|
||||
"英国",
|
||||
)
|
||||
|
||||
assert ratio == {"country": "德国", "ratio": "25%"}
|
||||
assert missing_ratio2 == {"country": "英国", "ratio": ""}
|
||||
|
||||
|
||||
def test_parse_status_option_rows_keeps_value_and_raw_text():
|
||||
rows = InventoryManage._parse_status_option_rows(
|
||||
[
|
||||
{"raw_text": "在售 (1,234)", "value": "Active"},
|
||||
{"raw_text": "禁止显示", "value": "SearchSuppressed"},
|
||||
],
|
||||
"郭亚芳",
|
||||
"德国",
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"status": "在售",
|
||||
"quantity": 1234,
|
||||
"value": "Active",
|
||||
"raw_text": "在售 (1,234)",
|
||||
},
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"status": "禁止显示",
|
||||
"quantity": None,
|
||||
"value": "SearchSuppressed",
|
||||
"raw_text": "禁止显示",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_status_text_accepts_chinese_parentheses():
|
||||
assert InventoryManage._parse_status_text("不可售(42)") == ("不可售", 42)
|
||||
|
||||
|
||||
def test_parse_status_text_preserves_status_without_quantity():
|
||||
assert InventoryManage._parse_status_text("非在售") == ("非在售", None)
|
||||
|
||||
|
||||
def test_parse_listing_status_section_rows_extracts_rendered_status_tabs():
|
||||
rows = InventoryManage._parse_listing_status_section_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"全部(6182) 在售(4097) 在搜索结果中禁止显示(2) 不可售(2083) "
|
||||
"详情页面已删除(2) 定价问题(1) 需要批准(2080) 商品信息草稿 缺少的信息(1)"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"status": "全部", "quantity": "6182", "raw_text": "全部(6182)"},
|
||||
{"status": "在售", "quantity": "4097", "raw_text": "在售(4097)"},
|
||||
{"status": "在搜索结果中禁止显示", "quantity": "2", "raw_text": "在搜索结果中禁止显示(2)"},
|
||||
{"status": "不可售", "quantity": "2083", "raw_text": "不可售(2083)"},
|
||||
{"status": "详情页面已删除", "quantity": "2", "raw_text": "详情页面已删除(2)"},
|
||||
{"status": "定价问题", "quantity": "1", "raw_text": "定价问题(1)"},
|
||||
{"status": "需要批准", "quantity": "2080", "raw_text": "需要批准(2080)"},
|
||||
{"status": "商品信息草稿", "quantity": "", "raw_text": "商品信息草稿"},
|
||||
{"status": "缺少的信息", "quantity": "1", "raw_text": "缺少的信息(1)"},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_listing_status_section_rows_supports_order_page_deleted_alias():
|
||||
rows = InventoryManage._parse_listing_status_section_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": "不可售(2083) 订单页面已删除(2) 定价问题(1) 需要批准(2080)"
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"status": "不可售", "quantity": "2083", "raw_text": "不可售(2083)"},
|
||||
{"status": "订单页面已删除", "quantity": "2", "raw_text": "订单页面已删除(2)"},
|
||||
{"status": "定价问题", "quantity": "1", "raw_text": "定价问题(1)"},
|
||||
{"status": "需要批准", "quantity": "2080", "raw_text": "需要批准(2080)"},
|
||||
]
|
||||
|
||||
|
||||
def test_build_country_section_rows_adds_required_placeholder_fields():
|
||||
rows = InventoryManage._build_country_section_rows(
|
||||
[
|
||||
{"status": "正常", "quantity": "12"},
|
||||
{"status": "需要批准", "quantity": "2080"},
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"status": "正常", "quantity": "12", "deleteQuantity": "", "processStatus": ""},
|
||||
{"status": "需要批准", "quantity": "2080", "deleteQuantity": "", "processStatus": ""},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_listing_status_section_rows_supports_latest_status_labels():
|
||||
rows = InventoryManage._parse_listing_status_section_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"全部(10) 在售(4) 配送问题(1) 缺少报价(2) 已停售(3) "
|
||||
"在搜索结果中禁止显示(0) 需要批准(0)"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"status": "全部", "quantity": "10", "raw_text": "全部(10)"},
|
||||
{"status": "在售", "quantity": "4", "raw_text": "在售(4)"},
|
||||
{"status": "配送问题", "quantity": "1", "raw_text": "配送问题(1)"},
|
||||
{"status": "缺少报价", "quantity": "2", "raw_text": "缺少报价(2)"},
|
||||
{"status": "已停售", "quantity": "3", "raw_text": "已停售(3)"},
|
||||
{"status": "在搜索结果中禁止显示", "quantity": "0", "raw_text": "在搜索结果中禁止显示(0)"},
|
||||
{"status": "需要批准", "quantity": "0", "raw_text": "需要批准(0)"},
|
||||
]
|
||||
|
||||
|
||||
def test_build_deletable_status_rows_skips_whitelisted_statuses():
|
||||
rows = [
|
||||
{"status": "全部", "quantity": "12"},
|
||||
{"status": "定价问题", "quantity": "2"},
|
||||
{"status": "需要批准", "quantity": "3"},
|
||||
{"status": "在搜索结果中禁止显示", "quantity": "1"},
|
||||
{"status": "配送问题", "quantity": "5"},
|
||||
{"status": "缺少报价", "quantity": "4"},
|
||||
{"status": "已停售", "quantity": "6"},
|
||||
{"status": "不可售", "quantity": "8"},
|
||||
{"status": "在售", "quantity": "7"},
|
||||
]
|
||||
|
||||
assert InventoryManage._build_deletable_status_rows(rows) == []
|
||||
|
||||
|
||||
def test_build_deletable_status_rows_keeps_non_whitelisted_statuses():
|
||||
rows = [
|
||||
{"status": "商品信息草稿", "quantity": "2"},
|
||||
{"status": "自定义异常状态", "quantity": "5"},
|
||||
{"status": "全部", "quantity": "9"},
|
||||
]
|
||||
|
||||
assert InventoryManage._build_deletable_status_rows(rows) == [
|
||||
{"status": "商品信息草稿", "canonicalStatus": "商品信息草稿", "quantity": 2},
|
||||
{"status": "自定义异常状态", "canonicalStatus": "自定义异常状态", "quantity": 5},
|
||||
]
|
||||
|
||||
|
||||
def test_build_deletable_status_rows_compatibility_map_prevents_whitelist_misdelete():
|
||||
rows = [
|
||||
{"status": "搜尋結果中禁止顯示", "quantity": "4"},
|
||||
{"status": "在搜索中禁止显示结果", "quantity": "1"},
|
||||
{"status": "配送問題", "quantity": "2"},
|
||||
{"status": "缺少報價", "quantity": "3"},
|
||||
]
|
||||
|
||||
assert InventoryManage._build_deletable_status_rows(rows) == []
|
||||
|
||||
|
||||
def test_build_deletable_status_rows_keeps_legacy_non_whitelist_statuses_deletable():
|
||||
rows = [
|
||||
{"status": "详情页面已删除", "quantity": "1"},
|
||||
{"status": "缺少的信息", "quantity": "2"},
|
||||
{"status": "订单页面已删除", "quantity": "3"},
|
||||
]
|
||||
|
||||
assert InventoryManage._build_deletable_status_rows(rows) == [
|
||||
{"status": "详情页面已删除", "canonicalStatus": "详情页面已删除", "quantity": 1},
|
||||
{"status": "缺少的信息", "canonicalStatus": "缺少的信息", "quantity": 2},
|
||||
{"status": "订单页面已删除", "canonicalStatus": "详情页面已删除", "quantity": 3},
|
||||
]
|
||||
|
||||
|
||||
def test_limit_delete_candidates_enforces_single_delete_cap():
|
||||
candidates = [
|
||||
{"status": "商品信息草稿", "canonicalStatus": "商品信息草稿", "quantity": 2},
|
||||
{"status": "自定义异常状态", "canonicalStatus": "自定义异常状态", "quantity": 5},
|
||||
]
|
||||
|
||||
assert InventoryManage._limit_delete_candidates(candidates, max_delete_count=1) == [candidates[0]]
|
||||
|
||||
|
||||
def test_is_delete_success_message_accepts_both_copy_variants():
|
||||
assert InventoryManage._is_delete_success_message("1 个商品已经删除。所作更改需要15分钟才会显示在商品详情页面上")
|
||||
assert InventoryManage._is_delete_success_message("所做更改需要 15 分钟才会显示在商品详情页面上。 1 个商品已删除。")
|
||||
|
||||
|
||||
def test_parse_label_quantity_text_accepts_complete_draft_sample():
|
||||
assert InventoryManage._parse_label_quantity_text("未提交的草稿 (0)") == ("未提交的草稿", 0)
|
||||
|
||||
|
||||
def test_parse_label_quantity_text_preserves_long_colon_label():
|
||||
assert InventoryManage._parse_label_quantity_text("已提交:提供缺少的信息 (1)") == (
|
||||
"已提交:提供缺少的信息",
|
||||
1,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_label_quantity_text_accepts_chinese_parentheses():
|
||||
assert InventoryManage._parse_label_quantity_text("已提交:查看限制(0)") == ("已提交:查看限制", 0)
|
||||
|
||||
|
||||
def test_parse_label_quantity_text_accepts_dynamic_text_and_thousands():
|
||||
assert InventoryManage._parse_label_quantity_text("Some dynamic label (1,234)") == (
|
||||
"Some dynamic label",
|
||||
1234,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_label_quantity_text_rejects_empty_missing_quantity_and_numeric_label():
|
||||
assert InventoryManage._parse_label_quantity_text("") is None
|
||||
assert InventoryManage._parse_label_quantity_text("没有数量") is None
|
||||
assert InventoryManage._parse_label_quantity_text("123 (4)") is None
|
||||
assert InventoryManage._parse_label_quantity_text("未提交的草稿 (0) 已提交:提供缺少的信息 (1)") is None
|
||||
|
||||
|
||||
def test_parse_quick_view_tag_rows_supports_raw_and_split_dom_rows():
|
||||
rows = InventoryManage._parse_quick_view_tag_rows(
|
||||
[
|
||||
{"raw_text": "未提交的草稿 (0)"},
|
||||
{"raw_text": "未提交的草稿 (0)"},
|
||||
{"label_text": "已提交:提供缺少的信息", "quantity_text": "1"},
|
||||
{"raw_text": "没有数量"},
|
||||
],
|
||||
"郭亚芳",
|
||||
"德国",
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"tag": "未提交的草稿",
|
||||
"quantity": 0,
|
||||
"raw_text": "未提交的草稿 (0)",
|
||||
},
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"tag": "已提交:提供缺少的信息",
|
||||
"quantity": 1,
|
||||
"raw_text": "已提交:提供缺少的信息 (1)",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_quick_view_tag_rows_filters_navigation_and_pagination_noise():
|
||||
rows = InventoryManage._parse_quick_view_tag_rows(
|
||||
[
|
||||
{"raw_text": "补全草稿 (1)"},
|
||||
{"raw_text": "未提交的草稿 (0)"},
|
||||
{"raw_text": "已提交:提供缺少的信息 (1)"},
|
||||
{"raw_text": "已提交:查看限制 (0)"},
|
||||
{"raw_text": "商品信息草稿 至 0 / 0 (0)"},
|
||||
{"raw_text": "页面 / 0 (0)"},
|
||||
],
|
||||
"郭亚芳",
|
||||
"德国",
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"tag": "未提交的草稿",
|
||||
"quantity": 0,
|
||||
"raw_text": "未提交的草稿 (0)",
|
||||
},
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"tag": "已提交:提供缺少的信息",
|
||||
"quantity": 1,
|
||||
"raw_text": "已提交:提供缺少的信息 (1)",
|
||||
},
|
||||
{
|
||||
"shop_name": "郭亚芳",
|
||||
"country": "德国",
|
||||
"tag": "已提交:查看限制",
|
||||
"quantity": 0,
|
||||
"raw_text": "已提交:查看限制 (0)",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_cart_ratio_rows_extracts_chinese_day_ratios():
|
||||
rows = InventoryManage._parse_cart_ratio_rows(
|
||||
[{"raw_text": "推荐报价百分比 2 天前 25% 30 天前 30%"}],
|
||||
"德国",
|
||||
)
|
||||
|
||||
assert rows == {"country": "德国", "ratio2DaysAgo": "25%", "ratio30DaysAgo": "30%"}
|
||||
|
||||
|
||||
def test_parse_cart_ratio_rows_extracts_english_day_ratios():
|
||||
rows = InventoryManage._parse_cart_ratio_rows(
|
||||
[{"raw_text": "Featured Offer Percentage 2 days ago 25.5% 30 days ago 30%"}],
|
||||
"英国",
|
||||
)
|
||||
|
||||
assert rows == {"country": "英国", "ratio2DaysAgo": "25.5%", "ratio30DaysAgo": "30%"}
|
||||
|
||||
|
||||
def test_parse_cart_ratio_rows_supports_percent_before_day_label():
|
||||
rows = InventoryManage._parse_cart_ratio_rows(
|
||||
[{"raw_text": "25% 2 天前 30% 30 天前"}],
|
||||
"法国",
|
||||
)
|
||||
|
||||
assert rows == {"country": "法国", "ratio2DaysAgo": "25%", "ratio30DaysAgo": "30%"}
|
||||
|
||||
|
||||
def test_parse_cart_ratio_rows_returns_empty_for_missing_day():
|
||||
rows = InventoryManage._parse_cart_ratio_rows(
|
||||
[{"raw_text": "推荐报价百分比 2 天前 25%"}],
|
||||
"意大利",
|
||||
)
|
||||
|
||||
assert rows == {"country": "意大利", "ratio2DaysAgo": "25%", "ratio30DaysAgo": ""}
|
||||
|
||||
|
||||
def test_parse_all_cart_ratio_rows_extracts_all_target_countries_without_switching():
|
||||
rows = InventoryManage._parse_all_cart_ratio_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 2 天前 30 天前 "
|
||||
"欧洲 60% 64% "
|
||||
"英国 50% 61% "
|
||||
"德国 57% 65% "
|
||||
"法国 81% 77% "
|
||||
"西班牙 70% 70% "
|
||||
"意大利 70% 62%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60%", "ratio30DaysAgo": "64%"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%"},
|
||||
{"country": "法国", "ratio2DaysAgo": "81%", "ratio30DaysAgo": "77%"},
|
||||
{"country": "西班牙", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "70%"},
|
||||
{"country": "意大利", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "62%"},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_all_cart_ratio_rows_prefers_direct_rendered_country_rows():
|
||||
rows = InventoryManage._parse_all_cart_ratio_rows(
|
||||
[
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60 %", "ratio30DaysAgo": "64%", "source": "rendered-country-row"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%", "source": "rendered-country-row"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%", "source": "rendered-country-row"},
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60%", "ratio30DaysAgo": "64%"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%"},
|
||||
{"country": "法国", "ratio2DaysAgo": "", "ratio30DaysAgo": ""},
|
||||
{"country": "西班牙", "ratio2DaysAgo": "", "ratio30DaysAgo": ""},
|
||||
{"country": "意大利", "ratio2DaysAgo": "", "ratio30DaysAgo": ""},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_all_cart_ratio_rows_supports_date_headers_without_day_labels():
|
||||
rows = InventoryManage._parse_all_cart_ratio_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 24 Apr 27 Mar "
|
||||
"欧洲 60% 64% "
|
||||
"英国 50% 61% "
|
||||
"德国 57% 65% "
|
||||
"法国 81% 77% "
|
||||
"西班牙 70% 70% "
|
||||
"意大利 70% 62%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60%", "ratio30DaysAgo": "64%"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%"},
|
||||
{"country": "法国", "ratio2DaysAgo": "81%", "ratio30DaysAgo": "77%"},
|
||||
{"country": "西班牙", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "70%"},
|
||||
{"country": "意大利", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "62%"},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_all_cart_ratio_rows_supports_rendered_geometry_rows():
|
||||
rows = InventoryManage._parse_all_cart_ratio_rows(
|
||||
[
|
||||
{"attrs": {"title": "欧洲"}, "rect_left": 1315.0, "rect_top": 346.5, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "60%", "rect_left": 1510.0, "rect_top": 357.6, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "64%", "rect_left": 1693.3, "rect_top": 357.6, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "英国"}, "rect_left": 1315.0, "rect_top": 390.6, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "50%", "rect_left": 1510.1, "rect_top": 401.7, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "61%", "rect_left": 1693.3, "rect_top": 401.6, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "德国"}, "rect_left": 1315.0, "rect_top": 433.8, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "57%", "rect_left": 1510.1, "rect_top": 444.9, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "65%", "rect_left": 1693.3, "rect_top": 444.9, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "法国"}, "rect_left": 1315.0, "rect_top": 477.0, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "81%", "rect_left": 1510.1, "rect_top": 488.1, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "77%", "rect_left": 1693.3, "rect_top": 488.1, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "西班牙"}, "rect_left": 1315.0, "rect_top": 520.2, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "70%", "rect_left": 1510.1, "rect_top": 531.3, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "70%", "rect_left": 1693.3, "rect_top": 531.3, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "意大利"}, "rect_left": 1315.0, "rect_top": 563.4, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "70%", "rect_left": 1510.1, "rect_top": 574.5, "rect_width": 32.0, "rect_height": 20.0},
|
||||
{"label_text": "62%", "rect_left": 1693.3, "rect_top": 574.5, "rect_width": 32.0, "rect_height": 20.0},
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60%", "ratio30DaysAgo": "64%"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%"},
|
||||
{"country": "法国", "ratio2DaysAgo": "81%", "ratio30DaysAgo": "77%"},
|
||||
{"country": "西班牙", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "70%"},
|
||||
{"country": "意大利", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "62%"},
|
||||
]
|
||||
|
||||
|
||||
def test_parse_all_cart_ratio_rows_dedupes_nested_rendered_percentage_nodes():
|
||||
rows = InventoryManage._parse_all_cart_ratio_rows(
|
||||
[
|
||||
{"attrs": {"title": "欧洲"}, "rect_left": 1315.0, "rect_top": 346.5, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "60%", "rect_left": 1510.1, "rect_top": 357.6, "rect_width": 160.0, "rect_height": 20.0},
|
||||
{"label_text": "60%", "rect_left": 1510.1, "rect_top": 357.6, "rect_width": 29.6, "rect_height": 20.0},
|
||||
{"raw_text": "64%", "rect_left": 1681.7, "rect_top": 346.5, "rect_width": 183.2, "rect_height": 43.2},
|
||||
{"label_text": "64%", "rect_left": 1693.3, "rect_top": 357.6, "rect_width": 160.0, "rect_height": 20.0},
|
||||
{"attrs": {"title": "英国"}, "rect_left": 1315.0, "rect_top": 390.6, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "50%", "rect_left": 1510.1, "rect_top": 401.7, "rect_width": 160.0, "rect_height": 18.2},
|
||||
{"label_text": "50%", "rect_left": 1510.1, "rect_top": 401.7, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"label_text": "61%", "rect_left": 1693.3, "rect_top": 401.6, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"attrs": {"title": "德国"}, "rect_left": 1315.0, "rect_top": 433.8, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "57%", "rect_left": 1510.1, "rect_top": 444.9, "rect_width": 160.0, "rect_height": 18.2},
|
||||
{"label_text": "57%", "rect_left": 1510.1, "rect_top": 444.9, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"label_text": "65%", "rect_left": 1693.3, "rect_top": 444.9, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"attrs": {"title": "法国"}, "rect_left": 1315.0, "rect_top": 477.0, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "81%", "rect_left": 1510.1, "rect_top": 488.1, "rect_width": 160.0, "rect_height": 18.2},
|
||||
{"label_text": "81%", "rect_left": 1510.1, "rect_top": 488.1, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"label_text": "77%", "rect_left": 1693.3, "rect_top": 488.1, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"attrs": {"title": "西班牙"}, "rect_left": 1315.0, "rect_top": 520.2, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "70%", "rect_left": 1510.1, "rect_top": 531.3, "rect_width": 160.0, "rect_height": 18.2},
|
||||
{"label_text": "70%", "rect_left": 1510.1, "rect_top": 531.3, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"label_text": "70%", "rect_left": 1693.3, "rect_top": 531.3, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"attrs": {"title": "意大利"}, "rect_left": 1315.0, "rect_top": 563.4, "rect_width": 550.0, "rect_height": 43.0},
|
||||
{"raw_text": "70%", "rect_left": 1510.1, "rect_top": 574.5, "rect_width": 160.0, "rect_height": 18.2},
|
||||
{"label_text": "70%", "rect_left": 1510.1, "rect_top": 574.5, "rect_width": 27.6, "rect_height": 18.2},
|
||||
{"raw_text": "62%", "rect_left": 1681.7, "rect_top": 563.4, "rect_width": 183.2, "rect_height": 43.2},
|
||||
{"label_text": "62%", "rect_left": 1693.3, "rect_top": 574.5, "rect_width": 27.6, "rect_height": 18.2},
|
||||
]
|
||||
)
|
||||
|
||||
assert rows == [
|
||||
{"country": "欧洲", "ratio2DaysAgo": "60%", "ratio30DaysAgo": "64%"},
|
||||
{"country": "英国", "ratio2DaysAgo": "50%", "ratio30DaysAgo": "61%"},
|
||||
{"country": "德国", "ratio2DaysAgo": "57%", "ratio30DaysAgo": "65%"},
|
||||
{"country": "法国", "ratio2DaysAgo": "81%", "ratio30DaysAgo": "77%"},
|
||||
{"country": "西班牙", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "70%"},
|
||||
{"country": "意大利", "ratio2DaysAgo": "70%", "ratio30DaysAgo": "62%"},
|
||||
]
|
||||
|
||||
|
||||
def test_has_any_cart_ratio_detects_country_table_rows():
|
||||
assert InventoryManage._has_any_cart_ratio(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 2 天前 30 天前 "
|
||||
"欧洲 60% 64% 英国 50% 61% 德国 57% 65%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_has_any_cart_ratio_detects_date_header_country_table_rows():
|
||||
assert InventoryManage._has_any_cart_ratio(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 24 Apr 27 Mar "
|
||||
"欧洲 60% 64% 英国 50% 61% 德国 57% 65%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_has_complete_cart_ratio_rows_requires_all_target_countries():
|
||||
assert not InventoryManage._has_complete_cart_ratio_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 2 天前 30 天前 "
|
||||
"欧洲 60% 64% 英国 50% 61% 德国 57% 65%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_has_complete_cart_ratio_rows_detects_full_country_table():
|
||||
assert InventoryManage._has_complete_cart_ratio_rows(
|
||||
[
|
||||
{
|
||||
"raw_text": (
|
||||
"推荐报价百分比 商城 2 天前 30 天前 "
|
||||
"欧洲 60% 64% "
|
||||
"英国 50% 61% "
|
||||
"德国 57% 65% "
|
||||
"法国 81% 77% "
|
||||
"西班牙 70% 70% "
|
||||
"意大利 70% 62%"
|
||||
)
|
||||
}
|
||||
]
|
||||
)
|
||||
Reference in New Issue
Block a user