refactor: route/schema consistency (parseId, broad invalidation, Czech messages, Zod 4 strictObject)
- OfferDetail: invalidate broad ["offers"] not ["offers","list"] (CLAUDE.md convention) - trips.ts/sessions.ts: use parseId helper (validated 400) instead of raw parseInt for route ids - audit-log.ts: z.object().strict() -> z.strictObject() (Zod 4 idiom) - attendance.ts, orders/offers schemas: English user-facing strings -> Czech - project-files.ts: unify 'not found' phrasing to the codebase-dominant 'nenalezen' form Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -678,7 +678,7 @@ export default function OfferDetail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isEdit && result.data?.id) {
|
if (!isEdit && result.data?.id) {
|
||||||
queryClient.invalidateQueries({ queryKey: ["offers", "list"] });
|
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||||
@@ -690,7 +690,7 @@ export default function OfferDetail() {
|
|||||||
items,
|
items,
|
||||||
sections,
|
sections,
|
||||||
});
|
});
|
||||||
queryClient.invalidateQueries({ queryKey: ["offers", "list"] });
|
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||||
@@ -736,7 +736,7 @@ export default function OfferDetail() {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
setShowOrderModal(false);
|
setShowOrderModal(false);
|
||||||
alert.success(result.message || "Objednávka byla vytvořena");
|
alert.success(result.message || "Objednávka byla vytvořena");
|
||||||
await queryClient.invalidateQueries({ queryKey: ["offers", "list"] });
|
await queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["orders"] });
|
await queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["projects"] });
|
await queryClient.invalidateQueries({ queryKey: ["projects"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
await queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||||
@@ -762,7 +762,7 @@ export default function OfferDetail() {
|
|||||||
setInvalidateConfirm(false);
|
setInvalidateConfirm(false);
|
||||||
setOfferStatus("invalidated");
|
setOfferStatus("invalidated");
|
||||||
alert.success(result.message || "Nabídka byla zneplatněna");
|
alert.success(result.message || "Nabídka byla zneplatněna");
|
||||||
queryClient.invalidateQueries({ queryKey: ["offers", "list"] });
|
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||||
@@ -789,7 +789,7 @@ export default function OfferDetail() {
|
|||||||
deletingRef.current = true;
|
deletingRef.current = true;
|
||||||
queryClient.removeQueries({ queryKey: ["offers", id] });
|
queryClient.removeQueries({ queryKey: ["offers", id] });
|
||||||
alert.success(result.message || "Nabídka byla smazána");
|
alert.success(result.message || "Nabídka byla smazána");
|
||||||
await queryClient.invalidateQueries({ queryKey: ["offers", "list"] });
|
await queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["orders"] });
|
await queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["projects"] });
|
await queryClient.invalidateQueries({ queryKey: ["projects"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
await queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export default async function attendanceRoutes(
|
|||||||
return error(reply, "Nedostatečná oprávnění", 403);
|
return error(reply, "Nedostatečná oprávnění", 403);
|
||||||
}
|
}
|
||||||
const attendanceId = Number(query.attendance_id);
|
const attendanceId = Number(query.attendance_id);
|
||||||
if (!attendanceId) return error(reply, "Missing attendance_id", 400);
|
if (!attendanceId) return error(reply, "Chybí attendance_id", 400);
|
||||||
const data = await attendanceService.getProjectLogs(attendanceId);
|
const data = await attendanceService.getProjectLogs(attendanceId);
|
||||||
return reply.send({ success: true, data });
|
return reply.send({ success: true, data });
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ export default async function attendanceRoutes(
|
|||||||
// --- action=location: single record with GPS data ---
|
// --- action=location: single record with GPS data ---
|
||||||
if (action === "location") {
|
if (action === "location") {
|
||||||
const id = Number(query.id);
|
const id = Number(query.id);
|
||||||
if (!id) return error(reply, "Missing id", 400);
|
if (!id) return error(reply, "Chybí id záznamu", 400);
|
||||||
const record = await attendanceService.getLocationRecord(id);
|
const record = await attendanceService.getLocationRecord(id);
|
||||||
if (!record) return error(reply, "Záznam nenalezen", 404);
|
if (!record) return error(reply, "Záznam nenalezen", 404);
|
||||||
const isAdmin = authData.permissions.includes("attendance.manage");
|
const isAdmin = authData.permissions.includes("attendance.manage");
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ import { parseBody } from "../../schemas/common";
|
|||||||
// forensic history.
|
// forensic history.
|
||||||
const DELETE_ALL_CONFIRM = "DELETE_ALL_AUDIT" as const;
|
const DELETE_ALL_CONFIRM = "DELETE_ALL_AUDIT" as const;
|
||||||
|
|
||||||
const AuditCleanupSchema = z
|
const AuditCleanupSchema = z.strictObject({
|
||||||
.object({
|
days: z.number().int().nonnegative().optional(),
|
||||||
days: z.number().int().nonnegative().optional(),
|
confirm: z.string().optional(),
|
||||||
confirm: z.string().optional(),
|
});
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
export default async function auditLogRoutes(
|
export default async function auditLogRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default async function projectFilesRoutes(
|
|||||||
const { project_id: projectIdStr, path: subPath = "" } = parsedQuery.data;
|
const { project_id: projectIdStr, path: subPath = "" } = parsedQuery.data;
|
||||||
const projectId = Number(projectIdStr);
|
const projectId = Number(projectIdStr);
|
||||||
const project = await getProjectForFiles(projectId);
|
const project = await getProjectForFiles(projectId);
|
||||||
if (!project) return error(reply, "Projekt nebyl nalezen", 404);
|
if (!project) return error(reply, "Projekt nenalezen", 404);
|
||||||
|
|
||||||
if (!fm.isConfigured()) {
|
if (!fm.isConfigured()) {
|
||||||
return error(reply, "Souborový systém není nakonfigurován", 500);
|
return error(reply, "Souborový systém není nakonfigurován", 500);
|
||||||
@@ -70,7 +70,7 @@ export default async function projectFilesRoutes(
|
|||||||
return error(reply, "Projekt nemá číslo projektu");
|
return error(reply, "Projekt nemá číslo projektu");
|
||||||
|
|
||||||
const result = fm.downloadFile(project.project_number, subPath);
|
const result = fm.downloadFile(project.project_number, subPath);
|
||||||
if (!result) return error(reply, "Soubor nebyl nalezen", 404);
|
if (!result) return error(reply, "Soubor nenalezen", 404);
|
||||||
|
|
||||||
const stream = fs.createReadStream(result.filePath);
|
const stream = fs.createReadStream(result.filePath);
|
||||||
const encodedName = encodeURIComponent(result.fileName);
|
const encodedName = encodeURIComponent(result.fileName);
|
||||||
@@ -89,7 +89,7 @@ export default async function projectFilesRoutes(
|
|||||||
|
|
||||||
const result = fm.listFiles(project.project_number, subPath);
|
const result = fm.listFiles(project.project_number, subPath);
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
return error(reply, "Složka nebyla nalezena", 404);
|
return error(reply, "Složka nenalezena", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success(reply, {
|
return success(reply, {
|
||||||
@@ -109,7 +109,7 @@ export default async function projectFilesRoutes(
|
|||||||
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
||||||
const projectId = Number(parsedQuery.data.project_id);
|
const projectId = Number(parsedQuery.data.project_id);
|
||||||
const project = await getProjectForFiles(projectId);
|
const project = await getProjectForFiles(projectId);
|
||||||
if (!project) return error(reply, "Projekt nebyl nalezen", 404);
|
if (!project) return error(reply, "Projekt nenalezen", 404);
|
||||||
if (!project.project_number)
|
if (!project.project_number)
|
||||||
return error(reply, "Projekt nemá číslo projektu");
|
return error(reply, "Projekt nemá číslo projektu");
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export default async function projectFilesRoutes(
|
|||||||
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
||||||
const projectId = Number(parsedQuery.data.project_id);
|
const projectId = Number(parsedQuery.data.project_id);
|
||||||
const project = await getProjectForFiles(projectId);
|
const project = await getProjectForFiles(projectId);
|
||||||
if (!project) return error(reply, "Projekt nebyl nalezen", 404);
|
if (!project) return error(reply, "Projekt nenalezen", 404);
|
||||||
if (!project.project_number)
|
if (!project.project_number)
|
||||||
return error(reply, "Projekt nemá číslo projektu");
|
return error(reply, "Projekt nemá číslo projektu");
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ export default async function projectFilesRoutes(
|
|||||||
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
||||||
const projectId = Number(parsedQuery.data.project_id);
|
const projectId = Number(parsedQuery.data.project_id);
|
||||||
const project = await getProjectForFiles(projectId);
|
const project = await getProjectForFiles(projectId);
|
||||||
if (!project) return error(reply, "Projekt nebyl nalezen", 404);
|
if (!project) return error(reply, "Projekt nenalezen", 404);
|
||||||
if (!project.project_number)
|
if (!project.project_number)
|
||||||
return error(reply, "Projekt nemá číslo projektu");
|
return error(reply, "Projekt nemá číslo projektu");
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ export default async function projectFilesRoutes(
|
|||||||
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
if ("error" in parsedQuery) return error(reply, parsedQuery.error, 400);
|
||||||
const projectId = Number(parsedQuery.data.project_id);
|
const projectId = Number(parsedQuery.data.project_id);
|
||||||
const project = await getProjectForFiles(projectId);
|
const project = await getProjectForFiles(projectId);
|
||||||
if (!project) return error(reply, "Projekt nebyl nalezen", 404);
|
if (!project) return error(reply, "Projekt nenalezen", 404);
|
||||||
if (!project.project_number)
|
if (!project.project_number)
|
||||||
return error(reply, "Projekt nemá číslo projektu");
|
return error(reply, "Projekt nemá číslo projektu");
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FastifyInstance } from "fastify";
|
import { FastifyInstance } from "fastify";
|
||||||
import prisma from "../../config/database";
|
import prisma from "../../config/database";
|
||||||
import { requireAuth } from "../../middleware/auth";
|
import { requireAuth } from "../../middleware/auth";
|
||||||
import { success, error } from "../../utils/response";
|
import { success, error, parseId } from "../../utils/response";
|
||||||
import { hashToken } from "../../services/auth";
|
import { hashToken } from "../../services/auth";
|
||||||
|
|
||||||
/** Parse user-agent string into browser, OS, and device icon */
|
/** Parse user-agent string into browser, OS, and device icon */
|
||||||
@@ -81,8 +81,8 @@ export default async function sessionsRoutes(
|
|||||||
"/:id",
|
"/:id",
|
||||||
{ preHandler: requireAuth },
|
{ preHandler: requireAuth },
|
||||||
async (request, reply) => {
|
async (request, reply) => {
|
||||||
const id = parseInt(request.params.id, 10);
|
const id = parseId((request.params as any).id, reply);
|
||||||
if (Number.isNaN(id)) return error(reply, "Neplatné ID relace", 400);
|
if (id === null) return;
|
||||||
const authData = request.authData!;
|
const authData = request.authData!;
|
||||||
|
|
||||||
const session = await prisma.refresh_tokens.findFirst({
|
const session = await prisma.refresh_tokens.findFirst({
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { FastifyInstance } from "fastify";
|
|||||||
import prisma from "../../config/database";
|
import prisma from "../../config/database";
|
||||||
import { requireAuth, requirePermission } from "../../middleware/auth";
|
import { requireAuth, requirePermission } from "../../middleware/auth";
|
||||||
import { logAudit } from "../../services/audit";
|
import { logAudit } from "../../services/audit";
|
||||||
import { success, error } from "../../utils/response";
|
import { success, error, parseId } from "../../utils/response";
|
||||||
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
|
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
|
||||||
import { parseBody } from "../../schemas/common";
|
import { parseBody } from "../../schemas/common";
|
||||||
import { CreateTripSchema, UpdateTripSchema } from "../../schemas/trips.schema";
|
import { CreateTripSchema, UpdateTripSchema } from "../../schemas/trips.schema";
|
||||||
@@ -189,8 +189,8 @@ export default async function tripsRoutes(
|
|||||||
"/last-km/:vehicleId",
|
"/last-km/:vehicleId",
|
||||||
{ preHandler: requirePermission("trips.manage") },
|
{ preHandler: requirePermission("trips.manage") },
|
||||||
async (request, reply) => {
|
async (request, reply) => {
|
||||||
const vehicleId = parseInt(request.params.vehicleId, 10);
|
const vehicleId = parseId((request.params as any).vehicleId, reply);
|
||||||
if (isNaN(vehicleId)) return error(reply, "Neplatné ID vozidla", 400);
|
if (vehicleId === null) return;
|
||||||
|
|
||||||
const [lastTrip, vehicle] = await Promise.all([
|
const [lastTrip, vehicle] = await Promise.all([
|
||||||
prisma.trips.findFirst({
|
prisma.trips.findFirst({
|
||||||
@@ -261,8 +261,8 @@ export default async function tripsRoutes(
|
|||||||
"/:id",
|
"/:id",
|
||||||
{ preHandler: requireAuth },
|
{ preHandler: requireAuth },
|
||||||
async (request, reply) => {
|
async (request, reply) => {
|
||||||
const id = parseInt(request.params.id, 10);
|
const id = parseId((request.params as any).id, reply);
|
||||||
if (isNaN(id)) return error(reply, "Neplatné ID", 400);
|
if (id === null) return;
|
||||||
const parsed = parseBody(UpdateTripSchema, request.body);
|
const parsed = parseBody(UpdateTripSchema, request.body);
|
||||||
if ("error" in parsed) return error(reply, parsed.error, 400);
|
if ("error" in parsed) return error(reply, parsed.error, 400);
|
||||||
const body = parsed.data;
|
const body = parsed.data;
|
||||||
@@ -335,8 +335,8 @@ export default async function tripsRoutes(
|
|||||||
"/:id",
|
"/:id",
|
||||||
{ preHandler: requireAuth },
|
{ preHandler: requireAuth },
|
||||||
async (request, reply) => {
|
async (request, reply) => {
|
||||||
const id = parseInt(request.params.id, 10);
|
const id = parseId((request.params as any).id, reply);
|
||||||
if (isNaN(id)) return error(reply, "Neplatné ID", 400);
|
if (id === null) return;
|
||||||
const authData = request.authData!;
|
const authData = request.authData!;
|
||||||
const existing = await prisma.trips.findUnique({ where: { id } });
|
const existing = await prisma.trips.findUnique({ where: { id } });
|
||||||
if (!existing) return error(reply, "Jízda nenalezena", 404);
|
if (!existing) return error(reply, "Jízda nenalezena", 404);
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ const QuotationItemSchema = z.object({
|
|||||||
quantity: z
|
quantity: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(1),
|
.default(1),
|
||||||
unit: z.string().nullish(),
|
unit: z.string().nullish(),
|
||||||
unit_price: z
|
unit_price: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(0),
|
.default(0),
|
||||||
is_included_in_total: z
|
is_included_in_total: z
|
||||||
@@ -23,7 +23,7 @@ const QuotationItemSchema = z.object({
|
|||||||
position: z
|
position: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ const ScopeSectionSchema = z.object({
|
|||||||
position: z
|
position: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export const CreateQuotationSchema = z.object({
|
|||||||
vat_rate: z
|
vat_rate: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(21.0),
|
.default(21.0),
|
||||||
apply_vat: z
|
apply_vat: z
|
||||||
@@ -75,7 +75,7 @@ export const UpdateQuotationSchema = z.object({
|
|||||||
customer_id: z
|
customer_id: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
created_at: z.union([z.string(), z.null()]).optional(),
|
created_at: z.union([z.string(), z.null()]).optional(),
|
||||||
valid_until: z.union([z.string(), z.null()]).optional(),
|
valid_until: z.union([z.string(), z.null()]).optional(),
|
||||||
@@ -84,7 +84,7 @@ export const UpdateQuotationSchema = z.object({
|
|||||||
vat_rate: z
|
vat_rate: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
apply_vat: z
|
apply_vat: z
|
||||||
.preprocess((v) => v === true || v === 1 || v === "1", z.boolean())
|
.preprocess((v) => v === true || v === 1 || v === "1", z.boolean())
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ const OrderItemSchema = z.object({
|
|||||||
quantity: z
|
quantity: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(1),
|
.default(1),
|
||||||
unit: z.string().nullish(),
|
unit: z.string().nullish(),
|
||||||
unit_price: z
|
unit_price: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(0),
|
.default(0),
|
||||||
is_included_in_total: z
|
is_included_in_total: z
|
||||||
@@ -23,7 +23,7 @@ const OrderItemSchema = z.object({
|
|||||||
position: z
|
position: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ const OrderSectionSchema = z.object({
|
|||||||
position: z
|
position: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export const CreateOrderFromQuotationSchema = z.object({
|
|||||||
quotationId: z
|
quotationId: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" }),
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" }),
|
||||||
customerOrderNumber: z.string().optional().default(""),
|
customerOrderNumber: z.string().optional().default(""),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ export const CreateOrderSchema = z.object({
|
|||||||
vat_rate: z
|
vat_rate: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(21.0),
|
.default(21.0),
|
||||||
apply_vat: z
|
apply_vat: z
|
||||||
@@ -78,7 +78,7 @@ export const CreateOrderSchema = z.object({
|
|||||||
exchange_rate: z
|
exchange_rate: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional()
|
.optional()
|
||||||
.default(1.0),
|
.default(1.0),
|
||||||
scope_title: z.string().nullish(),
|
scope_title: z.string().nullish(),
|
||||||
@@ -103,7 +103,7 @@ export const UpdateOrderSchema = z.object({
|
|||||||
vat_rate: z
|
vat_rate: z
|
||||||
.union([z.number(), z.string()])
|
.union([z.number(), z.string()])
|
||||||
.transform((v) => Number(v))
|
.transform((v) => Number(v))
|
||||||
.refine((v) => !Number.isNaN(v), { message: "Must be a valid number" })
|
.refine((v) => !Number.isNaN(v), { message: "Musí být platné číslo" })
|
||||||
.optional(),
|
.optional(),
|
||||||
apply_vat: z
|
apply_vat: z
|
||||||
.preprocess((v) => v === true || v === 1 || v === "1", z.boolean())
|
.preprocess((v) => v === true || v === 1 || v === "1", z.boolean())
|
||||||
|
|||||||
Reference in New Issue
Block a user