From 8b5a4a3bf494210e9b0c736d07808a7c04d5ea50 Mon Sep 17 00:00:00 2001 From: OoO Date: Wed, 13 May 2026 11:56:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E4=B8=8A=20MOMO=20=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E6=AF=94=E5=83=B9=E7=88=AC=E8=9F=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../claude_inventory_validation_20260513.md | 1 + routes/price_comparison_routes.py | 10 ++-- tests/test_price_comparison_routes.py | 51 +++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 tests/test_price_comparison_routes.py diff --git a/docs/memory/claude_inventory_validation_20260513.md b/docs/memory/claude_inventory_validation_20260513.md index 13a6382..a82ab50 100644 --- a/docs/memory/claude_inventory_validation_20260513.md +++ b/docs/memory/claude_inventory_validation_20260513.md @@ -50,6 +50,7 @@ - `tests/test_pg_sync.py` 已改為 opt-in integration test:預設不再連 localhost PostgreSQL 或建立/刪除測試表,需 `RUN_PG_SYNC_INTEGRATION=1` 且提供 `POSTGRES_PASSWORD` 才執行。 - `services/pg_sync_service.py` 是顯式 opt-in legacy CLI,不是生產自動同步路徑;`tests/test_pg_sync_contract.py` 已守住預設 OFF 與 runtime paths 不自動 import。 - `qwen3:14b` 不是未使用 Ollama 模型:OpenClaw QA、NemoTron dispatch 與 LLM model router 仍有現役路徑;`tests/test_qwen3_runtime_usage.py` 已守住,不能只因體積大就三主機移除。 +- `routes/price_comparison_routes.py` 的 MOMO crawler TODO 已接到既有 `services.momo_crawler.search_momo_products()`;未手動上傳 MOMO 商品時會自動抓 MOMO,再交給比價服務。 - Telegram `momo:eig:` callback 已在 `routes/openclaw_bot_routes.py` 與 `services/telegram_bot_service.py` 實作並有 webhook 測試覆蓋,不是未實作缺口。 - Telegram `date_*` / `goal_*` 不是死 callback handler:按鈕先送 `await:*` 進入輸入等待狀態,使用者下一則文字才由 pending action 消費;`tests/test_openclaw_bot_menu_keyboards.py` 與 `tests/test_openclaw_bot_routes_webhook.py` 已覆蓋。 - `services/ai_automation_smoke_service.py` 不是死 service:`run_scheduler.py` 每日 09:10 掛 `run_ai_smoke_daily_summary_task()`,該 task 會呼叫 `send_smoke_daily_summary()`;`tests/test_ai_automation_smoke_service.py` 與 `tests/test_ai_automation_metrics.py` 已覆蓋。 diff --git a/routes/price_comparison_routes.py b/routes/price_comparison_routes.py index 8a61186..49494d3 100644 --- a/routes/price_comparison_routes.py +++ b/routes/price_comparison_routes.py @@ -12,6 +12,7 @@ from services.price_comparison import ( BRAND_ALIASES, BRAND_NORMALIZE_MAP ) +from services.momo_crawler import search_momo_products from services.pchome_crawler import search_pchome_products logger = logging.getLogger(__name__) @@ -93,10 +94,11 @@ def compare_prices(): # 取得 MOMO 商品 momo_products = data.get('momo_products') if not momo_products: - # TODO: 實作 MOMO 爬蟲 - # 暫時使用空列表 - logger.info(f"MOMO 商品需手動提供或實作爬蟲") - momo_products = [] + logger.info(f"自動搜尋 MOMO: {brand}") + success, msg, momo_products = search_momo_products(brand, limit=100) + if not success: + logger.warning(f"MOMO 搜尋失敗: {msg}") + momo_products = [] # 執行比價 result = compare_brand_prices(brand, pchome_products, momo_products) diff --git a/tests/test_price_comparison_routes.py b/tests/test_price_comparison_routes.py new file mode 100644 index 0000000..4db61f8 --- /dev/null +++ b/tests/test_price_comparison_routes.py @@ -0,0 +1,51 @@ +from flask import Flask + + +def test_compare_prices_auto_fetches_momo_when_not_provided(monkeypatch): + from routes import price_comparison_routes as routes + + captured = {} + + def fake_search_momo(keyword, limit=10): + captured["momo_search"] = (keyword, limit) + return True, "ok", [ + { + "name": "理膚寶水 B5 修復霜", + "price": 890, + "product_id": "12345678", + "product_url": "https://www.momoshop.com.tw/goods/GoodsDetail.jsp?i_code=12345678", + } + ] + + def fake_compare(brand, pchome_products, momo_products): + captured["compare"] = (brand, pchome_products, momo_products) + return { + "pchome_count": len(pchome_products), + "momo_count": len(momo_products), + "matched_count": 0, + "matches": [], + "stats": {}, + } + + monkeypatch.setattr(routes, "search_momo_products", fake_search_momo) + monkeypatch.setattr(routes, "compare_brand_prices", fake_compare) + + app = Flask(__name__) + with app.test_request_context( + "/api/price_comparison/compare", + method="POST", + json={ + "brand": "理膚寶水", + "pchome_products": [ + {"name": "理膚寶水 B5 修復霜", "price": 900, "product_id": "PCHOME-1"}, + ], + }, + ): + response = routes.compare_prices.__wrapped__() + + payload = response.get_json() + assert payload["success"] is True + assert payload["data"]["momo_count"] == 1 + assert captured["momo_search"] == ("理膚寶水", 100) + assert captured["compare"][0] == "理膚寶水" + assert captured["compare"][2][0]["product_id"] == "12345678"