sourceDb = $sourceDb; $this->targetDb = $targetDb; $this->logger = $logger; } /** * Migre les passages d'un secteur dans une opération * * @param int $oldOperationId ID ancienne opération * @param int $newOperationId ID nouvelle opération * @param int $oldSectorId ID ancien secteur * @param int $newOpeSectorId ID nouveau ope_sectors * @param array $userMapping Mapping oldUserId => newOpeUserId * @return int Nombre de passages migrés */ public function migratePassages( int $oldOperationId, int $newOperationId, int $oldSectorId, int $newOpeSectorId, array $userMapping ): int { $stmt = $this->sourceDb->prepare(" SELECT * FROM ope_pass WHERE fk_operation = :operation_id AND fk_sector = :sector_id "); $stmt->execute([ ':operation_id' => $oldOperationId, ':sector_id' => $oldSectorId ]); $passages = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($passages)) { return 0; } $count = 0; foreach ($passages as $passage) { // Vérifier que l'utilisateur a été migré if (!isset($userMapping[$passage['fk_user']])) { $this->logger->warning(" ⚠ Passage {$passage['rowid']}: User {$passage['fk_user']} non trouvé dans mapping"); continue; } // Récupérer l'ID de ope_users depuis le mapping $newOpeUserId = $userMapping[$passage['fk_user']]; // Vérifier que le trio (operation, user, sector) existe dans ope_users_sectors if (!$this->verifyUserSectorAssociation($newOperationId, $newOpeUserId, $newOpeSectorId)) { $this->logger->warning(" ⚠ Passage {$passage['rowid']}: Trio (op={$newOperationId}, user={$newOpeUserId}, sector={$newOpeSectorId}) inexistant"); continue; } // Insérer le passage avec l'ID de ope_users $newPassId = $this->insertPassage($passage, $newOperationId, $newOpeSectorId, $newOpeUserId); if ($newPassId) { // Migrer l'historique du passage $this->migratePassageHisto($passage['rowid'], $newPassId, $userMapping); $count++; } } if ($count > 0) { $this->logger->success(" ✓ {$count} passage(s) migré(s)"); } return $count; } /** * Vérifie qu'une association user-sector existe dans ope_users_sectors * * @param int $operationId ID opération * @param int $userId ID ope_users (mapping) * @param int $sectorId ID ope_sectors * @return bool True si l'association existe */ private function verifyUserSectorAssociation(int $operationId, int $userId, int $sectorId): bool { $stmt = $this->targetDb->prepare(" SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = :operation_id AND fk_user = :user_id AND fk_sector = :sector_id "); $stmt->execute([ ':operation_id' => $operationId, ':user_id' => $userId, ':sector_id' => $sectorId ]); return $stmt->fetchColumn() > 0; } /** * Insère un passage dans la nouvelle base * * @param array $passage Données du passage * @param int $newOperationId ID nouvelle opération * @param int $newOpeSectorId ID nouveau secteur * @param int $userId ID de ope_users (mapping) * @return int|null ID du nouveau passage ou null en cas d'erreur */ private function insertPassage( array $passage, int $newOperationId, int $newOpeSectorId, int $userId ): ?int { try { $stmt = $this->targetDb->prepare(" INSERT INTO ope_pass ( fk_operation, fk_sector, fk_user, fk_adresse, passed_at, fk_type, numero, rue, rue_bis, ville, fk_habitat, appt, niveau, residence, gps_lat, gps_lng, encrypted_name, montant, fk_type_reglement, remarque, nom_recu, encrypted_email, email_erreur, chk_email_sent, encrypted_phone, docremis, date_repasser, nb_passages, chk_gps_maj, chk_map_create, chk_mobile, chk_synchro, chk_api_adresse, chk_maj_adresse, anomalie, created_at, fk_user_creat, updated_at, fk_user_modif, chk_active ) VALUES ( :fk_operation, :fk_sector, :fk_user, :fk_adresse, :passed_at, :fk_type, :numero, :rue, :rue_bis, :ville, :fk_habitat, :appt, :niveau, :residence, :gps_lat, :gps_lng, :encrypted_name, :montant, :fk_type_reglement, :remarque, :nom_recu, :encrypted_email, :email_erreur, :chk_email_sent, :encrypted_phone, :docremis, :date_repasser, :nb_passages, :chk_gps_maj, :chk_map_create, :chk_mobile, :chk_synchro, :chk_api_adresse, :chk_maj_adresse, :anomalie, :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active ) "); // Chiffrer les données sensibles require_once dirname(__DIR__, 4) . '/src/Services/ApiService.php'; $stmt->execute([ ':fk_operation' => $newOperationId, ':fk_sector' => $newOpeSectorId, ':fk_user' => $userId, // ID de ope_users (mapping) ':fk_adresse' => $passage['fk_adresse'], ':passed_at' => $passage['date_eve'], ':fk_type' => $passage['fk_type'], ':numero' => $passage['numero'], ':rue' => $passage['rue'], ':rue_bis' => $passage['rue_bis'], ':ville' => $passage['ville'], ':fk_habitat' => $passage['fk_habitat'], ':appt' => $passage['appt'], ':niveau' => $passage['niveau'], ':residence' => $passage['lieudit'] ?? null, ':gps_lat' => $passage['gps_lat'], ':gps_lng' => $passage['gps_lng'], ':encrypted_name' => $passage['libelle'] ? ApiService::encryptData($passage['libelle']) : '', // Chiffrer avec IV aléatoire ':montant' => $passage['montant'], ':fk_type_reglement' => (!empty($passage['fk_type_reglement']) && $passage['fk_type_reglement'] > 0) ? $passage['fk_type_reglement'] : 4, ':remarque' => $passage['remarque'], ':nom_recu' => $passage['recu'] ?? null, ':encrypted_email' => $passage['email'] ? ApiService::encryptSearchableData($passage['email']) : null, ':email_erreur' => $passage['email_erreur'], ':chk_email_sent' => $passage['chk_email_sent'], ':encrypted_phone' => $passage['phone'] ? ApiService::encryptData($passage['phone']) : '', ':docremis' => $passage['docremis'], ':date_repasser' => $passage['date_repasser'], ':nb_passages' => ($passage['fk_type'] == 2) ? 0 : $passage['nb_passages'], ':chk_gps_maj' => $passage['chk_gps_maj'], ':chk_map_create' => $passage['chk_map_create'], ':chk_mobile' => $passage['chk_mobile'], ':chk_synchro' => $passage['chk_synchro'], ':chk_api_adresse' => $passage['chk_api_adresse'], ':chk_maj_adresse' => $passage['chk_maj_adresse'], ':anomalie' => $passage['anomalie'], ':created_at' => $passage['date_creat'], ':fk_user_creat' => $passage['fk_user_creat'] ?? 0, ':updated_at' => $passage['date_modif'], ':fk_user_modif' => $passage['fk_user_modif'] ?? 0, ':chk_active' => $passage['active'] ]); return (int)$this->targetDb->lastInsertId(); } catch (Exception $e) { $this->logger->error(" ❌ Erreur insertion passage {$passage['rowid']}: " . $e->getMessage()); return null; } } /** * Migre l'historique d'un passage * * @param int $oldPassId ID ancien passage * @param int $newPassId ID nouveau passage * @param array $userMapping Non utilisé (conservé pour compatibilité) * @return int Nombre d'entrées d'historique migrées */ public function migratePassageHisto(int $oldPassId, int $newPassId, array $userMapping): int { $stmt = $this->sourceDb->prepare(" SELECT * FROM ope_pass_histo WHERE fk_pass = :pass_id "); $stmt->execute([':pass_id' => $oldPassId]); $histos = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($histos)) { return 0; } $count = 0; foreach ($histos as $histo) { $stmt = $this->targetDb->prepare(" INSERT INTO ope_pass_histo ( fk_pass, date_histo, sujet, remarque ) VALUES ( :fk_pass, :date_histo, :sujet, :remarque ) "); $stmt->execute([ ':fk_pass' => $newPassId, ':date_histo' => $histo['date_histo'], ':sujet' => $histo['sujet'], ':remarque' => $histo['remarque'] ]); $count++; } return $count; } }