Items can now be marked as "requires delivery" in admin — these items cannot be picked up and must be delivered (and struck). - Admin item editor: "Requires delivery" checkbox + custom base/per-mile rate fields that appear when the toggle is on - ProductCard: "Delivery & setup required" note on the card - CartDrawer: pickup toggle is hidden and replaced with an explanation when any cart item requires delivery; the quote call passes the item's custom rate override (highest base + highest per-mile wins when multiple requires-delivery items are in the cart) - delivery-quote API: accepts optional rateOverride to apply per-item pricing on top of the inferred tier Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import { readFileSync, existsSync } from 'fs'
|
|
import path from 'path'
|
|
import { atomicWriteJSON } from './file-utils'
|
|
|
|
export interface ItemOverride {
|
|
hidden?: boolean
|
|
featured?: boolean
|
|
categoryOverride?: string
|
|
categoryLabelOverride?: string
|
|
sortOrder?: number
|
|
showColors?: boolean
|
|
hiddenModifierIds?: string[]
|
|
hiddenVariationIds?: string[]
|
|
descriptionOverride?: string
|
|
/** Per-modifier minimum selections override. Key = modifier list ID, value = min count. */
|
|
modifierMinSelected?: Record<string, number>
|
|
/** Minimum latex colors the customer must pick (default 1 when showColors=true). */
|
|
colorMin?: number
|
|
/** Maximum latex colors the customer can pick (null = unlimited). */
|
|
colorMax?: number
|
|
/** Extra charge in cents added per chrome color selected (0 = no per-color surcharge). */
|
|
chromeSurchargePerColor?: number
|
|
/** Color names that are hidden from the customer picker for this item. */
|
|
disabledColors?: string[]
|
|
/** Unit label for the quantity field, e.g. "ft". When set, the quantity control shows "X ft". */
|
|
quantityUnit?: string
|
|
/** When true, pickup is not offered — item must be delivered. */
|
|
requiresDelivery?: boolean
|
|
/** Override delivery base charge in cents for this item (replaces the tier default). */
|
|
deliveryBaseOverride?: number | null
|
|
/** Override per-mile rate in cents for this item (replaces the tier default). */
|
|
deliveryPerMileOverride?: number | null
|
|
}
|
|
|
|
export type OverridesMap = Record<string, ItemOverride>
|
|
|
|
const OVERRIDES_PATH = path.join(process.cwd(), 'data', 'item-overrides.json')
|
|
|
|
export function readOverrides(): OverridesMap {
|
|
if (!existsSync(OVERRIDES_PATH)) return {}
|
|
try {
|
|
return JSON.parse(readFileSync(OVERRIDES_PATH, 'utf-8'))
|
|
} catch {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
export function writeOverrides(overrides: OverridesMap): void {
|
|
atomicWriteJSON(OVERRIDES_PATH, overrides)
|
|
}
|
|
|
|
export function setOverride(itemId: string, patch: Partial<ItemOverride>): void {
|
|
const all = readOverrides()
|
|
all[itemId] = { ...(all[itemId] ?? {}), ...patch }
|
|
writeOverrides(all)
|
|
}
|
|
|
|
export function clearOverride(itemId: string): void {
|
|
const all = readOverrides()
|
|
delete all[itemId]
|
|
writeOverrides(all)
|
|
}
|