feat(collect): choose product status scope

This commit is contained in:
chengma
2026-07-18 16:46:59 +08:00
parent 0cf23db403
commit 4658a1ca61
11 changed files with 420 additions and 41 deletions
+161
View File
@@ -24,6 +24,7 @@ from app.gui.workers import (
ProductSuiteAiWriteWorker,
ProductSuiteGenerateWorker,
ProductSuiteHistoryExportWorker,
CollectWorker,
)
@@ -119,6 +120,166 @@ class WorkerTests(unittest.TestCase):
self.assertEqual([(-1, "模拟失败")], failed)
self.assertEqual([{"ok": False, "error": "模拟失败"}], finished)
def test_collect_worker_scope_skips_non_normal_without_overwriting_old_content(self):
with tempfile.TemporaryDirectory() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
db.init_db(db_path)
batch_id = db.create_batch(["input.xlsx"], path=db_path)
db.insert_tasks(
batch_id,
[
{
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
"source_sheet": "Sheet1",
"source_row": index,
"account_name": "店铺",
"alias": "alias",
"item_id": str(51100639510 + index),
}
for index in range(2, 6)
],
path=db_path,
)
tasks = db.list_tasks(batch_id=batch_id, path=db_path)
connection = db.connect(db_path)
try:
with connection:
connection.execute(
"UPDATE tasks SET old_title = ?, old_cover_path = ? WHERE id = ?",
("历史标题", "history.jpg", tasks[1].id),
)
finally:
connection.close()
status_by_item = {
tasks[0].item_id: "normal",
tasks[1].item_id: "unlisted",
tasks[2].item_id: "reviewing",
tasks[3].item_id: "unknown",
}
account = SimpleNamespace(alias="alias", account_name="店铺", debug_port=9222)
def fake_collect(_account, task, on_step=None):
status = status_by_item[task["item_id"]]
self.assertEqual("normal_only", task["collection_scope"])
on_step("read_product_status")
if status != "normal":
labels = {
"unlisted": "未上架",
"reviewing": "审核中",
"unknown": "状态未知",
}
return {
"product_status": status,
"product_status_note": f"{labels[status]}提示",
"collection_skipped": True,
"collection_skip_reason": f"{labels[status]},按本轮范围略过",
}
on_step("download_cover")
return {
"product_status": status,
"product_status_note": None,
"old_title": "新采集标题",
"old_cover_path": "new.jpg",
}
with mock.patch(
"app.gui.workers.accounts.list_accounts",
return_value=[account],
), mock.patch(
"app.gui.workers.accounts.detect_login",
return_value={"logged_in": True, "reason": None},
), mock.patch(
"app.gui.workers.editor.collect",
side_effect=fake_collect,
):
summary = CollectWorker(
tasks,
db_path=db_path,
preflight=False,
collect_scope="normal_only",
).execute()
self.assertEqual(1, summary["collected"])
self.assertEqual(3, summary["skipped"])
self.assertEqual(0, summary["failed"])
self.assertEqual(3, summary["status_scope_skipped"])
self.assertEqual(
{"normal": 1, "unlisted": 1, "reviewing": 1, "unknown": 1},
summary["product_status_counts"],
)
refreshed = db.list_tasks(batch_id=batch_id, path=db_path)
by_status = {task.product_status: task for task in refreshed}
self.assertEqual("collected", by_status["normal"].stage)
self.assertEqual("success", by_status["normal"].status)
self.assertEqual("skipped", by_status["unlisted"].status)
self.assertEqual("imported", by_status["unlisted"].stage)
self.assertEqual("历史标题", by_status["unlisted"].old_title)
self.assertEqual("history.jpg", by_status["unlisted"].old_cover_path)
def test_collect_worker_all_scope_collects_every_detected_status(self):
with tempfile.TemporaryDirectory() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
db.init_db(db_path)
batch_id = db.create_batch(["input.xlsx"], path=db_path)
db.insert_tasks(
batch_id,
[
{
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
"source_sheet": "Sheet1",
"source_row": index,
"account_name": "店铺",
"alias": "alias",
"item_id": str(51100639600 + index),
}
for index in range(2, 6)
],
path=db_path,
)
tasks = db.list_tasks(batch_id=batch_id, path=db_path)
statuses = ["normal", "unlisted", "reviewing", "unknown"]
account = SimpleNamespace(alias="alias", account_name="店铺", debug_port=9222)
def fake_collect(_account, task, on_step=None):
self.assertEqual("all", task["collection_scope"])
on_step("read_product_status")
status = statuses.pop(0)
return {
"product_status": status,
"product_status_note": None,
"old_title": f"标题{status}",
"old_cover_path": f"{status}.jpg",
}
with mock.patch(
"app.gui.workers.accounts.list_accounts",
return_value=[account],
), mock.patch(
"app.gui.workers.accounts.detect_login",
return_value={"logged_in": True, "reason": None},
), mock.patch(
"app.gui.workers.editor.collect",
side_effect=fake_collect,
):
summary = CollectWorker(
tasks,
db_path=db_path,
preflight=False,
collect_scope="all",
).execute()
self.assertEqual(4, summary["collected"])
self.assertEqual(0, summary["skipped"])
self.assertEqual(0, summary["status_scope_skipped"])
self.assertEqual(
{"normal": 1, "unlisted": 1, "reviewing": 1, "unknown": 1},
summary["product_status_counts"],
)
self.assertTrue(
all(task.stage == "collected" for task in db.list_tasks(batch_id=batch_id, path=db_path))
)
def test_run_worker_rejects_plain_object(self):
with self.assertRaises(TypeError):
run_worker(object(), start=False)