58 lines
3.2 KiB
TypeScript
58 lines
3.2 KiB
TypeScript
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
|
|
})
|