- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
313 lines
11 KiB
PHP
313 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Migration des opérations complètes
|
|
*
|
|
* Orchestre la migration d'une opération avec tous ses utilisateurs,
|
|
* secteurs, passages et médias. Utilise UserMigrator et SectorMigrator.
|
|
*/
|
|
class OperationMigrator
|
|
{
|
|
private PDO $sourceDb;
|
|
private PDO $targetDb;
|
|
private MigrationLogger $logger;
|
|
private UserMigrator $userMigrator;
|
|
private SectorMigrator $sectorMigrator;
|
|
|
|
/**
|
|
* Constructeur
|
|
*
|
|
* @param PDO $sourceDb Connexion source
|
|
* @param PDO $targetDb Connexion cible
|
|
* @param MigrationLogger $logger Logger
|
|
* @param UserMigrator $userMigrator Migrator d'utilisateurs
|
|
* @param SectorMigrator $sectorMigrator Migrator de secteurs
|
|
*/
|
|
public function __construct(
|
|
PDO $sourceDb,
|
|
PDO $targetDb,
|
|
MigrationLogger $logger,
|
|
UserMigrator $userMigrator,
|
|
SectorMigrator $sectorMigrator
|
|
) {
|
|
$this->sourceDb = $sourceDb;
|
|
$this->targetDb = $targetDb;
|
|
$this->logger = $logger;
|
|
$this->userMigrator = $userMigrator;
|
|
$this->sectorMigrator = $sectorMigrator;
|
|
}
|
|
|
|
/**
|
|
* Récupère les opérations à migrer pour une entité
|
|
* - 1 opération active
|
|
* - 2 dernières opérations inactives avec au moins 10 passages effectués
|
|
*
|
|
* @param int $entityId ID de l'entité
|
|
* @return array Liste des IDs d'opérations à migrer
|
|
*/
|
|
public function getOperationsToMigrate(int $entityId): array
|
|
{
|
|
$operationIds = [];
|
|
|
|
// 1. Récupérer l'opération active (pour vérification)
|
|
$stmt = $this->sourceDb->prepare("
|
|
SELECT rowid
|
|
FROM operations
|
|
WHERE fk_entite = :entity_id AND active = 1
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([':entity_id' => $entityId]);
|
|
$activeOp = $stmt->fetch(PDO::FETCH_COLUMN);
|
|
|
|
// 2. Récupérer les 2 dernières opérations inactives avec >= 10 passages effectués
|
|
// ORDER BY DESC pour avoir les plus récentes, puis on inverse
|
|
$stmt = $this->sourceDb->prepare("
|
|
SELECT o.rowid, COUNT(p.rowid) as nb_passages
|
|
FROM operations o
|
|
LEFT JOIN ope_pass p ON p.fk_operation = o.rowid AND p.fk_type = 1
|
|
WHERE o.fk_entite = :entity_id
|
|
AND o.active = 0
|
|
" . ($activeOp ? "AND o.rowid != :active_id" : "") . "
|
|
GROUP BY o.rowid
|
|
HAVING nb_passages >= 10
|
|
ORDER BY o.rowid DESC
|
|
LIMIT 2
|
|
");
|
|
|
|
$params = [':entity_id' => $entityId];
|
|
if ($activeOp) {
|
|
$params[':active_id'] = $activeOp;
|
|
}
|
|
|
|
$stmt->execute($params);
|
|
$inactiveOps = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Inverser pour avoir l'ordre chronologique (plus ancienne → plus récente)
|
|
$inactiveOps = array_reverse($inactiveOps);
|
|
|
|
foreach ($inactiveOps as $op) {
|
|
$operationIds[] = $op['rowid'];
|
|
$this->logger->info("✓ Opération inactive trouvée: {$op['rowid']} ({$op['nb_passages']} passages)");
|
|
}
|
|
|
|
// 3. Ajouter l'opération active EN DERNIER
|
|
if ($activeOp) {
|
|
$operationIds[] = $activeOp;
|
|
$this->logger->info("✓ Opération active trouvée: {$activeOp}");
|
|
}
|
|
|
|
$this->logger->info("📊 Total: " . count($operationIds) . " opération(s) à migrer");
|
|
|
|
return $operationIds;
|
|
}
|
|
|
|
/**
|
|
* Migre une opération complète avec tous ses utilisateurs et secteurs
|
|
*
|
|
* @param int $oldOperationId ID de l'opération dans l'ancienne base
|
|
* @return array|null Tableau de statistiques ou null en cas d'erreur
|
|
*/
|
|
public function migrateOperation(int $oldOperationId): ?array
|
|
{
|
|
$this->logger->separator();
|
|
$this->logger->info("🔄 Migration de l'opération ID: {$oldOperationId}");
|
|
|
|
try {
|
|
// 1. Récupérer l'opération source
|
|
$stmt = $this->sourceDb->prepare("
|
|
SELECT * FROM operations
|
|
WHERE rowid = :id
|
|
");
|
|
$stmt->execute([':id' => $oldOperationId]);
|
|
$operation = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$operation) {
|
|
$this->logger->warning("Opération {$oldOperationId} non trouvée");
|
|
return null;
|
|
}
|
|
|
|
// 2. Créer l'opération dans la nouvelle base
|
|
$newOperationId = $this->createOperation($operation);
|
|
|
|
if (!$newOperationId) {
|
|
return null;
|
|
}
|
|
|
|
$this->logger->success("✓ Opération créée avec ID: {$newOperationId}");
|
|
|
|
// 3. Migrer les utilisateurs de l'opération
|
|
// Pour opération active : tous les users actifs de l'entité
|
|
// Pour opération inactive : uniquement ceux dans ope_users_sectors
|
|
$entityId = (int)$operation['fk_entite'];
|
|
$isActiveOperation = (int)$operation['active'] === 1;
|
|
|
|
$userResult = $this->userMigrator->migrateOperationUsers(
|
|
$oldOperationId,
|
|
$newOperationId,
|
|
$entityId,
|
|
$isActiveOperation
|
|
);
|
|
$userMapping = $userResult['mapping'];
|
|
$usersCount = $userResult['count'];
|
|
|
|
if (empty($userMapping)) {
|
|
$this->logger->warning("Aucun utilisateur migré, abandon de l'opération {$oldOperationId}");
|
|
return null;
|
|
}
|
|
|
|
// 4. Récupérer les secteurs DISTINCTS de l'opération
|
|
$stmt = $this->sourceDb->prepare("
|
|
SELECT DISTINCT fk_sector
|
|
FROM ope_users_sectors
|
|
WHERE fk_operation = :operation_id AND active = 1
|
|
");
|
|
$stmt->execute([':operation_id' => $oldOperationId]);
|
|
$sectors = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
$this->logger->info("📍 " . count($sectors) . " secteur(s) distinct(s) à migrer");
|
|
|
|
// 5. Migrer chaque secteur et collecter les stats
|
|
$sectorsDetail = [];
|
|
$totalPassages = 0;
|
|
|
|
foreach ($sectors as $oldSectorId) {
|
|
$sectorStats = $this->sectorMigrator->migrateSector(
|
|
$oldOperationId,
|
|
$newOperationId,
|
|
$oldSectorId,
|
|
$userMapping
|
|
);
|
|
|
|
if ($sectorStats) {
|
|
$sectorsDetail[] = $sectorStats;
|
|
$totalPassages += $sectorStats['passages'];
|
|
}
|
|
}
|
|
|
|
// 6. Migrer les médias de l'opération (support='operations')
|
|
$this->migrateOperationMedias($oldOperationId, $newOperationId);
|
|
|
|
$this->logger->success("✅ Migration de l'opération {$oldOperationId} terminée");
|
|
|
|
// 7. Retourner les statistiques
|
|
return [
|
|
'id' => $newOperationId,
|
|
'name' => $operation['libelle'],
|
|
'users' => $usersCount,
|
|
'sectors' => count($sectorsDetail),
|
|
'total_passages' => $totalPassages,
|
|
'sectors_detail' => $sectorsDetail
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error("❌ Erreur migration opération {$oldOperationId}: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crée une opération dans la nouvelle base
|
|
*
|
|
* @param array $operation Données de l'opération
|
|
* @return int|null ID de la nouvelle opération ou null en cas d'erreur
|
|
*/
|
|
private function createOperation(array $operation): ?int
|
|
{
|
|
try {
|
|
$stmt = $this->targetDb->prepare("
|
|
INSERT INTO operations (
|
|
fk_entite, libelle, date_deb, date_fin,
|
|
chk_distinct_sectors,
|
|
created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
|
|
) VALUES (
|
|
:fk_entite, :libelle, :date_deb, :date_fin,
|
|
:chk_distinct_sectors,
|
|
:created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
|
|
)
|
|
");
|
|
|
|
$stmt->execute([
|
|
':fk_entite' => $operation['fk_entite'],
|
|
':libelle' => $operation['libelle'],
|
|
':date_deb' => $operation['date_deb'],
|
|
':date_fin' => $operation['date_fin'],
|
|
':chk_distinct_sectors' => $operation['chk_distinct_sectors'],
|
|
':created_at' => $operation['date_creat'],
|
|
':fk_user_creat' => $operation['fk_user_creat'],
|
|
':updated_at' => $operation['date_modif'],
|
|
':fk_user_modif' => $operation['fk_user_modif'] ?? 0,
|
|
':chk_active' => $operation['active']
|
|
]);
|
|
|
|
return (int)$this->targetDb->lastInsertId();
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error("❌ Erreur création opération: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Migre les médias d'une opération
|
|
*
|
|
* @param int $oldOperationId ID ancienne opération
|
|
* @param int $newOperationId ID nouvelle opération
|
|
* @return int Nombre de médias migrés
|
|
*/
|
|
private function migrateOperationMedias(int $oldOperationId, int $newOperationId): int
|
|
{
|
|
$stmt = $this->sourceDb->prepare("
|
|
SELECT * FROM medias
|
|
WHERE support = 'operations' AND support_rowid = :operation_id
|
|
");
|
|
$stmt->execute([':operation_id' => $oldOperationId]);
|
|
$medias = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (empty($medias)) {
|
|
return 0;
|
|
}
|
|
|
|
$count = 0;
|
|
foreach ($medias as $media) {
|
|
$stmt = $this->targetDb->prepare("
|
|
INSERT INTO medias (
|
|
dir0, dir1, dir2, support, support_rowid,
|
|
fichier, type_fichier, description, position,
|
|
hauteur, largeur, niveaugris,
|
|
created_at, fk_user_creat, updated_at, fk_user_modif
|
|
) VALUES (
|
|
:dir0, :dir1, :dir2, :support, :support_rowid,
|
|
:fichier, :type_fichier, :description, :position,
|
|
:hauteur, :largeur, :niveaugris,
|
|
:created_at, :fk_user_creat, :updated_at, :fk_user_modif
|
|
)
|
|
");
|
|
|
|
$stmt->execute([
|
|
':dir0' => $media['dir0'],
|
|
':dir1' => $media['dir1'],
|
|
':dir2' => $media['dir2'],
|
|
':support' => $media['support'],
|
|
':support_rowid' => $newOperationId,
|
|
':fichier' => $media['fichier'],
|
|
':type_fichier' => $media['type_fichier'],
|
|
':description' => $media['description'],
|
|
':position' => $media['position'],
|
|
':hauteur' => $media['hauteur'],
|
|
':largeur' => $media['largeur'],
|
|
':niveaugris' => $media['niveaugris'],
|
|
':created_at' => $media['date_creat'],
|
|
':fk_user_creat' => $media['fk_user_creat'],
|
|
':updated_at' => $media['date_modif'],
|
|
':fk_user_modif' => $media['fk_user_modif']
|
|
]);
|
|
|
|
$count++;
|
|
}
|
|
|
|
$this->logger->success("✓ {$count} média(s) migré(s)");
|
|
|
|
return $count;
|
|
}
|
|
}
|