public IHttpActionResult GetRecommendations(Guid id) { // Allow find by ScenarioId (original) or RunId var run = _runRepository.Find(id); if (run == null) // Not a RunId passed, check if a ScenarioId { run = _runRepository.FindByScenarioId(id); } if (run == null) { return(NotFound()); } bool isScenarioId = (run.Id != id); var recommendations = _recommendationRepository.GetByScenarioId(isScenarioId ? id : run.Scenarios[0].Id); var items = _mapper.Map <List <RecommendationModel> >(recommendations); // For Smooth recommendations only then return "Unplaced", instead // of null, for unplaced breaks foreach (var item in items) { if (item.Processor == "smooth" && String.IsNullOrEmpty(item.ExternalBreakNo)) { item.ExternalBreakNo = Globals.UnplacedBreakString; } } return(Ok(items)); }
public IHttpActionResult GetBRSIndicator(Guid runId, int?brsConfigurationTemplateId = null) { var run = _runRepository.Find(runId); if (run == null) { return(NotFound()); } var scenarioResults = _brsManager.CalculateBRSIndicators(run, brsConfigurationTemplateId); return(Ok(_mapper.Map <List <BRSIndicatorValueForScenarioResultModel> >(scenarioResults))); }
protected override string DownloadRunInputFiles(Guid runId, string localFolder, string localInputFolder) { var run = _runRepository.Find(runId); if (run is null) { throw new Exception($"Run {runId.ToString()} was not found"); } return(_inputFilesGenerator.PopulateRunData(run)); }
public OutputImmutableDataSnapshot(RunWithScenarioReference runWithScenarioRef, IRunRepository runRepository, IScenarioRepository scenarioRepository, IPassRepository passRepository, ICampaignRepository campaignRepository, IScheduleRepository scheduleRepository, ISalesAreaRepository salesAreaRepository, IDemographicRepository demographicRepository, IProgrammeDictionaryRepository programmeDictionaryRepository, ISpotRepository spotRepository, IMetadataRepository metadataRepository) { var runStartDate = new Lazy <DateTime>(() => Run.Value.StartDate.Add(Run.Value.StartTime)); var runEndDate = new Lazy <DateTime>(() => DateHelper.ConvertBroadcastToStandard(Run.Value.EndDate, Run.Value.EndTime)); Run = new Lazy <Run>(() => runRepository.Find(runWithScenarioRef.RunId)); Scenario = new Lazy <Scenario>(() => scenarioRepository.Get(runWithScenarioRef.ScenarioId), true); ScenarioPasses = new Lazy <IEnumerable <Pass> >(() => passRepository.FindByScenarioId(runWithScenarioRef.ScenarioId), true); AllCampaigns = new Lazy <IEnumerable <Campaign> >(campaignRepository.GetAll, true); AllSalesAreas = new Lazy <IEnumerable <SalesArea> >(salesAreaRepository.GetAll, true); AllDemographics = new Lazy <IEnumerable <Demographic> >(demographicRepository.GetAll, true); AllProgrammeDictionaries = new Lazy <IEnumerable <ProgrammeDictionary> >(programmeDictionaryRepository.GetAll, true); BreakTypes = new Lazy <IEnumerable <string> >(() => metadataRepository.GetByKey(MetaDataKeys.BreakTypes).Select(e => (string)e.Value)); SpotsForRun = new Lazy <IEnumerable <Spot> >(() => { var salesAreaPriorities = Run.Value.SalesAreaPriorities.Count == 0 ? AllSalesAreas.Value : AllSalesAreas.Value.Where(sa => Run.Value.SalesAreaPriorities.Find(rsa => rsa.SalesArea == sa.Name) != null); return(spotRepository.Search( runStartDate.Value, runEndDate.Value, salesAreaPriorities.Select(sa => sa.Name).ToList() )); }, true ); BreaksForRun = new Lazy <IEnumerable <BreakSimple> >(() => scheduleRepository.GetScheduleSimpleBreaks( AllSalesAreas.Value.Select(c => c.Name).ToList(), runStartDate.Value, runEndDate.Value ), true ); }
/// <summary> /// Handles completed with error, no results /// </summary> public void HandleCompletedFatalError(AutoBook autoBook) { IRunRepository runRepository = null; try { using var scope = _repositoryFactory.BeginRepositoryScope(); // Get scenario snapshot for diagnostics //_scenarioSnapshotGenerator.Generate(autoBook, _scenarioId); // Flag scenario as CompletedError, no results available DateTime?completedDateTime = DateTime.UtcNow; RunManager.UpdateScenarioStatuses(_repositoryFactory, _auditEventRepository, RunId, new List <Guid>() { ScenarioId }, new List <ScenarioStatuses>() { ScenarioStatuses.CompletedError }, null, new List <DateTime?>() { completedDateTime }); // Get run details runRepository = scope.CreateRepository <IRunRepository>(); var run = runRepository.Find(RunId); var scenario = run.Scenarios.Find(currentScenario => currentScenario.Id == ScenarioId); // Notification run scenario completed with error try { _runCompletionNotifier.Notify(run, scenario, false); } catch (System.Exception exception) { // Log failure, don't throw _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating notification for run completed failure (RunID={0}, ScenarioID={1})", RunId, ScenarioId), exception)); } } catch { throw; } finally { using var scope = _repositoryFactory.BeginRepositoryScope(); // Load run so that we can check number of completed scenarios, use fresh repo instance in case run changed elsewhere runRepository = scope.CreateRepository <IRunRepository>(); var run = runRepository.Find(RunId); // Generate notification if all scenarios completed, success if at least one scenario generated results if (run.Scenarios.Count == run.CompletedScenarios.Count) { _synchronizationService.Release(run.Id); int countSucccess = run.Scenarios.Where(currentScenario => currentScenario.Status == ScenarioStatuses.CompletedSuccess).ToList().Count; try { _runCompletionNotifier.Notify(run, (countSucccess > 0)); } catch (System.Exception exception) { // Log failure, don't throw _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating notification for run completed failure (RunID={0})", run.Id), exception)); } } } }
/// <summary> /// Handles completed successfully, downloads and processes output data. If we can't process the output data (E.g. Cloud issues) /// then that is a failure too. /// </summary> public void HandleCompletedSuccess() { bool success = false; IRunRepository runRepository = null; try { try { using var scope = _repositoryFactory.BeginRepositoryScope(); // Update status to GettingResults RunManager.UpdateScenarioStatuses(_repositoryFactory, _auditEventRepository, RunId, new List <Guid>() { ScenarioId }, new List <ScenarioStatuses>() { ScenarioStatuses.GettingResults }); // Get run details runRepository = scope.CreateRepository <IRunRepository>(); var scenarioResultRepository = scope.CreateRepository <IScenarioResultRepository>(); var run = runRepository.Find(RunId); var scenario = run.Scenarios.Find(currentScenario => currentScenario.Id == ScenarioId); // Get results _autoBookOutputHandler.Handle(run, ScenarioId); success = true; // Notification run scenario completed try { _runCompletionNotifier.Notify(run, scenario, success); } catch (System.Exception exception) { // Log failure, don't throw _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating notification for run completed success (RunID={0}, ScenarioID={1})", RunId, ScenarioId), exception)); } } catch { throw; } finally { // Update status to CompletedSuccess/CompletedError DateTime? completedDateTime = DateTime.UtcNow; ScenarioStatuses scenarioStatus = success ? ScenarioStatuses.CompletedSuccess : ScenarioStatuses.CompletedError; RunManager.UpdateScenarioStatuses(_repositoryFactory, _auditEventRepository, RunId, new List <Guid>() { ScenarioId }, new List <ScenarioStatuses>() { scenarioStatus }, null, new List <DateTime?>() { completedDateTime }); } } catch { throw; } finally { using var scope = _repositoryFactory.BeginRepositoryScope(); // Load run so that we can check number of completed scenarios, use fresh repo instance in case run changed elsewhere runRepository = scope.CreateRepository <IRunRepository>(); var run = runRepository.Find(RunId); // Generate notification if all scenarios completed, success if at least one scenario generates results if (run.Scenarios.Count == run.CompletedScenarios.Count) { _synchronizationService.Release(run.Id); int countSucccess = run.Scenarios.Where(currentScenario => currentScenario.Status == ScenarioStatuses.CompletedSuccess).ToList().Count; try { _runCompletionNotifier.Notify(run, (countSucccess > 0)); } catch (System.Exception exception) { // Log failure, don't throw _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating notification for run completed success (RunID={0})", RunId), exception)); } try { // Calculate BRS Indicator IEnumerable <ScenarioResult> calculatedScenarioResults = _brsIndicatorManager.CalculateBRSIndicatorsAfterRunCompleted(run); SendToLandmark(run, calculatedScenarioResults); } catch (Exception exception) { _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, $"Error calculation brs indicator for run completed success (RunID={RunId})", exception)); } } } }
/// <summary> /// Validates for saving run /// </summary> /// <param name="run"></param> /// <param name="allScenarios"></param> /// <param name="allPassesByScenario"></param> public void ValidateForSave( Run run, List <Scenario> allScenarios, List <List <Pass> > allPassesByScenario, List <SalesArea> allSalesAreas) { // Basic validation Run.ValidateForSave(run); ValidateAnalysisGroupTargets(run.AnalysisGroupTargets); if (run.RunTypeId != 0) { if (_featureManager.IsEnabled(nameof(ProductFeature.RunType))) { var runType = _runTypeRepository.Get(run.RunTypeId); if (runType is null || runType.Hidden) { throw new Exception("Run type not found"); } } else { run.RunTypeId = 0; } } if (run.Scenarios.Count > 1 && !_brsConfigurationTemplateRepository.Exists(run.BRSConfigurationTemplateId)) { throw new Exception("BRS template not found"); } RunsValidations.ValidateScenarios(allScenarios); // validate all passes for (int index = 0; index < allPassesByScenario.Count; index++) { allPassesByScenario[index]?.ForEach(pass => { Pass.ValidateForSave(pass); Pass.ValidateScenarioNamingUniqueness(pass, new List <Scenario>() { allScenarios[index] }); }); } // Check that run doesn't contain default scenario, can only contain // a copy TenantSettings tenantSettings = _tenantSettingsRepository.Get(); if (tenantSettings.DefaultScenarioId != Guid.Empty && run.Scenarios.Where(s => s.Id == tenantSettings.DefaultScenarioId).Any()) { throw new Exception("Run cannot contain the default scenario. It must contain a copy"); } if (string.IsNullOrWhiteSpace(tenantSettings.PeakStartTime) || string.IsNullOrWhiteSpace(tenantSettings.PeakEndTime)) { throw new ArgumentNullException(nameof(tenantSettings), "Peak daypart is not set. Please check the tenant settings."); } if (string.IsNullOrWhiteSpace(tenantSettings.MidnightStartTime) || string.IsNullOrWhiteSpace(tenantSettings.MidnightEndTime)) { throw new ArgumentNullException(nameof(tenantSettings), "Midnight daypart is not set. Please check the tenant settings."); } // Check sales areas priorities if (run.SalesAreaPriorities != null && run.SalesAreaPriorities.Any()) { var existingSalesAreaNames = new HashSet <string>(allSalesAreas.Select(s => s.Name)); var runSalesAreaNames = new HashSet <string>(); var unknownSalesAreas = new List <string>(); var duplicatedSalesAreas = new List <string>(); bool areAllExcluded = true; foreach (var priority in run.SalesAreaPriorities) { if (!existingSalesAreaNames.Contains(priority.SalesArea)) { unknownSalesAreas.Add(priority.SalesArea); } if (runSalesAreaNames.Contains(priority.SalesArea)) { duplicatedSalesAreas.Add(priority.SalesArea); } if (priority.Priority != SalesAreaPriorityType.Exclude) { areAllExcluded = false; } runSalesAreaNames.Add(priority.SalesArea); } if (unknownSalesAreas.Any()) { throw new Exception(string.Format("Sales area {0} is not valid", unknownSalesAreas[0])); } if (areAllExcluded) { throw new Exception("All Sales area priorities are set to Exclude"); } if (duplicatedSalesAreas.Any()) { throw new Exception(string.Format("Run Sales area priorities contains duplicate {0}", duplicatedSalesAreas[0])); } } // Get runs & scenarios var runsWithScenarioId = _runRepository.GetRunsWithScenarioId(); // Get scenarios & passes var scenariosWithPassId = _scenarioRepository.GetScenariosWithPassId(); if (run.Scenarios != null && run.Scenarios.Any()) { var runSalesAreas = run.SalesAreaPriorities?.Where(sa => sa.Priority != SalesAreaPriorityType.Exclude).Select(x => x.SalesArea).ToList(); var salesAreasToValidate = new List <string>(); for (int scenarioIndex = 0; scenarioIndex < run.Scenarios.Count; scenarioIndex++) { var scenario = run.Scenarios[scenarioIndex]; var passes = allPassesByScenario[scenarioIndex]; // Check that scenario isn't linked to another run var otherRunIdsForScenarioId = runsWithScenarioId.Where(rws => rws.ScenarioId == scenario.Id && rws.RunId != run.Id).Select(rws => rws.RunId).ToList(); if (otherRunIdsForScenarioId.Any()) { var otherRun = _runRepository.Find(otherRunIdsForScenarioId.First()); throw new Exception(string.Format("Scenario is already linked to Run {0}", otherRun.Description)); } if (passes != null && passes.Any()) { foreach (var pass in passes) { // Check that passes aren't linked to other scenarios var otherScenarioIdsForPassId = scenariosWithPassId.Where(swp => swp.PassId == pass.Id && swp.ScenarioId != scenario.Id).Select(swp => swp.ScenarioId).ToList(); if (otherScenarioIdsForPassId.Any()) { var otherScenario = _scenarioRepository.Get(otherScenarioIdsForPassId.First()); throw new Exception(string.Format("Pass is already linked to Scenario {0}", otherScenario.Name)); } // Check that passes aren't linked to other // scenarios in this run if (pass.Id > 0) { if (passes.Where(p => p.Id == pass.Id).ToList().Count > 1) { throw new Exception("Scenario cannot contain multiple instances of the same PassID"); } for (int scenarioIndex2 = 0; scenarioIndex2 < run.Scenarios.Count; scenarioIndex2++) { if (scenarioIndex != scenarioIndex2) { if (allPassesByScenario[scenarioIndex2].Select(p => p.Id).Contains(pass.Id)) { throw new Exception("Pass is already linked to another Scenario for this run"); } } } } var errorMsg = RunsValidations.ValidatePassSalesAreaPriorities(run, pass, tenantSettings, runSalesAreas); if (!string.IsNullOrWhiteSpace(errorMsg)) { throw new Exception(errorMsg); } } } // Check break exclusions if (passes != null && passes.Any() && passes.Any(p => p.BreakExclusions != null && p.BreakExclusions.Any())) { var breakExclusions = passes .Where(p => p?.BreakExclusions != null && p.BreakExclusions.Any()) .SelectMany(p => p.BreakExclusions) .Select(b => b.SalesArea); salesAreasToValidate.AddRange(breakExclusions); } } if (salesAreasToValidate.Any()) { _salesAreaRepository.ValidateSaleArea(salesAreasToValidate); } } // Check campaigns if (run.Campaigns != null && run.Campaigns.Count > 0) { var existingCampaigns = new HashSet <string>(_campaignRepository.GetAllFlat().Select(x => x.ExternalId)); var unknownCampaigns = run.Campaigns.Select(ca => ca.ExternalId) .Where(externalId => !existingCampaigns.Contains(externalId)).ToList(); if (unknownCampaigns.Any()) { throw new Exception(string.Format("Campaign {0} is not valid", unknownCampaigns[0])); } } // Validation for slotting control by Demograph if (run.Scenarios != null && run.Scenarios.Any()) { var demographicsToValidate = new List <string>(); for (int scenarioIndex = 0; scenarioIndex < run.Scenarios.Count; scenarioIndex++) { var passes = allPassesByScenario[scenarioIndex]; if (passes != null && passes.Any() && passes.Any(p => p.SlottingLimits != null && p.SlottingLimits.Any())) { var slottingLimits = passes .Where(p => p?.SlottingLimits != null && p.SlottingLimits.Any()) .SelectMany(p => p.SlottingLimits) .Select(b => b.Demographs); demographicsToValidate.AddRange(slottingLimits); } } demographicsToValidate = demographicsToValidate.Where(x => x != null).Distinct().ToList(); if (demographicsToValidate.Any() && !_demographicRepository.ValidateDemographics(demographicsToValidate, out List <string> invalidDemographics)) { var msg = string.Concat( "Invalid Demographic in slotting control by Demograph: ", invalidDemographics != null ? string.Join(",", invalidDemographics) : string.Empty); throw new InvalidDataException(msg); } } ValidateDeliveryCappingGroupIds(_mapper.Map <IEnumerable <CampaignRunProcessesSettingsModel> >(run.CampaignsProcessesSettings)); }