// Offer validation (F22). Same rules as the Odoo constraints; used by the editor (inline) and the server. import { num } from "./offer-text"; export interface OfferInput { name: string; badge?: string | null; description?: string | null; type: string; discountType: string; discountValue: number | string; mixQty: number; buyQty: number; getQty: number; getPercent: number | string; startsAt?: string | null; endsAt?: string | null; maxPerOrder: number; sequence: number; lines: { productId: string; variantId?: string | null; quantity: number }[]; scopes: { role: string; kind: string; refId: string }[]; } export type Errors = Partial>; export function validateOffer(o: OfferInput): Errors { const e: Errors = {}; if (!o.name?.trim()) e.name = "Name is required."; else if (o.name.length > 80) e.name = "Use at most 80 characters (it is shown at checkout)."; if (!["fixed", "mix", "bxgy"].includes(o.type)) e.type = "Choose a bundle type."; if (o.startsAt && o.endsAt && new Date(o.endsAt) < new Date(o.startsAt)) { e.endsAt = "The end date must be after the start date."; } if (!(o.maxPerOrder >= 0) || !Number.isInteger(o.maxPerOrder)) e.maxPerOrder = "Use 0 (no limit) or a whole number."; if (o.type === "fixed" || o.type === "mix") { if (!["percent", "amount", "fixed_price"].includes(o.discountType)) e.discountType = "Choose a discount type."; const v = num(o.discountValue); if (!(v > 0)) e.discountValue = "The discount value must be greater than 0."; else if (o.discountType === "percent" && v > 100) e.discountValue = "A percentage can't be more than 100."; } if (o.type === "fixed") { if (!o.lines.length) e.lines = "Add at least one product to the bundle."; else if (o.lines.some((l) => !(l.quantity >= 1) || !Number.isInteger(l.quantity))) e.lines = "Each quantity must be at least 1."; } if (o.type === "mix") { if (!o.scopes.some((s) => s.role === "mix")) e.scopes_mix = "Add products or collections."; if (!(o.mixQty >= 1)) e.mixQty = "The number of items must be at least 1."; } if (o.type === "bxgy") { if (!o.scopes.some((s) => s.role === "buy")) e.scopes_buy = "Add what the customer buys."; if (!o.scopes.some((s) => s.role === "get")) e.scopes_get = "Add what the customer gets."; if (!(o.buyQty >= 1)) e.buyQty = "The buy quantity must be at least 1."; if (!(o.getQty >= 1)) e.getQty = "The get quantity must be at least 1."; const gp = num(o.getPercent); if (!(gp > 0 && gp <= 100)) e.getPercent = "Use a percentage above 0 and up to 100 (100 = free)."; } return e; }