- New app_config key-value table for system settings, with in-memory cache (mirrors ModuleService pattern) - GET/PATCH /v1/config endpoints for reading and updating config (settings.view/settings.edit permissions) - Runtime log level: PATCH /v1/config/log_level applies immediately, persists across restarts - Startup loads log level from DB in onReady hook (env var is default, DB overrides) - Add structured request.log.info() to POS routes: transaction create/complete/void, drawer open/close, discount create/update/delete Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
3.0 KiB
TypeScript
55 lines
3.0 KiB
TypeScript
import type { FastifyPluginAsync } from 'fastify'
|
|
import { PaginationSchema, DiscountCreateSchema, DiscountUpdateSchema } from '@lunarfront/shared/schemas'
|
|
import { DiscountService } from '../../services/discount.service.js'
|
|
|
|
export const discountRoutes: FastifyPluginAsync = async (app) => {
|
|
app.post('/discounts', { preHandler: [app.authenticate, app.requirePermission('pos.admin')] }, async (request, reply) => {
|
|
const parsed = DiscountCreateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const discount = await DiscountService.create(app.db, parsed.data)
|
|
request.log.info({ discountId: discount.id, name: parsed.data.name, userId: request.user.id }, 'Discount created')
|
|
return reply.status(201).send(discount)
|
|
})
|
|
|
|
app.get('/discounts', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const query = request.query as Record<string, string | undefined>
|
|
const params = PaginationSchema.parse(query)
|
|
const result = await DiscountService.list(app.db, params)
|
|
return reply.send(result)
|
|
})
|
|
|
|
app.get('/discounts/all', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const discounts = await DiscountService.listAll(app.db)
|
|
return reply.send(discounts)
|
|
})
|
|
|
|
app.get('/discounts/:id', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const discount = await DiscountService.getById(app.db, id)
|
|
if (!discount) return reply.status(404).send({ error: { message: 'Discount not found', statusCode: 404 } })
|
|
return reply.send(discount)
|
|
})
|
|
|
|
app.patch('/discounts/:id', { preHandler: [app.authenticate, app.requirePermission('pos.admin')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const parsed = DiscountUpdateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const discount = await DiscountService.update(app.db, id, parsed.data)
|
|
if (!discount) return reply.status(404).send({ error: { message: 'Discount not found', statusCode: 404 } })
|
|
request.log.info({ discountId: id, userId: request.user.id }, 'Discount updated')
|
|
return reply.send(discount)
|
|
})
|
|
|
|
app.delete('/discounts/:id', { preHandler: [app.authenticate, app.requirePermission('pos.admin')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const discount = await DiscountService.softDelete(app.db, id)
|
|
if (!discount) return reply.status(404).send({ error: { message: 'Discount not found', statusCode: 404 } })
|
|
request.log.info({ discountId: id, userId: request.user.id }, 'Discount deactivated')
|
|
return reply.send(discount)
|
|
})
|
|
}
|