From cbf7318594e056098c249757b2f09806f8864434 Mon Sep 17 00:00:00 2001 From: AV77web Date: Tue, 9 Jun 2026 14:44:14 +0200 Subject: [PATCH] modifica a select dipendenti --- initdb/00_database.sql | 29 ++++++++++ initdb/01_schema.sql | 96 ++++++++++++++++++++++++++++----- initdb/02_seed.sql | 48 ++++++++++++----- initdb/03_fix_ruoli_utenti.sql | 7 +++ src/services/rimborsiService.ts | 8 ++- 5 files changed, 161 insertions(+), 27 deletions(-) create mode 100644 initdb/00_database.sql create mode 100644 initdb/03_fix_ruoli_utenti.sql diff --git a/initdb/00_database.sql b/initdb/00_database.sql new file mode 100644 index 0000000..79cee0b --- /dev/null +++ b/initdb/00_database.sql @@ -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; diff --git a/initdb/01_schema.sql b/initdb/01_schema.sql index 84e3c5b..aa4be2e 100644 --- a/initdb/01_schema.sql +++ b/initdb/01_schema.sql @@ -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; diff --git a/initdb/02_seed.sql b/initdb/02_seed.sql index 379280b..ec12675 100644 --- a/initdb/02_seed.sql +++ b/initdb/02_seed.sql @@ -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); diff --git a/initdb/03_fix_ruoli_utenti.sql b/initdb/03_fix_ruoli_utenti.sql new file mode 100644 index 0000000..d5768bb --- /dev/null +++ b/initdb/03_fix_ruoli_utenti.sql @@ -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); diff --git a/src/services/rimborsiService.ts b/src/services/rimborsiService.ts index a8f7a95..114ca36 100644 --- a/src/services/rimborsiService.ts +++ b/src/services/rimborsiService.ts @@ -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( - "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 }[]; }