51fee198f4
No test infrastructure existed in this repo yet. Covers the pure logic most likely to silently produce wrong numbers on a live order: discount/ shipping math, per-rate invoice grouping, and bundle-contents string building. Extracted describeBundleContents() out of the checkout route into its own module so it's importable from a test (route.ts files only allow HTTP-method exports).
22 lines
1.1 KiB
TypeScript
22 lines
1.1 KiB
TypeScript
import type { RawProduct } from "./productsServer";
|
||
|
||
// A bundle's `bundleItems` is only ever resolved once, at checkout, into a
|
||
// plain readable string — the order line stores this snapshot
|
||
// (`items[].bundleContents`), not a structured sub-list, so a later change
|
||
// to the bundle's own composition can never rewrite what a past order
|
||
// actually contained. `product.bundleItems[].product` is a relationship
|
||
// resolved by fetchProductsBySlug's depth:2 fetch — {id, name} objects
|
||
// when populated, a bare id if depth somehow didn't reach it (skipped).
|
||
//
|
||
// Extracted out of app/api/checkout/route.ts into its own module (not
|
||
// just kept as a local function there) so it's importable from a unit
|
||
// test — Next.js route.ts files only allow HTTP-method + a few config
|
||
// exports, not arbitrary named exports.
|
||
export function describeBundleContents(product: RawProduct): string | null {
|
||
if (!product.bundleItems || product.bundleItems.length === 0) return null;
|
||
return product.bundleItems
|
||
.map((line) => (typeof line.product === "object" ? `${line.quantity}× ${line.product.name}` : null))
|
||
.filter((s): s is string => Boolean(s))
|
||
.join(", ");
|
||
}
|