from datetime import datetime, timedelta def test_revalidator_promotes_legacy_same_product_without_refreshing_expired_price(): from services.competitor_identity_revalidator import classify_legacy_competitor_row row = { "sku": "10950080", "momo_name": "【台酒生技】黑酵母酒粕逆齡活膚青春露5入-(120ml/入)", "momo_price": 999, "pchome_price": 899, "competitor_product_id": "PC-1", "competitor_product_name": "【台酒生技】金粹黑酵母酒粕逆齡活膚青春露120ml_5入", "tags": ["discount_10pct"], "is_expired": True, "expires_at": datetime.utcnow() - timedelta(hours=1), } decision = classify_legacy_competitor_row(row) assert decision.accepted is True assert decision.status == "expired_match" assert decision.score >= 0.76 assert "identity_v2" in decision.tags assert "legacy_revalidated" in decision.tags def test_revalidator_rejects_legacy_brand_conflict(): from services.competitor_identity_revalidator import classify_legacy_competitor_row row = { "sku": "BAD-1", "momo_name": "【蘭蔻】官方直營 玫瑰霜60ml+玫瑰精露150ml", "momo_price": 18765, "pchome_price": 1249, "competitor_product_id": "PC-BAD", "competitor_product_name": "LOREAL Paris 巴黎萊雅 金致臻顏花蜜奢養膠原輕盈乳霜_60ml", "tags": [], "is_expired": False, } decision = classify_legacy_competitor_row(row) assert decision.accepted is False assert decision.status == "identity_veto" assert decision.hard_veto is True assert "brand_conflict" in decision.diagnostic def test_dashboard_match_status_distinguishes_expired_and_legacy_rows(): from routes.dashboard_routes import _build_pchome_match_status expired = _build_pchome_match_status( None, ineligible={"reason": "expired_match", "match_score": 0.91}, ) legacy = _build_pchome_match_status( None, ineligible={"reason": "legacy_without_identity_v2", "match_score": 0.82}, ) assert expired["label"] == "價格過期待刷新" assert expired["tone"] == "watch" assert legacy["label"] == "舊版配對待重驗" assert "identity_v2" in legacy["summary"] def test_dashboard_match_status_explains_identity_veto_reason(): from routes.dashboard_routes import _build_pchome_match_status bundle = _build_pchome_match_status({ "attempt_status": "identity_veto", "best_match_score": 0.32, "error_message": "score=0.32; reasons=bundle_offer_conflict,product_line_conflict", }) refill = _build_pchome_match_status({ "attempt_status": "identity_veto", "best_match_score": 0.32, "error_message": "score=0.32; reasons=refill_pack_conflict", }) assert bundle["label"] == "組合差異待審" assert "組合包/多件組" in bundle["summary"] assert refill["label"] == "補充包差異待審" assert "補充瓶/補充包" in refill["summary"] def test_dashboard_match_status_explains_unit_comparable_bundle(): from routes.dashboard_routes import _build_pchome_match_status status = _build_pchome_match_status({ "attempt_status": "unit_comparable", "best_match_score": 0.74, "error_message": "score=0.74; reasons=bundle_offer_conflict,unit_comparable", "unit_comparison": { "comparable": True, "summary": "MOMO $14.99/ml vs PChome $16.98/ml (-11.7%)", }, }) assert status["label"] == "需單位價比較" assert status["tone"] == "watch" assert "已換算單位價" in status["summary"]