Livraison d ela gestion des opérations v0.4.0

This commit is contained in:
d6soft
2025-06-24 13:01:43 +02:00
parent 25c9d5874c
commit 416d648a14
813 changed files with 234012 additions and 73933 deletions

View File

@@ -0,0 +1,933 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xls;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
require_once __DIR__ . '/../Services/FileService.php';
class ExportService {
private \PDO $db;
private FileService $fileService;
public function __construct() {
$this->db = Database::getInstance();
$this->fileService = new FileService();
}
/**
* Génère un export Excel complet d'une opération
*
* @param int $operationId ID de l'opération
* @param int $entiteId ID de l'entité
* @param int|null $userId Filtrer par utilisateur (optionnel)
* @return array Informations du fichier généré
*/
public function generateExcelExport(int $operationId, int $entiteId, ?int $userId = null): array {
try {
// Récupérer les données de l'opération
$operationData = $this->getOperationData($operationId, $entiteId);
if (!$operationData) {
throw new Exception('Opération non trouvée');
}
// Créer le dossier de destination
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}/exports/excel");
LogService::log('exportDir', [
'level' => 'warning',
'exportDir' => $exportDir,
]);
// Générer le nom du fichier
$timestamp = date('Ymd-His');
$userSuffix = $userId ? "-user{$userId}" : '';
$filename = "geosector-export-{$operationId}{$userSuffix}-{$timestamp}.xlsx";
$filepath = $exportDir . '/' . $filename;
// Créer le spreadsheet
$spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
// Insérer les données
$this->createPassagesSheet($spreadsheet, $operationId, $userId);
$this->createUsersSheet($spreadsheet, $operationId);
$this->createSectorsSheet($spreadsheet, $operationId);
$this->createUserSectorsSheet($spreadsheet, $operationId);
// Supprimer la feuille par défaut (Worksheet) qui est créée automatiquement
$defaultSheet = $spreadsheet->getSheetByName('Worksheet');
if ($defaultSheet) {
$spreadsheet->removeSheetByIndex($spreadsheet->getIndex($defaultSheet));
}
// Essayer d'abord le writer XLSX, sinon utiliser CSV
try {
$writer = new Xls($spreadsheet);
$writer->save($filepath);
} catch (Exception $e) {
// Si XLSX échoue, utiliser CSV comme fallback
$csvPath = str_replace('.xlsx', '.csv', $filepath);
$csvWriter = new Csv($spreadsheet);
$csvWriter->setDelimiter(';');
$csvWriter->setEnclosure('"');
$csvWriter->save($csvPath);
// Mettre à jour les variables pour le CSV
$filepath = $csvPath;
$filename = str_replace('.xlsx', '.csv', $filename);
LogService::log('Fallback vers CSV car XLSX a échoué', [
'level' => 'warning',
'error' => $e->getMessage(),
'operationId' => $operationId
]);
}
// Appliquer les permissions sur le fichier
$this->fileService->setFilePermissions($filepath);
// Déterminer le type de fichier réellement généré
$fileType = str_ends_with($filename, '.csv') ? 'csv' : 'xlsx';
// Enregistrer en base de données
$mediaId = $this->fileService->saveToMediasTable($entiteId, $operationId, $filename, $filepath, $fileType, 'Export Excel opération - ' . $operationData['libelle']);
LogService::log('Export Excel généré', [
'level' => 'info',
'operationId' => $operationId,
'entiteId' => $entiteId,
'path' => $exportDir,
'filename' => $filename,
'mediaId' => $mediaId
]);
return [
'id' => $mediaId,
'filename' => $filename,
'path' => str_replace(getcwd() . '/', '', $filepath),
'size' => filesize($filepath),
'type' => 'excel'
];
} catch (Exception $e) {
LogService::log('Erreur lors de la génération de l\'export Excel', [
'level' => 'error',
'error' => $e->getMessage(),
'operationId' => $operationId,
'entiteId' => $entiteId
]);
throw $e;
}
}
/**
* Génère un export JSON complet d'une opération (chiffré et compressé)
*
* @param int $operationId ID de l'opération
* @param int $entiteId ID de l'entité
* @param string $type Type d'export (auto, manual)
* @return array Informations du fichier généré
*/
public function generateJsonExport(int $operationId, int $entiteId, string $type = 'manual'): array {
try {
// Récupérer toutes les données de l'opération
$exportData = $this->collectOperationData($operationId, $entiteId);
// Créer le dossier de destination
$exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}/exports/json");
// Initialiser le service de chiffrement
$backupService = new BackupEncryptionService();
// Générer le JSON original
$jsonData = json_encode($exportData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
// Chiffrer et compresser les données
$encryptedData = $backupService->encryptBackup($jsonData);
// Générer le nom du fichier avec extension appropriée
$timestamp = date('Ymd-His');
$filename = $backupService->generateBackupFilename($operationId, $timestamp, $type);
$filepath = $exportDir . '/' . $filename;
// Sauvegarder le fichier chiffré
file_put_contents($filepath, $encryptedData);
// Appliquer les permissions sur le fichier
$this->fileService->setFilePermissions($filepath);
// Obtenir les statistiques de compression
$stats = $backupService->getCompressionStats($jsonData, $encryptedData);
// Enregistrer en base de données avec le bon type MIME
$mediaId = $this->fileService->saveToMediasTable(
$entiteId,
$operationId,
$filename,
$filepath,
'enc',
"Sauvegarde chiffrée opération - {$type} - " . $exportData['operation']['libelle'],
'backup'
);
LogService::log('Export JSON chiffré généré', [
'level' => 'info',
'operationId' => $operationId,
'entiteId' => $entiteId,
'filename' => $filename,
'type' => $type,
'mediaId' => $mediaId,
'original_size' => $stats['original_size'],
'final_size' => $stats['final_size'],
'compression_ratio' => $stats['compression_ratio'] . '%',
'is_compressed' => $stats['is_compressed'],
'cipher' => $stats['cipher']
]);
return [
'id' => $mediaId,
'filename' => $filename,
'path' => str_replace(getcwd() . '/', '', $filepath),
'size' => filesize($filepath),
'type' => 'encrypted_json',
'compression_stats' => $stats
];
} catch (Exception $e) {
LogService::log('Erreur lors de la génération de l\'export JSON chiffré', [
'level' => 'error',
'error' => $e->getMessage(),
'operationId' => $operationId,
'entiteId' => $entiteId
]);
throw $e;
}
}
/**
* Crée la feuille des passages
*/
private function createPassagesSheet(Spreadsheet $spreadsheet, int $operationId, ?int $userId = null): void {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Passages');
// En-têtes
$headers = [
'ID_Passage',
'Date',
'Heure',
'Prénom',
'Nom',
'Tournée',
'Type',
'N°',
'Bis',
'Rue',
'Ville',
'Habitat',
'Donateur',
'Email',
'Tél',
'Montant',
'Règlement',
'Remarque',
'FK_User',
'FK_Sector',
'FK_Operation'
];
// Écrire les en-têtes
$sheet->fromArray([$headers], null, 'A1');
// Récupérer les données des passages
$sql = '
SELECT
p.id, p.passed_at, p.fk_type, p.numero, p.rue_bis, p.rue, p.ville,
p.fk_habitat, p.appt, p.niveau, p.encrypted_name, p.encrypted_email,
p.encrypted_phone, p.montant, p.fk_type_reglement, p.remarque,
p.fk_user, p.fk_sector, p.fk_operation,
u.encrypted_name as user_name, u.first_name as user_first_name, u.sect_name,
xtr.libelle as reglement_libelle
FROM ope_pass p
LEFT JOIN users u ON u.id = p.fk_user
LEFT JOIN x_types_reglements xtr ON xtr.id = p.fk_type_reglement
WHERE p.fk_operation = ? AND p.chk_active = 1
';
$params = [$operationId];
if ($userId) {
$sql .= ' AND p.fk_user = ?';
$params[] = $userId;
}
$sql .= ' ORDER BY p.passed_at DESC';
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$passages = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Remplir les données
$row = 2;
foreach ($passages as $passage) {
$dateEve = $passage['passed_at'] ? date('d/m/Y', strtotime($passage['passed_at'])) : '';
$heureEve = $passage['passed_at'] ? date('H:i', strtotime($passage['passed_at'])) : '';
// Déchiffrer les données
$donateur = ApiService::decryptData($passage['encrypted_name']);
$email = !empty($passage['encrypted_email']) ? ApiService::decryptSearchableData($passage['encrypted_email']) : '';
$phone = !empty($passage['encrypted_phone']) ? ApiService::decryptData($passage['encrypted_phone']) : '';
$userName = ApiService::decryptData($passage['user_name']);
// Type de passage
$typeLabels = [
1 => 'Effectué',
2 => 'A finaliser',
3 => 'Refusé',
4 => 'Don',
9 => 'Habitat vide'
];
$typeLabel = $typeLabels[$passage['fk_type']] ?? $passage['fk_type'];
// Habitat
$habitat = $passage['fk_habitat'] == 1 ? 'Individuel' :
"Etage {$passage['niveau']} - Appt {$passage['appt']}";
$rowData = [
$passage['id'],
$dateEve,
$heureEve,
$passage['user_first_name'],
$userName,
$passage['sect_name'],
$typeLabel,
$passage['numero'],
$passage['rue_bis'],
$passage['rue'],
$passage['ville'],
$habitat,
$donateur,
$email,
$phone,
$passage['montant'],
$passage['reglement_libelle'],
$passage['remarque'],
$passage['fk_user'],
$passage['fk_sector'],
$passage['fk_operation']
];
$sheet->fromArray([$rowData], null, "A{$row}");
$row++;
}
// Auto-ajuster les colonnes
foreach (range('A', 'T') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
}
/**
* Crée la feuille des utilisateurs
*/
private function createUsersSheet(Spreadsheet $spreadsheet, int $operationId): void {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Utilisateurs');
// En-têtes
$headers = [
'ID_User',
'Nom',
'Prénom',
'Email',
'Téléphone',
'Mobile',
'Rôle',
'Date_création',
'Actif',
'FK_Entite'
];
$sheet->fromArray([$headers], null, 'A1');
// Récupérer les utilisateurs de l'opération
$sql = '
SELECT DISTINCT
u.id, u.encrypted_name, u.first_name, u.encrypted_email,
u.encrypted_phone, u.encrypted_mobile, u.fk_role, u.created_at,
u.chk_active, u.fk_entite,
r.libelle as role_libelle
FROM users u
INNER JOIN ope_users ou ON ou.fk_user = u.id
LEFT JOIN x_users_roles r ON r.id = u.fk_role
WHERE ou.fk_operation = ? AND ou.chk_active = 1
ORDER BY u.encrypted_name
';
$stmt = $this->db->prepare($sql);
$stmt->execute([$operationId]);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
$row = 2;
foreach ($users as $user) {
$rowData = [
$user['id'],
ApiService::decryptData($user['encrypted_name']),
$user['first_name'],
!empty($user['encrypted_email']) ? ApiService::decryptSearchableData($user['encrypted_email']) : '',
!empty($user['encrypted_phone']) ? ApiService::decryptData($user['encrypted_phone']) : '',
!empty($user['encrypted_mobile']) ? ApiService::decryptData($user['encrypted_mobile']) : '',
$user['role_libelle'],
date('d/m/Y H:i', strtotime($user['created_at'])),
$user['chk_active'] ? 'Oui' : 'Non',
$user['fk_entite']
];
$sheet->fromArray([$rowData], null, "A{$row}");
$row++;
}
foreach (range('A', 'J') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
}
/**
* Crée la feuille des secteurs
*/
private function createSectorsSheet(Spreadsheet $spreadsheet, int $operationId): void {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Secteurs');
$headers = ['ID_Sector', 'Libellé', 'Couleur', 'Date_création', 'Actif', 'FK_Operation'];
$sheet->fromArray([$headers], null, 'A1');
$sql = '
SELECT id, libelle, color, created_at, chk_active, fk_operation
FROM ope_sectors
WHERE fk_operation = ? AND chk_active = 1
ORDER BY libelle
';
$stmt = $this->db->prepare($sql);
$stmt->execute([$operationId]);
$sectors = $stmt->fetchAll(PDO::FETCH_ASSOC);
$row = 2;
foreach ($sectors as $sector) {
$rowData = [
$sector['id'],
$sector['libelle'],
$sector['color'],
date('d/m/Y H:i', strtotime($sector['created_at'])),
$sector['chk_active'] ? 'Oui' : 'Non',
$sector['fk_operation']
];
$sheet->fromArray([$rowData], null, "A{$row}");
$row++;
}
foreach (range('A', 'F') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
}
/**
* Crée la feuille des relations secteurs-utilisateurs
*/
private function createUserSectorsSheet(Spreadsheet $spreadsheet, int $operationId): void {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Secteurs-Utilisateurs');
$headers = [
'ID_Relation',
'FK_Sector',
'Nom_Secteur',
'FK_User',
'Nom_Utilisateur',
'Date_assignation',
'FK_Operation'
];
$sheet->fromArray([$headers], null, 'A1');
$sql = '
SELECT
ous.id, ous.fk_sector, ous.fk_user, ous.created_at, ous.fk_operation,
s.libelle as sector_name,
u.encrypted_name as user_name, u.first_name
FROM ope_users_sectors ous
INNER JOIN ope_sectors s ON s.id = ous.fk_sector
INNER JOIN users u ON u.id = ous.fk_user
WHERE ous.fk_operation = ? AND ous.chk_active = 1
ORDER BY s.libelle, u.encrypted_name
';
$stmt = $this->db->prepare($sql);
$stmt->execute([$operationId]);
$userSectors = $stmt->fetchAll(PDO::FETCH_ASSOC);
$row = 2;
foreach ($userSectors as $us) {
$userName = ApiService::decryptData($us['user_name']);
$fullUserName = $us['first_name'] ? $us['first_name'] . ' ' . $userName : $userName;
$rowData = [
$us['id'],
$us['fk_sector'],
$us['sector_name'],
$us['fk_user'],
$fullUserName,
date('d/m/Y H:i', strtotime($us['created_at'])),
$us['fk_operation']
];
$sheet->fromArray([$rowData], null, "A{$row}");
$row++;
}
foreach (range('A', 'G') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
}
/**
* Collecte toutes les données d'une opération pour l'export JSON
*/
private function collectOperationData(int $operationId, int $entiteId): array {
// Métadonnées de l'export
$exportData = [
'export_metadata' => [
'version' => '1.0',
'export_date' => date('c'),
'source_entite_id' => $entiteId,
'export_type' => 'full_operation'
]
];
// Données de l'opération
$exportData['operation'] = $this->getOperationData($operationId, $entiteId);
// Utilisateurs de l'opération
$exportData['users'] = $this->getOperationUsers($operationId);
// Secteurs de l'opération
$exportData['sectors'] = $this->getOperationSectors($operationId);
// Passages de l'opération
$exportData['passages'] = $this->getOperationPassages($operationId);
// Relations utilisateurs-secteurs
$exportData['user_sectors'] = $this->getOperationUserSectors($operationId);
return $exportData;
}
/**
* Récupère les données de l'opération
*/
private function getOperationData(int $operationId, int $entiteId): ?array {
$stmt = $this->db->prepare('
SELECT * FROM operations
WHERE id = ? AND fk_entite = ?
');
$stmt->execute([$operationId, $entiteId]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
/**
* Récupère les utilisateurs de l'opération
*/
private function getOperationUsers(int $operationId): array {
$stmt = $this->db->prepare('
SELECT DISTINCT u.*
FROM users u
INNER JOIN ope_users ou ON ou.fk_user = u.id
WHERE ou.fk_operation = ? AND ou.chk_active = 1
');
$stmt->execute([$operationId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Récupère les secteurs de l'opération
*/
private function getOperationSectors(int $operationId): array {
$stmt = $this->db->prepare('
SELECT * FROM ope_sectors
WHERE fk_operation = ? AND chk_active = 1
');
$stmt->execute([$operationId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Récupère les passages de l'opération
*/
private function getOperationPassages(int $operationId): array {
$stmt = $this->db->prepare('
SELECT * FROM ope_pass
WHERE fk_operation = ? AND chk_active = 1
');
$stmt->execute([$operationId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Récupère les relations utilisateurs-secteurs
*/
private function getOperationUserSectors(int $operationId): array {
$stmt = $this->db->prepare('
SELECT * FROM ope_users_sectors
WHERE fk_operation = ? AND chk_active = 1
');
$stmt->execute([$operationId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Récupère les données des passages dans un format simple pour l'export Excel
* (inspiré de l'ancienne version qui fonctionne)
*/
private function getSimplePassagesData(int $operationId, ?int $userId = null): array {
// En-têtes (comme dans l'ancienne version)
$aData = [];
$aData[] = [
'Date',
'Heure',
'Prenom',
'Nom',
'Tournee',
'Type',
'N°',
'Rue',
'Ville',
'Habitat',
'Donateur',
'Email',
'Tel',
'Montant',
'Reglement',
'Remarque'
];
// Récupérer les données des passages
$sql = '
SELECT
p.passed_at, p.fk_type, p.numero, p.rue_bis, p.rue, p.ville,
p.fk_habitat, p.appt, p.niveau, p.encrypted_name, p.encrypted_email,
p.encrypted_phone, p.montant, p.fk_type_reglement, p.remarque,
u.encrypted_name as user_name, u.first_name as user_first_name, u.sect_name,
xtr.libelle as reglement_libelle
FROM ope_pass p
LEFT JOIN users u ON u.id = p.fk_user
LEFT JOIN x_types_reglements xtr ON xtr.id = p.fk_type_reglement
WHERE p.fk_operation = ? AND p.chk_active = 1
';
$params = [$operationId];
if ($userId) {
$sql .= ' AND p.fk_user = ?';
$params[] = $userId;
}
$sql .= ' ORDER BY p.passed_at DESC';
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$passages = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Traiter les données comme dans l'ancienne version
foreach ($passages as $p) {
// Type de passage
switch ($p["fk_type"]) {
case 1:
$ptype = "Effectué";
$preglement = $p["reglement_libelle"];
break;
case 2:
$ptype = "A finaliser";
$preglement = "";
break;
case 3:
$ptype = "Refusé";
$preglement = "";
break;
case 4:
$ptype = "Don";
$preglement = "";
break;
case 9:
$ptype = "Habitat vide";
$preglement = "";
break;
default:
$ptype = $p["fk_type"];
$preglement = "";
break;
}
// Habitat
if ($p["fk_habitat"] == 1) {
$phabitat = "Individuel";
} else {
$phabitat = "Etage " . $p["niveau"] . " - Appt " . $p["appt"];
}
// Dates
$dateEve = $p["passed_at"] ? date("d/m/Y", strtotime($p["passed_at"])) : "";
$heureEve = $p["passed_at"] ? date("H:i", strtotime($p["passed_at"])) : "";
// Déchiffrer les données
$donateur = ApiService::decryptData($p["encrypted_name"]);
$email = !empty($p["encrypted_email"]) ? ApiService::decryptSearchableData($p["encrypted_email"]) : "";
$phone = !empty($p["encrypted_phone"]) ? ApiService::decryptData($p["encrypted_phone"]) : "";
$userName = ApiService::decryptData($p["user_name"]);
// Nettoyer les données (comme dans l'ancienne version)
$nom = str_replace("/", "-", $userName);
$tournee = str_replace("/", "-", $p["sect_name"]);
$aData[] = [
$dateEve,
$heureEve,
$p["user_first_name"],
$nom,
$tournee,
$ptype,
$p["numero"] . $p["rue_bis"],
$p["rue"],
$p["ville"],
$phabitat,
$donateur,
$email,
$phone,
$p["montant"],
$preglement,
$p["remarque"]
];
}
return $aData;
}
/**
* Restaure une opération à partir d'un backup chiffré
*
* @param string $backupFilePath Chemin vers le fichier de backup
* @param int $targetEntiteId ID de l'entité cible (pour restauration cross-entité)
* @return array Résultat de la restauration
* @throws Exception En cas d'erreur de restauration
*/
public function restoreFromBackup(string $backupFilePath, int $targetEntiteId): array {
try {
// Initialiser le service de chiffrement
$backupService = new BackupEncryptionService();
// Lire et déchiffrer le backup
$backupData = $backupService->readBackupFile($backupFilePath);
// Valider la structure du backup
if (!isset($backupData['operation']) || !isset($backupData['export_metadata'])) {
throw new Exception('Structure de backup invalide');
}
$operationData = $backupData['operation'];
$originalEntiteId = $backupData['export_metadata']['source_entite_id'];
// Commencer la transaction
$this->db->beginTransaction();
// Créer la nouvelle opération
$newOperationId = $this->restoreOperation($operationData, $targetEntiteId);
// Restaurer les utilisateurs (si même entité)
if ($targetEntiteId === $originalEntiteId && isset($backupData['users'])) {
$this->restoreUsers($backupData['users'], $newOperationId);
}
// Restaurer les secteurs
if (isset($backupData['sectors'])) {
$this->restoreSectors($backupData['sectors'], $newOperationId);
}
// Restaurer les relations utilisateurs-secteurs
if (isset($backupData['user_sectors'])) {
$this->restoreUserSectors($backupData['user_sectors'], $newOperationId);
}
// Restaurer les passages
if (isset($backupData['passages'])) {
$this->restorePassages($backupData['passages'], $newOperationId);
}
$this->db->commit();
LogService::log('Restauration de backup réussie', [
'level' => 'info',
'backup_file' => $backupFilePath,
'original_operation_id' => $operationData['id'],
'new_operation_id' => $newOperationId,
'target_entite_id' => $targetEntiteId,
'original_entite_id' => $originalEntiteId
]);
return [
'success' => true,
'new_operation_id' => $newOperationId,
'original_operation_id' => $operationData['id'],
'restored_data' => [
'operation' => true,
'users' => isset($backupData['users']) && $targetEntiteId === $originalEntiteId,
'sectors' => isset($backupData['sectors']),
'user_sectors' => isset($backupData['user_sectors']),
'passages' => isset($backupData['passages'])
]
];
} catch (Exception $e) {
$this->db->rollBack();
LogService::log('Erreur lors de la restauration du backup', [
'level' => 'error',
'backup_file' => $backupFilePath,
'target_entite_id' => $targetEntiteId,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* Restaure les données de l'opération
*/
private function restoreOperation(array $operationData, int $targetEntiteId): int {
$stmt = $this->db->prepare('
INSERT INTO operations (
fk_entite, libelle, date_deb, date_fin, chk_distinct_sectors,
fk_user_creat, chk_active, created_at
) VALUES (?, ?, ?, ?, ?, ?, 0, NOW())
');
$userId = Session::getUserId() ?? 1;
$stmt->execute([
$targetEntiteId,
$operationData['libelle'] . ' (Restaurée)',
$operationData['date_deb'],
$operationData['date_fin'],
$operationData['chk_distinct_sectors'] ?? 0,
$userId
]);
return (int)$this->db->lastInsertId();
}
/**
* Restaure les utilisateurs (uniquement si même entité)
*/
private function restoreUsers(array $users, int $newOperationId): void {
foreach ($users as $user) {
// Vérifier si l'utilisateur existe déjà
$stmt = $this->db->prepare('SELECT id FROM users WHERE id = ?');
$stmt->execute([$user['id']]);
if ($stmt->fetch()) {
// Associer l'utilisateur existant à la nouvelle opération
$stmt = $this->db->prepare('
INSERT IGNORE INTO ope_users (fk_operation, fk_user, chk_active, created_at)
VALUES (?, ?, 1, NOW())
');
$stmt->execute([$newOperationId, $user['id']]);
}
}
}
/**
* Restaure les secteurs
*/
private function restoreSectors(array $sectors, int $newOperationId): void {
foreach ($sectors as $sector) {
$stmt = $this->db->prepare('
INSERT INTO ope_sectors (
fk_operation, libelle, color, chk_active, created_at
) VALUES (?, ?, ?, 1, NOW())
');
$stmt->execute([
$newOperationId,
$sector['libelle'],
$sector['color']
]);
}
}
/**
* Restaure les relations utilisateurs-secteurs
*/
private function restoreUserSectors(array $userSectors, int $newOperationId): void {
foreach ($userSectors as $us) {
// Trouver le nouveau secteur par son libellé
$stmt = $this->db->prepare('
SELECT id FROM ope_sectors
WHERE fk_operation = ? AND libelle = ?
LIMIT 1
');
$stmt->execute([$newOperationId, $us['libelle'] ?? '']);
$newSector = $stmt->fetch();
if ($newSector) {
$stmt = $this->db->prepare('
INSERT IGNORE INTO ope_users_sectors (
fk_operation, fk_sector, fk_user, chk_active, created_at
) VALUES (?, ?, ?, 1, NOW())
');
$stmt->execute([
$newOperationId,
$newSector['id'],
$us['fk_user']
]);
}
}
}
/**
* Restaure les passages
*/
private function restorePassages(array $passages, int $newOperationId): void {
foreach ($passages as $passage) {
$stmt = $this->db->prepare('
INSERT INTO ope_pass (
fk_operation, fk_user, fk_sector, fk_type, passed_at,
numero, rue_bis, rue, ville, fk_habitat, appt, niveau,
encrypted_name, encrypted_email, encrypted_phone,
montant, fk_type_reglement, remarque, chk_active, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, NOW())
');
$stmt->execute([
$newOperationId,
$passage['fk_user'],
$passage['fk_sector'],
$passage['fk_type'],
$passage['passed_at'],
$passage['numero'],
$passage['rue_bis'],
$passage['rue'],
$passage['ville'],
$passage['fk_habitat'],
$passage['appt'],
$passage['niveau'],
$passage['encrypted_name'],
$passage['encrypted_email'],
$passage['encrypted_phone'],
$passage['montant'],
$passage['fk_type_reglement'],
$passage['remarque']
]);
}
}
}