AuthorBot Cursor commited on
Commit
9109863
Β·
1 Parent(s): 1cd05b8

fix: cheapest/how-much answers use Buy button only, not full price grid

Browse files
.agent/PRICE_INTELLIGENCE_RULES.md CHANGED
@@ -46,7 +46,8 @@ No new endpoints.
46
 
47
  ## 5. UI
48
 
49
- - **Widget:** 3-column grid Platform | Price | Buy under bot bubble
 
50
  - **Empty price:** display `See site`; Buy uses that platform's `listing_url`
51
  - **Telegram:** stacked URL buttons (`Platform β€” $x.xx`), max 4
52
 
 
46
 
47
  ## 5. UI
48
 
49
+ - **Widget:** 3-column grid Platform | Price | Buy under bot bubble β€” **only** for list-all / compare turns
50
+ - **Single-winner turns** (cheapest, most expensive, how much, buy link for X): text + one Buy button; no grid
51
  - **Empty price:** display `See site`; Buy uses that platform's `listing_url`
52
  - **Telegram:** stacked URL buttons (`Platform β€” $x.xx`), max 4
53
 
app/services/price_catalog_service.py CHANGED
@@ -306,13 +306,11 @@ class PriceCatalogService:
306
  "platform_offers": [offer_to_platform_item(o) for o in offers],
307
  }
308
  best = min(priced, key=lambda o: o.price_cents or 10**9)
309
- others = [o for o in offers if o.platform_id != best.platform_id]
310
  text = (
311
  f"The lowest listed price for {book_title} is {best.price_display} "
312
  f"on {best.platform}."
313
  )
314
- platform_offers = [offer_to_platform_item(best, is_best=True)]
315
- platform_offers.extend(offer_to_platform_item(o) for o in others[:5])
316
  return {
317
  "text": text,
318
  "links": [{
@@ -322,7 +320,7 @@ class PriceCatalogService:
322
  "icon": "πŸ›’",
323
  }],
324
  "has_links": True,
325
- "platform_offers": platform_offers,
326
  }
327
 
328
  def _build_expensive_answer(self, offers: list[Offer], book_title: str) -> dict[str, Any]:
@@ -343,10 +341,7 @@ class PriceCatalogService:
343
  "icon": "πŸ›’",
344
  }],
345
  "has_links": True,
346
- "platform_offers": [
347
- offer_to_platform_item(top, is_best=True),
348
- *[offer_to_platform_item(o) for o in offers if o.platform_id != top.platform_id][:5],
349
- ],
350
  }
351
 
352
  def _build_compare_answer(
@@ -405,7 +400,7 @@ class PriceCatalogService:
405
  "icon": "πŸ›’",
406
  }],
407
  "has_links": True,
408
- "platform_offers": [offer_to_platform_item(target, is_best=True)],
409
  }
410
  if target is None:
411
  target = next((o for o in offers if o.is_source), offers[0])
@@ -427,7 +422,7 @@ class PriceCatalogService:
427
  "icon": "πŸ›’",
428
  }],
429
  "has_links": True,
430
- "platform_offers": [offer_to_platform_item(target, is_best=True)],
431
  }
432
 
433
  def _build_how_much_answer(
@@ -462,5 +457,5 @@ class PriceCatalogService:
462
  "icon": "πŸ›’",
463
  }],
464
  "has_links": True,
465
- "platform_offers": [offer_to_platform_item(target, is_best=True)],
466
  }
 
306
  "platform_offers": [offer_to_platform_item(o) for o in offers],
307
  }
308
  best = min(priced, key=lambda o: o.price_cents or 10**9)
 
309
  text = (
310
  f"The lowest listed price for {book_title} is {best.price_display} "
311
  f"on {best.platform}."
312
  )
313
+ # Single winner + Buy button only β€” no full Platform/Price/Buy grid.
 
314
  return {
315
  "text": text,
316
  "links": [{
 
320
  "icon": "πŸ›’",
321
  }],
322
  "has_links": True,
323
+ "platform_offers": None,
324
  }
325
 
326
  def _build_expensive_answer(self, offers: list[Offer], book_title: str) -> dict[str, Any]:
 
341
  "icon": "πŸ›’",
342
  }],
343
  "has_links": True,
344
+ "platform_offers": None,
 
 
 
345
  }
346
 
347
  def _build_compare_answer(
 
400
  "icon": "πŸ›’",
401
  }],
402
  "has_links": True,
403
+ "platform_offers": None,
404
  }
405
  if target is None:
406
  target = next((o for o in offers if o.is_source), offers[0])
 
422
  "icon": "πŸ›’",
423
  }],
424
  "has_links": True,
425
+ "platform_offers": None,
426
  }
427
 
428
  def _build_how_much_answer(
 
457
  "icon": "πŸ›’",
458
  }],
459
  "has_links": True,
460
+ "platform_offers": None,
461
  }
tests/unit/test_price_catalog_service.py CHANGED
@@ -93,8 +93,22 @@ async def test_build_cheapest_marks_is_best():
93
  result = svc._build_cheapest_answer(offers, "Lethal Lines")
94
  assert "Kobo" in result["text"]
95
  assert "$9.99" in result["text"]
96
- assert result["platform_offers"][0]["is_best"] is True
97
- assert result["platform_offers"][0]["platform"] == "Kobo"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
 
100
  @pytest.mark.asyncio
@@ -177,19 +191,6 @@ async def test_catalog_for_book_excludes_google_books():
177
  assert [o.platform_id for o in offers] == ["amazon"]
178
 
179
 
180
- @pytest.mark.asyncio
181
- async def test_google_books_link_ask_redirects_to_retail():
182
- svc = PriceCatalogService.__new__(PriceCatalogService)
183
- offers = [
184
- Offer("amazon", "Amazon", "$14.99", 1499, "https://a.com", True),
185
- ]
186
- result = svc._build_platform_link_answer(offers, "Lethal Lines", ("google_books",))
187
- assert "Google Books" in result["text"]
188
- assert "Amazon" in result["text"]
189
- assert result["links"][0]["url"] == "https://a.com"
190
- assert result["platform_offers"][0]["platform_id"] == "amazon"
191
-
192
-
193
  @pytest.mark.asyncio
194
  async def test_handle_how_much_uses_source():
195
  svc = PriceCatalogService(MagicMock())
@@ -201,3 +202,4 @@ async def test_handle_how_much_uses_source():
201
  assert "$14.99" in result["text"]
202
  assert "Amazon" in result["text"]
203
  assert result["links"][0]["url"] == "https://a.com"
 
 
93
  result = svc._build_cheapest_answer(offers, "Lethal Lines")
94
  assert "Kobo" in result["text"]
95
  assert "$9.99" in result["text"]
96
+ assert result["platform_offers"] is None
97
+ assert result["links"][0]["url"] == "https://k.com"
98
+ assert "Buy on Kobo" in result["links"][0]["label"]
99
+
100
+
101
+ @pytest.mark.asyncio
102
+ async def test_google_books_link_ask_redirects_to_retail():
103
+ svc = PriceCatalogService.__new__(PriceCatalogService)
104
+ offers = [
105
+ Offer("amazon", "Amazon", "$14.99", 1499, "https://a.com", True),
106
+ ]
107
+ result = svc._build_platform_link_answer(offers, "Lethal Lines", ("google_books",))
108
+ assert "Google Books" in result["text"]
109
+ assert "Amazon" in result["text"]
110
+ assert result["links"][0]["url"] == "https://a.com"
111
+ assert result["platform_offers"] is None
112
 
113
 
114
  @pytest.mark.asyncio
 
191
  assert [o.platform_id for o in offers] == ["amazon"]
192
 
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  @pytest.mark.asyncio
195
  async def test_handle_how_much_uses_source():
196
  svc = PriceCatalogService(MagicMock())
 
202
  assert "$14.99" in result["text"]
203
  assert "Amazon" in result["text"]
204
  assert result["links"][0]["url"] == "https://a.com"
205
+ assert result.get("platform_offers") is None