feat: named registers, X/Z reports, daily rollup, fix drawerSessionId
Registers: - New register table with location association - CRUD service + API routes (POST/GET/PATCH/DELETE /registers) - Drawer sessions now link to a register via registerId - Register ID persisted in localStorage per device X/Z Reports: - ReportService with getDrawerReport() (X or Z depending on session state) - Z report auto-displayed on drawer close in the drawer dialog - X report (Current Shift Report) button on open drawer view - Report shows: sales summary, payment breakdown, discounts, cash accountability, adjustments Daily Rollup: - ReportService.getDailyReport() aggregates all sessions at a location for a date - New /reports/daily endpoint with locationId + date params - Frontend daily report page with date picker, location selector, session breakdown Critical Fix: - drawerSessionId is now populated on transactions when completing (was never set before) - This enables accurate per-drawer reporting and cash accountability Migration 0044: register table, drawer_session.register_id column Tests: 14 new (register CRUD, drawer report X/Z, drawerSessionId population, daily rollup, register-drawer link) Full suite: 367 passed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
packages/backend/src/routes/v1/register.ts
Normal file
50
packages/backend/src/routes/v1/register.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { FastifyPluginAsync } from 'fastify'
|
||||
import { PaginationSchema, RegisterCreateSchema, RegisterUpdateSchema } from '@lunarfront/shared/schemas'
|
||||
import { RegisterService } from '../../services/register.service.js'
|
||||
|
||||
export const registerRoutes: FastifyPluginAsync = async (app) => {
|
||||
app.post('/registers', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
|
||||
const parsed = RegisterCreateSchema.safeParse(request.body)
|
||||
if (!parsed.success) {
|
||||
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
||||
}
|
||||
const register = await RegisterService.create(app.db, parsed.data)
|
||||
return reply.status(201).send(register)
|
||||
})
|
||||
|
||||
app.get('/registers', { 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 RegisterService.list(app.db, params, { locationId: query.locationId })
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
app.get('/registers/all', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
||||
const query = request.query as Record<string, string | undefined>
|
||||
const data = await RegisterService.listAll(app.db, query.locationId)
|
||||
return reply.send({ data })
|
||||
})
|
||||
|
||||
app.get('/registers/:id', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
|
||||
const { id } = request.params as { id: string }
|
||||
const register = await RegisterService.getById(app.db, id)
|
||||
if (!register) return reply.status(404).send({ error: { message: 'Register not found', statusCode: 404 } })
|
||||
return reply.send(register)
|
||||
})
|
||||
|
||||
app.patch('/registers/:id', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
|
||||
const { id } = request.params as { id: string }
|
||||
const parsed = RegisterUpdateSchema.safeParse(request.body)
|
||||
if (!parsed.success) {
|
||||
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
||||
}
|
||||
const register = await RegisterService.update(app.db, id, parsed.data)
|
||||
return reply.send(register)
|
||||
})
|
||||
|
||||
app.delete('/registers/:id', { preHandler: [app.authenticate, app.requirePermission('pos.admin')] }, async (request, reply) => {
|
||||
const { id } = request.params as { id: string }
|
||||
const register = await RegisterService.delete(app.db, id)
|
||||
return reply.send(register)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user