modifiche a required dataRitiro e dataConsegna
This commit is contained in:
parent
797f425a24
commit
c289bd5003
8 changed files with 109 additions and 52 deletions
|
|
@ -50,14 +50,16 @@ CREATE TABLE IF NOT EXISTS cliente (
|
|||
|
||||
-- ----------------------------------------------------------------
|
||||
-- Tabella consegna (API: GET/POST/PUT/DELETE /consegna)
|
||||
-- DataRitiro e DataConsegna sono eventi indipendenti: nessun vincolo
|
||||
-- di ordine tra le due date, solo retroattività rispetto a oggi.
|
||||
-- DataRitiro = giorno in cui il corriere ritira dal cliente.
|
||||
-- DataConsegna = giorno in cui il corriere consegna al cliente.
|
||||
-- Sono eventi indipendenti (nessun vincolo di ordine); almeno una delle due
|
||||
-- date deve essere valorizzata. Se presente, la data non può essere retroattiva.
|
||||
-- ----------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS consegna (
|
||||
ConsegnaID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
ClienteID INT UNSIGNED NOT NULL,
|
||||
DataRitiro DATE NOT NULL,
|
||||
DataConsegna DATE NOT NULL,
|
||||
DataRitiro DATE NULL,
|
||||
DataConsegna DATE NULL,
|
||||
Stato ENUM('da ritirare', 'in deposito', 'in consegna', 'in giacenza') NOT NULL DEFAULT 'in deposito',
|
||||
ChiaveConsegna VARCHAR(8) NOT NULL,
|
||||
|
||||
|
|
@ -69,7 +71,10 @@ CREATE TABLE IF NOT EXISTS consegna (
|
|||
FOREIGN KEY (ClienteID)
|
||||
REFERENCES cliente (ClienteID)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE RESTRICT
|
||||
ON DELETE RESTRICT,
|
||||
|
||||
CONSTRAINT chk_consegna_almeno_una_data
|
||||
CHECK (DataRitiro IS NOT NULL OR DataConsegna IS NOT NULL)
|
||||
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
|
|
@ -89,12 +94,12 @@ CREATE TRIGGER trg_consegna_no_retroattivita_insert
|
|||
BEFORE INSERT ON consegna
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.DataRitiro < CURDATE() THEN
|
||||
IF NEW.DataRitiro IS NOT NULL AND NEW.DataRitiro < CURDATE() THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'DataRitiro non può essere anteriore alla data odierna';
|
||||
END IF;
|
||||
|
||||
IF NEW.DataConsegna < CURDATE() THEN
|
||||
IF NEW.DataConsegna IS NOT NULL AND NEW.DataConsegna < CURDATE() THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'DataConsegna non può essere anteriore alla data odierna';
|
||||
END IF;
|
||||
|
|
@ -104,12 +109,16 @@ CREATE TRIGGER trg_consegna_no_retroattivita_update
|
|||
BEFORE UPDATE ON consegna
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.DataRitiro <> OLD.DataRitiro AND NEW.DataRitiro < CURDATE() THEN
|
||||
IF NEW.DataRitiro IS NOT NULL
|
||||
AND (OLD.DataRitiro IS NULL OR NEW.DataRitiro <> OLD.DataRitiro)
|
||||
AND NEW.DataRitiro < CURDATE() THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'DataRitiro non può essere anteriore alla data odierna';
|
||||
END IF;
|
||||
|
||||
IF NEW.DataConsegna <> OLD.DataConsegna AND NEW.DataConsegna < CURDATE() THEN
|
||||
IF NEW.DataConsegna IS NOT NULL
|
||||
AND (OLD.DataConsegna IS NULL OR NEW.DataConsegna <> OLD.DataConsegna)
|
||||
AND NEW.DataConsegna < CURDATE() THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'DataConsegna non può essere anteriore alla data odierna';
|
||||
END IF;
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@ INSERT INTO cliente (Nome, Cognome, Via, Comune, Provincia, Telefono, Email, Not
|
|||
-- ClienteID: 1=Mario, 2=Laura, 3=Marco, 4=Giulia, 5=Paolo
|
||||
-- ------------------------------------------------------------
|
||||
-- Date dinamiche: compatibili con i trigger di retroattività (>= CURDATE())
|
||||
-- DataRitiro e DataConsegna sono indipendenti (es. riga 4: consegna prima del ritiro)
|
||||
-- DataRitiro e DataConsegna sono indipendenti; almeno una delle due è obbligatoria.
|
||||
-- Esempi: solo ritiro (CNSG2406), solo consegna (CNSG5522), entrambe (CNSG9001).
|
||||
INSERT INTO consegna (ClienteID, DataRitiro, DataConsegna, Stato, ChiaveConsegna) VALUES
|
||||
(1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 2 DAY), 'in deposito', 'CNSG9001'),
|
||||
(2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 1 DAY), 'in consegna', 'CNSG3344'),
|
||||
(3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 1 DAY), 'da ritirare', 'CNSG2406'),
|
||||
(3, CURDATE(), NULL, 'da ritirare', 'CNSG2406'),
|
||||
(4, DATE_ADD(CURDATE(), INTERVAL 5 DAY), DATE_ADD(CURDATE(), INTERVAL 2 DAY), 'in giacenza', 'CNSG7788'),
|
||||
(5, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 1 DAY), 'in deposito', 'CNSG5522'),
|
||||
(5, NULL, DATE_ADD(CURDATE(), INTERVAL 1 DAY), 'in deposito', 'CNSG5522'),
|
||||
(1, DATE_ADD(CURDATE(), INTERVAL 1 DAY), DATE_ADD(CURDATE(), INTERVAL 3 DAY), 'da ritirare', 'CNSG9876'),
|
||||
(2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 2 DAY), 'in consegna', 'CNSG1122');
|
||||
|
|
|
|||
|
|
@ -58,6 +58,16 @@ export function mapDbError(error: unknown): DbErrorResponse | null {
|
|||
}
|
||||
}
|
||||
|
||||
if (err.code === "ER_CHECK_CONSTRAINT_VIOLATED") {
|
||||
if (message.includes("chk_consegna_almeno_una_data")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Inserire almeno una data di ritiro o di consegna",
|
||||
fields: { _form: "Inserire almeno una data di ritiro o di consegna" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (err.code === "ER_ROW_IS_REFERENCED_2") {
|
||||
return {
|
||||
status: 409,
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ const router = Router();
|
|||
interface ConsegnaRow extends RowDataPacket {
|
||||
ConsegnaID: number;
|
||||
ClienteID: number;
|
||||
DataRitiro: Date | string;
|
||||
DataConsegna: Date | string;
|
||||
DataRitiro: Date | string | null;
|
||||
DataConsegna: Date | string | null;
|
||||
Stato: string;
|
||||
ChiaveConsegna: string;
|
||||
ClienteNome: string;
|
||||
|
|
@ -37,7 +37,8 @@ const SELECT_BASE = `
|
|||
INNER JOIN cliente cl ON cl.ClienteID = c.ClienteID
|
||||
`;
|
||||
|
||||
function formatDate(value: Date | string): string {
|
||||
function formatDate(value: Date | string | null): string | null {
|
||||
if (value == null) return null;
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
|
@ -142,7 +143,7 @@ router.put("/:id", validateBody(validateConsegnaUpdate), async (req, res) => {
|
|||
|
||||
const updates = res.locals.validatedBody as Partial<ConsegnaInput>;
|
||||
const setClauses: string[] = [];
|
||||
const values: (string | number)[] = [];
|
||||
const values: (string | number | null)[] = [];
|
||||
|
||||
if (updates.dataRitiro !== undefined) {
|
||||
setClauses.push("DataRitiro = ?");
|
||||
|
|
@ -165,6 +166,23 @@ router.put("/:id", validateBody(validateConsegnaUpdate), async (req, res) => {
|
|||
values.push(updates.clienteId);
|
||||
}
|
||||
|
||||
const mergedRitiro =
|
||||
updates.dataRitiro !== undefined
|
||||
? updates.dataRitiro
|
||||
: formatDate(existing.DataRitiro);
|
||||
const mergedConsegna =
|
||||
updates.dataConsegna !== undefined
|
||||
? updates.dataConsegna
|
||||
: formatDate(existing.DataConsegna);
|
||||
|
||||
if (!mergedRitiro && !mergedConsegna) {
|
||||
res.status(400).json({
|
||||
error: "Inserire almeno una data di ritiro o di consegna",
|
||||
fields: { _form: "Inserire almeno una data di ritiro o di consegna" },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await pool.execute<ResultSetHeader>(
|
||||
`UPDATE consegna SET ${setClauses.join(", ")} WHERE ConsegnaID = ?`,
|
||||
|
|
|
|||
|
|
@ -12,15 +12,16 @@ import {
|
|||
const router = Router();
|
||||
|
||||
interface VerificaRow extends RowDataPacket {
|
||||
DataRitiro: Date | string;
|
||||
DataConsegna: Date | string;
|
||||
DataRitiro: Date | string | null;
|
||||
DataConsegna: Date | string | null;
|
||||
Stato: string;
|
||||
ClienteNome: string;
|
||||
ClienteCognome: string;
|
||||
Comune: string;
|
||||
}
|
||||
|
||||
function formatDate(value: Date | string): string {
|
||||
function formatDate(value: Date | string | null): string | null {
|
||||
if (value == null) return null;
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ export interface Cliente {
|
|||
export interface Consegna {
|
||||
ConsegnaID: number;
|
||||
ClienteID: number;
|
||||
DataRitiro: Date;
|
||||
DataConsegna: Date;
|
||||
DataRitiro: Date | null;
|
||||
DataConsegna: Date | null;
|
||||
Stato: StatoConsegna;
|
||||
ChiaveConsegna: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,18 @@ import {
|
|||
} from "./primitives.js";
|
||||
|
||||
export interface ConsegnaInput {
|
||||
dataRitiro: string;
|
||||
dataConsegna: string;
|
||||
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);
|
||||
|
|
@ -48,10 +53,31 @@ function validateDateNotRetroactive(
|
|||
}
|
||||
}
|
||||
|
||||
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: normalizeString(raw.dataRitiro),
|
||||
dataConsegna: normalizeString(raw.dataConsegna),
|
||||
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),
|
||||
|
|
@ -65,20 +91,17 @@ function validateConsegnaFields(
|
|||
options: { requireAll: boolean }
|
||||
): void {
|
||||
if (options.requireAll || "dataRitiro" in raw) {
|
||||
validateRequired(errors, "dataRitiro", data.dataRitiro, "Data ritiro obbligatoria");
|
||||
validateDate(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
validateDateNotRetroactive(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
validateOptionalDateField(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
}
|
||||
|
||||
if (options.requireAll || "dataConsegna" in raw) {
|
||||
validateRequired(
|
||||
errors,
|
||||
"dataConsegna",
|
||||
data.dataConsegna,
|
||||
"Data consegna obbligatoria"
|
||||
);
|
||||
validateDate(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
||||
validateDateNotRetroactive(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
||||
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) {
|
||||
|
|
@ -129,22 +152,17 @@ export function validateConsegnaUpdate(
|
|||
const data: Partial<ConsegnaInput> = {};
|
||||
|
||||
if ("dataRitiro" in raw) {
|
||||
data.dataRitiro = normalizeString(raw.dataRitiro);
|
||||
validateRequired(errors, "dataRitiro", data.dataRitiro, "Data ritiro obbligatoria");
|
||||
validateDate(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
validateDateNotRetroactive(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
data.dataRitiro = normalizeOptionalDate(raw.dataRitiro);
|
||||
validateOptionalDateField(errors, "dataRitiro", data.dataRitiro, "Data ritiro");
|
||||
}
|
||||
|
||||
if ("dataConsegna" in raw) {
|
||||
data.dataConsegna = normalizeString(raw.dataConsegna);
|
||||
validateRequired(
|
||||
errors,
|
||||
"dataConsegna",
|
||||
data.dataConsegna,
|
||||
"Data consegna obbligatoria"
|
||||
);
|
||||
validateDate(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
||||
validateDateNotRetroactive(errors, "dataConsegna", data.dataConsegna, "Data consegna");
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ export const UTENTE_CONSTRAINTS = {
|
|||
} as const;
|
||||
|
||||
|
||||
export const CONSEGNA_CONSTRAINTS = {
|
||||
dataconsegna: { required: true },
|
||||
dataritiro: {required: true},
|
||||
export const CONSEGNA_CONSTRAINTS = {
|
||||
dataRitiro: { required: false },
|
||||
dataConsegna: { required: false },
|
||||
stato: {
|
||||
allowedValues: ["da ritirare", "in consegna", "in giacenza", "in deposito"],
|
||||
required: true,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue