fix: clear price to null when a comparison finds no merchant offer
Build & Deploy / build (push) Failing after 3s
Build & Deploy / docker (push) Skipped

Several memory sticks (e.g. Crucial CT8G48C40U5, Patriot Signature Line,
Kingston FURY Beast) kept displaying their pc-builder.io catalog price
("€35.99", "€39.99"...) even after clicking "Compare prices" and getting
"No live price found, using catalog price" - an unconfirmed number was
being shown as if it were still valid, which is misleading given
pc-builder.io's catalog is known to go stale (see the earlier RTX 5070
€128 vs €66.89 case).

New clearPriceIfNoOffers(): when ScrapedPartsController#compare finds
zero offers across all 7 supported merchants, the part's price/priceSource
are reset to null, regardless of whether the price previously came from
the pc-builder.io catalog or an earlier verified merchant match - per
explicit product decision, an empty comparison always wins over keeping a
possibly-stale number around.

- ScrapedPartsController#compare now calls clearPriceIfNoOffers() in the
  empty-offers branch, and returns the resulting price in the JSON
  response so the frontend can mirror it exactly
- NewPartSearch.vue: comparePrices() now sets part.price from the
  response's `price` field (mirroring exactly what the backend just
  persisted) instead of only updating it on a cheaper find; removed the
  now-inaccurate "using catalog price €X" message since that price no
  longer exists once compared with no result
- 3 new tests for clearPriceIfNoOffers: clears an unverified
  pc-builder.io price, also clears a previously-verified merchant price
  when no longer confirmed, and is a no-op when there was no price to
  begin with

Verified end-to-end against the reported Crucial CT8G48C40U5 example:
price went from 35.99 (pc-builder.io) to null after a real comparison
found zero matching offers on any merchant.
This commit is contained in:
Kevin L'Hereec committed 2026-07-24 11:20:47 +02:00
1 parent fa74791c92
commit 0ce6a7f4a7
4 files changed
+96 -19

No files matched your search

+22
View File
@@ -415,12 +415,34 @@ async function updatePriceIfCheaper(
await part.save()
}
/**
* Clears a part's price when a live comparison found no matching offer on
* any supported merchant (see ScrapedPartsController#compare), regardless
* of where the price previously came from (pc-builder.io catalog or an
* earlier verified merchant match). The pc-builder.io catalog price this
* part started with is frequently stale (see shouldKeepExistingPrice's
* doc for a confirmed example: pc-builder.io showed €128 for a CPU
* actually selling for €66.89) — once a user explicitly asks to verify a
* price and no merchant confirms it anymore, keeping the old number
* around is misleading, so it's dropped to null instead of silently
* falling back to "using catalog price €X".
*/
async function clearPriceIfNoOffers(part: ScrapedPart): Promise<void> {
if (part.price === null) return
part.price = null
part.priceSource = null
part.priceCheckedAt = DateTime.now()
await part.save()
}
export {
scrapeAllCategories,
scrapeComponentType,
ensureFreshCategory,
isCategoryStale,
updatePriceIfCheaper,
clearPriceIfNoOffers,
shouldKeepExistingPrice,
CATEGORY_CONFIG,
CATEGORY_SLUGS,