modifica a select dipendenti
All checks were successful
Deploy to VPS / build (push) Successful in 17s
Deploy to VPS / deploy (push) Successful in 21s

This commit is contained in:
AV77web 2026-06-09 14:44:14 +02:00
parent cad02db518
commit cbf7318594
5 changed files with 161 additions and 27 deletions

29
initdb/00_database.sql Normal file
View file

@ -0,0 +1,29 @@
-- ============================================================
-- Database: Gestione Rimborsi Spese Aziendali (Prova S5)
-- Creazione database e utente applicativo
-- MySQL 8.0+
-- ============================================================
-- Con Docker Compose il database e l'utente vengono creati
-- automaticamente dalle variabili MYSQL_* nel file .env.
-- Questo script è utile per installazione manuale su MySQL locale.
-- ============================================================
CREATE DATABASE IF NOT EXISTS provapratica
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'provapratica_user'@'%'
IDENTIFIED BY 'altra_password_sicura';
CREATE USER IF NOT EXISTS 'provapratica_user'@'localhost'
IDENTIFIED BY 'altra_password_sicura';
GRANT SELECT, INSERT, UPDATE, DELETE
ON provapratica.*
TO 'provapratica_user'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE
ON provapratica.*
TO 'provapratica_user'@'localhost';
FLUSH PRIVILEGES;

View file

@ -1,25 +1,48 @@
-- ============================================================
-- Schema tabelle Gestione Rimborsi Spese Aziendali
-- ============================================================
USE provapratica;
-- ------------------------------------------------------------
-- Tabella UTENTI
-- Ruoli: DIPENDENTE | RESPONSABILE_AMMINISTRATIVO
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS utenti (
utente_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
nome VARCHAR(100) NOT NULL,
cognome VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
ruolo ENUM('DIPENDENTE', 'RESPONSABILE_AMMINISTRATIVO') NOT NULL DEFAULT 'DIPENDENTE',
password_hash VARCHAR(255) NOT NULL COMMENT 'Password salvata come hash (es. bcrypt)',
ruolo ENUM('DIPENDENTE', 'RESPONSABILE_AMMINISTRATIVO')
NOT NULL DEFAULT 'DIPENDENTE',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (utente_id),
UNIQUE KEY uk_utenti_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
PRIMARY KEY (utente_id),
UNIQUE KEY uk_utenti_email (email),
KEY idx_utenti_ruolo (ruolo)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;
-- ------------------------------------------------------------
-- Tabella CATEGORIE_SPESA
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS categorie_spesa (
categoria_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
descrizione VARCHAR(150) NOT NULL,
PRIMARY KEY (categoria_id),
UNIQUE KEY uk_categorie_spesa_descrizione (descrizione)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;
-- ------------------------------------------------------------
-- Tabella RICHIESTE_RIMBORSO
-- Stati: IN_ATTESA | APPROVATA | RIFIUTATA | LIQUIDATA
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS richieste_rimborso (
richiesta_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data_inserimento DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
@ -28,15 +51,64 @@ CREATE TABLE IF NOT EXISTS richieste_rimborso (
importo DECIMAL(10, 2) NOT NULL,
descrizione VARCHAR(500) NOT NULL,
riferimento_giustificativo VARCHAR(255) NULL,
stato ENUM('IN_ATTESA', 'APPROVATA', 'RIFIUTATA', 'LIQUIDATA') NOT NULL DEFAULT 'IN_ATTESA',
stato ENUM('IN_ATTESA', 'APPROVATA', 'RIFIUTATA', 'LIQUIDATA')
NOT NULL DEFAULT 'IN_ATTESA',
dipendente_id INT UNSIGNED NOT NULL,
data_valutazione DATETIME NULL,
responsabile_valutazione_id INT UNSIGNED NULL,
motivazione_rifiuto VARCHAR(500) NULL,
data_liquidazione DATETIME NULL,
PRIMARY KEY (richiesta_id),
CONSTRAINT fk_richieste_categoria FOREIGN KEY (categoria_id) REFERENCES categorie_spesa (categoria_id),
CONSTRAINT fk_richieste_dipendente FOREIGN KEY (dipendente_id) REFERENCES utenti (utente_id),
CONSTRAINT fk_richieste_responsabile FOREIGN KEY (responsabile_valutazione_id) REFERENCES utenti (utente_id),
CONSTRAINT chk_richieste_importo_positivo CHECK (importo > 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CONSTRAINT fk_richieste_categoria
FOREIGN KEY (categoria_id)
REFERENCES categorie_spesa (categoria_id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_richieste_dipendente
FOREIGN KEY (dipendente_id)
REFERENCES utenti (utente_id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_richieste_responsabile
FOREIGN KEY (responsabile_valutazione_id)
REFERENCES utenti (utente_id)
ON UPDATE CASCADE
ON DELETE SET NULL,
CONSTRAINT chk_richieste_importo_positivo
CHECK (importo > 0),
CONSTRAINT chk_richieste_descrizione_non_vuota
CHECK (CHAR_LENGTH(TRIM(descrizione)) > 0),
CONSTRAINT chk_richieste_data_valutazione
CHECK (
data_valutazione IS NULL
OR data_valutazione >= data_inserimento
),
CONSTRAINT chk_richieste_data_liquidazione
CHECK (
data_liquidazione IS NULL
OR data_valutazione IS NULL
OR data_liquidazione >= data_valutazione
),
CONSTRAINT chk_richieste_rifiuto_motivazione
CHECK (
stato <> 'RIFIUTATA'
OR motivazione_rifiuto IS NOT NULL
),
KEY idx_richieste_stato (stato),
KEY idx_richieste_data_spesa (data_spesa),
KEY idx_richieste_dipendente (dipendente_id),
KEY idx_richieste_categoria (categoria_id),
KEY idx_richieste_data_inserimento (data_inserimento)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;

View file

@ -1,25 +1,45 @@
-- ============================================================
-- Dati iniziali di test Gestione Rimborsi Spese Aziendali
-- Utenti: già presenti in tabella utenti (id 1-4)
-- 1 andrea villari responsabile valutazioni
-- 2 mario rossi
-- 3 marco bianchi
-- 4 anna verdi
-- ============================================================
USE provapratica;
INSERT INTO categorie_spesa (descrizione) VALUES
-- Ruoli corretti per gli utenti di test (id 1 = responsabile, 2-4 = dipendenti)
UPDATE utenti SET ruolo = 'RESPONSABILE_AMMINISTRATIVO' WHERE utente_id = 1;
UPDATE utenti SET ruolo = 'DIPENDENTE' WHERE utente_id IN (2, 3, 4);
INSERT IGNORE INTO categorie_spesa (descrizione) VALUES
('Trasferta'),
('Pasto'),
('Pedaggio'),
('Parcheggio'),
('Acquisto autorizzato');
-- Password per tutti: Password123!
INSERT INTO utenti (nome, cognome, email, password_hash, ruolo) VALUES
('Marco', 'Rossi', 'marco.rossi@azienda.it', '$2b$10$xJ9shj7EP1XZzcKztutcs.K4np19OVExwZcSGlBmS/5WTZSt9W.c6', 'DIPENDENTE'),
('Laura', 'Bianchi', 'laura.bianchi@azienda.it', '$2b$10$xJ9shj7EP1XZzcKztutcs.K4np19OVExwZcSGlBmS/5WTZSt9W.c6', 'DIPENDENTE'),
('Giulia', 'Verdi', 'giulia.verdi@azienda.it', '$2b$10$xJ9shj7EP1XZzcKztutcs.K4np19OVExwZcSGlBmS/5WTZSt9W.c6', 'DIPENDENTE'),
('Paolo', 'Admin', 'admin@azienda.it', '$2b$10$xJ9shj7EP1XZzcKztutcs.K4np19OVExwZcSGlBmS/5WTZSt9W.c6', 'RESPONSABILE_AMMINISTRATIVO');
-- categoria_id: 1=Trasferta, 2=Pasto, 3=Pedaggio, 4=Parcheggio, 5=Acquisto autorizzato
INSERT INTO richieste_rimborso
(data_inserimento, data_spesa, categoria_id, importo, descrizione, riferimento_giustificativo, stato, dipendente_id, data_valutazione, responsabile_valutazione_id, motivazione_rifiuto, data_liquidazione)
VALUES
('2026-05-02 09:00:00', '2026-05-01', 1, 120.50, 'Trasferta Milano-Bologna', 'BIGL-001', 'IN_ATTESA', 1, NULL, NULL, NULL, NULL),
('2026-05-03 10:00:00', '2026-05-02', 2, 35.00, 'Pranzo con cliente', 'SCONTR-102', 'IN_ATTESA', 1, NULL, NULL, NULL, NULL),
('2026-05-05 11:00:00', '2026-05-04', 3, 18.50, 'Pedaggio autostrada A1', 'PED-445', 'APPROVATA', 2, '2026-05-06 14:00:00', 4, NULL, NULL),
('2026-05-07 08:30:00', '2026-05-06', 4, 12.00, 'Parcheggio centro storico', NULL, 'LIQUIDATA', 2, '2026-05-08 09:00:00', 4, NULL, '2026-05-10 16:00:00'),
('2026-05-08 15:00:00', '2026-05-07', 5, 45.00, 'Cancelleria per ufficio', 'FATT-778', 'RIFIUTATA', 3, '2026-05-09 10:00:00', 4, 'Spesa non autorizzata preventivamente', NULL),
('2026-05-10 09:00:00', '2026-05-09', 1, 89.00, 'Taxi aeroporto', 'TAXI-22', 'APPROVATA', 3, '2026-05-11 11:00:00', 4, NULL, NULL);
-- IN_ATTESA (modificabili/eliminabili dal dipendente)
('2026-06-01 09:15:00', '2026-05-28', 1, 145.80, 'Trasferta Roma-Milano per riunione commerciale', 'BIGL-2026-041', 'IN_ATTESA', 2, NULL, NULL, NULL, NULL),
('2026-06-03 11:20:00', '2026-06-02', 2, 42.50, 'Pranzo di lavoro con fornitore', 'SCONTR-887', 'IN_ATTESA', 3, NULL, NULL, NULL, NULL),
('2026-06-05 08:45:00', '2026-06-04', 4, 9.00, 'Parcheggio presso cliente', NULL, 'IN_ATTESA', 4, NULL, NULL, NULL, NULL),
-- APPROVATA (in attesa di liquidazione)
('2026-05-20 10:00:00', '2026-05-18', 3, 22.40, 'Pedaggio autostrada A14 Ancona-Rimini', 'PED-9921', 'APPROVATA', 2, '2026-05-21 15:30:00', 1, NULL, NULL),
('2026-05-25 14:30:00', '2026-05-24', 1, 67.00, 'Taxi da stazione a sede cliente', 'TAXI-334', 'APPROVATA', 3, '2026-05-26 09:00:00', 1, NULL, NULL),
-- RIFIUTATA
('2026-05-15 16:00:00', '2026-05-14', 5, 89.90, 'Acquisto materiale ufficio non preventivato', 'FATT-5567', 'RIFIUTATA', 4, '2026-05-16 11:00:00', 1, 'Mancanza di autorizzazione preventiva dal responsabile', NULL),
-- LIQUIDATA
('2026-05-10 09:00:00', '2026-05-08', 2, 28.00, 'Cena durante trasferta serale', 'SCONTR-412', 'LIQUIDATA', 2, '2026-05-11 10:00:00', 1, NULL, '2026-05-13 17:00:00'),
('2026-05-12 08:30:00', '2026-05-10', 4, 15.50, 'Parcheggio aeroporto Fiumicino', 'PARC-221', 'LIQUIDATA', 3, '2026-05-13 09:30:00', 1, NULL, '2026-05-15 16:45:00'),
-- Altri mesi per test filtro statistiche
('2026-04-08 10:00:00', '2026-04-07', 1, 198.00, 'Volo andata/ritorno Napoli-Torino', 'VOL-7788', 'LIQUIDATA', 4, '2026-04-09 11:00:00', 1, NULL, '2026-04-12 14:00:00'),
('2026-04-22 13:00:00', '2026-04-20', 3, 31.20, 'Pedaggi trasferta settimanale', 'PED-4401', 'APPROVATA', 2, '2026-04-23 09:00:00', 1, NULL, NULL);

View file

@ -0,0 +1,7 @@
-- Correzione ruoli utenti di test su database già esistente.
-- Eseguire manualmente se il seed iniziale è già stato applicato senza gli UPDATE.
USE provapratica;
UPDATE utenti SET ruolo = 'RESPONSABILE_AMMINISTRATIVO' WHERE utente_id = 1;
UPDATE utenti SET ruolo = 'DIPENDENTE' WHERE utente_id IN (2, 3, 4);

View file

@ -219,7 +219,13 @@ export async function listCategorie(): Promise<{ categoria_id: number; descrizio
export async function listDipendenti(): Promise<{ utente_id: number; nome: string; cognome: string }[]> {
const [rows] = await pool.execute<RowDataPacket[]>(
"SELECT utente_id, nome, cognome FROM utenti WHERE ruolo = 'DIPENDENTE' ORDER BY cognome, nome"
`SELECT DISTINCT u.utente_id, u.nome, u.cognome
FROM utenti u
WHERE u.ruolo = 'DIPENDENTE'
OR EXISTS (
SELECT 1 FROM richieste_rimborso r WHERE r.dipendente_id = u.utente_id
)
ORDER BY u.cognome, u.nome`
);
return rows as { utente_id: number; nome: string; cognome: string }[];
}