🚀 Début de la migration Multi-Tenant"; try { $stmt = $meta_pdo->query("SELECT db_name, name FROM families WHERE is_active = 1"); $families = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($families as $family) { $dbName = $family['db_name']; echo "

Famille : {$family['name']} ($dbName)

"; try { $pdo = new PDO( "mysql:host=$db_host;dbname=$dbName;charset=utf8mb4", $db_user, $db_pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // --------------------------------------------------------- // 1. UPDATE DE pf_people (Juste la date de naissance et l'état actif) // --------------------------------------------------------- $colCheck = $pdo->prepare("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'pf_people' AND COLUMN_NAME = 'birthdate'"); $colCheck->execute([$dbName]); if ($colCheck->rowCount() === 0) { $pdo->exec("ALTER TABLE pf_people ADD COLUMN birthdate DATE DEFAULT NULL, ADD COLUMN is_active TINYINT(1) DEFAULT 1 "); echo "✅ pf_people mis à jour (birthdate ajouté).
"; } else { echo "➖ pf_people déjà à jour.
"; } // --------------------------------------------------------- // 2. CRÉATION DES NOUVELLES TABLES (IF NOT EXISTS) // --------------------------------------------------------- // Comptes bancaires $pdo->exec("CREATE TABLE IF NOT EXISTS pf_bank_accounts ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, owner_person_id INT DEFAULT NULL, account_type VARCHAR(50) DEFAULT 'savings', is_default TINYINT(1) DEFAULT 0, FOREIGN KEY (owner_person_id) REFERENCES pf_people(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); // Catégories de budget $pdo->exec("CREATE TABLE IF NOT EXISTS pf_budget_categories ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(50) NOT NULL, label VARCHAR(100) NOT NULL, type VARCHAR(50) NOT NULL, color VARCHAR(20) DEFAULT '#ccc', icon VARCHAR(20) DEFAULT '💰', UNIQUE KEY (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); // Types de congés $pdo->exec("CREATE TABLE IF NOT EXISTS pf_leave_types ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(20) NOT NULL, label VARCHAR(100) NOT NULL, default_allowance DECIMAL(5,2) DEFAULT 0, reset_month INT DEFAULT 1, allow_carry_over TINYINT(1) DEFAULT 0, UNIQUE KEY (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); // Fêtes (Cadeaux) $pdo->exec("CREATE TABLE IF NOT EXISTS pf_gift_occasions ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(20) NOT NULL, name VARCHAR(100) NOT NULL, month_date VARCHAR(5) DEFAULT NULL, is_active TINYINT(1) DEFAULT 1, UNIQUE KEY (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); // Règles Cadeaux $pdo->exec("CREATE TABLE IF NOT EXISTS pf_gift_rules ( id INT AUTO_INCREMENT PRIMARY KEY, adult_person_id INT NOT NULL, child_person_id INT NOT NULL, occasion_id INT NOT NULL, FOREIGN KEY (adult_person_id) REFERENCES pf_people(id) ON DELETE CASCADE, FOREIGN KEY (child_person_id) REFERENCES pf_people(id) ON DELETE CASCADE, FOREIGN KEY (occasion_id) REFERENCES pf_gift_occasions(id) ON DELETE CASCADE, UNIQUE KEY adult_child_occ (adult_person_id, child_person_id, occasion_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); echo "✅ Nouvelles tables de configuration créées ou vérifiées.
"; // --------------------------------------------------------- // 3. INJECTION DE DONNÉES PAR DÉFAUT (Pour ne rien casser) // --------------------------------------------------------- if ($pdo->query("SELECT COUNT(*) FROM pf_bank_accounts")->fetchColumn() == 0) { $pdo->exec("INSERT INTO pf_bank_accounts (name, account_type, is_default) VALUES ('Compte Commun', 'checking', 1), ('Livret A Alex', 'savings', 0), ('Livret A Laia', 'savings', 0), ('Livret A Pol', 'savings', 0), ('Livret A Pep', 'savings', 0) "); } if ($pdo->query("SELECT COUNT(*) FROM pf_budget_categories")->fetchColumn() == 0) { $pdo->exec("INSERT INTO pf_budget_categories (code, label, type, color, icon) VALUES ('INCOME', 'Revenus', 'Income', '#22c55e', '💵'), ('FMCG', 'Alimentation', 'Expense', '#3b82f6', '🛒'), ('FUEL', 'Carburant', 'Expense', '#f59e0b', '⛽'), ('SCHOOL', 'École / Garde', 'Expense', '#a855f7', '🎒'), ('HEALTH', 'Santé', 'Expense', '#ef4444', '⚕️') "); } if ($pdo->query("SELECT COUNT(*) FROM pf_leave_types")->fetchColumn() == 0) { $pdo->exec("INSERT INTO pf_leave_types (code, label, default_allowance, reset_month, allow_carry_over) VALUES ('CA', 'Congés Annuels', 25, 6, 1), ('JRA', 'Jours de Repos', 10, 1, 0), ('JA', 'Jour Anniversaire', 1, 1, 0) "); } if ($pdo->query("SELECT COUNT(*) FROM pf_gift_occasions")->fetchColumn() == 0) { $pdo->exec("INSERT INTO pf_gift_occasions (code, name, month_date) VALUES ('NOEL', 'Noël', '12-25'), ('ROIS', 'Les Rois', '01-06'), ('ANNIV', 'Anniversaire', NULL) "); } echo "✅ Données de base injectées (si nécessaire).
"; // --------------------------------------------------------- // 4. MIGRATION SPECIFIQUE : MODULE CALENDRIER (CONGÉS GRANULAIRES) // --------------------------------------------------------- $tableExists = $pdo->query("SHOW TABLES LIKE 'pf_person_leave_meta'")->rowCount() > 0; if (!$tableExists) { $pdo->exec(" CREATE TABLE pf_person_leave_meta ( id INT AUTO_INCREMENT PRIMARY KEY, person_id INT NOT NULL, leave_type VARCHAR(50) NOT NULL, anniversary_date DATE NOT NULL, UNIQUE KEY uq_person_leave (person_id, leave_type), FOREIGN KEY (person_id) REFERENCES pf_people(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "); echo "✅ Table pf_person_leave_meta créée (Nouvelle installation).
"; } else { $checkColumn = $pdo->query("SHOW COLUMNS FROM pf_person_leave_meta LIKE 'leave_type'")->rowCount(); if ($checkColumn === 0) { $pdo->exec("ALTER TABLE pf_person_leave_meta ADD COLUMN leave_type VARCHAR(50) NULL AFTER person_id"); $pdo->exec("UPDATE pf_person_leave_meta SET leave_type = 'CP' WHERE leave_type IS NULL"); $pdo->exec("ALTER TABLE pf_person_leave_meta MODIFY COLUMN leave_type VARCHAR(50) NOT NULL"); try { $pdo->exec("ALTER TABLE pf_person_leave_meta DROP INDEX person_id"); } catch (\Throwable $e) { // On ignore si l'index n'avait pas ce nom } $pdo->exec("ALTER TABLE pf_person_leave_meta ADD UNIQUE KEY uq_person_leave (person_id, leave_type)"); echo "✅ Table pf_person_leave_meta mise à jour avec le type granulaire.
"; } else { echo "➖ Table pf_person_leave_meta déjà à jour.
"; } } } catch (PDOException $e) { echo "❌ Erreur sur la base $dbName : " . $e->getMessage() . "
"; } } echo "

🎉 Migration terminée avec succès !

"; } catch (Exception $e) { die("❌ Erreur fatale Meta DB : " . $e->getMessage()); } ?>