/// <summary> /// Met à jour les libellés des causes d'écarts sur les actions. /// </summary> private void UpdateDifferenceReasons() { if (this.SelectedOriginalScenario != null && this.SelectedTargetScenario != null) { foreach (var action in this.SelectedOriginalScenario.Actions.Concat( this.SelectedTargetScenario.Actions)) { action.DifferenceReasonManaged = action.DifferenceReason; } foreach (var action in this.SelectedOriginalScenario.Actions) { var derived = ScenarioActionHierarchyHelper.GetDerivedAction(action, this.SelectedTargetScenario); if (derived != null && action.DifferenceReason != null) { derived.DifferenceReasonManaged = action.DifferenceReason; } } foreach (var action in this.SelectedTargetScenario.Actions) { var ancestor = ScenarioActionHierarchyHelper.GetAncestorAction(action, this.SelectedOriginalScenario); if (ancestor != null && action.DifferenceReason != null) { ancestor.DifferenceReasonManaged = action.DifferenceReason; } } } }
/// <summary> /// Obtient les données pour l'écran Simuler. /// </summary> /// <param name="context">le contexte EF.</param> /// <param name="projectId">L'identifiant du projet.</param> /// <param name="natureFilter">Le filtre des codes de nature.</param> /// <returns> /// Les données /// </returns> public static async Task <SimulateData> GetSimulateData(KsmedEntities context, int projectId, GetDataScenarioNatures natureFilter) { IDictionary <ProcessReferentialIdentifier, bool> referentialsUsed = await GetReferentialsUse(context, projectId); await Queries.LoadAllReferentialsOfProject(context, projectId, referentialsUsed); await context.Projects .Include(nameof(Project.Process)) .Include($"{nameof(Project.Process)}.{nameof(Procedure.Videos)}") .Where(p => p.ProjectId == projectId) .SelectMany(p => p.Process.Videos) .ToArrayAsync(); Scenario[] scenarios = await LoadScenarios(context, projectId, referentialsUsed, natureFilter); Project project = await context.Projects.SingleAsync(p => p.ProjectId == projectId); ScenarioActionHierarchyHelper.MapScenariosActionsOriginals(scenarios); SimulateData data = new SimulateData() { Scenarios = scenarios, ActionTypes = await context.ActionTypes.ToArrayAsync(), CustomFieldsLabels = GetCustomFieldsLabels(project), }; return(data); }
/// <summary> /// Obtient les données pour l'écran Construire. /// </summary> /// <param name="context">Le contexte EF.</param> /// <param name="projectId">L'identifiant du projet.</param> /// <param name="natureFilter">Le filtre sur les codes de nature de scénario.</param> /// <returns>Les données</returns> public static async Task <BuildData> GetBuildData(KsmedEntities context, int projectId, GetDataScenarioNatures natureFilter) { IDictionary <ProcessReferentialIdentifier, bool> referentialsUsed = await GetReferentialsUse(context, projectId); Referentials referentials = await Queries.LoadAllReferentialsOfProject(context, projectId, referentialsUsed); BuildData data = new BuildData { Categories = referentials.Categories, Skills = referentials.Skills, Resources = referentials.Resources, Videos = await context.Projects .Include(nameof(Project.Process)) .Include($"{nameof(Project.Process)}.{nameof(Procedure.Videos)}") .Where(p => p.ProjectId == projectId) .SelectMany(p => p.Process.Videos) .ToArrayAsync(), ActionTypes = (await context.ActionTypes.ToArrayAsync()).OrderBy(a => a.ActionTypeCode, new KnownActionCategoryTypes.ActionCategoryTypeDefaultOrderComparer()).ToArray() }; Project project = await context.Projects.SingleAsync(p => p.ProjectId == projectId); data.CustomFieldsLabels = GetCustomFieldsLabels(project); Scenario[] scenarios = await LoadScenarios(context, projectId, referentialsUsed, natureFilter); ScenarioActionHierarchyHelper.MapScenariosActionsOriginals(scenarios); data.Scenarios = scenarios; return(data); }
/// <summary> /// Obtient la source de la cause des écarts. /// </summary> /// <param name="action">L'action où la cause des écarts a changé.</param> /// <param name="isFromValidationScenario"><c>true</c> si l'action provient du scénario de validation. <c>false</c> si elle provient du scénario cible.</param> /// <param name="targetAction">L'action du scénario cible.</param> /// <param name="validationAction">L'action du scénario de validation.</param> /// <returns></returns> private DifferenceReasonSource GetDifferenceReasonSource(KAction action, out bool isFromValidationScenario, out KAction targetAction, out KAction validationAction) { isFromValidationScenario = this.SelectedTargetScenario != null && this.SelectedTargetScenario.Actions.Contains(action); if (isFromValidationScenario) { validationAction = action; targetAction = ScenarioActionHierarchyHelper.GetAncestorAction(action, this.SelectedOriginalScenario); if (targetAction == null) { return(DifferenceReasonSource.FromSourceScenarioNew); } else { return(DifferenceReasonSource.FromBoth); } } else { targetAction = action; validationAction = ScenarioActionHierarchyHelper.GetDerivedAction(action, this.SelectedTargetScenario); if (validationAction == null) { return(DifferenceReasonSource.FromTargetScenarioDeleted); } else { return(DifferenceReasonSource.FromBoth); } } }
/// <summary> /// Obtient les données pour l'écran Restituer. /// </summary> /// <param name="context">le contexte EF.</param> /// <param name="projectId">L'identifiant du projet.</param> /// <returns> /// Les données /// </returns> public static async Task <RestitutionData> GetRestitutionData(KsmedEntities context, int projectId) { IDictionary <ProcessReferentialIdentifier, bool> referentialsUsed = await GetReferentialsUse(context, projectId); Referentials referentials = await Queries.LoadAllReferentialsOfProject(context, projectId, referentialsUsed); ActionCategory[] categories = referentials.Categories; await context.Projects .Include(nameof(Project.Process)) .Include($"{nameof(Project.Process)}.{nameof(Procedure.Videos)}") .Where(p => p.ProjectId == projectId) .SelectMany(p => p.Process.Videos) .ToArrayAsync(); Scenario[] scenarios = await context.Scenarios .Where(s => s.ProjectId == projectId) .ToArrayAsync(); await Queries.LoadScenariosDetails(context, scenarios, referentialsUsed); ILookup <int, KAction> actionsToLoad = scenarios .SelectMany(a => a.Actions) .Where(a => a.IsReduced && a.OriginalActionId.HasValue) .ToLookup(a => a.OriginalActionId.Value, a => a); if (actionsToLoad.Any()) { foreach (ActionDuration duration in await GetActionsBuildDurations(context, actionsToLoad.Select(g => g.Key))) { foreach (KAction action in actionsToLoad[duration.ActionId]) { action.Reduced.Saving = duration.BuildDuration - action.BuildDuration; } } } ScenarioActionHierarchyHelper.MapScenariosActionsOriginals(scenarios); foreach (Scenario scenario in scenarios) { UpdateIsGroup(scenario); } RestitutionData data = new RestitutionData() { Scenarios = scenarios, ActionCategories = categories, }; return(data); }
/// <summary> /// Exporte les solutions. /// </summary> /// <param name="scenario">Le scénario.</param> /// <param name="cellReference">La référence de la cellule.</param> /// <param name="file">Le fichier.</param> /// <param name="sheet">La feuille.</param> private void ExportSolutions(Scenario scenario, CellReference cellReference, WorksheetPart sheet) { ITimeTicksFormatService timeFormatService = IoC.Resolve <IServiceBus>().Get <ITimeTicksFormatService>(); long timeScale = _data.Project.TimeScale; List <SolutionWrapper> solutions = new List <SolutionWrapper>(); foreach (var solution in scenario.Solutions.OrderBy(s => s.SolutionDescription)) { var w = CreateSolutionWrapper(scenario.Actions, solution); solutions.Add(w); } var originalScenario = scenario.Original; while (originalScenario != null) { // Déterminer les actions qui sont concernées var originalActions = originalScenario.Actions.Where(originalAction => scenario.Actions.Any(currentScenarioAction => ScenarioActionHierarchyHelper.IsAncestor(originalAction, currentScenarioAction))); foreach (var solution in originalScenario.Solutions.OrderBy(s => s.SolutionDescription)) { var wrapper = CreateSolutionWrapper(originalActions, solution); // Ignorer les solutions qui n'apportent pas de gain. C'est un surplus d'infos inutile if (wrapper.Saving != 0) { solutions.Add(wrapper); } } originalScenario = originalScenario.Original; } // Définir l'index int i = 1; foreach (var wrapper in solutions) { wrapper.Index = i++; } var solutionsFormats = new ColumnFormat[] { #region Format pour les solutions // Index new ColumnFormat() { Header = "" }, // Scénario new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Scenario") }, // Solution new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Solution") }, // Tâches liées new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_RelatedActions") }, // Gain new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Saving") }, // Investissement new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Investment") }, // I/G new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_IG") }, // Difficulté new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Diffculty") }, // Coûts new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Cost") }, // DC/G new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_DCG") }, // OK new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_OK") }, // Comments new ColumnFormat() { Header = LocalizationManager.GetString("View_RestitutionSolutions_Columns_Comments") }, #endregion }; CellContent[][] data = new CellContent[solutions.Count][]; i = 0; foreach (var solution in solutions) { CellContent[] row = new CellContent[solutionsFormats.Length]; int j = 0; #region Data // Index row[j++] = solution.Index; // Scénario row[j++] = solution.Solution.Scenario.Label; // Solution row[j++] = solution.Solution.SolutionDescription; // Tâches liées row[j++] = solution.RelatedActions; // Gain row[j++] = CellContent.TimeSpan(timeFormatService.RoundTime(solution.Saving, timeScale)); // Investissement if (solution.Solution.Investment.HasValue) { row[j++] = solution.Solution.Investment; } else { row[j++] = null; } // I/G if (solution.IG.HasValue) { row[j++] = solution.IG; } else { row[j++] = null; } // Difficulté if (solution.Solution.Difficulty.HasValue) { row[j++] = solution.Solution.Difficulty; } else { row[j++] = null; } // Coûts if (solution.Solution.Cost.HasValue) { row[j++] = solution.Solution.Cost; } else { row[j++] = null; } // DC/G if (solution.DCG.HasValue) { row[j++] = solution.DCG; } else { row[j++] = null; } // OK row[j++] = solution.Solution.Approved.ToString(); // Comments row[j++] = solution.Solution.Comments; #endregion data[i] = row; i++; } _file.AddTable(sheet, solutionsFormats, data, cellReference); }
/// <summary> /// Obtient les données pour l'écran Acquérir. /// </summary> /// <param name="context">Le contexte EF.</param> /// <param name="projectId">L'identifiant du projet.</param> /// <param name="natureFilter">Le filtre sur les codes de nature de scénario.</param> /// <returns> /// Les données /// </returns> public static async Task <AcquireData> GetAcquireData(KsmedEntities context, int projectId, GetDataScenarioNatures natureFilter) { IDictionary <ProcessReferentialIdentifier, bool> referentialsUsed = await GetReferentialsUse(context, projectId); int processId = (await context.Projects.SingleAsync(p => p.ProjectId == projectId)).ProcessId; AcquireData data = new AcquireData { Categories = await Queries.FilterReferentials(context.ActionCategories, processId, ProcessReferentialIdentifier.Category).ToArrayAsync(), Skills = await Queries.FilterReferentials(context.Skills, processId, ProcessReferentialIdentifier.Skill).ToArrayAsync(), Resources = await Queries.FilterResources(context, processId).ToArrayAsync(), Videos = await context.Projects .Include(nameof(Project.Process)) .Include($"{nameof(Project.Process)}.{nameof(Procedure.Videos)}") .Where(p => p.ProjectId == projectId) .SelectMany(p => p.Process.Videos) .OrderBy(v => v.CameraName).OrderBy(v => v.DefaultResourceId).OrderBy(v => v.ResourceView).OrderBy(v => v.ShootingDate) .ToArrayAsync() }; if (referentialsUsed[ProcessReferentialIdentifier.Ref1]) { data.Ref1s = await Queries.FilterReferentials(context.Refs1, processId, ProcessReferentialIdentifier.Ref1).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref2]) { data.Ref2s = await Queries.FilterReferentials(context.Refs2, processId, ProcessReferentialIdentifier.Ref2).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref3]) { data.Ref3s = await Queries.FilterReferentials(context.Refs3, processId, ProcessReferentialIdentifier.Ref3).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref4]) { data.Ref4s = await Queries.FilterReferentials(context.Refs4, processId, ProcessReferentialIdentifier.Ref4).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref5]) { data.Ref5s = await Queries.FilterReferentials(context.Refs5, processId, ProcessReferentialIdentifier.Ref5).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref6]) { data.Ref6s = await Queries.FilterReferentials(context.Refs6, processId, ProcessReferentialIdentifier.Ref6).ToArrayAsync(); } if (referentialsUsed[ProcessReferentialIdentifier.Ref7]) { data.Ref7s = await Queries.FilterReferentials(context.Refs7, processId, ProcessReferentialIdentifier.Ref7).ToArrayAsync(); } Project project = await context.Projects.Include(nameof(Project.Process)).SingleAsync(p => p.ProjectId == projectId); data.CustomFieldsLabels = GetCustomFieldsLabels(project); Scenario[] scenarios = null; Scenario[] scenariosUsedForMapping = null; if (natureFilter == GetDataScenarioNatures.InitialAndTarget) { // Il y a tout ce qu'il faut pour faire le mapping dans les scenarii chargés scenariosUsedForMapping = await LoadScenarios(context, projectId, referentialsUsed, GetDataScenarioNatures.InitialAndTarget); scenarios = scenariosUsedForMapping; } else if (natureFilter == GetDataScenarioNatures.Realized) { // Il faut charger au moins les scenarii cibles également scenariosUsedForMapping = await LoadScenarios(context, projectId, referentialsUsed, GetDataScenarioNatures.All); scenarios = scenariosUsedForMapping.Where(scenario => scenario.NatureCode == KnownScenarioNatures.Realized).ToArray(); } else { // Le cas all à priori, on considère de toute façon qu'il s'agit du cas par défaut scenariosUsedForMapping = await LoadScenarios(context, projectId, referentialsUsed, natureFilter); scenarios = scenariosUsedForMapping; } ScenarioActionHierarchyHelper.MapScenariosActionsOriginals(scenariosUsedForMapping); data.Scenarios = scenarios; return(data); }
/// <summary> /// Charge le scénario spécifié. /// </summary> private void LoadScenario(Scenario oldScenario, Scenario newScenario) { if (oldScenario == newScenario) { return; } _scenario = newScenario; if (oldScenario != null) { foreach (var solution in oldScenario.Solutions) { base.UnregisterToStateChanged(solution); solution.StopTracking(); } } if (newScenario != null) { var solutions = new List <SolutionWrapper>(); // On ne doit pas afficher les solutions du scénario de validation et du scénario initial if (newScenario.NatureCode != KnownScenarioNatures.Realized && newScenario.NatureCode != KnownScenarioNatures.Initial) { foreach (var solution in newScenario.Solutions.OrderBy(s => s.SolutionDescription)) { var w = CreateSolutionWrapper(newScenario.Actions, solution); w.IsNotReadOnly = true; solutions.Add(w); } } var originalScenario = newScenario.Original; while (originalScenario != null) { // On ne doit pas afficher le scénario initial if (originalScenario.NatureCode == KnownScenarioNatures.Initial) { break; } // Déterminer les actions qui sont concernées var originalActions = originalScenario.Actions.Where(originalAction => newScenario.Actions.Any(currentScenarioAction => ScenarioActionHierarchyHelper.IsAncestor(originalAction, currentScenarioAction))); foreach (var solution in originalScenario.Solutions.OrderBy(s => s.SolutionDescription)) { var wrapper = CreateSolutionWrapper(originalActions, solution); // Ignorer les solutions qui n'apportent pas de gain. C'est un surplus d'infos inutile if (wrapper.Saving != 0) { solutions.Add(wrapper); } } originalScenario = originalScenario.Original; } // Définir l'index int i = 1; foreach (var wrapper in solutions) { wrapper.Index = i++; } this.Solutions = solutions.ToArray(); } else { this.Solutions = null; } }
/// <summary> /// Obtient toutes les données du projet spécifié. /// </summary> /// <param name="projectId">L'identifiant du projet.</param> public virtual async Task <RestitutionData> GetFullProjectDetails(int projectId) => await Task.Run(async() => { using (var context = ContextFactory.GetNewContext(_securityContext.CurrentUser, _localizationManager)) { IDictionary <ProcessReferentialIdentifier, bool> referentialsUsed = await _sharedScenarioActionsOperations.GetReferentialsUse(context, projectId); Referentials referentials = await Queries.LoadAllReferentialsOfProject(context, projectId, referentialsUsed); //await context.Videos.Where(v => v.ProjectId == projectId).ToArrayAsync(); await context.ScenarioNatures.ToArrayAsync(); await context.ScenarioStates.ToArrayAsync(); await context.ActionTypes.ToArrayAsync(); await context.ActionValues.ToArrayAsync(); Project project = await context.Projects .Include(nameof(Project.Process)) .Include($"{nameof(Project.Process)}.{nameof(Procedure.Videos)}") .Include($"{nameof(Project.Process)}.{nameof(Procedure.UserRoleProcesses)}") .Include($"{nameof(Project.Process)}.{nameof(Procedure.UserRoleProcesses)}.{nameof(UserRoleProcess.User)}") .Include($"{nameof(Project.Process)}.{nameof(Procedure.UserRoleProcesses)}.{nameof(UserRoleProcess.User)}.{nameof(User.DefaultLanguage)}") .Include(nameof(Project.Scenarios)) .Include($"{nameof(Project.Scenarios)}.{nameof(Scenario.Actions)}") .Include(nameof(Project.Objective)) .FirstAsync(s => s.ProjectId == projectId); project.ScenariosCriticalPath = PrepareService.GetSummary(project, true); // Scénarios foreach (Scenario scenario in project.Scenarios.Where(s => s.OriginalScenarioId.HasValue)) { // Remapper l'original scenario.Original = project.Scenarios.Single(s => s.ScenarioId == scenario.OriginalScenarioId); ScenarioCriticalPath matchingCriticalItem = project.ScenariosCriticalPath.FirstOrDefault(i => i.Id == scenario.ScenarioId); if (matchingCriticalItem != null) { matchingCriticalItem.OriginalLabel = scenario.Original.Label; } } ProjectReferential[] projectReferentials = await context.ProjectReferentials.Where(pr => pr.ProjectId == projectId).ToArrayAsync(); User user = await context.Users.FirstAsync(u => u.UserId == project.CreatedByUserId); ModificationsUsers modificationsUsers = new ModificationsUsers { CreatedByFullName = (await context.Users.FirstAsync(u => u.UserId == project.ModifiedByUserId)).FullName, LastModifiedByFullName = (await context.Users.FirstAsync(u => u.UserId == project.ModifiedByUserId)).FullName }; Scenario[] scenarios = await context.Scenarios .Where(s => s.ProjectId == projectId) .ToArrayAsync(); await Queries.LoadScenariosDetails(context, scenarios, referentialsUsed); ILookup <int, KAction> actionsToLoad = scenarios .SelectMany(a => a.Actions) .Where(a => a.IsReduced && a.OriginalActionId.HasValue) .ToLookup(a => a.OriginalActionId.Value, a => a); if (actionsToLoad.Any()) { foreach (var duration in await _sharedScenarioActionsOperations.GetActionsBuildDurations(context, actionsToLoad.Select(g => g.Key))) { foreach (KAction action in actionsToLoad[duration.ActionId]) { action.Reduced.Saving = duration.BuildDuration - action.BuildDuration; } } } ScenarioActionHierarchyHelper.MapScenariosActionsOriginals(scenarios); return(new RestitutionData() { Project = project, ProjectCreatedByUser = user, Scenarios = scenarios, ActionCategories = referentials.Categories, ModificationsUsers = modificationsUsers, ReferentialsUse = projectReferentials, }); } });
/// <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> /// <returns> /// Les scénarios impactés. /// </returns> internal static Scenario[] PredictImpactedScenarios(Scenario sourceModifiedScenario, Scenario[] allScenarios, KAction[] actionsToDelete, KAction[] actionsWithUpdatedWBS) { var derivedScenarios = ScenarioActionHierarchyHelper.GetDerivedScenarios(sourceModifiedScenario, allScenarios); var scenariosToInspect = new List <Scenario>(derivedScenarios); var actions = GetActionsSortedWBS(sourceModifiedScenario); if (actions.Any(a => a.IsMarkedAsAdded)) { scenariosToInspect.Clear(); } else { foreach (var originalAction in actions) { bool hasUpdatedWBS = actionsWithUpdatedWBS != null && actionsWithUpdatedWBS.Contains(originalAction); if (originalAction.IsMarkedAsModified || hasUpdatedWBS) { var modifiedValues = originalAction.ChangeTracker.ModifiedValues; // S'il y a une correspondance entre le nom d'une propriété modifiée et les propriétés qui sont impactantes if (hasUpdatedWBS || modifiedValues.Keys.Intersect(_kActionPropertyNamesToCopy).Any()) { // rechercher tous les scénarios qui possèdent ces actions dérivées foreach (var derivedScenario in scenariosToInspect.ToArray()) { var derivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario); if (derivedAction != null) { scenariosToInspect.Remove(derivedScenario); } if (!scenariosToInspect.Any()) { break; } } } if (modifiedValues.ContainsKey(ActionsTimingsMoveManagement.KActionBuildStartPropertyName) || modifiedValues.ContainsKey(ActionsTimingsMoveManagement.KActionBuildFinishPropertyName)) { ActionsTimingsMoveManagement.GetOrignalModifiedBuildDurations(originalAction, out long originalDuration, out long modifiedDuration); if (modifiedDuration != originalDuration) { // rechercher tous les scénarios qui possèdent ces actions dérivées foreach (var derivedScenario in scenariosToInspect.ToArray()) { var derivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario); if (derivedAction != null && derivedAction.IsReduced) { scenariosToInspect.Remove(derivedScenario); } if (!scenariosToInspect.Any()) { break; } } } } } } } if (actionsToDelete != null) { foreach (var originalAction in actionsToDelete) { // rechercher tous les scénarios qui possèdent ces actions dérivées foreach (var derivedScenario in scenariosToInspect.ToArray()) { var derivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario); if (derivedAction != null) { scenariosToInspect.Remove(derivedScenario); } } if (!scenariosToInspect.Any()) { break; } } } return(derivedScenarios.Except(scenariosToInspect).ToArray()); }
/// <summary> /// Met à jour les actions récursivement sur les scénarios dérivés de celui spécifié. /// </summary> /// <param name="context">Le contexte EF.</param> /// <param name="sourceScenario">Le scénario source.</param> /// <param name="allScenarios">Tous les scénarios qui peuvent être impactés.</param> /// <param name="actionsToRemove">Les actions à supprimer manuellement.</param> internal static void UpdateActions(KsmedEntities context, Scenario sourceScenario, Scenario[] allScenarios, out KAction[] actionsToRemove, out IList <KAction> actionsWithOriginal) { var derivedScenarios = ScenarioActionHierarchyHelper.GetDerivedScenarios(sourceScenario, allScenarios); var actions = GetActionsSortedWBS(sourceScenario); actionsWithOriginal = new List <KAction>(); foreach (var scenario in derivedScenarios) { // Mettre à jour IsGroup foreach (var action in scenario.Actions) { action.IsGroup = WBSHelper.HasChildren(action, scenario.Actions); } } foreach (var originalAction in actions) { // J'enlève le IsMArkedAsModified car les 2 références sont la sauvegarde des actions depuis la construction et depuis l'optimisation // Or depuis la construction, en modification, le bout de code cidessous est déjà appelé // Et depuis l'optimisation, il n'y a pas de changement de temps video if (originalAction.IsMarkedAsAdded /*|| originalAction.IsMarkedAsModified*/) { var originalValues = originalAction.ChangeTracker.OriginalValues; var modifiedValues = originalAction.ChangeTracker.ModifiedValues; if (originalAction.IsMarkedAsAdded || modifiedValues.ContainsKey(ActionsTimingsMoveManagement.KActionStartPropertyName) || modifiedValues.ContainsKey(ActionsTimingsMoveManagement.KActionFinishPropertyName)) { // Vérifier si le temps vidéo a changé ActionsTimingsMoveManagement.GetOrignalModifiedVideoDurations(originalAction, out long originalDuration, out long modifiedDuration); bool hasVideoDurationChanged = originalDuration != modifiedDuration; // Si c'est une tâche créée et non dupliquée, le buildDuration est à 0, donc on doit le mettre à jour //Sinon, si c'est une tâche dupliquée, on le laisse tel quel. if (originalAction.BuildDuration == 0) { var paceRating = originalAction.Resource != null ? originalAction.Resource.PaceRating : 1d; originalAction.BuildDuration = Convert.ToInt64(modifiedDuration * paceRating); } } } if (originalAction.IsMarkedAsAdded) { // Si l'action est une action nouvelle dans un scénario cible, définir automatiquement la partie réduite if (sourceScenario.NatureCode == KnownScenarioNatures.Target && originalAction.Reduced == null) { SharedScenarioActionsOperations.ApplyNewReduced(originalAction); } var originalActionKey = context.CreateEntityKey(KsmedEntities.KActionsEntitySetName, originalAction); var parentOriginalAction = WBSHelper.GetParent(originalAction, actions); foreach (var derivedScenario in derivedScenarios) { var derivedActions = GetActionsSortedWBS(derivedScenario); // Rechercher le parent dans le scénario dérivé var parentDerivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(parentOriginalAction, derivedScenario); // Cloner l'action originale var newAction = ScenarioCloneManager.CloneAction(originalAction, ActionCloneBehavior.Cascade); // Assigner l'original var originalActionForCurrentDerivedScenario = derivedScenario.Original == sourceScenario ? originalAction : ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario.Original); newAction.Original = originalActionForCurrentDerivedScenario; actionsWithOriginal.Add(newAction); // Insérer l'action clonée dans le scénario dérivé ActionsTimingsMoveManagement.InsertUpdateWBS( derivedActions, newAction, parentDerivedAction, WBSHelper.GetParts(originalAction.WBS).Last(), (a, wbs) => EnsureTracking(a)); // Rafraichir les actions derivedScenario.Actions.Add(newAction); derivedActions = GetActionsSortedWBS(derivedScenario); // Ajouter les mêmes prédécesseurs et successeurs foreach (var originalPredecessor in originalAction.Predecessors) { var derivedPredecessor = ScenarioActionHierarchyHelper.GetDerivedAction(originalPredecessor, derivedScenario); if (derivedPredecessor != null) { EnsureTracking(derivedPredecessor); ActionsTimingsMoveManagement.AddPredecessor(derivedActions, newAction, derivedPredecessor); } } foreach (var originalSuccessor in originalAction.Successors) { var derivedSuccessor = ScenarioActionHierarchyHelper.GetDerivedAction(originalSuccessor, derivedScenario); if (derivedSuccessor != null) { EnsureTracking(derivedSuccessor); ActionsTimingsMoveManagement.AddPredecessor(derivedActions, derivedSuccessor, newAction); } } EnsureTracking(derivedScenario); SharedScenarioActionsOperations.EnsureEmptySolutionExists(derivedScenario); SharedScenarioActionsOperations.UdpateSolutionsApprovedState(derivedScenario); ActionsTimingsMoveManagement.DebugCheckAllWBS(derivedActions); } } else if (originalAction.IsMarkedAsModified) { var originalValues = originalAction.ChangeTracker.OriginalValues; var modifiedValues = originalAction.ChangeTracker.ModifiedValues; var propertiesToCopyValues = new Dictionary <string, object>(); foreach (var propertyName in _kActionPropertyNamesToCopy) { if (modifiedValues.ContainsKey(propertyName)) { propertiesToCopyValues[propertyName] = modifiedValues[propertyName]; } } // Vérifier si les reduced doit être impactés également ActionsTimingsMoveManagement.GetOrignalModifiedBuildDurations(originalAction, out long originalDuration, out long modifiedDuration); bool hasBuildDurationChanged = originalDuration != modifiedDuration; foreach (var derivedScenario in derivedScenarios) { var derivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario); if (derivedAction != null) { EnsureTracking(derivedAction); foreach (var kvp in propertiesToCopyValues) { derivedAction.SetPropertyValue(kvp.Key, kvp.Value); } if (hasBuildDurationChanged) { if (derivedAction.IsReduced) { // Modifier l'original duration et recalculer le temps final en fonction du gain EnsureTracking(derivedAction.Reduced); derivedAction.Reduced.OriginalBuildDuration = modifiedDuration; ActionsTimingsMoveManagement.UpdateTimingsFromReducedReduction(derivedAction); } else { // Simplement recopier la durée derivedAction.BuildDuration = modifiedDuration; } } } } } } var toRemove = new List <KAction>(); // Gérer les actions supprimées // EF gérant mal l'ordre des suppressions, ça créer une ConstraintException sur la FK OriginalActionId // Malheureusement un CascadeDelete est impossible puisque la FK est sur un même table if (sourceScenario.ChangeTracker.ObjectsRemovedFromCollectionProperties.ContainsKey("Actions")) { var removedActions = sourceScenario.ChangeTracker.ObjectsRemovedFromCollectionProperties["Actions"].ToArray(); foreach (KAction originalAction in removedActions) { EnsureTracking(originalAction); toRemove.Add(originalAction); originalAction.MarkAsUnchanged(); foreach (var derivedScenario in derivedScenarios) { var derivedAction = ScenarioActionHierarchyHelper.GetDerivedAction(originalAction, derivedScenario); if (derivedAction != null) { var derivedActions = GetActionsSortedWBS(derivedScenario); // Mettre à jour les WBS des autres actions ActionsTimingsMoveManagement.DeleteUpdateWBS(derivedActions, derivedAction, (a, wbs) => EnsureTracking(a)); EnsureTracking(derivedAction); toRemove.Add(derivedAction); } } } // Il faut maintenant trier les actions à supprimer pour que la suppression se fasse dans le bon ordre toRemove.Reverse(); actionsToRemove = toRemove.ToArray(); } else { actionsToRemove = new KAction[] { } }; sourceScenario.CriticalPathIDuration = ActionsTimingsMoveManagement.GetInternalCriticalPathDuration(sourceScenario); foreach (var scenario in derivedScenarios) { EnsureTracking(scenario); ActionsTimingsMoveManagement.FixPredecessorsSuccessorsTimings(scenario.Actions.ToArray(), false); ActionsTimingsMoveManagement.UpdateVideoGroupsTiming(scenario.Actions.ToArray()); ActionsTimingsMoveManagement.UpdateBuildGroupsTiming(scenario.Actions.ToArray()); scenario.CriticalPathIDuration = ActionsTimingsMoveManagement.GetInternalCriticalPathDuration(scenario); } }