/// <summary> /// Prédit les scénarios qui seront impactés par les modifications en attente de sauvegarde. /// </summary> /// <param name="sourceModifiedScenario">Le scenério source modifié.</param> /// <param name="allScenarios">Tous les scénarios.</param> /// <param name="actionsToDelete">Les actions à supprimer.</param> public virtual Task <Scenario[]> PredictImpactedScenarios( Scenario sourceModifiedScenario, Scenario[] allScenarios, KAction[] actionsToDelete, KAction[] actionsWithUpdatedWBS) => Task.Run(() => { return(ActionsRecursiveUpdate.PredictImpactedScenarios(sourceModifiedScenario, allScenarios, actionsToDelete, actionsWithUpdatedWBS)); });
/// <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 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> /// 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> private 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; } }