fix: code review fixes + unit/API tests for repair-POS integration

Code review fixes:
- Wrap createFromRepairTicket() in DB transaction for atomicity
- Wrap complete() inventory + status updates in DB transaction
- Repair ticket status update now atomic with transaction completion
- Add Zod validation on from-repair route body
- Fix requiresDiscountOverride: threshold and manual_discount are independent checks
- Order discount distributes proportionally across line items (not first-only)
- Extract shared receipt calculations into useReceiptData/useBarcode hooks
- Add error handling for barcode generation

Tests:
- Unit: consumable tax category mapping, exempt rate short-circuit
- API: ready-for-pickup listing + search, from-repair transaction creation,
  consumable exclusion from line items, tax rate verification (labor=service,
  part=goods), duplicate prevention, ticket auto-pickup on payment completion,
  isConsumable product filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ryan
2026-04-05 01:43:02 +00:00
parent 95cf017b4b
commit be8cc0ad8b
7 changed files with 422 additions and 128 deletions

View File

@@ -1,4 +1,5 @@
import type { FastifyPluginAsync } from 'fastify'
import { z } from 'zod'
import {
PaginationSchema,
TransactionCreateSchema,
@@ -8,6 +9,10 @@ import {
} from '@lunarfront/shared/schemas'
import { TransactionService } from '../../services/transaction.service.js'
const FromRepairBodySchema = z.object({
locationId: z.string().uuid().optional(),
})
export const transactionRoutes: FastifyPluginAsync = async (app) => {
app.post('/transactions', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
const parsed = TransactionCreateSchema.safeParse(request.body)
@@ -21,9 +26,12 @@ export const transactionRoutes: FastifyPluginAsync = async (app) => {
app.post('/transactions/from-repair/:ticketId', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, async (request, reply) => {
const { ticketId } = request.params as { ticketId: string }
const body = request.body as { locationId?: string } | undefined
const txn = await TransactionService.createFromRepairTicket(app.db, ticketId, body?.locationId, request.user.id)
request.log.info({ transactionId: txn?.id, ticketId, userId: request.user.id }, 'Repair payment transaction created')
const parsed = FromRepairBodySchema.safeParse(request.body ?? {})
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const txn = await TransactionService.createFromRepairTicket(app.db, ticketId, parsed.data.locationId, request.user.id)
request.log.info({ transactionId: txn.id, ticketId, userId: request.user.id }, 'Repair payment transaction created')
return reply.status(201).send(txn)
})