202 lines
5.4 KiB
TypeScript
202 lines
5.4 KiB
TypeScript
import { CONSEGNA_CONSTRAINTS } from "./constraints";
|
|
import {
|
|
buildResult,
|
|
normalizePositiveInt,
|
|
normalizeString,
|
|
validateDate,
|
|
validateEnum,
|
|
validateMaxLength,
|
|
validatePositiveInt,
|
|
validateRequired,
|
|
type FieldErrors,
|
|
type ValidationResult,
|
|
} from "./primitives";
|
|
|
|
export type StatoConsegna =
|
|
(typeof CONSEGNA_CONSTRAINTS.stato.allowedValues)[number];
|
|
|
|
export interface ConsegnaInput {
|
|
dataRitiro: string | null;
|
|
dataConsegna: string | null;
|
|
stato: StatoConsegna;
|
|
chiaveConsegna: string;
|
|
clienteId: number;
|
|
}
|
|
|
|
function normalizeOptionalDate(value: unknown): string | null {
|
|
const str = normalizeString(value);
|
|
return str || null;
|
|
}
|
|
|
|
function todayAtMidnight(): Date {
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
return today;
|
|
}
|
|
|
|
function validateDateNotRetroactive(
|
|
errors: FieldErrors,
|
|
field: string,
|
|
value: string,
|
|
label: string
|
|
): void {
|
|
if (!value || errors[field]) return;
|
|
|
|
const parsed = new Date(`${value}T00:00:00`);
|
|
if (parsed < todayAtMidnight()) {
|
|
errors[field] = `${label} non può essere anteriore alla data odierna`;
|
|
}
|
|
}
|
|
|
|
function validateOptionalDateField(
|
|
errors: FieldErrors,
|
|
field: string,
|
|
value: string | null,
|
|
label: string
|
|
): void {
|
|
if (!value) return;
|
|
validateDate(errors, field, value, label);
|
|
validateDateNotRetroactive(errors, field, value, label);
|
|
}
|
|
|
|
function validateAtLeastOneDate(
|
|
errors: FieldErrors,
|
|
dataRitiro: string | null,
|
|
dataConsegna: string | null
|
|
): void {
|
|
if (!dataRitiro && !dataConsegna) {
|
|
errors._form = "Inserire almeno una data di ritiro o di consegna";
|
|
}
|
|
}
|
|
|
|
export function normalizeConsegnaInput(raw: Record<string, unknown>): ConsegnaInput {
|
|
return {
|
|
dataRitiro: normalizeOptionalDate(raw.dataRitiro),
|
|
dataConsegna: normalizeOptionalDate(raw.dataConsegna),
|
|
stato: normalizeString(raw.stato || "in deposito") as StatoConsegna,
|
|
chiaveConsegna: normalizeString(raw.chiaveConsegna).toUpperCase(),
|
|
clienteId: normalizePositiveInt(raw.clienteId),
|
|
};
|
|
}
|
|
|
|
function validateConsegnaFields(
|
|
raw: Record<string, unknown>,
|
|
data: ConsegnaInput,
|
|
errors: FieldErrors,
|
|
options: { requireAll: boolean }
|
|
): void {
|
|
if (options.requireAll || "dataRitiro" in raw) {
|
|
validateOptionalDateField(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
|
}
|
|
|
|
if (options.requireAll || "dataConsegna" in raw) {
|
|
validateOptionalDateField(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
|
}
|
|
|
|
if (options.requireAll) {
|
|
validateAtLeastOneDate(errors, data.dataRitiro, data.dataConsegna);
|
|
} else if ("dataRitiro" in raw && "dataConsegna" in raw) {
|
|
validateAtLeastOneDate(errors, data.dataRitiro, data.dataConsegna);
|
|
}
|
|
|
|
if (options.requireAll || "stato" in raw) {
|
|
validateRequired(errors, "stato", data.stato, "Stato obbligatorio");
|
|
validateEnum(
|
|
errors,
|
|
"stato",
|
|
data.stato,
|
|
CONSEGNA_CONSTRAINTS.stato.allowedValues,
|
|
"Stato"
|
|
);
|
|
}
|
|
|
|
if (options.requireAll || "chiaveConsegna" in raw) {
|
|
validateRequired(
|
|
errors,
|
|
"chiaveConsegna",
|
|
data.chiaveConsegna,
|
|
"Chiave consegna obbligatoria"
|
|
);
|
|
validateMaxLength(
|
|
errors,
|
|
"chiaveConsegna",
|
|
data.chiaveConsegna,
|
|
CONSEGNA_CONSTRAINTS.chiaveConsegna.maxLength,
|
|
"Chiave consegna"
|
|
);
|
|
}
|
|
|
|
if (options.requireAll || "clienteId" in raw) {
|
|
validatePositiveInt(errors, "clienteId", data.clienteId, "Cliente", options.requireAll);
|
|
}
|
|
}
|
|
|
|
export function validateConsegnaCreate(
|
|
raw: Record<string, unknown>
|
|
): ValidationResult<ConsegnaInput> {
|
|
const data = normalizeConsegnaInput(raw);
|
|
const errors: FieldErrors = {};
|
|
validateConsegnaFields(raw, data, errors, { requireAll: true });
|
|
return buildResult(data, errors);
|
|
}
|
|
|
|
export function validateConsegnaUpdate(
|
|
raw: Record<string, unknown>
|
|
): ValidationResult<Partial<ConsegnaInput>> {
|
|
const errors: FieldErrors = {};
|
|
const data: Partial<ConsegnaInput> = {};
|
|
|
|
if ("dataRitiro" in raw) {
|
|
data.dataRitiro = normalizeOptionalDate(raw.dataRitiro);
|
|
validateOptionalDateField(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
|
}
|
|
|
|
if ("dataConsegna" in raw) {
|
|
data.dataConsegna = normalizeOptionalDate(raw.dataConsegna);
|
|
validateOptionalDateField(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
|
}
|
|
|
|
if ("dataRitiro" in raw && "dataConsegna" in raw) {
|
|
validateAtLeastOneDate(errors, data.dataRitiro ?? null, data.dataConsegna ?? null);
|
|
}
|
|
|
|
if ("stato" in raw) {
|
|
data.stato = normalizeString(raw.stato) as StatoConsegna;
|
|
validateRequired(errors, "stato", data.stato, "Stato obbligatorio");
|
|
validateEnum(
|
|
errors,
|
|
"stato",
|
|
data.stato,
|
|
CONSEGNA_CONSTRAINTS.stato.allowedValues,
|
|
"Stato"
|
|
);
|
|
}
|
|
|
|
if ("chiaveConsegna" in raw) {
|
|
data.chiaveConsegna = normalizeString(raw.chiaveConsegna).toUpperCase();
|
|
validateRequired(
|
|
errors,
|
|
"chiaveConsegna",
|
|
data.chiaveConsegna,
|
|
"Chiave consegna obbligatoria"
|
|
);
|
|
validateMaxLength(
|
|
errors,
|
|
"chiaveConsegna",
|
|
data.chiaveConsegna,
|
|
CONSEGNA_CONSTRAINTS.chiaveConsegna.maxLength,
|
|
"Chiave consegna"
|
|
);
|
|
}
|
|
|
|
if ("clienteId" in raw) {
|
|
data.clienteId = normalizePositiveInt(raw.clienteId);
|
|
validatePositiveInt(errors, "clienteId", data.clienteId, "Cliente");
|
|
}
|
|
|
|
if (Object.keys(data).length === 0) {
|
|
errors._form = "Nessun campo da aggiornare";
|
|
}
|
|
|
|
return buildResult(data, errors);
|
|
}
|