site-panzai/server/api/orders.post.ts

59 lines
3.2 KiB
TypeScript
Raw Normal View History

2026-11-13 13:57:04 +01:00
import type { Order, OrderItem, Payment, Size } from '../utils/store'
interface Body {
client?: { name?: string, phone?: string }
mode?: Order['mode']
address?: string
slot?: string
payment?: Payment
items?: { dishId: string, size: Size, meat?: string, sauce?: string, extras?: string[], note?: string, qty: number }[]
}
// Création d'une commande. Les prix sont toujours recalculés côté serveur.
export default defineEventHandler(async (event) => {
const body = await readBody<Body>(event)
const s = db.settings
if (!s.open) throw createError({ statusCode: 409, statusMessage: 'Les commandes sont en pause pour le moment.' })
if (!body.items?.length) throw createError({ statusCode: 400, statusMessage: 'Panier vide.' })
if (!body.client?.name?.trim() || !body.client?.phone?.trim()) throw createError({ statusCode: 400, statusMessage: 'Nom et téléphone obligatoires.' })
const mode = body.mode === 'retrait' ? 'retrait' : 'livraison'
if (mode === 'livraison' && !body.address?.trim()) throw createError({ statusCode: 400, statusMessage: 'Adresse de livraison obligatoire.' })
const payment: Payment = ['carte', 'apple', 'google', 'especes'].includes(body.payment as string) ? body.payment as Payment : 'carte'
if (payment === 'especes' && mode === 'livraison') throw createError({ statusCode: 400, statusMessage: 'Espèces uniquement au retrait.' })
const items: OrderItem[] = body.items.map((i) => {
const dish = db.dishes.find(d => d.id === i.dishId)
if (!dish || !dish.available) throw createError({ statusCode: 409, statusMessage: `${dish?.name || 'Un plat'} n'est plus disponible.` })
const base = dish.prices[i.size]
if (base == null) throw createError({ statusCode: 409, statusMessage: `Prix non défini pour ${dish.name}.` })
const picked = db.extras.filter(x => (i.extras || []).includes(x.id))
const unit = base + picked.reduce((a, x) => a + x.price, 0)
const extras = picked.map(x => x.label)
return {
dishId: dish.id, name: dish.name, size: i.size,
meat: dish.meats.includes(i.meat || '') ? i.meat! : (dish.meats[0] || 'Légumes'),
sauce: dish.sauces?.includes(i.sauce || '') ? i.sauce : undefined,
extras, note: i.note?.slice(0, 200), qty: Math.max(1, Math.min(20, Math.round(i.qty || 1))), unit
}
})
const subtotal = items.reduce((a, i) => a + i.unit * i.qty, 0)
if (mode === 'livraison' && subtotal < s.minOrder) throw createError({ statusCode: 400, statusMessage: 'Minimum de commande non atteint pour la livraison.' })
const fee = mode === 'livraison' && subtotal < s.freeFrom ? s.deliveryFee : 0
const now = Date.now()
const n = db.seq++
const order: Order = {
id: Math.random().toString(36).slice(2, 10),
num: 'PZ-0' + n,
createdAt: now,
client: { name: body.client.name.trim(), phone: body.client.phone.trim() },
mode,
address: mode === 'livraison' ? body.address!.trim() : undefined,
slot: mode === 'retrait' ? (body.slot || 'Dès que possible') : undefined,
items, subtotal, fee, total: subtotal + fee,
payment, paid: payment !== 'especes', status: 'new',
history: [{ at: now, label: payment === 'especes' ? 'Commande reçue · espèces au retrait' : 'Commande reçue · payée' }]
}
db.orders.push(order)
return order
})