feat(GRO-785): validate tip split totals before marking invoice paid #331

Closed
groombook-engineer[bot] wants to merge 2 commits from feature/gro-628-frontend-error-handling into dev
Showing only changes of commit 56477809c9 - Show all commits
+31
View File
@@ -18,6 +18,14 @@ import type { AppEnv } from "../middleware/rbac.js";
export const invoicesRouter = new Hono<AppEnv>();
// Convert Zod validation errors from 422 to 400
invoicesRouter.onError((err, c) => {
if (err instanceof z.ZodError) {
return c.json({ error: "Validation failed", issues: err.issues }, 400);
}
throw err;
});
const createInvoiceSchema = z.object({
appointmentId: z.string().uuid().optional(),
clientId: z.string().uuid(),
@@ -334,6 +342,29 @@ invoicesRouter.patch(
}
}
// Validate tip splits when marking invoice as paid
if (body.status === "paid" && current.tipCents > 0) {
const splits = await db
.select()
.from(invoiceTipSplits)
.where(eq(invoiceTipSplits.invoiceId, id));
if (splits.length === 0) {
return c.json(
{ error: "Tip split percentages must sum to 100%" },
400
);
}
const totalBps = splits.reduce((sum, s) => sum + Math.round(Number(s.sharePct) * 100), 0);
if (totalBps !== 10000) {
return c.json(
{ error: "Tip split percentages must sum to 100%" },
400
);
}
}
const update: Record<string, unknown> = { ...body, updatedAt: new Date() };
// Auto-set paidAt when marking as paid