feat: add Zod validation schemas for all domain routes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-23 08:57:38 +01:00
parent a4303b0188
commit d2b22e9399
32 changed files with 819 additions and 140 deletions

View File

@@ -4,6 +4,8 @@ import { requirePermission } from '../../middleware/auth';
import { logAudit } from '../../services/audit';
import { success, error, parseId } from '../../utils/response';
import { parsePagination, buildPaginationMeta } from '../../utils/pagination';
import { parseBody } from '../../schemas/common';
import { CreateOrderFromQuotationSchema, CreateOrderSchema, UpdateOrderSchema } from '../../schemas/orders.schema';
import multipart from '@fastify/multipart';
@@ -275,12 +277,14 @@ export default async function ordersRoutes(fastify: FastifyInstance): Promise<vo
}
// === JSON body — either from-quotation (no attachment) or manual order ===
const body = request.body as Record<string, unknown>;
const rawBody = request.body as Record<string, unknown>;
// From-quotation flow via JSON (no attachment)
if (body.quotationId) {
const quotationId = Number(body.quotationId);
const customerOrderNumber = body.customerOrderNumber ? String(body.customerOrderNumber) : '';
if (rawBody.quotationId) {
const fromQuotParsed = parseBody(CreateOrderFromQuotationSchema, rawBody);
if ('error' in fromQuotParsed) return error(reply, fromQuotParsed.error, 400);
const quotationId = fromQuotParsed.data.quotationId;
const customerOrderNumber = fromQuotParsed.data.customerOrderNumber;
if (!quotationId || isNaN(quotationId)) {
return error(reply, 'Chybí ID nabídky', 400);
@@ -369,21 +373,25 @@ export default async function ordersRoutes(fastify: FastifyInstance): Promise<vo
}
// Manual order creation
const manualParsed = parseBody(CreateOrderSchema, rawBody);
if ('error' in manualParsed) return error(reply, manualParsed.error, 400);
const body = manualParsed.data;
const order = await prisma.orders.create({
data: {
order_number: body.order_number ? String(body.order_number) : null,
customer_order_number: body.customer_order_number ? String(body.customer_order_number) : null,
quotation_id: body.quotation_id ? Number(body.quotation_id) : null,
customer_id: body.customer_id ? Number(body.customer_id) : null,
status: body.status ? String(body.status) : 'prijata',
currency: body.currency ? String(body.currency) : 'CZK',
language: body.language ? String(body.language) : 'cs',
vat_rate: body.vat_rate ? Number(body.vat_rate) : 21.0,
order_number: body.order_number ?? null,
customer_order_number: body.customer_order_number ?? null,
quotation_id: body.quotation_id ?? null,
customer_id: body.customer_id ?? null,
status: body.status,
currency: body.currency,
language: body.language,
vat_rate: body.vat_rate,
apply_vat: body.apply_vat !== false,
exchange_rate: body.exchange_rate ? Number(body.exchange_rate) : 1.0,
scope_title: body.scope_title ? String(body.scope_title) : null,
scope_description: body.scope_description ? String(body.scope_description) : null,
notes: body.notes ? String(body.notes) : null,
exchange_rate: body.exchange_rate,
scope_title: body.scope_title ?? null,
scope_description: body.scope_description ?? null,
notes: body.notes ?? null,
},
});
@@ -421,7 +429,9 @@ export default async function ordersRoutes(fastify: FastifyInstance): Promise<vo
fastify.put<{ Params: { id: string } }>('/:id', { preHandler: requirePermission('orders.edit') }, async (request, reply) => {
const id = parseId(request.params.id, reply);
if (id === null) return;
const body = request.body as Record<string, unknown>;
const parsed = parseBody(UpdateOrderSchema, request.body);
if ('error' in parsed) return error(reply, parsed.error, 400);
const body = parsed.data;
const existing = await prisma.orders.findUnique({ where: { id } });
if (!existing) return error(reply, 'Objednávka nenalezena', 404);