diff --git a/src/keepa.test.ts b/src/keepa.test.ts index c020cff..c3cb9a4 100644 --- a/src/keepa.test.ts +++ b/src/keepa.test.ts @@ -48,7 +48,7 @@ test("lookupKeepaUpcs returns found, not_found, and multiple_asins outcomes", as current: [null, null, null, 1234], avg: [2500, null, null, 1400], }, - csv: [[1, 2999]], + csv: [[5000000, 2999, 5000100]], }, { asin: "B000MULTI01", @@ -85,6 +85,7 @@ test("lookupKeepaUpcs returns found, not_found, and multiple_asins outcomes", as expect(details.get("012345678901")?.status).toBe("found"); expect(details.get("012345678901")?.asin).toBe("B000FOUND01"); expect(details.get("012345678901")?.keepaData?.currentPrice).toBe(29.99); + expect(details.get("012345678901")?.keepaData?.currentPrice).toBe(29.99); expect(details.get("098765432109")?.status).toBe("multiple_asins"); expect(details.get("098765432109")?.candidateAsins).toEqual([ diff --git a/src/keepa.ts b/src/keepa.ts index a230393..81d4632 100644 --- a/src/keepa.ts +++ b/src/keepa.ts @@ -529,14 +529,17 @@ function computeAmazonBuyBoxSharePctFromHistory( return Math.round((amazonMinutes / qualifiedMinutes) * 10_000) / 100; } -function extractLatestPositivePrice(series: unknown): number | null { - if (!Array.isArray(series) || series.length < 2) return null; - const last = series[series.length - 1]; - if (typeof last !== "number" || !Number.isFinite(last) || last <= 0) { - return null; - } - return last / 100; -} +function extractLatestPositivePrice(series: unknown): number | null { + if (!Array.isArray(series) || series.length < 2) return null; + for (let i = series.length - 1; i >= 1; i--) { + if (i % 2 === 0) continue; + const value = series[i]; + if (typeof value === "number" && Number.isFinite(value) && value > 0) { + return value / 100; + } + } + return null; +} function pickKeepaNumber(...values: unknown[]): number | null { for (const value of values) { @@ -548,16 +551,14 @@ function pickKeepaNumber(...values: unknown[]): number | null { return null; } -function extractCurrentPrice(csv: number[][] | undefined): number | null { - if (!csv) return null; - - // csv[0] = Amazon price history, csv[1] = Marketplace new price history - // Each is [time, price, time, price, ...] — last value is most recent - for (const series of [csv[0], csv[1]]) { - if (series && series.length >= 2) { - const lastPrice = series[series.length - 1]!; - if (lastPrice > 0) return lastPrice / 100; - } - } - return null; -} +function extractCurrentPrice(csv: number[][] | undefined): number | null { + if (!csv) return null; + + // csv[0] = Amazon price history, csv[1] = Marketplace new price history + // Each is [time, price, time, price, ...]. Only odd indexes are prices. + for (const series of [csv[0], csv[1]]) { + const latestPrice = extractLatestPositivePrice(series); + if (latestPrice != null) return latestPrice; + } + return null; +} diff --git a/src/stalker-sellability.test.ts b/src/stalker-sellability.test.ts index da5f4b8..5cdbc4a 100644 --- a/src/stalker-sellability.test.ts +++ b/src/stalker-sellability.test.ts @@ -89,7 +89,7 @@ test("sellability checks matched seller inventory, not the source ASIN", async ( current: [null, null, null, 12345, null, null, null, null, null, null, null, 7], avg: [2500], }, - csv: [[0, 1999]], + csv: [[5000000, 1999, 5000100]], }, ], tokensLeft: 10, diff --git a/src/stalker.ts b/src/stalker.ts index 306ef20..7a30589 100644 --- a/src/stalker.ts +++ b/src/stalker.ts @@ -1355,7 +1355,11 @@ function extractCurrentPrice(csv: unknown): number | null { function extractLatestPositiveKeepaPrice(history: unknown): number | null { if (!Array.isArray(history)) return null; - for (let i = history.length - 1; i >= 0; i--) { + + // Keepa CSV histories are [time, value, time, value, ...]. Only odd indexes + // are prices; even indexes are Keepa timestamps and can look like huge prices. + for (let i = history.length - 1; i >= 1; i--) { + if (i % 2 === 0) continue; const value = extractNumber(history[i]); if (value != null && value > 0) return value / 100; }