- New drawer_adjustment table (type: cash_in/cash_out, amount, reason) - POST/GET /drawer/:id/adjustments endpoints - Drawer close calculation now includes adjustments: expected = opening + sales + cash_in - cash_out - DrawerAdjustmentSchema for input validation - 5 new tests (44 total POS tests passing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
4.0 KiB
TypeScript
69 lines
4.0 KiB
TypeScript
import type { FastifyPluginAsync } from 'fastify'
|
|
import { PaginationSchema, DrawerOpenSchema, DrawerCloseSchema, DrawerAdjustmentSchema } from '@lunarfront/shared/schemas'
|
|
import { DrawerService } from '../../services/drawer.service.js'
|
|
|
|
export const drawerRoutes: FastifyPluginAsync = async (app) => {
|
|
app.post('/drawer/open', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
|
|
const parsed = DrawerOpenSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const session = await DrawerService.open(app.db, parsed.data, request.user.id)
|
|
request.log.info({ drawerSessionId: session.id, locationId: parsed.data.locationId, openingBalance: parsed.data.openingBalance, userId: request.user.id }, 'Drawer opened')
|
|
return reply.status(201).send(session)
|
|
})
|
|
|
|
app.post('/drawer/:id/close', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const parsed = DrawerCloseSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const session = await DrawerService.close(app.db, id, parsed.data, request.user.id)
|
|
request.log.info({ drawerSessionId: id, closingBalance: parsed.data.closingBalance, expectedBalance: session.expectedBalance, overShort: session.overShort, closedBy: request.user.id }, 'Drawer closed')
|
|
return reply.send(session)
|
|
})
|
|
|
|
app.get('/drawer/current', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const query = request.query as Record<string, string | undefined>
|
|
const locationId = query.locationId
|
|
if (!locationId) {
|
|
return reply.status(400).send({ error: { message: 'locationId query param is required', statusCode: 400 } })
|
|
}
|
|
const session = await DrawerService.getOpen(app.db, locationId)
|
|
if (!session) return reply.status(404).send({ error: { message: 'No open drawer session found', statusCode: 404 } })
|
|
return reply.send(session)
|
|
})
|
|
|
|
app.post('/drawer/:id/adjustments', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const parsed = DrawerAdjustmentSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const adjustment = await DrawerService.addAdjustment(app.db, id, parsed.data, request.user.id)
|
|
request.log.info({ drawerSessionId: id, type: parsed.data.type, amount: parsed.data.amount, userId: request.user.id }, 'Drawer adjustment')
|
|
return reply.status(201).send(adjustment)
|
|
})
|
|
|
|
app.get('/drawer/:id/adjustments', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const adjustments = await DrawerService.getAdjustments(app.db, id)
|
|
return reply.send({ data: adjustments })
|
|
})
|
|
|
|
app.get('/drawer/:id', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const session = await DrawerService.getById(app.db, id)
|
|
if (!session) return reply.status(404).send({ error: { message: 'Drawer session not found', statusCode: 404 } })
|
|
return reply.send(session)
|
|
})
|
|
|
|
app.get('/drawer', { 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 DrawerService.list(app.db, params)
|
|
return reply.send(result)
|
|
})
|
|
}
|