This commit is contained in:
@@ -329,19 +329,7 @@ def _fetch_top_competitor_risks_uncached(engine, limit: int = 10) -> list[dict]:
|
||||
|
||||
limit = max(1, min(int(limit or 10), 50))
|
||||
sql = text(f"""
|
||||
WITH latest_momo AS (
|
||||
SELECT
|
||||
p.id AS product_id,
|
||||
p.i_code AS sku,
|
||||
p.name,
|
||||
p.category,
|
||||
pr.price AS momo_price,
|
||||
ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY pr.timestamp DESC, pr.id DESC) AS rn
|
||||
FROM products p
|
||||
JOIN price_records pr ON pr.product_id = p.id
|
||||
WHERE p.status = 'ACTIVE'
|
||||
),
|
||||
valid_competitor AS (
|
||||
WITH valid_competitor AS (
|
||||
SELECT DISTINCT ON (cp.sku)
|
||||
cp.sku,
|
||||
cp.price AS pchome_price,
|
||||
@@ -359,21 +347,29 @@ def _fetch_top_competitor_risks_uncached(engine, limit: int = 10) -> list[dict]:
|
||||
ORDER BY cp.sku, cp.crawled_at DESC NULLS LAST
|
||||
)
|
||||
SELECT
|
||||
lm.sku,
|
||||
lm.name,
|
||||
lm.category,
|
||||
lm.momo_price,
|
||||
p.i_code AS sku,
|
||||
p.name,
|
||||
p.category,
|
||||
latest_price.momo_price,
|
||||
vc.pchome_price,
|
||||
vc.competitor_product_id,
|
||||
vc.competitor_product_name,
|
||||
vc.match_score,
|
||||
vc.crawled_at,
|
||||
(lm.momo_price - vc.pchome_price) AS gap_amount,
|
||||
((lm.momo_price - vc.pchome_price) / vc.pchome_price * 100) AS gap_pct
|
||||
FROM latest_momo lm
|
||||
JOIN valid_competitor vc ON vc.sku = lm.sku
|
||||
WHERE lm.rn = 1
|
||||
AND lm.momo_price > vc.pchome_price * 1.05
|
||||
(latest_price.momo_price - vc.pchome_price) AS gap_amount,
|
||||
((latest_price.momo_price - vc.pchome_price) / vc.pchome_price * 100) AS gap_pct
|
||||
FROM valid_competitor vc
|
||||
JOIN products p
|
||||
ON p.i_code = vc.sku
|
||||
AND p.status = 'ACTIVE'
|
||||
JOIN LATERAL (
|
||||
SELECT pr.price AS momo_price
|
||||
FROM price_records pr
|
||||
WHERE pr.product_id = p.id
|
||||
ORDER BY pr.timestamp DESC, pr.id DESC
|
||||
LIMIT 1
|
||||
) latest_price ON TRUE
|
||||
WHERE latest_price.momo_price > vc.pchome_price * 1.05
|
||||
ORDER BY gap_pct DESC NULLS LAST, gap_amount DESC NULLS LAST
|
||||
LIMIT :limit
|
||||
""")
|
||||
|
||||
@@ -58,3 +58,12 @@ def test_competitor_ppt_prompt_uses_neutral_ewooc_viewpoint():
|
||||
assert "待補身份/價格" in source
|
||||
assert "我方 = PChome" not in source
|
||||
assert "請以 PChome 視角" not in source
|
||||
|
||||
|
||||
def test_top_competitor_risks_reads_latest_momo_price_after_valid_competitor_filter():
|
||||
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
|
||||
|
||||
assert "FROM valid_competitor vc" in source
|
||||
assert "JOIN LATERAL" in source
|
||||
assert "WHERE pr.product_id = p.id" in source
|
||||
assert "ROW_NUMBER() OVER (PARTITION BY p.id" not in source.split("def _fetch_top_competitor_risks_uncached", 1)[1].split("def fetch_competitor_comparison_results", 1)[0]
|
||||
|
||||
Reference in New Issue
Block a user