/// <summary> /// Importe la décomposition vidéo spécifiée spécifié. /// </summary> /// <param name="mergeReferentials"><c>true</c> pour fusionner les référentiels.</param> /// <param name="videosDirectory">Le dossier où se situent les vidéos.</param> public async Task ImportVideoDecomposition(bool mergeReferentials, string videosDirectory) { var videoDecomposition = _import.ExportedVideoDecomposition; // Videos PrepareVideo(videosDirectory); // Referentials ImportReferentials(mergeReferentials); // Actions ImportActions(); // Remapper les référentiels du projet, des actions et des vidéos RemapReferentials(); FixupImportedActions(); // Custom text & Numeric labels ImportCustomFieldsLabels(); _context.DetectChanges(); // Passer les entités mappées à non modifiées FixupReferentialsTrackingState(); if (mergeReferentials) { ServicesDiagnosticsDebug.CheckNotInContext(_context, _referentialsToRemap.Keys); ServicesDiagnosticsDebug.CheckObjectStateManagerState(_context, System.Data.Entity.EntityState.Unchanged, _referentialsToRemap.Values); } await _context.SaveChangesAsync(); ServicesDiagnosticsDebug.CheckReferentialsState(); }
/// <summary> /// Importe le projet spécifié. /// </summary> /// <param name="context">Le contexte.</param> /// <param name="import">Le projet exporté.</param> /// <param name="mergeReferentials"><c>true</c> pour fusionner les référentiels.</param> /// <param name="videosDirectory">Le dossier où se situent les vidéos.</param> /// <returns>Le projet créé.</returns> private async Task <Project> ImportProject(KsmedEntities context, ProjectImport import, bool mergeReferentials, string videosDirectory) { // Projet var p = import.ExportedProject.Project; p.ProjectId = default(int); MarkAsAdded(p); // Ajouter l'utilisateur courant en tant qu'analyste créateur var owner = await context.Users.FirstAsync(u => !u.IsDeleted && u.Username == _securityContext.CurrentUser.Username); p.Process.Owner = owner; p.Process.UserRoleProcesses.Add(new UserRoleProcess() { User = owner, RoleCode = KnownRoles.Analyst, }); // Videos foreach (var video in p.Process.Videos) { if (video.DefaultResourceId.HasValue && video.DefaultResource == null) { // Bug présent dans certains exports de la version 2.5.0.0. Supprimer le lien vers la ressource par défaut. video.DefaultResourceId = null; } video.VideoId = default(int); MarkAsAdded(video); video.FilePath = IOHelper.ChangeDirectory(video.FilePath, videosDirectory); } var referentialsToRemap = new Dictionary <IActionReferential, IActionReferential>(); if (!mergeReferentials) { // Référentiels process foreach (var refe in import.ExportedProject.ReferentialsProject) { MarkAsAdded(refe); } // Référentiels standard foreach (var refe in import.ExportedProject.ReferentialsStandard) { var refProject = ReferentialsFactory.CopyToNewProject(refe); // Associer au process refProject.Process = p.Process; referentialsToRemap[refe] = refProject; } } else { // Référentiels process foreach (var refe in import.ExportedProject.ReferentialsProject) { // Ajouter au tableau de remap s'il y a une correspondance. if (import.ProjectReferentialsMergeCandidates.ContainsKey(refe)) { referentialsToRemap[refe] = import.ProjectReferentialsMergeCandidates[refe]; } else { MarkAsAdded(refe); } } // Référentiels standard foreach (var refe in import.ExportedProject.ReferentialsStandard) { if (import.StandardReferentialsMergeCandidates.ContainsKey(refe)) { referentialsToRemap[refe] = import.StandardReferentialsMergeCandidates[refe]; } else { var refProject = ReferentialsFactory.CopyToNewProject(refe); // Associer au process refProject.Process = p.Process; referentialsToRemap[refe] = refProject; } } } // Scénarios foreach (var scenario in p.Scenarios.Where(s => s.OriginalScenarioId.HasValue)) { // Remapper l'original scenario.Original = p.Scenarios.Single(s => s.ScenarioId == scenario.OriginalScenarioId); } foreach (var scenario in p.Scenarios) { foreach (var action in scenario.Actions.Where(a => a.OriginalActionId.HasValue)) { // Remapper l'original action.Original = p.Scenarios.SelectMany(s => s.Actions).Single(a => a.ActionId == action.OriginalActionId); } } foreach (var scenario in p.Scenarios) { scenario.ScenarioId = default(int); MarkAsAdded(scenario); // Supprimer le WebPublicationGuid scenario.WebPublicationGuid = null; // Actions foreach (var action in scenario.Actions) { action.ActionId = default(int); MarkAsAdded(action); // Actions réduites if (action.IsReduced) { MarkAsAdded(action.Reduced); } } } // Remapper les référentiels du projet, des actions et des vidéos foreach (var oldReferential in referentialsToRemap.Keys) { ReferentialsHelper.UpdateReferentialReferences(p, oldReferential, referentialsToRemap[oldReferential]); } foreach (var scenario in p.Scenarios) { if (scenario.Original != null) { context.Scenarios.ApplyChanges(scenario); ObjectContextExt.SetRelationShipReferenceValue(context, scenario, scenario.Original, s => s.OriginalScenarioId); foreach (var action in scenario.Actions) { if (action.Original != null) { context.KActions.ApplyChanges(action); ObjectContextExt.SetRelationShipReferenceValue(context, action, action.Original, a => a.OriginalActionId); } } } } var resources = p.Scenarios.SelectMany(s => s.Actions).Select(a => a.Resource).Distinct().ToArray(); context.Projects.ApplyChanges(p); if (mergeReferentials) { ServicesDiagnosticsDebug.CheckNotInContext(context, referentialsToRemap.Keys); ServicesDiagnosticsDebug.CheckObjectStateManagerState(context, EntityState.Unchanged, referentialsToRemap.Values); } ServicesDiagnosticsDebug.CheckReferentialsState(); await context.SaveChangesAsync(); return(p); }
/// <summary> /// Sauvegarde le scénario spécifié. /// </summary> /// <param name="context">Le contexte EF.</param> /// <param name="allScenarios">Tous les scénarios liés.</param> /// <param name="recursive"><c>true</c> pour appliquer les changements récursivement sur les scénarios dérivés.</param> public static Task SaveBuildScenario(KsmedEntities context, Scenario[] allScenarios, Scenario updatedScenario, bool recursive) { // Consolider les solutions string[] distinctSolutionsLabels = updatedScenario.Actions .Where(a => a.IsReduced && !string.IsNullOrWhiteSpace(a.Reduced.Solution)) .Select(a => a.Reduced.Solution) .Distinct() .ToArray(); // Ajouter les nouvelles solutions foreach (string solutionLabel in distinctSolutionsLabels) { if (!updatedScenario.Solutions.Any(s => s.SolutionDescription == solutionLabel)) { // Créer une nouvelle solution Solution solution = new Solution() { SolutionDescription = solutionLabel, }; updatedScenario.Solutions.Add(solution); } } EnsureEmptySolutionExists(updatedScenario); // Supprimer les anciennes solutions Solution[] allSolutions = updatedScenario.Solutions.Where(s => !s.IsEmpty).ToArray(); foreach (Solution sol in allSolutions) { if (!distinctSolutionsLabels.Contains(sol.SolutionDescription)) { sol.MarkAsDeleted(); updatedScenario.Solutions.Remove(sol); } } // Copier le temps original foreach (KActionReduced reduced in updatedScenario.Actions .Where(a => a.IsReduced) .Select(a => a.Reduced) .Where(r => r.OriginalBuildDuration == default(long))) { reduced.OriginalBuildDuration = reduced.Action.BuildDuration; } // Appliquer l'état Approved UdpateSolutionsApprovedState(updatedScenario); ActionsRecursiveUpdate.UpdateActions(context, updatedScenario, allScenarios, out KAction[] actionsToDelete, out IList <KAction> actionsWithOriginal); KAction[] allActions = allScenarios .SelectMany(s => s.Actions) .Where(a => a.IsNotMarkedAsUnchanged || (a.IsReduced && a.Reduced.IsNotMarkedAsUnchanged)) .ToArray(); foreach (KAction action in allActions) { context.KActions.ApplyChanges(action); if (action.IsReduced) { context.KActionsReduced.ApplyChanges(action.Reduced); } } foreach (KAction action in actionsWithOriginal) { SetActionsOriginalReference(context, action); } foreach (Scenario scenario in allScenarios.Where(s => s.IsNotMarkedAsUnchanged)) { context.Scenarios.ApplyChanges(scenario); } foreach (Solution solution in updatedScenario.Solutions) { context.Solutions.ApplyChanges(solution); } // Vérifier que tout est correct ActionsTimingsMoveManagement.DebugCheckAllWBS(allScenarios.Where(s => s.IsNotMarkedAsUnchanged)); return(context.SaveChangesAsync()); }
/// <summary> /// Sauvegarde les actions spécifiées. /// </summary> /// <param name="context">Le contexte.</param> /// <param name="allScenarios">Tous les scénarios liés.</param> /// <param name="updatedScenario">Le scénario qui a été mis à jour.</param> /// <param name="recursive"><c>true</c> pour appliquer les changements récursivement sur les scénarios dérivés.</param> public static Task SaveAcquireData(KsmedEntities context, Scenario[] allScenarios, Scenario updatedScenario, bool recursive) { KAction[] actionsToDelete; IList <KAction> actionsWithOriginal; if (recursive) { ActionsRecursiveUpdate.UpdateActions(context, updatedScenario, allScenarios, out actionsToDelete, out actionsWithOriginal); } else { actionsWithOriginal = null; actionsToDelete = updatedScenario.Actions.Where(a => a.IsMarkedAsDeleted).ToArray(); updatedScenario.CriticalPathIDuration = ActionsTimingsMoveManagement.GetInternalCriticalPathDuration(updatedScenario); } // Consolider les solutions vides EnsureEmptySolutionExists(updatedScenario); UdpateSolutionsApprovedState(updatedScenario); KAction[] allActions = allScenarios .SelectMany(s => s.Actions) .Where(a => a.IsNotMarkedAsUnchanged) .ToArray(); foreach (KAction action in allActions) { if (!action.IsReduced) { ApplyNewReduced(action, KnownActionCategoryTypes.I); } context.KActions.ApplyChanges(action); context.KActionsReduced.ApplyChanges(action.Reduced); } if (actionsWithOriginal != null) { foreach (KAction action in actionsWithOriginal) { SetActionsOriginalReference(context, action); } } foreach (Scenario scenario in allScenarios.Where(s => s.IsNotMarkedAsUnchanged)) { context.Scenarios.ApplyChanges(scenario); } context.Scenarios.ApplyChanges(updatedScenario); foreach (KAction action in actionsToDelete) { action.Predecessors.Clear(); action.Successors.Clear(); action.MarkAsDeleted(); // Ne pas appeler ApplyChanges car les self tracking le gèrent mal (plantage lors de la sauvegarde) // Ajouter l'action au contexte si elle n'y est pas attachée if (!context.ObjectStateManager.TryGetObjectStateEntry(action, out ObjectStateEntry entry)) { context.AddObject(KsmedEntities.KActionsEntitySetName, action); context.ObjectStateManager.ChangeObjectState(action, EntityState.Deleted); } else { context.KActions.DeleteObject(action); } } // Vérifier que tout est correct if (recursive) { ActionsTimingsMoveManagement.DebugCheckAllWBS(allScenarios.Where(s => s.IsNotMarkedAsUnchanged)); } return(context.SaveChangesAsync()); }
/// <summary> /// Crée un scénario cible à partir d'un autre scénario, initial ou cible. /// </summary> /// <param name="context">Le contexte.</param> /// <param name="sourceScenario">Le scenario source.</param> /// <param name="natureCode">Le code de la nature.</param> /// <param name="save"><c>true</c> pour sauvegarder le scénario créé.</param> /// <param name="targetNumber">Le numéro cible.</param> /// <returns> /// Le scénario créé /// </returns> public static async Task <Scenario> CreateDerivatedScenario(KsmedEntities context, Scenario sourceScenario, string natureCode, bool save, int targetNumber) { // Charger les données du scénario source var newScenario = new Scenario(); ActionCloneBehavior cloneBehavior; if (sourceScenario.NatureCode == KnownScenarioNatures.Initial && natureCode == KnownScenarioNatures.Target) { cloneBehavior = ActionCloneBehavior.InitialToTarget; } else if (sourceScenario.NatureCode == KnownScenarioNatures.Target && natureCode == KnownScenarioNatures.Target) { cloneBehavior = ActionCloneBehavior.TargetToTarget; } else if (sourceScenario.NatureCode == KnownScenarioNatures.Target && natureCode == KnownScenarioNatures.Realized) { cloneBehavior = ActionCloneBehavior.TargetToRealized; } else if (sourceScenario.NatureCode == KnownScenarioNatures.Realized && natureCode == KnownScenarioNatures.Initial) { cloneBehavior = ActionCloneBehavior.RealizedToNewInitial; } else if (sourceScenario.NatureCode == KnownScenarioNatures.Target && natureCode == KnownScenarioNatures.Initial) { cloneBehavior = ActionCloneBehavior.TargetToNewInitial; } else if (sourceScenario.NatureCode == KnownScenarioNatures.Initial && natureCode == KnownScenarioNatures.Initial) { cloneBehavior = ActionCloneBehavior.InitialToNewInitial; } else { throw new InvalidOperationException("Conversion impossible pour ces scénarios"); } switch (natureCode) { case KnownScenarioNatures.Target: newScenario.Label = LocalizationManager.GetString("Business_AnalyzeService_TargetScenarioLabel") + " " + targetNumber; break; case KnownScenarioNatures.Realized: newScenario.Label = LocalizationManager.GetString("Business_AnalyzeService_ValidationScenarioLabel"); break; case KnownScenarioNatures.Initial: newScenario.Label = LocalizationManager.GetString("Business_AnalyzeService_InitialScenarioLabel"); break; default: throw new ArgumentOutOfRangeException(nameof(natureCode)); } newScenario.StateCode = KnownScenarioStates.Draft; newScenario.NatureCode = natureCode; if (cloneBehavior != ActionCloneBehavior.RealizedToNewInitial && cloneBehavior != ActionCloneBehavior.TargetToNewInitial && cloneBehavior != ActionCloneBehavior.InitialToNewInitial) { newScenario.ProjectId = sourceScenario.ProjectId; newScenario.Original = sourceScenario; newScenario.OriginalScenarioId = sourceScenario.ScenarioId; } newScenario.IsShownInSummary = true; newScenario.CriticalPathIDuration = sourceScenario.CriticalPathIDuration; string[] scenarioLAbels = await EnsureCanShowScenarioInSummary(newScenario, true); // Copier toutes les actions foreach (var action in sourceScenario.Actions.ToArray()) { var newAction = CloneAction(action, cloneBehavior); newAction.OriginalActionId = action.ActionId; newAction.Original = action; if (newAction.Reduced != null) { newAction.Reduced.OriginalBuildDuration = action.BuildDuration; } // S'il s'agit d'un scénario validé, utiliser les temps process en tant que temps vidéo if (cloneBehavior == ActionCloneBehavior.TargetToRealized) { newAction.Start = newAction.BuildStart; newAction.Finish = newAction.BuildFinish; } newScenario.Actions.Add(newAction); } SharedScenarioActionsOperations.EnsureEmptySolutionExists(newScenario); SharedScenarioActionsOperations.UdpateSolutionsApprovedState(newScenario); // Copier les liens prédécesseurs successeurs foreach (var action in sourceScenario.Actions.ToArray()) { var newAction = newScenario.Actions.FirstOrDefault(a => a.OriginalActionId == action.ActionId); if (newAction != null) { foreach (var predecessor in action.Predecessors) { var newPredecessor = newScenario.Actions.FirstOrDefault(a => a.OriginalActionId == predecessor.ActionId); if (newPredecessor != null) { newAction.Predecessors.Add(newPredecessor); } } } } //Suppression des actions avec durée = 0 if (cloneBehavior == ActionCloneBehavior.TargetToRealized || cloneBehavior == ActionCloneBehavior.TargetToTarget) { ActionsRecursiveUpdate.RemoveEmptyDurationActionsAndGroupsFromNewScenario(newScenario); } if (cloneBehavior != ActionCloneBehavior.TargetToRealized && // ToDelete ne s'applique pas aux scenarios validés cloneBehavior != ActionCloneBehavior.InitialToNewInitial && // ToDelete ne s'applique pas aux scenarios initiaux cloneBehavior != ActionCloneBehavior.TargetToNewInitial && // ToDelete ne s'applique pas aux scenarios initiaux cloneBehavior != ActionCloneBehavior.RealizedToNewInitial) // ToDelete ne s'applique pas aux scenarios initiaux { foreach (var newAction in newScenario.Actions) { // Si la category associée est dite "à supprimer", modifier la tache optimisée à "à supprimer" if (newAction.Category != null && newAction.Category.ActionTypeCode == KnownActionCategoryTypes.S) { SharedScenarioActionsOperations.ApplyNewReduced(newAction, KnownActionCategoryTypes.S); } } } if (save) { context.Scenarios.ApplyChanges(newScenario); await context.SaveChangesAsync(); } ActionsTimingsMoveManagement.FixPredecessorsSuccessorsTimings(newScenario.Actions.ToArray(), false); ActionsTimingsMoveManagement.UpdateVideoGroupsTiming(newScenario.Actions.ToArray()); ActionsTimingsMoveManagement.UpdateBuildGroupsTiming(newScenario.Actions.ToArray()); newScenario.CriticalPathIDuration = ActionsTimingsMoveManagement.GetInternalCriticalPathDuration(newScenario); // Supprimer les liens vers les originaux car dans un autre projet if (cloneBehavior == ActionCloneBehavior.RealizedToNewInitial || cloneBehavior == ActionCloneBehavior.TargetToNewInitial || cloneBehavior == ActionCloneBehavior.InitialToNewInitial) { foreach (var action in newScenario.Actions) { action.Original = null; action.OriginalActionId = null; } newScenario.Original = null; newScenario.OriginalScenarioId = null; } return(newScenario); }
/// <summary> /// Sauvegarde les actions spécifiées. /// </summary> /// <param name="context">Le contexte.</param> /// <param name="allScenarios">Tous les scénarios liés.</param> /// <param name="updatedScenario">Le scénario qui a été mis à jour.</param> /// <param name="recursive"><c>true</c> pour appliquer les changements récursivement sur les scénarios dérivés.</param> public async Task <Scenario> SaveAcquireData(KsmedEntities context, Scenario[] allScenarios, Scenario updatedScenario, bool recursive) { try { // Don't insert a thumbnail that already exists var actionsWithNewThumbnail = updatedScenario.Actions.Where(_ => (_.IsMarkedAsAdded && _.Thumbnail != null) || (_.IsMarkedAsModified && _.ChangeTracker.ModifiedValues.ContainsKey(nameof(KAction.Thumbnail)) && _.Thumbnail != null)); foreach (var action in actionsWithNewThumbnail) { CloudFile thumbnail = updatedScenario.Actions.Where(_ => _.Thumbnail != null && _.ActionId != action.ActionId).Select(_ => _.Thumbnail).FirstOrDefault(_ => _.Hash == action.ThumbnailHash); if (thumbnail == null) { thumbnail = await context.CloudFiles.SingleOrDefaultAsync(_ => _.Hash == action.Thumbnail.Hash); } if (thumbnail != null) { action.Thumbnail = thumbnail; } } KAction[] actionsToDelete; IList <KAction> actionsWithOriginal; if (recursive) { ActionsRecursiveUpdate.UpdateActions(context, updatedScenario, allScenarios, out actionsToDelete, out actionsWithOriginal); } else { actionsWithOriginal = null; actionsToDelete = updatedScenario.Actions.Where(a => a.IsMarkedAsDeleted).ToArray(); updatedScenario.CriticalPathIDuration = ActionsTimingsMoveManagement.GetInternalCriticalPathDuration(updatedScenario); } // Consolider les solutions vides EnsureEmptySolutionExists(updatedScenario); UdpateSolutionsApprovedState(updatedScenario); // Update InheritedAction if original will be deleted var actionIdsToDelete = actionsToDelete.Select(_ => _.ActionId).ToList(); var inheritedActions = await context.KActions .Where(_ => _.OriginalActionId != null && actionIdsToDelete.Contains(_.OriginalActionId.Value)) .ToListAsync(); foreach (var inheritedAction in inheritedActions) { inheritedAction.OriginalActionId = null; context.KActions.ApplyChanges(inheritedAction); } KAction[] allActions = allScenarios .SelectMany(s => s.Actions) .Where(a => a.IsNotMarkedAsUnchanged) .ToArray(); foreach (KAction action in allActions) { if (!action.IsReduced) { ApplyNewReduced(action, KnownActionCategoryTypes.I); } context.KActions.ApplyChanges(action); context.KActionsReduced.ApplyChanges(action.Reduced); } if (actionsWithOriginal != null) { foreach (KAction action in actionsWithOriginal) { SetActionsOriginalReference(context, action); } } foreach (Scenario scenario in allScenarios.Where(s => s.IsNotMarkedAsUnchanged)) { context.Scenarios.ApplyChanges(scenario); } context.Scenarios.ApplyChanges(updatedScenario); foreach (KAction action in actionsToDelete) { action.Predecessors.Clear(); action.Successors.Clear(); action.MarkAsDeleted(); // Ne pas appeler ApplyChanges car les self tracking le gèrent mal (plantage lors de la sauvegarde) // Ajouter l'action au contexte si elle n'y est pas attachée if (!context.ObjectStateManager.TryGetObjectStateEntry(action, out ObjectStateEntry entry)) { context.AddObject(KsmedEntities.KActionsEntitySetName, action); context.ObjectStateManager.ChangeObjectState(action, EntityState.Deleted); } else { context.KActions.DeleteObject(action); } } // Vérifier que tout est correct if (recursive) { ActionsTimingsMoveManagement.DebugCheckAllWBS(allScenarios.Where(s => s.IsNotMarkedAsUnchanged)); } await context.SaveChangesAsync(); return(updatedScenario); } catch (Exception ex) { TraceManager.TraceError(ex, $"Error while saving scenario {updatedScenario.ScenarioId}"); throw; } }