2349 lines
95 KiB
Python
2349 lines
95 KiB
Python
from sqlalchemy import create_engine, text
|
||
|
||
|
||
def test_marketplace_matcher_accepts_same_product_identity():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"理膚寶水 B5 修復霜 40ml",
|
||
"理膚寶水 全面修復霜 B5 40ml",
|
||
momo_price=699,
|
||
competitor_price=679,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.9
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
assert "spec_match" in diagnostics.tags
|
||
assert diagnostics.match_type == "exact"
|
||
assert diagnostics.price_basis == "total_price"
|
||
assert diagnostics.alert_tier == "price_alert_exact"
|
||
assert "match_type_exact" in diagnostics.tags
|
||
|
||
|
||
def test_marketplace_matcher_rejects_brand_conflict_even_when_volume_matches():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【蘭蔻】官方直營 玫瑰霜60ml+玫瑰精露150ml",
|
||
"LOREAL Paris 巴黎萊雅 金致臻顏花蜜奢養膠原輕盈乳霜_60ml",
|
||
momo_price=18765,
|
||
competitor_price=1249,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "brand_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_volume_conflict_for_same_brand():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【CLARINS 克蘭詩】黃金亮眼萃20mlX2囤貨組",
|
||
"【CLARINS克蘭詩】黃金雙萃精華 75ml",
|
||
momo_price=4500,
|
||
competitor_price=3549,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "volume_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_handles_bundle_piece_count():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Relove】馬甲纖纖飲-莓果風味X3盒 共72包",
|
||
"【3入超值組】Relove 馬甲纖纖飲 24包/7克",
|
||
momo_price=4590,
|
||
competitor_price=4590,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_accepts_strong_model_line_without_specs():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Stadler Form】Sophie 無線香氛水氧機 水氧機 香氛機",
|
||
"【瑞士Stadler Form】無線香氛水氧機 露營燈造型 Sophie",
|
||
momo_price=3780,
|
||
competitor_price=3980,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "strong_product_line_match" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_bundle_to_single_even_when_brand_matches():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【NARS】小白餅閨蜜分享組(裸光蜜粉餅/定妝蜜粉)",
|
||
"【NARS】裸光蜜粉餅(小白餅) 10g",
|
||
momo_price=3300,
|
||
competitor_price=1099,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "bundle_offer_conflict" in diagnostics.reasons
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
|
||
|
||
def test_marketplace_matcher_marks_bundle_single_as_unit_comparable_not_exact():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"理膚寶水 B5 全面修復霜 40ml x2 超值組",
|
||
"理膚寶水 全面修復霜 B5 40ml",
|
||
momo_price=1199,
|
||
competitor_price=679,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "unit_comparable"
|
||
assert diagnostics.match_type == "same_product_different_pack"
|
||
assert diagnostics.price_basis == "unit_price"
|
||
assert diagnostics.alert_tier == "unit_price_review"
|
||
assert "unit_comparable" in diagnostics.reasons
|
||
assert "comparison_unit_comparable" in diagnostics.tags
|
||
|
||
|
||
def test_marketplace_matcher_suppresses_same_line_variant_price_alert():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Dashing Diva】時尚潮流美甲片 月影柔霧",
|
||
"Dashing Diva 時尚潮流美甲片 銀絲柔彩 30片",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.match_type == "no_match"
|
||
assert diagnostics.price_basis == "none"
|
||
assert diagnostics.alert_tier == "suppress"
|
||
assert "variant_descriptor_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_unit_price_comparison_builds_normalized_evidence():
|
||
from services.marketplace_product_matcher import build_unit_price_comparison
|
||
|
||
comparison = build_unit_price_comparison(
|
||
"理膚寶水 B5 全面修復霜 40ml x2 超值組",
|
||
"理膚寶水 全面修復霜 B5 40ml",
|
||
momo_price=1199,
|
||
competitor_price=679,
|
||
)
|
||
|
||
assert comparison["comparable"] is True
|
||
assert comparison["unit_label"] == "ml"
|
||
assert comparison["momo_total_quantity"] == 80
|
||
assert comparison["competitor_total_quantity"] == 40
|
||
assert comparison["momo_unit_price"] == 14.9875
|
||
assert comparison["competitor_unit_price"] == 16.975
|
||
assert comparison["unit_gap_pct"] < 0
|
||
|
||
|
||
def test_marketplace_matcher_routes_same_base_different_piece_pack_to_unit_comparable():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【日本Beauty Foot】去角質足膜25mlx2枚入 5入組(一般尺寸、大尺寸可選)",
|
||
"【日本Beauty Foot 】煥膚足膜(25ml*2枚入)四入組",
|
||
momo_price=1290,
|
||
competitor_price=989,
|
||
)
|
||
|
||
assert diagnostics.comparison_mode == "unit_comparable"
|
||
assert diagnostics.match_type == "same_product_different_pack"
|
||
assert diagnostics.price_basis == "unit_price"
|
||
assert "pack_quantity_difference" in diagnostics.reasons
|
||
assert "unit_comparable" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_does_not_unit_compare_multi_component_set():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【蘭蔻】官方直營 玫瑰霜60ml+玫瑰精露150ml",
|
||
"【蘭蔻】絕對完美玫瑰霜 60ml",
|
||
momo_price=18765,
|
||
competitor_price=5349,
|
||
)
|
||
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "unit_comparable" not in diagnostics.reasons
|
||
|
||
comparison = score_marketplace_match(
|
||
"【蘭蔻】官方直營 玫瑰霜60ml+玫瑰精露150ml",
|
||
"【蘭蔻】絕對完美玫瑰霜 60ml",
|
||
momo_price=18765,
|
||
competitor_price=5349,
|
||
)
|
||
assert comparison.comparison_mode == "not_comparable"
|
||
|
||
|
||
def test_marketplace_matcher_does_not_promote_wide_price_refill_candidate():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【蘭蔻】官方直營 絕對完美永生玫瑰逆齡乳霜60ml補充瓶",
|
||
"LANCOME蘭蔻 絕對完美永生玫瑰逆齡乳霜 60ml",
|
||
momo_price=11205,
|
||
competitor_price=5349,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "refill_pack_conflict" in diagnostics.reasons
|
||
assert "strong_product_line_match" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_partial_overlap_in_multi_spec_set():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【蘭蔻】玫瑰霜60ml+玫瑰精露150ml",
|
||
"【蘭蔻】玫瑰霜60ml+玫瑰精露20ml",
|
||
momo_price=18765,
|
||
competitor_price=7999,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "volume_conflict" in diagnostics.reasons
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
|
||
|
||
def test_marketplace_matcher_rejects_dosage_conflict():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"品牌 葉黃素 10mg 60錠",
|
||
"品牌 葉黃素 20mg 60錠",
|
||
momo_price=990,
|
||
competitor_price=890,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "dosage_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_product_type_conflict_even_when_line_matches():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"理膚寶水 MelaB3 淡斑精華 30ml",
|
||
"理膚寶水 MelaB3 淡斑化妝水 30ml",
|
||
momo_price=1280,
|
||
competitor_price=1180,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "type_conflict" in diagnostics.reasons
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
|
||
|
||
def test_marketplace_matcher_rejects_foundation_stick_vs_foundation_liquid():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【蘭蔻】零粉感超持久粉底棒9.5g",
|
||
"【LANCOME 蘭蔻】零粉感超持久粉底 30ml",
|
||
momo_price=1620,
|
||
competitor_price=1580,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "type_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_nivea_deodorant_spray_identity():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【NIVEA 妮維雅】男士 止汗爽身噴霧 無印乾爽-清新海洋",
|
||
"NIVEA 妮維雅 男士止汗爽身噴霧 無印乾爽-清新海洋150ml",
|
||
momo_price=159,
|
||
competitor_price=169,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_promotes_nivea_deodorant_lotion_noise_variants():
|
||
from services.marketplace_product_matcher import build_search_terms, score_marketplace_match
|
||
|
||
momo_name = "【NIVEA 妮維雅】德國妮維雅 止汗爽身乳液50ml(無印止汗滾珠)"
|
||
diagnostics = score_marketplace_match(
|
||
momo_name,
|
||
"NIVEA 妮維雅 止汗爽身乳液 50ml",
|
||
momo_price=149,
|
||
competitor_price=169,
|
||
)
|
||
terms = build_search_terms(momo_name, max_terms=5)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert terms[0] == "妮維雅 止汗爽身乳液 50ml"
|
||
assert "德國妮維雅" not in " ".join(terms[:3])
|
||
assert "無印止汗滾珠" not in " ".join(terms[:3])
|
||
|
||
|
||
def test_marketplace_matcher_promotes_packaging_variant_for_same_nars_powder():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【NARS】官方直營 裸光蜜粉餅(璀璨奢金限定版/星沙金小白餅)",
|
||
"【NARS】裸光蜜粉餅(小白餅) 10g",
|
||
momo_price=1050,
|
||
competitor_price=1050,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_packaging_variant" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_private_wash_same_identity():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
summer = score_marketplace_match(
|
||
"【Summer’s Eve 舒摩兒】浴潔露237ml 單入任選(私密清潔 經典防護王)",
|
||
"eve舒摩兒 賦活美學浴潔露-全肌防護 237ml",
|
||
momo_price=441,
|
||
competitor_price=441,
|
||
)
|
||
femfresh = score_marketplace_match(
|
||
"【femfresh 芳芯】弱酸性植萃複方溫和潤澤護理私密肌潔膚露250ml/瓶(pH值平衡護潔露淨味沐浴乳香氛凝膠)",
|
||
"【femfresh芳芯 官方直營】私密潔膚露250ml (任選)",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
for diagnostics in (summer, femfresh):
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_rejects_private_spray_vs_private_gel():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【isLeaf】韓國isLeaf男性私密醒肌抑菌噴霧60ml-夏夜微醺(SGS 24小時抑菌)",
|
||
"韓國 isLeaf 男性私密激淨凝露 湛藍海洋 60ml",
|
||
momo_price=299,
|
||
competitor_price=299,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "type_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_marketing_variant_same_maybelline_lip_tint():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【MAYBELLINE 媚比琳】超持久水光鎖吻唇釉(絲絨甜點新色/鎖吻棒/水光持色)",
|
||
"MAYBELLINE 媚比琳 超持久水光鎖吻唇釉 4.2ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_marketing_variant" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_besthot_aroma_machine_marketing_variant():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【BESTHOT】天然陶瓷精油香薰機-贈精油一瓶(水氧機 加濕器 精油機 香薰機 擴香機 小夜燈)",
|
||
"Besthot 天然陶瓷超聲波大噴霧精油香薰機-贈送薰衣草精油 水氧機 加濕器 精油機",
|
||
momo_price=899,
|
||
competitor_price=899,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_promotes_precise_cosmetics_and_skincare_lines():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
samples = [
|
||
(
|
||
"【NARS】官方直營 裸光幻閃亮采餅",
|
||
"NARS 裸光幻閃亮采餅 2g #Heavenly",
|
||
),
|
||
(
|
||
"【PONY EFFECT】絕對持久定妝噴霧 100ml(持久定妝/控油特霧)",
|
||
"【PONY EFFECT】絕對持久定妝噴霧(控油特霧版)",
|
||
),
|
||
(
|
||
"【植村秀】官方直營 自動武士刀眉筆(Shu uemura/眉筆)",
|
||
"《Shu Uemura 植村秀》自動武士刀眉筆 0.3g",
|
||
),
|
||
(
|
||
"【SHISEIDO 資生堂國際櫃】超進化光感輕潤遮瑕棒(遮瑕/修容/打亮/新品)",
|
||
"【資生堂國際櫃】超進化光感輕潤遮瑕棒2.7g",
|
||
),
|
||
(
|
||
"【LANCOME 蘭蔻】唯我玫瑰裸光潤唇膏(多款任選 國際航空版 送禮)",
|
||
"LANCOME 唯我玫瑰裸光潤唇膏 3g",
|
||
),
|
||
(
|
||
"【Les nez 香鼻子】晨曦冷香儀贈複方擴香精油 30ml(無水擴香 智能霧化)",
|
||
"les nez 晨曦冷香儀(無水擴香、智能霧化)",
|
||
),
|
||
(
|
||
"【Mustela 慕之恬廊】舒恬良 修護霜 40ml(Vit.B5 嬰兒界萬用霜 醫師好辣推薦)",
|
||
"Mustela 慕之恬廊舒恬良修護霜40ml",
|
||
),
|
||
]
|
||
|
||
for left, right in samples:
|
||
diagnostics = score_marketplace_match(left, right, momo_price=399, competitor_price=399)
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_suppresses_price_penalty_for_exact_identity_toner():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Estee Lauder 雅詩蘭黛】微分子肌底原生露/櫻花版200ml任選(新上市/化妝水/水精華/無酒精)",
|
||
"ESTEE LAUDER 雅詩蘭黛 微分子肌底原生露 200ml",
|
||
momo_price=4750,
|
||
competitor_price=999,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "price_penalty_suppressed_exact_identity" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_exact_line_near_threshold_without_global_threshold_change():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
za = score_marketplace_match(
|
||
"【Za】官方直營 細芯睛彩雙頭眉筆(色號任選)",
|
||
"Za 細芯睛彩雙頭眉筆0.1g",
|
||
momo_price=158,
|
||
competitor_price=158,
|
||
)
|
||
|
||
assert za.score >= 0.76
|
||
assert "shared_identity_anchor_exact_line" in za.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_shared_variant_descriptor_alignment_for_shu():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Shu uemura 植村秀】武士刀眉筆(平輸航空版/多色任選/橡棕.暗灰. 灰棕)",
|
||
"《Shu Uemura 植村秀》武士刀眉筆(H9) 4g -#橡棕06",
|
||
momo_price=699,
|
||
competitor_price=699,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_variant_descriptor_alignment" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_ignores_generic_variant_noise_for_peripera_brow_pencil():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【peripera官方直營】雙頭旋轉極細眉筆_多色任選(1.5mm極細筆頭)",
|
||
"PERIPERA 雙頭旋轉極細眉筆 09灰褐棕 0.05g",
|
||
momo_price=180,
|
||
competitor_price=180,
|
||
)
|
||
|
||
assert "variant_descriptor_conflict" not in diagnostics.reasons
|
||
assert diagnostics.score < 0.76
|
||
|
||
|
||
def test_marketplace_matcher_promotes_brandless_exact_identity_when_anchor_is_strong():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【小米有品】小浪智能感應自動噴香機(三種噴香模式 霧化噴香 芳香除臭)",
|
||
"小浪智能感應自動噴香機 三種噴香模式 霧化噴香 芳香除臭 芳香劑 去異味",
|
||
momo_price=539,
|
||
competitor_price=539,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert (
|
||
"brandless_exact_identity" in diagnostics.reasons
|
||
or "shared_identity_anchor_variant_safe" in diagnostics.reasons
|
||
)
|
||
|
||
|
||
def test_marketplace_matcher_promotes_ludeya_line_with_platform_name_drift():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【LUDEYA】蜂王玫瑰外泌微臻霜超值兩入組(瑰泌霜60mlx2)",
|
||
"LUDEYA 蜂王玫瑰微泌新生霜 60ml x2",
|
||
momo_price=2000,
|
||
competitor_price=2000,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor" in diagnostics.reasons or "shared_identity_anchor_no_spec" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_recipe_box_marketing_line_drift():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Recipe Box】Recipe Box多效提亮防曬霜(兒童化妝品/無毒防曬霜/天然彩妝/防曬/提亮)",
|
||
"Recipe Box 韓兔 多效提亮防曬霜",
|
||
momo_price=299,
|
||
competitor_price=299,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor_recipe_box_line" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_st_deodorizer_with_brand_alias_and_line_anchor():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【日本雞仔牌ST】室內消臭力智能光感應3段定時無線自動除臭芳香噴霧機(內贈芳香劑39ml 衛浴精油擴香瓶棒組)",
|
||
"日本ST雞仔牌-室內消臭力智能光感應3段定時無線自動除臭芳香噴霧機1入(含芳香劑39ml)",
|
||
momo_price=699,
|
||
competitor_price=699,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor_exact_line" in diagnostics.reasons or "shared_identity_anchor_packaging_variant" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_nivea_dry_lotion_with_long_shared_anchor():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【NIVEA 妮維雅】男士無印乾爽止汗爽身乳液(無印止汗滾珠/德國妮維雅)",
|
||
"【NIVEA 妮維雅】止汗爽身乳液 無印乾爽50ml",
|
||
momo_price=129,
|
||
competitor_price=129,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor_nivea_dry_lotion" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_curel_body_lotion_with_brand_alias():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Curel 珂潤】潤浸保濕清爽身體乳液 220ml",
|
||
"珂潤 Curel 潤浸保濕清爽身體乳液220ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
assert "shared_identity_anchor" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_karadium_pearl_shadow_stick_anchor():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【KARADIUM】閃亮珍珠眼影棒 1.4g",
|
||
"karadium 閃亮珍珠眼影棒 1.4g",
|
||
momo_price=259,
|
||
competitor_price=259,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
assert "shared_identity_anchor" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_karadium_pearl_shadow_stick_without_spec_text():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Karadium】閃亮珍珠眼影棒(滑順柔軟 顯色持久 一筆多用眼影筆)",
|
||
"KARADIUM閃亮珍珠眼影棒",
|
||
momo_price=500,
|
||
competitor_price=500,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_karadium_eye_stick" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_lactacyd_private_wash_multi_option_title():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Lactacyd 立朵舒】柔軟滋潤/亮肌柔滑/加倍修護/全日清爽/生理呵護/滋潤緊緻 私密潔浴露250ml/瓶(多款任選)原廠公司貨_樂齡生醫",
|
||
"Lactacyd 立朵舒 私密潔浴露 多款任選(250ml/入)X1入",
|
||
momo_price=299,
|
||
competitor_price=299,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_lactacyd_wash" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_relove_private_cleanser_campaign_title():
|
||
from services.marketplace_product_matcher import score_marketplace_match, build_search_terms
|
||
|
||
source = "【Relove】胺基酸私密潔淨凝露120ml-限量聯名款(小虎/啾啾妹/煎妮花/PLAY BOY私密處清潔 涼感潔淨)"
|
||
diagnostics = score_marketplace_match(
|
||
source,
|
||
"RELOVE金盞花萃取低敏私密潔淨凝露 120ml",
|
||
momo_price=629,
|
||
competitor_price=629,
|
||
)
|
||
terms = build_search_terms(source, max_terms=4)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_relove_cleanser" in diagnostics.reasons
|
||
assert "play" not in terms[0].lower()
|
||
assert "boy" not in terms[0].lower()
|
||
|
||
|
||
def test_marketplace_matcher_rejects_serum_milk_vs_serum_cream():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【自白肌】官方直營 極潤玻尿酸精華乳200ml",
|
||
"自白肌 極潤玻尿酸精華霜50g",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "variant_descriptor_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_bridges_maquillage_shiseido_counter_alias():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【資生堂東京櫃】MAQuillAGE 心機星魅蜜光圈潤唇膏N",
|
||
"【MAQuillAGE 心機彩妝】心機星魅蜜光圈潤唇膏N",
|
||
momo_price=850,
|
||
competitor_price=850,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_kate_bare_lip_line_with_series_copy():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"即期品【KATE 凱婷】柔霧裸唇膏-東京夜喫茶系列(裸色系霧面唇膏/4色任選)",
|
||
"【KATE 凱婷】柔霧裸唇膏 (2.3g)",
|
||
momo_price=320,
|
||
competitor_price=320,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_kate_bare_lip" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_next_recoverable_exact_identity_cohorts():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【OBgE】【官方公司貨】控油清爽防曬棒 18g (清爽 輕薄 控油 防曬棒 補擦不卡粉 戶外通勤 油肌友善 李多慧)",
|
||
"OBgE/控油清爽防曬棒18g",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"【Play&Joy 官方直營】ARTMIS 蔓越莓私密清潔慕斯 250ml(私密清潔 胺基酸配方 綿密泡沫 粉嫩如春 私密保養)",
|
||
"ARTMIS 蔓越莓私密清潔慕斯 250ml",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"【Play&Joy 官方直營】ARTMIS 金縷梅私密清潔慕斯 250ml(私密清潔 胺基酸配方 綿密泡沫 粉嫩如春 私密保養)",
|
||
"ARTMIS 金縷梅私密清潔慕斯 250ml",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"美國 Seche Vite 快乾亮油",
|
||
"美國Seche Vite指甲快乾亮油14ml",
|
||
"shared_identity_anchor_seche_vite_top_coat",
|
||
),
|
||
(
|
||
"【TAICEND 泰陞】寶貝液體保護膜 屁屁噴(100ml/1入組)",
|
||
"TAICEND泰陞 寶貝液體護膜100ml 屁屁噴 屁屁膏",
|
||
"strong_exact_spec_match",
|
||
),
|
||
(
|
||
"【femfresh 芳芯】私密潔膚露 250ml 長效清新 純淨植萃 舒緩敏感肌膚 私密處清潔 私密處護理|繁華中西藥局|",
|
||
"【femfresh芳芯 官方直營】私密潔膚露250ml (任選)",
|
||
"shared_identity_anchor_femfresh_wash",
|
||
),
|
||
(
|
||
"【VIGILL 婦潔】男性私密沐浴露220ml(男性私密清潔 一瓶洗全身)",
|
||
"【VIGILL 婦潔】日常潔淨 私密沐浴露220ml",
|
||
"shared_identity_anchor_vigill_private_wash",
|
||
),
|
||
(
|
||
"【Solone】光采奪目眼部飾底乳(眼部打底 眼影打底)",
|
||
"Solone 光采奪目眼部飾底乳 2.8g",
|
||
"shared_identity_anchor_packaging_variant",
|
||
),
|
||
(
|
||
"【小米有品】HYDSTO 車載香薰(全車淨化/持久清香/車用香水/香薰)",
|
||
"小米有品 HYDSTO 車載香薰",
|
||
"shared_identity_anchor_packaging_variant",
|
||
),
|
||
(
|
||
"【小米】電動刮鬍刀 S101(米家電動刮鬍刀 小米刮鬍刀 電動刮鬍刀 米家刮鬍刀)",
|
||
"【小米 Xiaomi】 小米電動刮鬍刀 S101",
|
||
"shared_model_token_xiaomi_s101_shaver",
|
||
),
|
||
(
|
||
"【PRAMY 柏瑞美】磁吸控油定妝噴霧 100ML(柔焦霧面)",
|
||
"【柏瑞美PRAMY】 磁吸控油定粧噴霧 柔焦霧面",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"【PRAMY 柏瑞美】磁吸控油定妝噴霧 100ML(水光亮面)",
|
||
"【柏瑞美PRAMY】 磁吸控油定粧噴霧 水光亮面",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"【i’m meme】韓國 Multi Stick Dual 雙頭修容打亮棒 3.3g (修容 打亮 修容棒 打亮筆 修容筆)",
|
||
"【I’M MEME】我愛小臉修容打亮棒 3.3g",
|
||
"shared_identity_anchor",
|
||
),
|
||
(
|
||
"【檜山坊】檜木精油滾珠瓶5ml 兩入(療癒 放鬆 穩定心神)",
|
||
"【檜山坊】台灣原生檜木精油5ml滾珠瓶兩入組",
|
||
"shared_identity_anchor_hinoki_roller_oil",
|
||
),
|
||
(
|
||
"【ARM&HAMMER 鐵鎚】小蘇打配方體香膏(71g)",
|
||
"Arm & Hammer 小蘇打體香膏 2.5oz /71g 長效防護 植物萃取 溫合無鋁",
|
||
"strong_exact_spec_match",
|
||
),
|
||
(
|
||
"【Brush Baby】WildOnes 充電式兒童聲波電動牙刷 0-10Y(多款可選)",
|
||
"Brush Baby WildOnes 充電式兒童電動牙刷(0-10Y)-多款可選",
|
||
"shared_model_token_brush_baby_wildones",
|
||
),
|
||
(
|
||
"【PALMER’S 帕瑪氏】新撫紋按摩乳250ml(新配方效果全新升級)",
|
||
"Palmer s 可可脂撫紋按摩乳液 250ml",
|
||
"strong_exact_spec_match",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name, expected_reason in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name)
|
||
assert diagnostics.score >= 0.76, (momo_name, diagnostics)
|
||
assert diagnostics.hard_veto is False
|
||
if expected_reason == "shared_identity_anchor":
|
||
assert any(reason.startswith("shared_identity_anchor") for reason in diagnostics.reasons)
|
||
else:
|
||
assert expected_reason in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_fragrance_formula_and_finish_variant_mismatch():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【MUJI 無印良品】芬香蠟燭.茉莉花香味/85g",
|
||
"芬香蠟燭.梔子花香味/85g【MUJI 無印良品】",
|
||
"variant_option_conflict",
|
||
),
|
||
(
|
||
"【Play&Joy 官方直營】ARTMIS 蔓越莓私密清潔慕斯 250ml",
|
||
"ARTMIS 金縷梅私密清潔慕斯 250ml",
|
||
"variant_option_conflict",
|
||
),
|
||
(
|
||
"【PRAMY 柏瑞美】磁吸控油定妝噴霧 100ML(柔焦霧面)",
|
||
"【柏瑞美PRAMY】 磁吸控油定粧噴霧 水光亮面",
|
||
"variant_option_conflict",
|
||
),
|
||
(
|
||
"【Relove】8%菸鹼醯胺私密淨白清潔凝露120ml(私密清潔 私密美白 涼感潔淨 PH3.8弱酸呵護)",
|
||
"RELOVE胺基酸私密清潔凝露120ml",
|
||
"variant_option_conflict",
|
||
),
|
||
(
|
||
"【CeraVe 適樂膚】極抗痕抗老全配組★極抗痕A醇緊緻修護精華+極抗痕多肽緊緻修護霜+極抗痕C10煥亮修護精華",
|
||
"【CeraVe適樂膚】極抗痕A醇緊緻修護精華 30ml+極抗痕多肽緊緻修護霜 48g",
|
||
"multi_component_count_conflict",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name, expected_reason in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name)
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert diagnostics.score < 0.76
|
||
assert expected_reason in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_ignores_sunscreen_and_model_plus_markers_for_bundle_count():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【O.P.I】受損型硬甲油記得卸組-亮麗增強基礎護甲油15mL+專業去光水110mL-NTT80+AL414(禮物/官方直營)",
|
||
"OPI 護甲油記得卸組(亮麗增強基礎護甲油15mL+去光水110mL)",
|
||
),
|
||
(
|
||
"【Neutrogena 露得清】新品上市★水感透亮防曬乳SPF50+ PA++++(40mlx2入組)",
|
||
"露得清水感透亮防曬乳SPF50+ 40ml *2入",
|
||
),
|
||
(
|
||
"【AGE20】輕透光潤色素顏霜(SPF50+/PA++++/台灣總代理)",
|
||
"AGE20’S 輕透光潤色素顏霜SPF50+/PA++++",
|
||
),
|
||
(
|
||
"【Estee Lauder 雅詩蘭黛】粉持久完美鎖妝氣墊粉餅(SPF45/PA+++/一盒一蕊/IU同款)",
|
||
"【ESTEE LAUDER雅詩蘭黛】粉持久完美鎖妝氣墊粉餅SPF45/PA+++",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name, momo_price=1000, competitor_price=900)
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.score >= 0.76
|
||
assert "multi_component_count_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_ignores_quantity_plus_markers_inside_component_specs():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【HH草本新淨界】私密植萃抗菌潔淨露+私密衣物抗菌手洗精(200ml+200ml)",
|
||
"HH私密植萃抗菌潔淨露(200ML)+私密衣物抗菌手洗精(200ML)【裡外兼顧組】",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "multi_component_count_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_named_scent_catalog_in_identity_review():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【HH草本新淨界】女性私密衣物抗菌手洗精200ml(私密衣物手洗 衣物手洗精)",
|
||
"HH女性私密衣物抗菌手洗精 200ml (白麝香&清新花園&寶貝粉香)",
|
||
momo_price=399,
|
||
competitor_price=356,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "variant_selection_review" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_catalog_variant_recoveries_in_identity_review():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【Johnsons 嬌生】嬰兒潤膚乳500ml_嬰兒乳液(牛奶/純淨/甜夢/溫和/棉柔_任選)",
|
||
"嬌生嬰兒甜夢潤膚乳500ml",
|
||
),
|
||
(
|
||
"【im meme】我愛超磁妝定妝噴霧60ml(涼感/一般)",
|
||
"【I’M MEME】我愛超磁妝定妝噴霧-涼感控油",
|
||
),
|
||
(
|
||
"【SO NATURAL】FIXX 全天候超完美定妝噴霧 經典款/光澤款/霧面款/夏日款",
|
||
"【SO NATURAL】FIXX 全天候超完美定妝噴霧 120ml",
|
||
),
|
||
(
|
||
"【KATE 凱婷】怪獸級持色唇膏-經典款(獨家技術持久不沾 高保濕)",
|
||
"【KATE 凱婷】怪獸級持色唇膏 (3g)",
|
||
),
|
||
(
|
||
"【植村秀】官方直營 自動武士刀眉筆筆蕊(Shu uemura/筆蕊 8色任選)",
|
||
"《Shu Uemura 植村秀》自動武士刀眉筆 -筆蕊 0.3g",
|
||
),
|
||
(
|
||
"【The Forest 癒森林】焦糖楓葉香氛擴香花禮盒 含30ml品牌香氛油(居家香氛/香水精油/香氛擴香花/擴香禮物)",
|
||
"焦糖楓葉香氛擴香花禮盒 含30ml品牌香氛油",
|
||
),
|
||
(
|
||
"【O.P.I】類光繚指甲油 12色任選1瓶(小銀蓋/如膠似漆白日夢遊系列指彩/官方直營)",
|
||
"OPI 如膠似漆白日夢遊系列 類光繚指甲油12色任選",
|
||
),
|
||
(
|
||
"【O.P.I】類光繚指甲油 12色任選1瓶(小銀蓋/如膠似漆驕傲果凍系列指彩/官方直營)",
|
||
"OPI 如膠似漆驕傲果凍系列 類光繚指甲油11色任選",
|
||
),
|
||
(
|
||
"即期品【Summer’s Eve 舒摩兒】全肌防護浴潔露2入(私密清潔 經典防護王)無外盒裸瓶包裝",
|
||
"eve舒摩兒 賦活美學浴潔露-全肌防護 2入組",
|
||
),
|
||
(
|
||
"【rom&nd】果汁唇釉 2.0(the juicy 果汁唇釉 romand)",
|
||
"rom&nd 果汁唇釉2.0_3.5g_多款可選",
|
||
),
|
||
(
|
||
"【Solone】持久眼線筆(眼線膠 超防暈推薦)",
|
||
"Solone 持久眼線筆 1.5g",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name)
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "variant_selection_review" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_aligns_cushion_one_box_two_refills_with_spec_times_two():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【CLIO 珂莉奧 官方直營】羽緻無限緞光氣墊粉餅 SPF50+ PA+++(任選 一盒兩蕊)",
|
||
"珂莉奧 羽緻無限緞光氣墊粉餅 SPF50+, PA+++15g*2",
|
||
momo_price=885,
|
||
competitor_price=808,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "cushion_refill_pack_alignment" in diagnostics.reasons
|
||
assert "multi_component_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_cushion_four_refills_vs_spec_times_two_vetoed():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"即期品【CLIO 珂莉奧 官方直營】玫瑰精萃亮采氣墊粉餅SPF 50+ PA++++(2入組-任選 共2盒4蕊)",
|
||
"CLIO珂莉奧 粉鑽亮采氣墊粉餅 SPF50+, PA++++ (15gX2)",
|
||
momo_price=999,
|
||
competitor_price=1150,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "multi_component_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_multi_variant_catalog_listings():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【日本John’s Blend】香氛擴香罐85g(車用/任選/白麝香/黑麝香/茉莉/櫻花/繡球花/魔髮奇緣/青檸羅勒)",
|
||
"日本John’s Blend 車用香氛擴香罐85g(多款可選)",
|
||
),
|
||
(
|
||
"【日本John’s Blend】香氛擴香罐85g 任選3入((車用/任選/白麝香/黑麝香/茉莉/櫻花/繡球花/魔髮奇緣))",
|
||
"日本John’s Blend 車用香氛擴香罐85g 3入組",
|
||
),
|
||
(
|
||
"【COCODOR】香氛蠟燭170g(多款任選/官方直營)",
|
||
"COCODOR Premium Jar Candle 香氛精油蠟燭170g(多種香味任選)",
|
||
),
|
||
(
|
||
"【COCODOR】香氛蠟燭95g(多款任選/官方直營)",
|
||
"COCODOR Premium Jar Candle 香氛精油蠟燭95g(多種香味任選)",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name)
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert (
|
||
"catalog_variant_listing_alignment" in diagnostics.reasons
|
||
or "strong_exact_spec_match" in diagnostics.reasons
|
||
)
|
||
|
||
|
||
def test_marketplace_matcher_requires_non_brand_product_line_evidence():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【CEZANNE】柔潤腮紅",
|
||
"Cezanne",
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert "strong_product_line_match" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_baan_lip_catalog_with_same_options():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Baan 貝恩】嬰兒修護唇膏(草莓/原味) 4.5g/個 (新東海藥局)",
|
||
"【貝恩】嬰兒修護唇膏(原味/草莓)",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "catalog_variant_listing_alignment_baan_lip" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_kiehls_no1_lip_balm_as_product_line_not_color_number():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【契爾氏】官方直營 1號護唇膏15ml(Kiehl’s)",
|
||
"KIEHL’S 一號護唇膏 (原味) 15ml",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "variant_option_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_pshine_beauty_foot_file_identity_review():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【P.SHINE BEAUTY FOOT】日本製雙面足部去角質硬皮磨砂棒 足搓棒(日本進口)",
|
||
"P.SHINE BEAUTY FOOT 雙面足部去硬皮磨砂棒(日本製)",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "shared_model_token_pshine_beauty_foot_file" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_multi_color_catalog_against_single_color_candidate():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【L‘Original London 洛瑞歐】官方直營 皇家小羊皮車用香氛禮盒 琥珀橙/干邑棕/賽車綠 生日禮物送",
|
||
"英國L’Original精品小羊皮車用香氛禮盒-干邑棕(平行輸入)",
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "variant_option_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_starter_set_against_single_lotion():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【理膚寶水】安心抗敏入門組★多容安舒緩濕潤乳液_A(安心乳液/敏感肌保濕)",
|
||
"理膚寶水 多容安舒緩濕潤乳液 40ml",
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "bundle_offer_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_focused_low_score_exact_identity_lines():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
cases = [
|
||
(
|
||
"【Biodance】深層保濕面膜/膠原蛋白深層全效面膜 4片入(補水面膜 韓國 保濕 小分子玻尿酸)",
|
||
"【Biodance】實感深層全效面膜 4片(多重保濕鎮靜/膠原蛋白)",
|
||
"focused_exact_identity_biodance_deep_mask",
|
||
),
|
||
(
|
||
"【SAB 初淨肌】私密防護舒緩噴霧30mlX1入(私密舒緩/私密保養/日本愛宕柿淨味/洋甘菊/保濕/私密肌專用)",
|
||
"初淨肌 SAB 私密防護舒緩噴霧 30ml*1入",
|
||
"focused_exact_identity_sab_private_spray",
|
||
),
|
||
(
|
||
"【LUSH 嵐舒】櫻之花身體噴霧 200ml(香氛噴霧/茉莉花/檸檬/含羞草/苦橙花/花香)",
|
||
"英國原裝LUSH 櫻之花身體噴霧200ml Sakura Body Spray",
|
||
"focused_exact_identity_lush_sakura_body_spray",
|
||
),
|
||
(
|
||
"【Kanebo 佳麗寶】COFFRET D’OR 光透立體眼線筆蕊/眼線液蕊(多色任選)",
|
||
"【Kanebo 佳麗寶】COFFRET D’OR光透立體眼線筆(蕊)0.11g",
|
||
"focused_exact_identity_kanebo_coffret_eyeliner",
|
||
),
|
||
(
|
||
"【Play&Joy 官方直營】ARTMIS 葳兒柔私密賦活凝膠35ml(私密精華 體感升級 靈芝外泌體 費洛蒙香氛 親密互動)",
|
||
"ARTMIS葳兒柔賦活凝膠35ml",
|
||
"focused_exact_identity_artmis_virile_gel",
|
||
),
|
||
(
|
||
"【Nailmatic】兒童水漾亮彩指甲油 - 小精靈(兒童專用指甲油)",
|
||
"nailmatic 兒童指甲油(Casper小精靈)",
|
||
"focused_exact_identity_nailmatic_casper_polish",
|
||
),
|
||
(
|
||
"【小浪】智能感應自動噴香機+補充液3入組(三種噴香模式 霧化噴香 芳香除臭)",
|
||
"小浪智能感應自動噴香機+補充液3入組",
|
||
"focused_exact_identity_xiaolang_spray_machine_refill_set",
|
||
),
|
||
(
|
||
"【YUNMI】J10濕度數顯智能加濕器 雙噴頭納米霧化水氧機 香氛機 噴霧器 空氣清淨機 增濕器",
|
||
"YUNMI J10濕度數顯智能加濕器",
|
||
"focused_exact_identity_yunmi_j10_humidifier",
|
||
),
|
||
(
|
||
"【AQUIESSE】美國大豆蠟香氛蠟燭 5oz/141g(多款任選.清新茶香木質果香)",
|
||
"【AQUIESSE】香氛蠟燭 5oz 多款任選",
|
||
"focused_exact_identity_aquiesse_5oz_candle_catalog",
|
||
),
|
||
(
|
||
"【REJURAN 麗珠蘭】官方直營|麗駐蘭修復舒緩面膜5P(補水 保濕)|台灣總代理 動物性 PDRN",
|
||
"REJURAN 麗駐蘭修復舒緩面膜5P",
|
||
"focused_exact_identity_rejuran_repair_mask_5p",
|
||
),
|
||
(
|
||
"【SHISEIDO 資生堂國際櫃】新艷陽•夏 水離子熱防禦UV隔離露 SPF50(防曬/防曬乳/清爽/不黏膩)",
|
||
"《SHISEIDO 資生堂》新艷陽夏水離子熱防禦隔離露 50ml",
|
||
"focused_exact_identity_shiseido_blue_sunscreen",
|
||
),
|
||
(
|
||
"【Baan 貝恩】嬰兒修護唇膏4.5g",
|
||
"【貝恩】嬰兒修護唇膏(原味/草莓)",
|
||
"focused_exact_identity_baan_baby_lip_base_catalog",
|
||
),
|
||
(
|
||
"【植村秀】官方直營 3D極細防水眼線膠筆(Shu uemura)",
|
||
"《Shu Uemura 植村秀》3D極細防水眼線膠筆 0.08g-#深棕",
|
||
"focused_exact_identity_shu_3d_eyeliner",
|
||
),
|
||
(
|
||
"【YSL】官方直營 恆久完美透膚煙染腮紅(任選1款/新品上市)",
|
||
"【YSL聖羅蘭】恆久完美透膚煙染腮紅 6g ( #12/ #57/ #93)",
|
||
"focused_exact_identity_ysl_blush_catalog",
|
||
),
|
||
(
|
||
"【HH草本新淨界】私密植萃美白緊緻凝露30ml(私密美白 保濕緊緻 私密緊實)",
|
||
"HH 私密植萃美白緊緻凝露(30ml)",
|
||
"focused_exact_identity_hh_private_gel",
|
||
),
|
||
(
|
||
"【Lab52 齒妍堂】學習刷牙漱口水170g/瓶(食品級配方/牙菌斑顯示劑/口腔清潔居家檢測)",
|
||
"Lab52齒妍堂 汪汪隊立大功學習刷牙漱口水170g",
|
||
"focused_exact_identity_lab52_mouthwash",
|
||
),
|
||
(
|
||
"【benefit 貝玲妃】經典染唇液(唇頰兩用/持久不脫妝)",
|
||
"【Benefit】經典菲菲染唇液6ml(唇頰兩用/持久不脫妝)多色",
|
||
"focused_exact_identity_benefit_lip_tint",
|
||
),
|
||
(
|
||
"【草本24】Herb24 晨霧純精油擴香儀II_霧黑-無須用水(贈-紅桔 純質精油)(歐盟EMC證書 主機享半年保固)",
|
||
"【草本24。Herb24】晨霧純精油擴香儀II_黑色(贈:任選價值780元純質精油10ml)",
|
||
"focused_exact_identity_herb24_mist_diffuser_black",
|
||
),
|
||
(
|
||
"【Pavaruni】美國天然植物精油40香味10ml(香薰 擴香 萃取 薰香機 水氧機 薰衣草 檀香 玫瑰 雪松 白茶 茉莉)",
|
||
"【美國Pavaruni】天然植物香氛精油40種香味10ml 多款任選",
|
||
"focused_exact_identity_pavaruni_40_scent_oil",
|
||
),
|
||
(
|
||
"【Pavaruni】美國香氛蠟燭20種香味450g(禮盒大豆蠟植物天然精油花香木質果香生日聖誕交換女友女生情人禮物)",
|
||
"【美國Pavaruni】香氛蠟燭20種香味450g 卡啡那系列 多款任選",
|
||
"focused_exact_identity_pavaruni_20_scent_candle",
|
||
),
|
||
(
|
||
"【日本Laundrin朗德林】TOKYO汽車空調出風口專用夾式消臭芳香劑1入/袋(車用清新擴香劑香氛淨化馨香約30天)",
|
||
"日本Laundrin朗德林-TOKYO車用夾式消臭芳香劑1入/袋",
|
||
"focused_exact_identity_laundrin_tokyo_car_freshener",
|
||
),
|
||
(
|
||
"【好物良品】北歐簡樸融蠟燈桌面氣氛夜燈|附燈泡(氛圍燈 室內芳香 交換禮物 桌上檯燈 香氛蠟燭 擴香)",
|
||
"【好物良品】北歐簡樸融蠟燈桌面氣氛夜燈(2款任選|附燈泡)",
|
||
"focused_exact_identity_goodgoods_nordic_wax_lamp",
|
||
),
|
||
(
|
||
"【Derma 丹麥德瑪】大地有機植萃撫紋護膚油 150ml(有機植物油複合配方 滋潤不黏膩)",
|
||
"Derma 大地 Eco 有機植萃護膚油 150ml",
|
||
"focused_exact_identity_derma_eco_skin_oil",
|
||
),
|
||
(
|
||
"【悠斯晶】日本No.1維他命乳霜★經典乳霜30g(攜帶型 6入組)",
|
||
"【Yuskin悠斯晶】A乳霜 攜帶型 6盒組(30g/盒)",
|
||
"focused_exact_identity_yuskin_classic_cream_30g_6pack",
|
||
),
|
||
(
|
||
"【Herbacin 德國小甘菊】小甘菊1號護手霜20ml",
|
||
"小甘菊經典護手霜20ml",
|
||
"focused_exact_identity_herbacin_classic_hand_cream_20ml_brandless",
|
||
),
|
||
(
|
||
"【Johnsons 嬌生】嬰兒潤膚乳500ml_嬰兒乳液(牛奶/純淨/甜夢/溫和/棉柔_任選)",
|
||
"嬌生嬰兒甜夢潤膚乳500ml",
|
||
"focused_exact_identity_johnsons_baby_lotion_variant_catalog",
|
||
),
|
||
(
|
||
"【Johnsons 嬌生】嬰兒潤膚乳500mlx3(牛奶/純淨/甜夢/溫和/棉柔任選_嬰兒乳液)",
|
||
"嬌生嬰兒 純淨潤膚乳500mlx3",
|
||
"focused_exact_identity_johnsons_baby_lotion_variant_catalog",
|
||
),
|
||
(
|
||
"【im meme】我愛超磁妝定妝噴霧60ml(涼感/一般)",
|
||
"【I’M MEME】我愛超磁妝定妝噴霧-涼感控油",
|
||
"focused_exact_identity_im_meme_fixx_cool_setting_spray",
|
||
),
|
||
(
|
||
"【SO NATURAL】FIXX 全天候超完美定妝噴霧 經典款/光澤款/霧面款/夏日款",
|
||
"【SO NATURAL】FIXX 全天候超完美定妝噴霧 120ml",
|
||
"focused_exact_identity_so_natural_fixx_setting_spray_catalog",
|
||
),
|
||
(
|
||
"【KATE 凱婷】怪獸級持色唇膏-經典款(獨家技術持久不沾 高保濕)",
|
||
"【KATE 凱婷】怪獸級持色唇膏 (3g)",
|
||
"focused_exact_identity_kate_monster_lipstick_catalog",
|
||
),
|
||
(
|
||
"【植村秀】官方直營 自動武士刀眉筆筆蕊(Shu uemura/筆蕊 8色任選)",
|
||
"《Shu Uemura 植村秀》自動武士刀眉筆 -筆蕊 0.3g",
|
||
"focused_exact_identity_shu_auto_hard_formula_refill_catalog",
|
||
),
|
||
(
|
||
"【The Forest 癒森林】焦糖楓葉香氛擴香花禮盒 含30ml品牌香氛油(居家香氛/香水精油/香氛擴香花/擴香禮物)",
|
||
"焦糖楓葉香氛擴香花禮盒 含30ml品牌香氛油",
|
||
"focused_exact_identity_the_forest_maple_diffuser_flower_brandless",
|
||
),
|
||
(
|
||
"【O.P.I】類光繚指甲油 12色任選1瓶(小銀蓋/如膠似漆白日夢遊系列指彩/官方直營)",
|
||
"OPI 如膠似漆白日夢遊系列 類光繚指甲油12色任選",
|
||
"focused_exact_identity_opi_gel_polish_series_catalog",
|
||
),
|
||
(
|
||
"【O.P.I】類光繚指甲油 12色任選1瓶(小銀蓋/如膠似漆驕傲果凍系列指彩/官方直營)",
|
||
"OPI 如膠似漆驕傲果凍系列 類光繚指甲油11色任選",
|
||
"focused_exact_identity_opi_gel_polish_series_catalog",
|
||
),
|
||
(
|
||
"即期品【Summer’s Eve 舒摩兒】全肌防護浴潔露2入(私密清潔 經典防護王)無外盒裸瓶包裝",
|
||
"eve舒摩兒 賦活美學浴潔露-全肌防護 2入組",
|
||
"focused_exact_identity_summer_eve_full_skin_wash_2pack",
|
||
),
|
||
(
|
||
"【rom&nd】果汁唇釉 2.0(the juicy 果汁唇釉 romand)",
|
||
"rom&nd 果汁唇釉2.0_3.5g_多款可選",
|
||
"focused_exact_identity_romand_juicy_lip_tint_2_catalog",
|
||
),
|
||
(
|
||
"【Solone】持久眼線筆(眼線膠 超防暈推薦)",
|
||
"Solone 持久眼線筆 1.5g",
|
||
"focused_exact_identity_solone_longlasting_eyeliner",
|
||
),
|
||
(
|
||
"【GATSBY】爆水擦澡濕巾24張入(涼感乾洗澡)",
|
||
"GATSBY 爆水擦澡濕巾24張入(240g)",
|
||
"focused_exact_identity_gatsby_body_wipes_24",
|
||
),
|
||
]
|
||
|
||
for momo_name, competitor_name, expected_reason in cases:
|
||
diagnostics = score_marketplace_match(momo_name, competitor_name)
|
||
assert diagnostics.score >= 0.76, (momo_name, diagnostics)
|
||
assert diagnostics.hard_veto is False
|
||
assert expected_reason in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_high_variant_low_score_lines_outside_focused_promotion():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
lush = score_marketplace_match(
|
||
"【LUSH 嵐舒】Sticky Dates 椰棗布丁身體噴霧 200ml(香氛噴霧/安息香/檀木/甜蜜香氣)",
|
||
"英國原裝LUSH 睡公主身體噴霧200ml Sleepy Body Spray",
|
||
)
|
||
lactacyd = score_marketplace_match(
|
||
"【Lactacyd 立朵舒】清新舒涼 私密潔浴露250ml(天然薄荷涼感 私密清潔 私密保養 乾癢修護)",
|
||
"Lactacyd 立朵舒私密潔浴露-生理呵護250ml",
|
||
)
|
||
lunasol = score_marketplace_match(
|
||
"即期品【Kanebo 佳麗寶】LUNASOL 晶巧霓光/明艷頰彩(多色任選)",
|
||
"【Kanebo 佳麗寶】LUNASOL 晶巧霓光眼彩寵愛組",
|
||
)
|
||
muji_swab = score_marketplace_match(
|
||
"【MUJI 無印良品】細軸棉棒/200支",
|
||
"【MUJI 無印良品】棉棒(黑色)/200支",
|
||
)
|
||
kate_limited = score_marketplace_match(
|
||
"【KATE 凱婷】絕美綻放睫毛膏(NANA限量聯名款)",
|
||
"【KATE 凱婷】絕美綻放睫毛膏 7.1g",
|
||
)
|
||
schick_bundle_gap = score_marketplace_match(
|
||
"【Schick 舒適牌】舒芙仕女除毛刀把刀片組 (1刀把2刀片+刀片3入)",
|
||
"【Schick舒適牌】舒綺 仕女除毛刀 敏感肌用 1刀把+2刀片 送卡娜赫拉束口袋",
|
||
)
|
||
lancome_line_gap = score_marketplace_match(
|
||
"【LANCOME 蘭蔻】官方直營 超極光活粹晶露150ml(LANCOME/四重酸極光水/化妝水/精華水)",
|
||
"LANCOME 蘭蔻 超極限肌因精華露150ml 專櫃公司貨",
|
||
)
|
||
mac_finish_gap = score_marketplace_match(
|
||
"【M.A.C】MACximal極自我柔霧唇膏3.5g(子彈唇膏 #柔霧大巨彈_全新質地_新色登場)",
|
||
"M.A.C MACximal 極自我緞光唇膏 3.5g 多款可選",
|
||
)
|
||
ysl_powder_variant_guard = score_marketplace_match(
|
||
"【YSL】官方直營 恆久完美持久柔霧蜜粉餅(任選1款/皮革蜜粉)",
|
||
"YSL 恆久完美持久柔霧蜜粉餅(7.5g) [百貨公司專櫃貨]",
|
||
)
|
||
opi_series_gap = score_marketplace_match(
|
||
"【O.P.I】類光繚指甲油 12色任選1瓶(小銀蓋/如膠似漆白日夢遊系列指彩/官方直營)",
|
||
"OPI 如膠似漆驕傲果凍系列 類光繚指甲油11色任選",
|
||
)
|
||
romand_line_gap = score_marketplace_match(
|
||
"【rom&nd】水感唇釉",
|
||
"rom&nd 果汁唇釉5.5g_多款可選",
|
||
)
|
||
peripera_variant_gap = score_marketplace_match(
|
||
"【peripera官方直營】雙頭旋轉極細眉筆_多色任選(1.5mm極細筆頭)",
|
||
"PERIPERA 雙頭旋轉極細眉筆 09灰褐棕 0.05g",
|
||
)
|
||
summer_eve_variant_gap = score_marketplace_match(
|
||
"即期品【Summer’s Eve 舒摩兒】全肌防護浴潔露2入(私密清潔 經典防護王)無外盒裸瓶包裝",
|
||
"eve舒摩兒 生理呵護浴潔露 2入組",
|
||
)
|
||
solone_type_gap = score_marketplace_match(
|
||
"【Solone】持久眼線筆(眼線膠 超防暈推薦)",
|
||
"Solone 斜角眉筆 0.35g",
|
||
)
|
||
erbe_tool_gap = score_marketplace_match(
|
||
"ERBE 德國不鏽鋼指甲清垢棒",
|
||
"ERBE 德國雙頭指甲緣刨刀",
|
||
)
|
||
mirae_count_gap = score_marketplace_match(
|
||
"【MIRAE 未來美】EX8分鐘極速面膜 5片(補水/淨白/舒緩/修護)",
|
||
"未來美EX8分鐘極速補水/淨白/舒緩/修護面膜x8",
|
||
)
|
||
gonesh_scent_gap = score_marketplace_match(
|
||
"【GONESH】室內汽車用香氛固體凝膠78g(持久芳香)",
|
||
"【日本GONESH】室內汽車用香氛固體凝膠空氣芳香劑(No.4號 藤蔓果園78g/罐 長效8週持久芳香型)",
|
||
)
|
||
sunscreen_line_gap = score_marketplace_match(
|
||
"【我的心機】溫和寶貝兒童防曬乳35ml(SPF50+ PA+++)",
|
||
"我的心機 海洋友善保濕高效防曬乳35ml(SPF50+PA++++)",
|
||
)
|
||
|
||
for diagnostics in (
|
||
lush,
|
||
lactacyd,
|
||
lunasol,
|
||
muji_swab,
|
||
kate_limited,
|
||
schick_bundle_gap,
|
||
lancome_line_gap,
|
||
mac_finish_gap,
|
||
ysl_powder_variant_guard,
|
||
opi_series_gap,
|
||
romand_line_gap,
|
||
peripera_variant_gap,
|
||
summer_eve_variant_gap,
|
||
solone_type_gap,
|
||
erbe_tool_gap,
|
||
mirae_count_gap,
|
||
gonesh_scent_gap,
|
||
sunscreen_line_gap,
|
||
):
|
||
assert diagnostics.score < 0.76
|
||
assert not any(reason.startswith("focused_exact_identity_") for reason in diagnostics.reasons)
|
||
|
||
assert sunscreen_line_gap.hard_veto is True
|
||
assert "variant_descriptor_conflict" in sunscreen_line_gap.reasons
|
||
assert lactacyd.hard_veto is True
|
||
assert "lactacyd_variant_conflict" in lactacyd.reasons
|
||
assert lunasol.hard_veto is True
|
||
assert "makeup_usage_conflict" in lunasol.reasons
|
||
assert muji_swab.hard_veto is True
|
||
assert "cotton_swab_variant_conflict" in muji_swab.reasons
|
||
assert mirae_count_gap.hard_veto is True
|
||
assert "count_conflict" in mirae_count_gap.reasons
|
||
assert gonesh_scent_gap.hard_veto is True
|
||
assert "aroma_scent_variant_conflict" in gonesh_scent_gap.reasons
|
||
assert lancome_line_gap.hard_veto is True
|
||
assert "lancome_line_conflict" in lancome_line_gap.reasons
|
||
assert peripera_variant_gap.hard_veto is False
|
||
assert "variant_selection_review" in peripera_variant_gap.reasons
|
||
assert mac_finish_gap.hard_veto is True
|
||
assert "makeup_finish_conflict" in mac_finish_gap.reasons
|
||
assert schick_bundle_gap.hard_veto is True
|
||
assert "schick_razor_line_conflict" in schick_bundle_gap.reasons
|
||
assert erbe_tool_gap.hard_veto is True
|
||
assert "nail_tool_function_conflict" in erbe_tool_gap.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_saugella_private_wash_variant_gap():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
for momo_name in (
|
||
"【SAUGELLA 賽吉兒】菁萃潔浴凝露日用250ml二入組",
|
||
"【SAUGELLA 賽吉兒】菁萃潔浴凝露加強250ml二入組",
|
||
):
|
||
diagnostics = score_marketplace_match(
|
||
momo_name,
|
||
"SAUGELLA賽吉兒 pH3.5菁萃婦潔凝露【黃金女郎型】250ml(2入特惠)",
|
||
momo_price=1080,
|
||
competitor_price=990,
|
||
)
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "saugella_variant_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_dr_hsieh_labsmart_vs_repair_serum_line_gap():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
for momo_name in (
|
||
"【Dr.Hsieh 達特醫】官方直營★LabSmart Hi-Tech精華50ml-無盒(神經醯胺/A醇/維生素B3)",
|
||
"【Dr.Hsieh 達特醫】官方直營★LabSmart Classic精華50ml-無盒(神經醯胺/A醇/維生素B3/維生素C醣甘)",
|
||
):
|
||
diagnostics = score_marketplace_match(
|
||
momo_name,
|
||
"Dr.Hsieh達特醫 神經醯胺多重修復保濕精華液50ml",
|
||
momo_price=550,
|
||
competitor_price=960,
|
||
)
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "dr_hsieh_labsmart_line_conflict" in diagnostics.reasons
|
||
|
||
same_line = score_marketplace_match(
|
||
"Dr.Hsieh達特醫 神經醯胺多重修復保濕精華液50ml",
|
||
"Dr.Hsieh 達特醫 神經醯胺多重修復保濕精華液 50ml",
|
||
)
|
||
assert "dr_hsieh_labsmart_line_conflict" not in same_line.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_kanebo_milano_powder_vs_perfume_type_gap():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Kanebo 佳麗寶】Milano Collection 2024絕色蜜粉餅GR 30g",
|
||
"Kanebo Milano Collection 2026 絕色香水30mL",
|
||
momo_price=3500,
|
||
competitor_price=2900,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "kanebo_milano_type_conflict" in diagnostics.reasons
|
||
|
||
same_powder = score_marketplace_match(
|
||
"【Kanebo 佳麗寶】Milano Collection 2024絕色蜜粉餅GR 30g",
|
||
"Kanebo Milano Collection 2024 絕色蜜粉餅 GR 30g",
|
||
)
|
||
assert "kanebo_milano_type_conflict" not in same_powder.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_hoi_candle_product_line_gap():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【hoi! 好好生活】日京山風香氛天然蠟燭150g",
|
||
"hoi!LAB 實驗室香氛天然大豆香氛蠟燭經典篇 150g",
|
||
momo_price=780,
|
||
competitor_price=699,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "hoi_candle_line_conflict" in diagnostics.reasons
|
||
|
||
same_line = score_marketplace_match(
|
||
"【hoi! 好好生活】日京山風香氛天然蠟燭150g",
|
||
"hoi! 日京山風 香氛天然蠟燭 150g",
|
||
)
|
||
assert "hoi_candle_line_conflict" not in same_line.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_refill_core_vs_case_only_pack():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【KATE 凱婷】3D造型眉彩餅補充芯(眉彩刷、眉餅盒分開販售)",
|
||
"【KATE 凱婷】眉彩餅盒一入款(搭配3D造型眉彩餅補充芯)",
|
||
momo_price=280,
|
||
competitor_price=280,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "accessory_case_conflict" in diagnostics.reasons or "refill_pack_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_suppresses_wide_price_penalty_for_exact_lip_product():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【REJURAN 麗珠蘭】官方直營|REJURAN 麗駐蘭唇膏 3.7g|台灣總代理 動物性 PDRN",
|
||
"REJURAN 麗駐蘭唇膏 3.7g",
|
||
momo_price=169,
|
||
competitor_price=380,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "price_penalty_suppressed_wide_exact_identity" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_mac_brand_alias_and_exact_compact_name():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【M.A.C】口袋雙色修容打亮盤 7g(國際航空版)",
|
||
"【MAC】口袋雙色修容打亮盤 7g",
|
||
momo_price=1200,
|
||
competitor_price=1200,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
|
||
|
||
def test_marketplace_matcher_promotes_yuskin_bundle_when_only_bundle_wording_differs():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【悠斯晶】經典乳霜120g(4入組)",
|
||
"【Yuskin悠斯晶】經典乳霜 4盒組(120g/盒)",
|
||
momo_price=1200,
|
||
competitor_price=1200,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "variant_descriptor_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_ahc_line_with_keyword_reordering():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【AHC】瞬效B5微導玻尿酸保濕精華液30ml_3入(右旋B5/玻尿酸/保濕霸主/高效修護/敏感肌/醫美後適用)",
|
||
"【AHC】瞬效保濕B5微導 玻尿酸精華 30ML 3入組",
|
||
momo_price=1200,
|
||
competitor_price=1200,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor_reordered_line" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_bundle_equivalent_when_count_matches():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【悠斯晶】經典乳霜120g(4入組)",
|
||
"【Yuskin悠斯晶】經典乳霜 4盒組(120g/盒)",
|
||
momo_price=1200,
|
||
competitor_price=1200,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert "shared_identity_anchor_bundle_equivalent" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_same_count_different_unit_family():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"品牌 保濕面膜10片",
|
||
"品牌 保濕面膜10盒",
|
||
momo_price=399,
|
||
competitor_price=1990,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "count_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_marks_generic_bundle_words_as_unit_comparable():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【NARS】裸光蜜粉餅 雙件組 10g",
|
||
"【NARS】裸光蜜粉餅 10g",
|
||
momo_price=1999,
|
||
competitor_price=1099,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert "bundle_offer_conflict" in diagnostics.reasons
|
||
assert diagnostics.comparison_mode == "unit_comparable"
|
||
|
||
|
||
def test_marketplace_matcher_ignores_non_brand_bracket_copy():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【保濕組】理膚寶水 B5 修復霜 40ml",
|
||
"理膚寶水 B5 修復霜 40ml",
|
||
momo_price=699,
|
||
competitor_price=679,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_uses_brand_alias_and_chinese_line_signal():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【CLARINS 克蘭詩】黃金雙激萃50ml",
|
||
"克蘭詩 黃金雙萃精華 50ml",
|
||
momo_price=4500,
|
||
competitor_price=3549,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
assert "spec_match" in diagnostics.tags
|
||
|
||
|
||
def test_marketplace_matcher_matches_cetaphil_alias():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"舒特膚 AD 乳液 200ml",
|
||
"Cetaphil AD 乳液 200ml",
|
||
momo_price=980,
|
||
competitor_price=899,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.9
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
|
||
|
||
def test_marketplace_matcher_treats_piece_unit_synonyms_as_same_pack():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"品牌 葉黃素 10mg 60粒",
|
||
"品牌 葉黃素 10毫克 60錠",
|
||
momo_price=990,
|
||
competitor_price=890,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "count_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_normalizes_buy_get_pack_evidence():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"NARS 裸光蜜粉餅 買1送1 10g",
|
||
"NARS 裸光蜜粉餅 10g x2",
|
||
momo_price=1999,
|
||
competitor_price=1099,
|
||
)
|
||
|
||
assert diagnostics.comparison_mode == "unit_comparable"
|
||
assert "unit_comparable" in diagnostics.reasons
|
||
assert "count_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_accepts_strong_multi_component_line_without_full_specs():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Gennies 奇妮】COSVITAL乳頭霜50ml+滋潤彈力霜100ml+修復彈力霜100ml(金燦極緻法國頂級孕期產後保養組)",
|
||
"Gennies奇妮 COSVITAL 金燦極緻法國頂級保養(乳頭霜+滋潤彈力霜+修復彈力霜)(801062+801081+801082)",
|
||
momo_price=6980,
|
||
competitor_price=6980,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.comparison_mode == "exact_identity"
|
||
assert "strong_component_line_match" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_accepts_known_brand_alias_and_option_copy():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【OBgE】韓國 OBgE 男士自然遮瑕粉底棒13g",
|
||
"OBgE/自然遮瑕粉底棒13g - 多款可選",
|
||
momo_price=765,
|
||
competitor_price=1099,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.comparison_mode == "exact_identity"
|
||
|
||
|
||
def test_marketplace_matcher_accepts_same_pack_with_chinese_count_wording():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【SEBAMED】潔膚露1000ml共2入(大容量 平行輸入)",
|
||
"Sebamed施巴 潔膚露1000ml 兩入組",
|
||
momo_price=799,
|
||
competitor_price=899,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "brand_match" in diagnostics.tags
|
||
|
||
|
||
def test_marketplace_matcher_rejects_razor_series_and_blade_count_conflict():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Gillette 吉列】SkinGuard 紳適系列刮鬍刀頭(4刀頭)",
|
||
"【Gillette 吉列 】Fusion鋒隱系列刮鬍刀頭(8刀頭)",
|
||
momo_price=499,
|
||
competitor_price=906,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert "count_conflict" in diagnostics.reasons
|
||
assert "model_line_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_safe_exact_spec_near_threshold():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
opi = score_marketplace_match(
|
||
"【O.P.I】Top Coat 持久閃耀保色護甲油15mL-IST31(類光繚指甲油專用亮油/小銀蓋/如膠似漆/美甲/官方直營)",
|
||
"OPI 官方直營.持久閃耀保色護甲油15mL-IST31.如膠似漆閃耀系列",
|
||
momo_price=578,
|
||
competitor_price=680,
|
||
)
|
||
mustela = score_marketplace_match(
|
||
"【Mustela 慕之恬廊】慕之幼 免用水潔淨液 300ml(外出清潔 卸除髒汙 卸除防曬 卸防曬)",
|
||
"Mustela慕之恬廊 慕之幼免用水潔淨液300ml",
|
||
momo_price=275,
|
||
competitor_price=398,
|
||
)
|
||
romand = score_marketplace_match(
|
||
"【rom&nd】韓國 Rom&nd 果汁唇釉 5.5g(韓國彩妝 唇釉 唇彩 果汁 水光感)",
|
||
"rom&nd 果汁唇釉5.5g_多款可選",
|
||
momo_price=211,
|
||
competitor_price=319,
|
||
)
|
||
muji_hand_cream = score_marketplace_match(
|
||
"【MUJI 無印良品】精油芬香護手霜 50g",
|
||
"MUJI 無印良品 精油芬香護手霜/薰衣草&迷迭香/50g",
|
||
)
|
||
muji_brandless_hand_cream = score_marketplace_match(
|
||
"【MUJI 無印良品】精油芬香護手霜/50g(薰衣草&迷迭香/葡萄柚&柳橙/檜木&佛手柑)",
|
||
"精油芬香護手霜/薰衣草&迷迭香/50g",
|
||
)
|
||
mustela_lotion_2pack = score_marketplace_match(
|
||
"【Mustela 慕之恬廊】慕之幼 爽身潤膚乳500mlX2",
|
||
"Mustela慕之恬廊 慕之幼爽身潤膚乳500mlX2",
|
||
)
|
||
mustela_lotion_2pack_production_title = score_marketplace_match(
|
||
"【Mustela 慕之恬廊】慕之幼 加量版爽身潤膚乳 500mlX2入(寶寶 嬰兒乳液 公司貨 台灣獨家總代理)",
|
||
"【慕之恬廊】慕之幼爽身潤膚乳(500毫升X2入)",
|
||
momo_price=1390,
|
||
competitor_price=1210,
|
||
)
|
||
herbacin_hand_cream = score_marketplace_match(
|
||
"【Herbacin 德國小甘菊】小甘菊1號護手霜20ml",
|
||
"Herbacin 小甘菊經典護手霜20ml",
|
||
)
|
||
|
||
for diagnostics in (
|
||
opi,
|
||
mustela,
|
||
romand,
|
||
muji_hand_cream,
|
||
mustela_lotion_2pack,
|
||
mustela_lotion_2pack_production_title,
|
||
herbacin_hand_cream,
|
||
):
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "strong_exact_spec_match" in diagnostics.reasons
|
||
|
||
assert any(
|
||
reason.startswith("shared_identity_anchor")
|
||
for reason in mustela_lotion_2pack_production_title.reasons
|
||
)
|
||
|
||
assert muji_brandless_hand_cream.score >= 0.76
|
||
assert muji_brandless_hand_cream.hard_veto is False
|
||
assert "focused_exact_identity_muji_aroma_hand_cream_brandless" in muji_brandless_hand_cream.reasons
|
||
assert "variant_selection_review" in muji_brandless_hand_cream.reasons
|
||
|
||
|
||
def test_marketplace_matcher_does_not_promote_different_option_without_spec():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【DASHING DIVA】MAGICPRESS時尚潮流美甲片_極光之藍",
|
||
"Dashing Diva/F 時尚潮流美甲片-月光銀影 MDF5F010AG",
|
||
momo_price=331,
|
||
competitor_price=420,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert "strong_exact_spec_match" not in diagnostics.reasons
|
||
assert "variant_descriptor_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_named_option_vs_catalog_in_review():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【DASHING DIVA】MAGICPRESS時尚潮流美甲片_極光之藍",
|
||
"DASHING DIVA MAGIC PRESS 時尚潮流美甲片 多款任選",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "variant_selection_review" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_kate_catalog_vs_single_variant_in_review():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【KATE 凱婷】怪獸級持色唇膏 水光款/經典款/微發色款(獨家技術持久不沾 高保濕)",
|
||
"【KATE 凱婷】怪獸級持色唇膏(水光) 1.6g",
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.price_basis == "manual_review"
|
||
assert diagnostics.alert_tier == "identity_review"
|
||
assert "variant_selection_review" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_variant_safe_exact_option():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【DASHING DIVA】MAGICPRESS時尚潮流美甲片_極光之藍",
|
||
"Dashing Diva/F 時尚潮流美甲片-極光之藍 MDF5F001AG",
|
||
momo_price=331,
|
||
competitor_price=420,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_variant_safe" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_allows_catalog_piece_count_for_exact_dashing_diva_variant():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【DASHING DIVA】MAGICPRESS 時尚潮流美甲片-銀河綠波(貓眼 漸層)",
|
||
"Dashing Diva/F 時尚潮流美甲片-銀河綠波 30片/盒 MDF5F012AG",
|
||
momo_price=399,
|
||
competitor_price=420,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "count_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_rejects_explicit_shade_option_mismatch():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
lipstick = score_marketplace_match(
|
||
"【Maybelline 媚比琳】超持久水光鎖吻唇釉#62 4.2ml",
|
||
"MAYBELLINE 媚比琳 超持久水光鎖吻唇釉 #120 4.2ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
primer = score_marketplace_match(
|
||
"【植村秀】水凝光透妝前防護乳 紫色 30ml",
|
||
"植村秀 水凝光透妝前防護乳 粉色 30ml",
|
||
momo_price=1200,
|
||
competitor_price=1100,
|
||
)
|
||
|
||
for diagnostics in (lipstick, primer):
|
||
assert diagnostics.hard_veto is True
|
||
assert diagnostics.comparison_mode == "not_comparable"
|
||
assert diagnostics.score < 0.76
|
||
assert "variant_option_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_accepts_same_explicit_shade_option():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Maybelline 媚比琳】超持久水光鎖吻唇釉#62 4.2ml",
|
||
"MAYBELLINE 媚比琳 超持久水光鎖吻唇釉 #62 4.2ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.hard_veto is False
|
||
assert diagnostics.comparison_mode == "exact_identity"
|
||
assert diagnostics.score >= 0.76
|
||
assert "variant_option_conflict" not in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_shared_identity_anchor_near_threshold():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
obge = score_marketplace_match(
|
||
"【OBgE】自然遮瑕素顏霜 50g",
|
||
"OBgE/自然遮瑕素顏霜50g",
|
||
momo_price=699,
|
||
competitor_price=699,
|
||
)
|
||
unicat = score_marketplace_match(
|
||
"【UNICAT 變臉貓】超持久細滑眼線筆1.5ml",
|
||
"【UNICAT】超持久細滑眼線筆 1.5ml 新品搶先優惠",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
for diagnostics in (obge, unicat):
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_contained_identity_anchor_with_same_spec():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
sebamed = score_marketplace_match(
|
||
"【Sebamed】女性私密處護潔露200ml",
|
||
"Sebamed私密護潔露(pH6.8)黃金女郎型200ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
lab52 = score_marketplace_match(
|
||
"【Lab52 齒妍堂】兒童口腔清潔棒30入/盒",
|
||
"Lab52齒妍堂 兒童口腔清潔棒30入",
|
||
momo_price=299,
|
||
competitor_price=299,
|
||
)
|
||
|
||
for diagnostics in (sebamed, lab52):
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor" in lab52.reasons or "shared_identity_anchor" in sebamed.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_same_spec_name_alignment_near_threshold():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Sebamed】女性私密處護潔露200ml(國際航空版)",
|
||
"Sebamed私密護潔露(pH6.8)黃金女郎型200ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "spec_name_alignment" in diagnostics.reasons or "shared_identity_anchor" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_shared_anchor_without_spec_conflict():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Les nez 香鼻子】水晶香氛能量寶盒禮盒組(運財、智慧、愛情、守護、和諧、療癒、悟性 聖誕禮物)",
|
||
"【Les nez 香鼻子】水晶香氛能量寶盒禮盒組",
|
||
momo_price=2480,
|
||
competitor_price=2480,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_no_spec" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_recipe_box_near_threshold_with_variant_safe_anchor():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Recipebox】Recipe Box兒童防曬氣墊粉餅(兒童化妝品/無毒防曬粉餅/天然彩妝)",
|
||
"Recipe Box 韓兔 兒童防曬氣墊粉餅",
|
||
momo_price=699,
|
||
competitor_price=699,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_variant_safe" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_romand_palette_exact_line():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【rom&nd】勝過眼皮十色眼影盤",
|
||
"rom&nd X ZO&FRIENDS 勝過眼皮十色眼影盤 8g/7g",
|
||
momo_price=499,
|
||
competitor_price=499,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor_variant_safe" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_lactacyd_private_wash_exact_line():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Lactacyd 立朵舒】私密潔浴露250ml - 滋潤緊緻/加倍修護(私密清潔 產後私密保養 更年期乾癢修護)",
|
||
"Lactacyd 立朵舒私密潔浴露-滋潤緊緻250ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_identity_anchor" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_eaoron_classic_tone_up_cream_exact_line():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Eaoron】澳洲 經典素顏霜 50ml#0000199#(面霜 素顏霜 懶人霜 打造素顏女神)",
|
||
"【澳洲 EAORON】第三代經典版白素顏霜 50ml",
|
||
momo_price=399,
|
||
competitor_price=399,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "strong_exact_spec_match" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_promotes_shared_model_token_for_exact_model():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Panasonic 國際牌】男士身體除毛器 2025新款 ER-GK83 日版 日本直送",
|
||
"Panasonic 國際牌 男仕防水美體除毛器 國際版 (ER-GK83)",
|
||
momo_price=2490,
|
||
competitor_price=2290,
|
||
)
|
||
|
||
assert diagnostics.score >= 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "shared_model_token" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_matcher_keeps_variant_warmer_low_score():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Les nez 香鼻子】香氛融蠟燈 閃耀琥珀(附燈泡 定時 調節亮度 聖誕節禮物)",
|
||
"【Les nez 香鼻子】香氛融蠟燈 雲石玫瑰琥珀 贈燈泡(定時 可調光 香氛蠟燭 香氛)",
|
||
momo_price=1980,
|
||
competitor_price=1980,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is False
|
||
|
||
|
||
def test_marketplace_matcher_keeps_generic_vs_specific_warmer_low_score():
|
||
from services.marketplace_product_matcher import score_marketplace_match
|
||
|
||
diagnostics = score_marketplace_match(
|
||
"【Les nez 香鼻子】北歐香氛融蠟燈(附燈泡 定時 調節亮度)",
|
||
"【Les nez 香鼻子】香氛融蠟燈 星夜款",
|
||
momo_price=1980,
|
||
competitor_price=1980,
|
||
)
|
||
|
||
assert diagnostics.score < 0.76
|
||
assert diagnostics.hard_veto is False
|
||
assert "variant_descriptor_conflict" in diagnostics.reasons
|
||
|
||
|
||
def test_marketplace_search_terms_prefer_readable_brand_core_spec():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
terms = build_search_terms("【LA ROCHE-POSAY 理膚寶水】B5全面修復霜 40ml")
|
||
|
||
assert terms[0] == "理膚寶水 全面修復霜 b5 40ml"
|
||
assert not any(term.endswith(" l") for term in terms)
|
||
|
||
|
||
def test_marketplace_search_terms_prioritize_identity_phrase_over_ambiguous_copy():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
terms = build_search_terms("【TAICEND 泰陞】寶貝液體保護膜 屁屁噴 100ml", max_terms=5)
|
||
|
||
assert terms[0] == "泰陞 屁屁噴 100ml"
|
||
assert "保護膜" not in terms[0]
|
||
assert "屁屁噴" in " ".join(terms[:3])
|
||
|
||
|
||
def test_marketplace_search_terms_drop_option_and_marketing_noise():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
terms = build_search_terms("【YSL】情挑誘光嫩唇凍6ml(任選一款/新品上市)", max_terms=5)
|
||
|
||
assert terms[0] == "ysl 情挑誘光嫩唇凍 6ml"
|
||
assert not any("一款" in term or "上市" in term for term in terms)
|
||
|
||
|
||
def test_marketplace_search_terms_keep_professional_product_phrase():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
abysse_terms = build_search_terms("【Abysse】天然植萃身體按摩精油550ml", max_terms=5)
|
||
mustela_terms = build_search_terms(
|
||
"【Mustela 慕之恬廊】慕之幼 免用水潔淨液 300ml(外出清潔 卸除髒汙 卸除防曬 卸防曬)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert abysse_terms[0] == "abysse 身體按摩精油 550ml"
|
||
assert mustela_terms[0] == "慕之恬廊 免用水潔淨液 300ml"
|
||
assert not any("卸除防曬" in term or "外出清潔" in term for term in mustela_terms)
|
||
|
||
|
||
def test_marketplace_search_terms_keep_variant_descriptor_for_sensitive_lines():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
dashing_terms = build_search_terms("【DASHING DIVA】MAGICPRESS時尚潮流美甲片_極光之藍", max_terms=5)
|
||
romand_terms = build_search_terms("【rom&nd】勝過眼皮十色眼影盤", max_terms=5)
|
||
|
||
assert dashing_terms[0] == "dashing diva 時尚潮流美甲片 極光之藍"
|
||
assert romand_terms[0] == "romand 勝過眼皮十色眼影盤"
|
||
|
||
|
||
def test_marketplace_search_terms_prioritize_exact_dashing_diva_variant_name():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
moon_terms = build_search_terms(
|
||
"【DASHING DIVA】MAGICPRESS 時尚潮流美甲片-月影柔霧(貓眼 金色 漸層)",
|
||
max_terms=5,
|
||
)
|
||
silk_terms = build_search_terms(
|
||
"【DASHING DIVA】MAGICPRESS 時尚潮流美甲片-銀絲柔彩(紫色 漸層 貓眼)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert moon_terms[0] == "dashing diva 時尚潮流美甲片 月影柔霧"
|
||
assert silk_terms[0] == "dashing diva 時尚潮流美甲片 銀絲柔彩"
|
||
|
||
|
||
def test_marketplace_search_terms_prioritize_private_wash_identity_phrase():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
terms = build_search_terms(
|
||
"【Lactacyd 立朵舒】私密潔浴露250ml - 滋潤緊緻/加倍修護(私密清潔 產後私密保養 更年期乾癢修護)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert terms[0] == "立朵舒 私密潔浴露 250ml"
|
||
assert "滋潤緊緻" in terms[1]
|
||
|
||
|
||
def test_marketplace_search_terms_prioritize_precise_primer_identity_phrase():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
shu_terms = build_search_terms(
|
||
"【植村秀】官方直營 無極限保濕防曬妝前乳30ml(Shu uemura/防曬/保濕/校色",
|
||
max_terms=5,
|
||
)
|
||
meme_terms = build_search_terms(
|
||
"【im meme】我愛修膚/水凝光透/控油/好氣色妝前防護乳(SPF50+PA++++)",
|
||
max_terms=5,
|
||
)
|
||
eaoron_terms = build_search_terms(
|
||
"【Eaoron】澳洲 經典素顏霜 50ml#0000199#(面霜 素顏霜 懶人霜 打造素顏女神)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert shu_terms[0] == "植村秀 無極限保濕防曬妝前乳 30ml"
|
||
assert "校色" not in " ".join(shu_terms[:3])
|
||
assert any("水凝光透 妝前防護乳" in term for term in meme_terms[:4])
|
||
assert "好氣色" not in " ".join(meme_terms[:3])
|
||
assert eaoron_terms[0] == "eaoron 經典素顏霜 50ml"
|
||
assert "懶人霜" not in " ".join(eaoron_terms[:3])
|
||
|
||
|
||
def test_marketplace_search_terms_prefer_exact_identity_for_nail_foam_and_foot_mask():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
opi_terms = build_search_terms(
|
||
"【O.P.I】Top Coat 持久閃耀保色護甲油15mL-IST31(類光繚指甲油專用亮油/小銀蓋/如膠似漆/美甲/官方直營)",
|
||
max_terms=5,
|
||
)
|
||
arau_terms = build_search_terms(
|
||
"【arau baby】愛樂寶 溫和洗手慕斯300ml (溫和不乾澀;寶寶共和國)",
|
||
max_terms=5,
|
||
)
|
||
kameria_terms = build_search_terms(
|
||
"【KAMERIA】凱蜜菈 足足稱奇足膜17ml*2枚入(任選三款)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert opi_terms[0] == "opi 閃耀保色護甲油 15ml"
|
||
assert "小銀蓋" not in " ".join(opi_terms[:3])
|
||
assert arau_terms[0] == "愛樂寶 溫和洗手慕斯 300ml"
|
||
assert "溫和不乾澀" not in " ".join(arau_terms[:3])
|
||
assert kameria_terms[0] == "凱蜜菈 足足稱奇足膜 17ml 2包"
|
||
assert "枚入" not in " ".join(kameria_terms[:3])
|
||
|
||
|
||
def test_marketplace_search_terms_preserve_decimal_spec_and_shade_option():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
terms = build_search_terms(
|
||
"【Maybelline 媚比琳】超持久水光鎖吻唇釉#62 4.2ml",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert terms[0] == "媚比琳 超持久水光鎖吻唇釉 62 4.2ml"
|
||
assert "4 2ml" not in " ".join(terms)
|
||
|
||
|
||
def test_marketplace_search_terms_prefer_specific_line_over_generic_usage_words():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
mask_terms = build_search_terms("【SK-II】官方直營 青春敷面膜10+6+6送12(保濕/面膜/超品日)", max_terms=5)
|
||
bottle_terms = build_search_terms(
|
||
"【LANCOME 蘭蔻】官方直營 經典款小黑瓶100ml雙入組(LANCOME/經典款/抗老)",
|
||
max_terms=5,
|
||
)
|
||
rose_terms = build_search_terms(
|
||
"【蘭蔻】官方直營 玫瑰霜60ml+玫瑰精露150ml(LANCOME/永生玫瑰霜/抗老/PDRN)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert mask_terms[0] == "sk ii 青春敷面膜"
|
||
assert bottle_terms[0] == "蘭蔻 小黑瓶 100ml"
|
||
assert rose_terms[0] == "蘭蔻 永生玫瑰霜 60ml"
|
||
assert "抗老" not in " ".join(bottle_terms[:3] + rose_terms[:3])
|
||
assert "pdrn" not in " ".join(term.lower() for term in rose_terms[:3])
|
||
|
||
|
||
def test_marketplace_search_terms_prioritize_exact_identity_for_low_score_frontier_brands():
|
||
from services.marketplace_product_matcher import build_search_terms
|
||
|
||
ludeya_terms = build_search_terms(
|
||
"【LUDEYA】蜂王玫瑰外泌微臻霜超值兩入組(60mlX2入)",
|
||
max_terms=5,
|
||
)
|
||
estee_terms = build_search_terms(
|
||
"【Estee Lauder 雅詩蘭黛】微分子肌底原生露200ml-櫻花輕盈版(國際航空版)",
|
||
max_terms=5,
|
||
)
|
||
za_palette_terms = build_search_terms(
|
||
"【Za】3D立體持色眉彩盤 3.4g(多色可選)",
|
||
max_terms=5,
|
||
)
|
||
za_pencil_terms = build_search_terms(
|
||
"【Za】細芯睛彩雙頭眉筆 0.1g(多色任選)",
|
||
max_terms=5,
|
||
)
|
||
peripera_terms = build_search_terms(
|
||
"【PERIPERA】雙頭旋轉極細眉筆 0.05g(09灰褐棕)",
|
||
max_terms=5,
|
||
)
|
||
za_classic_terms = build_search_terms(
|
||
"【Za】官方直營 經典旋轉眉筆(色號任選)",
|
||
max_terms=5,
|
||
)
|
||
kate_refill_terms = build_search_terms(
|
||
"【KATE 凱婷】3D造型眉彩餅補充芯(眉彩刷、眉餅盒分開販售)",
|
||
max_terms=5,
|
||
)
|
||
peripera_liner_terms = build_search_terms(
|
||
"【peripera官方直營】速描眼線膠筆_多色任選(極細筆芯 防水抗暈)",
|
||
max_terms=5,
|
||
)
|
||
recipe_box_sunscreen_terms = build_search_terms(
|
||
"【Recipe Box】Recipe Box多效提亮防曬霜(兒童化妝品/無毒防曬霜/天然彩妝/防曬/提亮)",
|
||
max_terms=5,
|
||
)
|
||
opi_terms = build_search_terms(
|
||
"【O.P.I】紅蘋果 類光繚指甲油-ISLN25(小銀蓋/如膠似漆2.0系列指彩/美甲彩繪/官方直營)",
|
||
max_terms=5,
|
||
)
|
||
|
||
assert ludeya_terms[0] == "ludeya 蜂王玫瑰瑰泌霜 60ml"
|
||
assert "兩入組" not in " ".join(ludeya_terms[:3])
|
||
assert estee_terms[0] == "雅詩蘭黛 微分子肌底原生露 200ml"
|
||
assert "櫻花輕盈版" not in " ".join(estee_terms[:3])
|
||
assert za_palette_terms[0] == "za 3d立體持色眉彩盤 3.4g"
|
||
assert za_pencil_terms[0] == "za 細芯睛彩雙頭眉筆 0.1g"
|
||
assert peripera_terms[0] == "peripera 雙頭旋轉極細眉筆 09 0.05g"
|
||
assert za_classic_terms[0] == "za 經典旋轉眉筆"
|
||
assert kate_refill_terms[0] == "凱婷 3d造型眉彩餅補充芯"
|
||
assert peripera_liner_terms[0] == "peripera 速描眼線膠筆"
|
||
assert recipe_box_sunscreen_terms[0] == "recipe box 多效提亮防曬霜"
|
||
assert opi_terms[0] == "opi 類光繚指甲油 isln25"
|
||
|
||
|
||
def test_batch_compare_top_uses_latest_momo_price_not_revenue(monkeypatch):
|
||
from services import pchome_crawler
|
||
|
||
engine = create_engine("sqlite:///:memory:")
|
||
with engine.begin() as conn:
|
||
conn.execute(text("CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, i_code TEXT)"))
|
||
conn.execute(text("CREATE TABLE daily_sales (product_id INTEGER, revenue NUMERIC, date TEXT)"))
|
||
conn.execute(text("CREATE TABLE price_records (id INTEGER PRIMARY KEY, product_id INTEGER, price NUMERIC, timestamp TEXT)"))
|
||
conn.execute(text("INSERT INTO products VALUES (1, '理膚寶水 B5 修復霜 40ml', 'SKU001')"))
|
||
conn.execute(text("INSERT INTO daily_sales VALUES (1, 999999, '2026-05-19')"))
|
||
conn.execute(text("INSERT INTO price_records VALUES (1, 1, 699, '2026-05-19 10:00:00')"))
|
||
|
||
calls = []
|
||
|
||
def fake_compare_product(name, momo_price, momo_icode=""):
|
||
calls.append((name, momo_price, momo_icode))
|
||
return {"found": True, "momo_price": momo_price}
|
||
|
||
monkeypatch.setattr(pchome_crawler, "compare_product", fake_compare_product)
|
||
|
||
results = pchome_crawler.batch_compare_top(engine, top_n=1)
|
||
|
||
assert results == [{"found": True, "momo_price": 699.0}]
|
||
assert calls == [("理膚寶水 B5 修復霜 40ml", 699.0, "SKU001")]
|