feat(orders): issued-orders CRUD routes + audit entity type
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
146
src/routes/admin/issued-orders.ts
Normal file
146
src/routes/admin/issued-orders.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { requirePermission } from "../../middleware/auth";
|
||||
import { logAudit } from "../../services/audit";
|
||||
import { success, error, parseId, paginated } from "../../utils/response";
|
||||
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
|
||||
import { parseBody } from "../../schemas/common";
|
||||
import {
|
||||
CreateIssuedOrderSchema,
|
||||
UpdateIssuedOrderSchema,
|
||||
} from "../../schemas/issued-orders.schema";
|
||||
import {
|
||||
listIssuedOrders,
|
||||
getIssuedOrder,
|
||||
createIssuedOrder,
|
||||
updateIssuedOrder,
|
||||
deleteIssuedOrder,
|
||||
getNextIssuedOrderNumberPreview,
|
||||
} from "../../services/issued-orders.service";
|
||||
|
||||
export default async function issuedOrdersRoutes(fastify: FastifyInstance) {
|
||||
// GET /api/admin/issued-orders
|
||||
fastify.get(
|
||||
"/",
|
||||
{ preHandler: requirePermission("orders.view") },
|
||||
async (request, reply) => {
|
||||
const query = request.query as Record<string, unknown>;
|
||||
const { page, limit, skip, order, search } = parsePagination(query);
|
||||
const result = await listIssuedOrders({
|
||||
page,
|
||||
limit,
|
||||
skip,
|
||||
sort: String(query.sort || ""),
|
||||
order,
|
||||
search,
|
||||
status: query.status ? String(query.status) : undefined,
|
||||
customer_id: query.customer_id ? Number(query.customer_id) : undefined,
|
||||
});
|
||||
return paginated(
|
||||
reply,
|
||||
result.data,
|
||||
buildPaginationMeta(result.total, page, limit),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// GET /api/admin/issued-orders/next-number
|
||||
fastify.get(
|
||||
"/next-number",
|
||||
{ preHandler: requirePermission("orders.create") },
|
||||
async (_request, reply) => {
|
||||
return success(reply, await getNextIssuedOrderNumberPreview());
|
||||
},
|
||||
);
|
||||
|
||||
// GET /api/admin/issued-orders/:id
|
||||
fastify.get<{ Params: { id: string } }>(
|
||||
"/:id",
|
||||
{ preHandler: requirePermission("orders.view") },
|
||||
async (request, reply) => {
|
||||
const id = parseId(request.params.id, reply);
|
||||
if (id === null) return;
|
||||
const order = await getIssuedOrder(id);
|
||||
if (!order) return error(reply, "Objednávka nenalezena", 404);
|
||||
return success(reply, order);
|
||||
},
|
||||
);
|
||||
|
||||
// POST /api/admin/issued-orders
|
||||
fastify.post(
|
||||
"/",
|
||||
{ preHandler: requirePermission("orders.create") },
|
||||
async (request, reply) => {
|
||||
const parsed = parseBody(CreateIssuedOrderSchema, request.body);
|
||||
if ("error" in parsed) return error(reply, parsed.error, 400);
|
||||
const order = await createIssuedOrder(parsed.data);
|
||||
await logAudit({
|
||||
request,
|
||||
authData: request.authData,
|
||||
action: "create",
|
||||
entityType: "issued_order",
|
||||
entityId: order.id,
|
||||
description: `Vytvořena vydaná objednávka ${order.po_number}`,
|
||||
});
|
||||
return success(
|
||||
reply,
|
||||
{ id: order.id, po_number: order.po_number },
|
||||
201,
|
||||
"Objednávka byla vytvořena",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// PUT /api/admin/issued-orders/:id
|
||||
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 parsed = parseBody(UpdateIssuedOrderSchema, request.body);
|
||||
if ("error" in parsed) return error(reply, parsed.error, 400);
|
||||
const result = await updateIssuedOrder(id, parsed.data);
|
||||
if ("error" in result) {
|
||||
if (result.error === "not_found")
|
||||
return error(reply, "Objednávka nenalezena", 404);
|
||||
if (result.error === "invalid_transition")
|
||||
return error(
|
||||
reply,
|
||||
`Neplatný přechod stavu z "${result.currentStatus}" na "${result.newStatus}"`,
|
||||
400,
|
||||
);
|
||||
return error(reply, "Neznámá chyba", 500);
|
||||
}
|
||||
await logAudit({
|
||||
request,
|
||||
authData: request.authData,
|
||||
action: "update",
|
||||
entityType: "issued_order",
|
||||
entityId: id,
|
||||
description: `Upravena vydaná objednávka ${result.po_number}`,
|
||||
});
|
||||
return success(reply, { id }, 200, "Objednávka byla aktualizována");
|
||||
},
|
||||
);
|
||||
|
||||
// DELETE /api/admin/issued-orders/:id
|
||||
fastify.delete<{ Params: { id: string } }>(
|
||||
"/:id",
|
||||
{ preHandler: requirePermission("orders.delete") },
|
||||
async (request, reply) => {
|
||||
const id = parseId(request.params.id, reply);
|
||||
if (id === null) return;
|
||||
const existing = await deleteIssuedOrder(id);
|
||||
if (!existing) return error(reply, "Objednávka nenalezena", 404);
|
||||
await logAudit({
|
||||
request,
|
||||
authData: request.authData,
|
||||
action: "delete",
|
||||
entityType: "issued_order",
|
||||
entityId: id,
|
||||
description: `Smazána vydaná objednávka ${existing.po_number}`,
|
||||
});
|
||||
return success(reply, null, 200, "Objednávka smazána");
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user