feat(POS-010): completed feature

This commit is contained in:
chattie
2026-08-22 13:44:04 +02:00
parent 2c8a6f52ad
commit c089a4073a
11 changed files with 201 additions and 10 deletions

View File

@@ -640,4 +640,48 @@ export async function registerPosRoutes(app: FastifyInstance, deps: PosRouteDeps
return reply.send(result.rows[0]);
});
// ── POS-010: Discount validation ──────────────────────────────────────────
app.post('/pos/discounts/validate', {
schema: {
tags: ['POS Terminal'],
summary: 'Validate discount before applying',
body: {
type: 'object',
required: ['unitPriceCents', 'discountCents'],
properties: {
unitPriceCents: { type: 'integer', minimum: 0 },
discountCents: { type: 'integer', minimum: 0 },
discountPercent: { type: 'number', minimum: 0, maximum: 100 },
role: { type: 'string', enum: ['admin', 'pos_manager', 'pos_cashier'] },
},
},
response: { 401: errorSchema, 403: errorSchema },
} as FastifySchema,
}, async (request, reply) => {
const user = await authenticate(request);
requireAnyRole(user, ['admin', 'pos_manager', 'pos_cashier'] as ReadonlyArray<Role>);
const body = (request.body ?? {}) as { unitPriceCents?: number; discountCents?: number; discountPercent?: number; role?: string };
const unitPriceCents = body.unitPriceCents ?? 0;
const discountCents = body.discountCents ?? 0;
const discountPercent = body.discountPercent ?? (unitPriceCents > 0 ? (discountCents / unitPriceCents) * 100 : 0);
// Cashiers capped at 50% per item
const maxPercent = user.role === 'pos_manager' || user.role === 'admin' ? 100 : 50;
if (discountPercent > maxPercent) {
throw new AppError(403, 'DISCOUNT_EXCEEDED', `Discount ${discountPercent.toFixed(0)}% exceeds max ${maxPercent}% for role`);
}
if (discountCents > unitPriceCents) {
throw new AppError(400, 'INVALID_DISCOUNT', 'Discount cannot exceed unit price');
}
return reply.send({
valid: true,
maxPercent,
appliedPercent: discountPercent,
appliedCents: discountCents,
finalPriceCents: unitPriceCents - discountCents,
});
});
}