public async Task Execute(Guid runId)
        {
            var runCompleted = false;

            try
            {
                runCompleted = await WaitForRunCompletedAsync(runId).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0,
                                                                                            $"Completed run notification error (RunID={runId})", ex));
            }
            finally
            {
                if (runCompleted)
                {
                    _runManager.CreateNotificationForCompletedRun(_run);
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                         $"Completed run notification has sent (RunID={runId})"));
                }
                else
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                     $"Completed run notification warning, Run not found (RunID={runId})"));
                }
            }
        }
        public ProcessBreakEfficiencyOutput ProcessFile(Guid scenarioId, string folder)
        {
            var output             = new ProcessBreakEfficiencyOutput();
            var run                = _dataSnapshot.Run.Value;
            var efficiencySettings = _efficiencySettingsRepository.GetDefault();

            if (!run.Manual || run.Manual && efficiencySettings.PersistEfficiency == PersistEfficiency.AllRun)
            {
                if (scenarioId == run.Scenarios.OrderBy(c => c.Id).First().Id)
                {
                    try
                    {
                        output = ProcessFileInternal(scenarioId, folder);
                    }
                    catch (Exception exception)
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, $"Error processing Break Efficiency", exception));
                    }
                }
                else
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"Ignoring break efficiency because it should only be processed once for the run"));
                }
            }

            return(output);
        }
        public IEnumerable <ConversionEfficiency> Process(string pathToFile)
        {
            if (!File.Exists(pathToFile))
            {
                _audit?.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, "File was not found."));

                return(Enumerable.Empty <ConversionEfficiency>());
            }

            _audit?.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                   0, $"Processing output file {pathToFile}"));

            try
            {
                var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(ConversionEfficiencyHeaderMap), typeof(ConversionEfficiencyIndexMap));

                var conversionEfficiency = new CSVConversionEfficiencyImportRepository(importSettings);

                var data = conversionEfficiency.GetAll();

                var output = _mapper.Map <IEnumerable <ConversionEfficiency> >(data);

                _audit?.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                       0, $"Processed output file {pathToFile}"));

                return(output);
            }
            catch (Exception exception)
            {
                _audit?.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, $"Error processing file {pathToFile}", exception));

                return(Enumerable.Empty <ConversionEfficiency>());
            }
        }
        /// <summary>
        /// Load breaks for break efficiency import record if not already in memory
        /// </summary>
        /// <param name="salesArea"></param>
        /// <param name="breakEfficiencyImport"></param>
        /// <param name="schedules"></param>
        private void LoadBreaks(SalesArea salesArea, BreakEfficiencyImport breakEfficiencyImport, List <ScheduleIndexed <Break, int> > schedules, IScheduleRepository scheduleRepository)
        {
            DateTime startDateTime = GetStartDateTime(breakEfficiencyImport);

            // Load Schedule document if necessary
            var schedule = schedules.Where(s => s.SalesArea == salesArea.Name && s.Date.Date == startDateTime.Date).FirstOrDefault();

            if (schedule == null)       // Not in memory, load it
            {
                var scheduleObject = scheduleRepository.GetSchedule(salesArea.Name, startDateTime.Date);
                if (scheduleObject != null)
                {
                    if (scheduleObject.Breaks != null && scheduleObject.Breaks.Count > 0)  // Schedule has breaks
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0, string.Format("Break Efficiency processing. Schedule loaded for sales area {0} and date {1}", salesArea.Name, startDateTime.Date)));
                        scheduleObject.Breaks.ForEach(@break => @break.BreakEfficiencyList = null);
                    }
                    else    // No breaks
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, string.Format("Break Efficiency processing. Schedule document has no breaks for sales area {0} and date {1}", salesArea.Name, startDateTime.Date)));
                    }
                    schedules.Add(new ScheduleIndexed <Break, int>(scheduleObject, delegate(Break currentBreak) { return(currentBreak); }, delegate(Break currentBreak) { return(currentBreak.CustomId); }));
                }
                else    // No Schedule document, log warning
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, string.Format("Break Efficiency processing. Schedule document does not exist for sales area {0} and date {1}", salesArea.Name, startDateTime.Date)));
                }
            }
        }
        public CampaignsReqmOutput ProcessFile(Guid scenarioId, string folder)
        {
            string pathToFile = FileHelpers.GetPathToFileIfExists(folder, FileName);
            var    result     = new CampaignsReqmOutput();

            if (String.IsNullOrEmpty(pathToFile))
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"File {pathToFile} was not found."));

                return(result);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {pathToFile}"));

            var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(CampaignsReqmHeaderMap), typeof(CampaignsReqmIndexMap));

            ICampaignsReqmImportRepository _fileReader = new CSVCampaignsReqmImportRepository(importSettings);

            var data = _fileReader.GetAll().ToList();

            result.Data = _mapper.Map <IEnumerable <CampaignsReqm> >(data);

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {pathToFile}"));

            return(result);
        }
        public ScenarioCampaignLevelResult ProcessFile(Guid scenarioId, string folder)
        {
            string pathToFile = FileHelpers.GetPathToFileIfExists(folder, FileName);

            var result = new ScenarioCampaignLevelResult {
                Id = scenarioId
            };

            if (string.IsNullOrEmpty(pathToFile))
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"File {pathToFile} was not found."));

                return(result);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {pathToFile}"));

            var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(ScenarioCampaignLevelResultHeaderMap), typeof(ScenarioCampaignLevelResultIndexMap));
            IScenarioCampaignLevelResultsImportRepository repository = new CSVScenarioCampaignLevelResultsImportRepository(importSettings);

            var data = repository.GetAll();

            result.Items = _mapper.Map <List <ScenarioCampaignLevelResultItem> >(data);

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {pathToFile}"));

            return(result);
        }
Example #7
0
        public Failures ProcessFile(Guid scenarioId, string folder)
        {
            string pathToFile = FileHelpers.GetPathToFileIfExists(folder, FileName);
            var    failures   = new Failures {
                Id = scenarioId
            };

            if (string.IsNullOrEmpty(pathToFile))
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"File {pathToFile} was not found."));

                return(failures);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {pathToFile}"));

            var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(FailureHeaderMap), typeof(FailureIndexMap));

            var campaignsIndex = _dataSnapshot.AllCampaigns.Value.ToDictionary(c => (long)c.CustomId);
            var salesAreaIndex = _dataSnapshot.AllSalesAreas.Value.ToDictionary(c => c.CustomId);

            IFailureImportRepository failureRepository = new CSVFailureImportRepository(importSettings);

            foreach (var summary in failureRepository.GetAll())
            {
                var failure = new Failure();

                if (!campaignsIndex.TryGetValue(summary.Campaign, out var campaign))
                {
                    failure.ExternalId = failure.CampaignName = "Unknown";
                }
                else
                {
                    failure.ExternalId   = campaign.ExternalId;
                    failure.CampaignName = campaign.Name;
                }

                failure.Type     = summary.Type;
                failure.Failures = summary.Failures;
                failure.Campaign = summary.Campaign;

                failure.SalesAreaName = !salesAreaIndex.TryGetValue(summary.SalesAreaNumberOfBooking, out var salesArea)
                    ? "Unknown"
                    : salesArea.Name;

                failures.Items.Add(failure);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {pathToFile}"));

            return(failures);
        }
        public BaseRatingsOutput ProcessFile(Guid scenarioId, string folder)
        {
            string pathToFile = FileHelpers.GetPathToFileIfExists(folder, FileName);
            var    result     = new BaseRatingsOutput();

            if (String.IsNullOrEmpty(pathToFile))
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"File {pathToFile} was not found."));

                return(result);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {pathToFile}"));

            try
            {
                var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(BaseRatingsHeaderMap), typeof(BaseRatingsIndexMap));

                var baseRatingsImportRepository = new CSVBaseRatingsImportRepository(importSettings);

                var data = baseRatingsImportRepository.GetAll();

                result.Data = _mapper.Map <IEnumerable <BaseRatings> >(data);

                _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                      0, $"Processed output file {pathToFile}"));

                return(result);
            }
            catch (Exception exception)
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, "Error processing base ratings file", exception));

                return(result);
            }
        }
Example #9
0
        public SystemLogicalDateService(ITenantSettingsRepository tenantSettingsRepository, IFeatureManager featureManager, IClock clock, IAuditEventRepository auditEventRepository)
        {
            _clock = clock;

            var tenantSettings = tenantSettingsRepository.Get();

            var useSystemLogicalDate = featureManager.IsEnabled(nameof(ProductFeature.UseSystemLogicalDate));

            if (useSystemLogicalDate)
            {
                var isDateValid = DateTime.TryParseExact(tenantSettings.SystemLogicalDate, SystemLogicalDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var systemLogicalDate);

                if (isDateValid)
                {
                    _isSystemLogicalDateUsed = true;
                    _systemLogicalDate       = systemLogicalDate.Add(_clock.GetCurrentInstant().ToDateTimeUtc().TimeOfDay);
                }
                else
                {
                    auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"System Logical Date is not it valid format. " +
                                                                                                    $"Date set: '{tenantSettings.SystemLogicalDate}', but valid format is: '{SystemLogicalDateFormat}'. Using current Date instead."));
                }
            }
        }
        public ScenarioCampaignResult ProcessFile(Guid scenarioId, string folder)
        {
            string pathToFile = FileHelpers.GetPathToFileIfExists(folder, FileName);
            var    result     = new ScenarioCampaignResult {
                Id = scenarioId
            };

            if (string.IsNullOrEmpty(pathToFile))
            {
                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, $"File {pathToFile} was not found."));

                return(result);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {pathToFile}"));

            var importSettings = CSVImportSettings.GetImportSettings(pathToFile, typeof(ScenarioCampaignResultHeaderMap), typeof(ScenarioCampaignResultIndexMap));
            IScenarioCampaignResultsImportRepository repository = new CSVScenarioCampaignResultsImportRepository(importSettings);

            var data = repository.GetAll();

            var salesAreaIndex = _dataSnapshot.AllSalesAreas.Value.ToDictionary(c => c.CustomId);

            foreach (var importItem in data)
            {
                salesAreaIndex.TryGetValue(importItem.SalesAreaNo, out var salesArea);

                result.Items.Add(MapImportItem(importItem, salesArea));
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {pathToFile}"));

            return(result);
        }
Example #11
0
        public void Execute(
            Run run,
            RunScenario scenario,
            IReadOnlyCollection <AutoBookInstanceConfiguration> autoBookInstanceConfigurationsForRun,
            double autoBookRequiredStorageGB,
            ConcurrentBag <RunInstance> runInstances,
            ConcurrentDictionary <Guid, ScenarioStatuses> newScenarioStatuses,
            ConcurrentDictionary <Guid, bool> scenarioSyncStatuses,
            bool autoDistributed)

        {
            AutoBookDomainObject autoBook          = null;
            IAutoBook            autoBookInterface = null;
            bool runStarted = false;

            RaiseInfo($"Begin Execute for  ScenarioID: { scenario.Id}");

            try
            {
                AutoBookInstanceConfiguration runAutoBookInstanceConfiguration = null;

                if (autoDistributed)
                {
                    RaiseInfo($"AutoDistributed - RunScenarioTask Execute Starting ScenarioID ={ scenario.Id}, RunID ={ run.Id}");

                    //create instance for scenario
                    RunInstance runInstance = _runInstanceCreator.Create(run.Id, scenario.Id);

                    RaiseInfo($"AutoDistributed - about to enter: {nameof(runInstance.UploadInputFilesAndCreateAutoBookRequest)}");
                    runInstance.UploadInputFilesAndCreateAutoBookRequest(autoBookInstanceConfigurationsForRun, autoBookRequiredStorageGB);
                    RaiseInfo($"AutoDistributed - returned from: {nameof(runInstance.UploadInputFilesAndCreateAutoBookRequest)}");

                    // Flag run as started
                    runStarted = true;
                    runInstances.Add(runInstance);
                    _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end

                    scenarioSyncStatuses[scenario.Id] = false;

                    RaiseInfo($"AutoDistributed - RunScenarioTask Execute Started ScenarioID ={ scenario.Id}, RunID ={ run.Id}");
                }
                else
                {
                    try
                    {
                        using (MachineLock.Create("xggameplan.AWSAutoBooks.GetFreeAutoBook",
                                                  new TimeSpan(0, 10, 0)))
                        {
                            foreach (var autoBookInstanceConfiguration in autoBookInstanceConfigurationsForRun)
                            {
                                autoBook = _autoBooks.GetFirstAdequateIdleAutoBook(autoBookInstanceConfiguration, autoBookRequiredStorageGB, true);

                                if (autoBook != null) // Got free AutoBook
                                {
                                    RaiseInfo($"Got Free AutoBook: {autoBook.Id} ConfigurationId: {autoBook.InstanceConfigurationId}");
                                    runAutoBookInstanceConfiguration = autoBookInstanceConfiguration;
                                    break;
                                }
                            }
                        }
                    }
                    catch (MachineLockTimeoutException)
                    {
                        RaiseInfo($"MachineLockTimeoutException in xggameplan.AWSAutoBooks.GetFreeAutoBook");
                    }
                    // Get autobook interface
                    autoBookInterface = (autoBook == null) ? null : _autoBooks.GetInterface(autoBook);

                    // Get free AutoBook instance, will be locked so that it can't be used elsewhere
                    if (autoBook != null) // Free AutoBook - start run
                    {
                        RaiseInfo($"Free Autobook - Starting ScenarioID ={ scenario.Id}, AutoBookID ={autoBook?.Id}, RunID ={ run.Id}, Instance Configuration = { runAutoBookInstanceConfiguration.Description }");

                        // Start run, exception will cause cleanup below
                        RunInstance runInstance = _runInstanceCreator.Create(run.Id, scenario.Id);

                        runInstance.UploadInputFilesStartAutoBookRun(autoBookInterface, autoBook);

                        // Flag run as started
                        runStarted = true;
                        runInstances.Add(runInstance);
                        _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end

                        scenarioSyncStatuses[scenario.Id] = false;
                        RaiseInfo($"Started ScenarioID ={ scenario.Id}, AutoBookID ={ autoBook?.Id}, RunID ={ run.Id}, Instance Configuration = { runAutoBookInstanceConfiguration?.Description }");
                    }
                    else // No free AutoBook, awaiting for provisioning
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                         $"No free AutoBook, awaiting for provisioning, waiting for existing AutoBooks to be Idle (RunID={run.Id}, ScenarioID={scenario.Id})"));
                        // Update scenario so that it can be retried later when an AutoBook becomes idle
                        RunManager.UpdateScenarioStatuses(_repositoryFactory, _auditEventRepository, run.Id, new List <Guid> {
                            scenario.Id
                        },
                                                          new List <ScenarioStatuses> {
                            ScenarioStatuses.Scheduled
                        }, new List <DateTime?> {
                            null
                        });

                        _ = newScenarioStatuses.TryRemove(scenario.Id, out _); // Don't update scenario status at the end
                        scenarioSyncStatuses[scenario.Id] = false;
                    }
                }
            }
            catch (System.Exception exception)
            {
                // Log exception but don't throw it. We want to try and start other scenarios
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, $"Error starting scenario (RunID={run.Id}, ScenarioID={scenario.Id}, AutoBookID={(autoBook == null ? "Unknown" : autoBook.Id)})", exception));
            }
            finally
            {
                // If we locked a free AutoBook instance but didn't start the scenario then reset to free, unlocks it.
                if (!runStarted && autoBook != null)
                {
                    autoBookInterface.ResetFree();
                }
            }
        }
        private ProcessBreakEfficiencyOutput ProcessFileInternal(Guid scenarioId, string folder)
        {
            var    output = new ProcessBreakEfficiencyOutput();
            string breakEfficiencyFile = FileHelpers.GetPathToFileIfExists(folder, FileName);

            if (String.IsNullOrEmpty(breakEfficiencyFile))
            {
                return(output);
            }

            _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                                 0, $"Processing output file {breakEfficiencyFile}"));

            var demographicsById  = Demographic.IndexListById(_dataSnapshot.AllDemographics.Value);
            var salesAreasIndexed = SalesArea.IndexListByCustomId(_dataSnapshot.AllSalesAreas.Value);

            // Create memory cache of Schedule documents
            var      schedules           = new List <ScheduleIndexed <Break, int> >();
            string   lastScheduleDateKey = "";
            int      count           = 0;
            int      countUpdated    = 0;
            int      countNotUpdated = 0;
            DateTime nextYield       = DateTime.MinValue;

            // Process CSV in order of sales area + schedule date + schedule
            // time, allows us to keep as few Break/Schedule documents in memory
            var importSettings = CSVImportSettings.GetImportSettings(breakEfficiencyFile, typeof(BreakEfficiencyHeaderMap), typeof(BreakEfficiencyIndexMap));

            IBreakEfficiencyImportRepository breakEfficiencyImportRepository = new CSVBreakEfficiencyImportRepository(importSettings);
            IScheduleRepository scheduleRepository = null;

            var lazyScopeCreator = new Func <Lazy <IRepositoryScope> >(() => new Lazy <IRepositoryScope>(() => _repositoryFactory.BeginRepositoryScope()));
            var lazyScope        = lazyScopeCreator();

            try
            {
                foreach (BreakEfficiencyImport breakEfficiencyImport in breakEfficiencyImportRepository.GetAll()
                         .OrderBy(be => be.sare_no).ThenBy(be => be.brek_sched_date).ThenBy(be => be.brek_nom_time))
                {
                    count++;
                    bool   breakUpdated    = false;
                    string scheduleDateKey = string.Format("{0}{1}{2}", breakEfficiencyImport.sare_no, (Char)9,
                                                           breakEfficiencyImport.brek_sched_date);

                    try
                    {
                        // Save changes if different sales area + schedule date
                        if (!String.IsNullOrEmpty(lastScheduleDateKey) && scheduleDateKey != lastScheduleDateKey) // No longer need previous Break/Schedule docs
                        {
                            if (scheduleRepository != null)
                            {
                                schedules.ForEach(scheduleIndexed => scheduleRepository.Add(scheduleIndexed.Schedule));
                                scheduleRepository.SaveChanges();
                            }

                            scheduleRepository = null;
                            lazyScope.Value.Dispose();
                            lazyScope = lazyScopeCreator();

                            // Clear data that we no longer need
                            schedules.Clear();
                        }

                        if (scheduleRepository == null)
                        {
                            scheduleRepository = lazyScope.Value.CreateRepository <IScheduleRepository>();
                        }

                        SalesArea salesArea = salesAreasIndexed.ContainsKey(breakEfficiencyImport.sare_no)
                            ? salesAreasIndexed[breakEfficiencyImport.sare_no]
                            : null;

                        // Load breaks if necessary
                        LoadBreaks(salesArea, breakEfficiencyImport, schedules, scheduleRepository);

                        // Update break efficiency
                        if (UpdateBreakEfficiency(salesArea, breakEfficiencyImport, schedules,
                                                  demographicsById))
                        {
                            breakUpdated = true;
                        }
                    }
                    catch (System.Exception exception)
                    {
                        // Log exception, continue
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForException(0, 0,
                                                                                                    string.Format("Error processing break efficiency for break no {0} (Record {1})",
                                                                                                                  breakEfficiencyImport.break_no, count), exception));
                    }
                    finally
                    {
                        lastScheduleDateKey = scheduleDateKey;
                        if (breakUpdated)
                        {
                            countUpdated++;
                        }
                        else
                        {
                            countNotUpdated++;
                        }

                        DoYield(false, ref nextYield);
                    }
                }

                // Save changed
                if (scheduleRepository != null)
                {
                    schedules.ForEach(scheduleIndexed => scheduleRepository.Add(scheduleIndexed.Schedule));
                    scheduleRepository.SaveChanges();
                }
            }
            finally
            {
                if (scheduleRepository != null)
                {
                    lazyScope.Value.Dispose();
                }
            }

            if (countUpdated > 0 && countNotUpdated == 0)   // Success, log info event
            {
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0, string.Format("Updated {0} break efficiencies (Not updated={1})", countUpdated, countNotUpdated)));
            }
            else          // Some updates failed, log warning event
            {
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, string.Format("Updated {0} break efficiencies (Not updated={1})", countUpdated, countNotUpdated)));
            }

            _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                                 0, $"Processed output file {breakEfficiencyFile}"));

            return(output);
        }
        public SpotsReqmOutput ProcessFile(Guid scenarioId, string folder)
        {
            string spotFile     = FileHelpers.GetPathToFileIfExists(folder, FileName);
            string mainSpotFile = FileHelpers.GetPathToFileIfExists(folder, OutputFileNames.MainSpotTable);
            var    output       = new SpotsReqmOutput
            {
                ScenarioId = scenarioId
            };

            if (String.IsNullOrEmpty(spotFile) || String.IsNullOrEmpty(mainSpotFile))
            {
                return(output);
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {spotFile}"));

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processing output file {mainSpotFile}"));

            // Process file
            DateTime processorDateTime = DateTime.UtcNow;

            var importSettings = CSVImportSettings.GetImportSettings(mainSpotFile, typeof(SpotHeaderMap), typeof(SpotIndexMap));

            // Get main spots if path passed in
            ISpotImportRepository    spotImportRepository = new CSVSpotImportRepository(importSettings);
            IEnumerable <SpotImport> spotImports          = spotImportRepository.GetAll();

            importSettings = CSVImportSettings.GetImportSettings(spotFile, typeof(SpotReqmHeaderMap), typeof(SpotReqmIndexMap));

            ISpotReqmImportRepository spotReqmImportRepository = new CSVSpotReqmImportRepository(importSettings);
            var spotReqmImports = spotReqmImportRepository.GetAll();

            // Index for lookup performance
            var campaignsByCustomId       = CampaignReducedModel.IndexListByCustomId(_campaignRepository.GetAllFlat());
            var spotsByCustomId           = SpotHelper.IndexListById(_dataSnapshot.SpotsForRun.Value);
            var demographicsById          = Demographic.IndexListById(_dataSnapshot.AllDemographics.Value);
            var programmeDictionariesById = ProgrammeDictionary.IndexListById(_dataSnapshot.AllProgrammeDictionaries.Value);

            IEnumerable <Pass> scenarioPasses = _dataSnapshot.ScenarioPasses.Value;

            foreach (var currentSalesArea in _dataSnapshot.AllSalesAreas.Value)
            {
                foreach (SpotReqmImport spotReqmImport in spotReqmImports.Where(sri => sri.sare_no == currentSalesArea.CustomId))
                {
                    output.CountTotalSpots++;

                    try
                    {
                        Recommendation recommendation = _mapper.Map <Recommendation>(Tuple.Create(spotReqmImport, new List <ProgrammeDictionary>(), _dataSnapshot.BreakTypes.Value));
                        recommendation.ScenarioId        = scenarioId;
                        recommendation.ProcessorDateTime = processorDateTime;

                        bool isCancelledSpot = !String.IsNullOrEmpty(spotReqmImport.status) && spotReqmImport.status == "C";

                        if (isCancelledSpot)
                        {
                            output.CountCancelledSpots++;
                            recommendation.SpotSequenceNumber = default;

                            if (spotsByCustomId.TryGetValue((int)spotReqmImport.spot_no, out var spot))
                            {
                                recommendation.ExternalSpotRef       = spot.ExternalSpotRef;
                                recommendation.Sponsored             = spot.Sponsored;
                                recommendation.Preemptable           = spot.Preemptable;
                                recommendation.Preemptlevel          = spot.Preemptlevel;
                                recommendation.MultipartSpot         = spot.MultipartSpot;
                                recommendation.MultipartSpotPosition = spot.MultipartSpotPosition;
                                recommendation.MultipartSpotRef      = spot.MultipartSpotRef;
                            }
                            else
                            {
                                _audit.Insert(
                                    AuditEventFactory.CreateAuditEventForWarningMessage(
                                        0,
                                        0,
                                        $"Unable to set cancelled spot details for recommendations" +
                                        $" because spot {spotReqmImport.spot_no} does not exist")
                                    );
                            }
                        }
                        else
                        {
                            recommendation.SpotSequenceNumber = spotReqmImport.spot_no;
                        }

                        Pass pass;

                        if (scenarioPasses != null && scenarioPasses.Any() && (pass = scenarioPasses.FirstOrDefault(p => p.Id == spotReqmImport.abdn_no)) != null)
                        {
                            recommendation.PassName = pass.Name;
                            recommendation.OptimiserPassSequenceNumber = spotReqmImport.pass_sequence_no;
                        }

                        recommendation.CampaignPassPriority = spotReqmImport.campaign_pass_priority;
                        recommendation.RankOfEfficiency     = spotReqmImport.rank_of_efficiency;
                        recommendation.RankOfCampaign       = spotReqmImport.rank_of_campaign;
                        recommendation.CampaignWeighting    = spotReqmImport.campaign_weighting;

                        recommendation.SalesArea = recommendation.GroupCode = currentSalesArea.Name;

                        recommendation.NominalPrice = spotReqmImport.nominal_price;

                        recommendation.ExternalCampaignNumber = campaignsByCustomId.TryGetValue((int)spotReqmImport.camp_no, out var campaign)
                            ? campaign.ExternalId
                            : string.Empty;

                        recommendation.Demographic = demographicsById.TryGetValue(spotReqmImport.demo_no, out var demographic)
                            ? demographic.ExternalRef
                            : string.Empty;

                        if (programmeDictionariesById.TryGetValue((int)spotReqmImport.prog_no, out var programmeDictionary))
                        {
                            recommendation.ExternalProgrammeReference = programmeDictionary.ExternalReference;
                            recommendation.ProgrammeName = programmeDictionary.ProgrammeName;
                        }
                        else
                        {
                            recommendation.ExternalProgrammeReference = recommendation.ProgrammeName = string.Empty;
                        }

                        recommendation.ClientPicked    = spotReqmImport.client_picked.ToUpper() == "Y";
                        recommendation.ExternalBreakNo = spotReqmImport.brek_external_ref;

                        output.Recommendations.Add(recommendation);
                    }
                    catch (System.Exception exception)
                    {
                        // Log exception, continue
                        _audit.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating recommendation for spot no {0}", spotReqmImport.spot_no), exception));
                    }
                }
            }

            // TODO: Remove this when it has been confirmed that cancellations appear in Spot Req file
            // Process cancelled spots if they weren't present in the Spot Req
            // file above
            if (output.CountCancelledSpots == 0)
            {
                string scheduleIndexKey = string.Empty;

                var scheduleBreaksBySalesAreaAndDate = _dataSnapshot
                                                       .BreaksForRun
                                                       .Value
                                                       .GroupBy(k => GetScheduleIndexKey(k.SalesAreaName, k.ScheduleDate.Date))
                                                       .ToDictionary(c => c.Key, c => c.ToDictionary(v => v.CustomId));

                _audit.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, string.Format("Processing {0} for cancellations because no cancelled spots were found in {1}", Path.GetFileName(mainSpotFile), Path.GetFileName(spotFile))));

                foreach (var currentSalesArea in _dataSnapshot.AllSalesAreas.Value)
                {
                    foreach (SpotImport spotImport2 in spotImports.Where(s => s.status == "C" && s.sare_no == currentSalesArea.CustomId))
                    {
                        try
                        {
                            scheduleIndexKey = string.Empty;
                            bool isCancelledSpot = !String.IsNullOrEmpty(spotImport2.status) && spotImport2.status == "C";    // Should all be cancelled

                            // Update statistics for Spot Performance, Campaign
                            // Performance, New Efficiency, cancelled spots
                            // should be excluded
                            output.CountTotalSpots++;
                            if (isCancelledSpot)
                            {
                                output.CountCancelledSpots++;
                            }

                            // Create recommendation
                            Recommendation recommendation = _mapper.Map <Recommendation>(Tuple.Create(spotImport2, new List <ProgrammeDictionary>()));
                            recommendation.ScenarioId        = scenarioId;
                            recommendation.ProcessorDateTime = processorDateTime;

                            if (spotsByCustomId.TryGetValue((int)spotImport2.spot_no, out var spot))
                            {
                                recommendation.Sponsored             = spot.Sponsored;
                                recommendation.Preemptable           = spot.Preemptable;
                                recommendation.Preemptlevel          = spot.Preemptlevel;
                                recommendation.ExternalSpotRef       = spot.ExternalSpotRef;
                                recommendation.MultipartSpot         = spot.MultipartSpot;
                                recommendation.MultipartSpotPosition = spot.MultipartSpotPosition;
                                recommendation.MultipartSpotRef      = spot.MultipartSpotRef;
                            }
                            else
                            {
                                _audit.Insert(
                                    AuditEventFactory.CreateAuditEventForWarningMessage(
                                        0,
                                        0,
                                        $"Unable to set multipart spot details for recommendations because spot {spotImport2.spot_no} does not exist"
                                        )
                                    );
                            }

                            recommendation.SalesArea = recommendation.GroupCode = currentSalesArea.Name;

                            if (campaignsByCustomId.TryGetValue((int)spotImport2.camp_no, out CampaignReducedModel campaign))
                            {
                                recommendation.ExternalCampaignNumber = campaign.ExternalId;
                            }

                            if (demographicsById.TryGetValue(spotImport2.demo_no, out Demographic demographic))
                            {
                                recommendation.Demographic = demographic.ExternalRef;
                            }

                            scheduleIndexKey = GetScheduleIndexKey(recommendation.SalesArea, recommendation.StartDateTime.Date);

                            string breakNotSetReason = "Unknown reason";

                            if (spotImport2 == null)
                            {
                                breakNotSetReason = $"Spot not found in {Path.GetFileName(mainSpotFile)}";
                            }
                            else
                            {
                                if (!scheduleBreaksBySalesAreaAndDate.TryGetValue(scheduleIndexKey, out var scheduleBreakCache))
                                {
                                    breakNotSetReason = string.Format("Schedule document not found (SalesArea={0}, StartDateTime={1})", recommendation.SalesArea, recommendation.StartDateTime.ToString());
                                }
                                else
                                {
                                    recommendation.ExternalBreakNo = !scheduleBreakCache.TryGetValue(spotImport2.break_no, out var @break)
                                        ? recommendation.ExternalBreakNo
                                        : @break.ExternalBreakRef;

                                    // Set reason why ExternalBreakNo isn't set
                                    if (String.IsNullOrEmpty(recommendation.ExternalBreakNo))
                                    {
                                        if (!(scheduleBreakCache?.Any() ?? false))
                                        {
                                            breakNotSetReason = $"Schedule document exists but it contains no breakss (BreakNo={spotImport2.break_no}, Breaks=0)";
                                        }
                                        else if (@break == null)
                                        {
                                            breakNotSetReason = $"Schedule document exists but the break was not found (BreakNo={spotImport2.break_no}, Breaks={scheduleBreakCache.Count})";
                                        }
                                        else    // Break found but ExternalBreakRef is not set
                                        {
                                            breakNotSetReason = $"Schedule document exists and the break was found but the ExternalBreakRef is not set (BreakNo={spotImport2.break_no}, Breaks={scheduleBreakCache.Count})";
                                        }
                                    }
                                }

                                recommendation.ClientPicked = (spotImport2.client_picked.ToUpper() == "Y");
                            }

                            if (String.IsNullOrEmpty(recommendation.ExternalBreakNo))
                            {
                                _audit.Insert(
                                    AuditEventFactory.CreateAuditEventForWarningMessage(
                                        0,
                                        0,
                                        $"Unable to determine External Break No for recommendation for spot no {spotImport2.spot_no}: {breakNotSetReason}"
                                        )
                                    );
                            }

                            output.Recommendations.Add(recommendation);
                        }
                        catch (Exception exception)
                        {
                            // Log exception, continue
                            _audit.Insert(AuditEventFactory.CreateAuditEventForException(0, 0, string.Format("Error generating cancellation recommendation for spot no {0}", spotImport2.spot_no), exception));
                        }
                    }
                }
            }

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {spotFile}"));

            _audit.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0,
                                                                                  0, $"Processed output file {mainSpotFile}"));

            return(output);
        }
Example #14
0
        /// <summary>
        /// Handles run completed, all scenarios
        /// </summary>
        /// <param name="run"></param>
        /// <param name="success"></param>
        public void Notify(Run run, bool success)
        {
            TenantSettings tenantSettings          = _tenantSettingsRepository.Get();
            bool           notificationsConfigured = false;

            _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForRunCompleted(0, 0, run.Id, success ? "Completed successfully" : "Completed with errors"));

            // Get run event settings
            if (tenantSettings.RunEventSettings != null)
            {
                RunEventSettings runEventSettings = tenantSettings.RunEventSettings.Where(item => item.EventType == RunEvents.RunCompleted).FirstOrDefault();
                if (runEventSettings != null)
                {
                    var exceptions = new List <Exception>();

                    try
                    {
                        // Check HTTP notification
                        INotification <HTTPNotificationSettings> httpNotification = _notifications?.GetNotification <HTTPNotificationSettings>();
                        if (runEventSettings.HTTP != null && httpNotification != null && runEventSettings.HTTP.Enabled)
                        {
                            notificationsConfigured = true;
                            try
                            {
                                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineStart(0, 0,
                                                                                                                        PipelineEventIDs.STARTED_NOTIFYING_MULE_SOFT_API, run.Id, null, null, string.Format("Generating HTTP notification for run completed (RunID={0}, Success={1})", run.Id, success)));

                                _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun,
                                                                                                               PipelineEventIDs.STARTED_NOTIFYING_MULE_SOFT_API, run.Id, Guid.Empty, null));

                                httpNotification.RunCompleted(run, success, runEventSettings.HTTP);

                                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineEnd(0, 0,
                                                                                                                      PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, null, null, string.Format("Generated HTTP notification for run completed (RunID={0}, Success={1})", run.Id, success), null, null));

                                _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun,
                                                                                                               PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, Guid.Empty, null));
                            }
                            catch (System.Exception exception)
                            {
                                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForGameplanPipelineEnd(0, 0,
                                                                                                                      PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, null, null, string.Format("Failed to generate HTTP notification for run completed (RunID={0}, Success={1})", run.Id, success), exception.Message, exception));

                                _pipelineAuditEventRepository.Add(PipelineEventHelper.CreatePipelineAuditEvent(AuditEventTypes.GamePlanRun,
                                                                                                               PipelineEventIDs.FINISHED_NOTIFYING_MULE_SOFT_API, run.Id, Guid.Empty, exception.Message));
                                throw;
                            }
                            finally
                            {
                                _pipelineAuditEventRepository.SaveChanges();
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        exceptions.Add(exception);
                    }

                    if (exceptions.Count == 1)
                    {
                        throw exceptions[0];
                    }
                    else if (exceptions.Count > 0)
                    {
                        throw new AggregateException(exceptions);
                    }
                }
            }

            // Log warning if notifications not enabled so that there's no dispute over why they weren't generated
            if (!notificationsConfigured)
            {
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0, string.Format("Not generating notification for run completed because notifications are not configured or enabled (RunID={0}, Success={1})", run.Id, success)));
            }
        }
Example #15
0
        /// <summary>
        /// Starts task execution by starting the process with the TaskInstanceID
        /// </summary>
        /// <param name="taskInstance"></param>
        /// <returns></returns>
        public TaskResult Execute(TaskInstance taskInstance)
        {
            //int taskInstanceTimeout = defaultTaskInstanceTimeout;
            int taskInstanceTimeout;

            if (!int.TryParse(_configuration["Environment:TaskInstanceTimeout"], out taskInstanceTimeout))
            {
                taskInstanceTimeout = defaultTaskInstanceTimeout;
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                 string.Format("Cannot Parse Environment:TaskInstanceTimeout - defaulting to {0} seconds", defaultTaskInstanceTimeout)));
            }
            else
            {
                _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                 string.Format("Loaded Environment:TaskInstanceTimeout - setting to {0}", taskInstanceTimeout)));
            }

            var          waitSpan    = TimeSpan.FromSeconds(taskInstanceTimeout);
            StreamReader errorReader = null;
            var          taskResult  = new TaskResult();

            try
            {
                using var scope = _repositoryFactory.BeginRepositoryScope();
                var taskInstanceRepository = scope.CreateRepository <ITaskInstanceRepository>();

                if (_auditEventRepository != null)
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                         string.Format("Need to execute task {0}: {1} (RootFolder={2})", taskInstance.Id, taskInstance.TaskId, _rootFolder)));
                }

                // Save task instance
                taskInstanceRepository.Add(taskInstance);
                taskInstanceRepository.SaveChanges();

                // Start Task Executor process
                const Char quotes           = '"';
                var        process          = new Process();
                var        processStartInfo = new ProcessStartInfo();
                processStartInfo.FileName = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "xggameplan.taskexecutor.exe");
                if (!System.IO.File.Exists(processStartInfo.FileName))  // Not found in same folder as this assembly, try [root]\bin
                {
                    processStartInfo.FileName = string.Format(@"{0}\bin\xggameplan.taskexecutor.exe", _rootFolder);
                }

                if (!System.IO.File.Exists(processStartInfo.FileName))
                {
                    if (_auditEventRepository != null)
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                         string.Format("Cannot start process {0} because file does not exist", processStartInfo.FileName)));
                    }
                    throw new System.IO.FileNotFoundException(string.Format("Task Executor executable {0} does not exist", processStartInfo.FileName), processStartInfo.FileName);
                }
                processStartInfo.Arguments = string.Format("/TaskInstanceID={1}{0}{1} /RootFolder={1}{2}{1}", taskInstance.Id, quotes, _rootFolder);
                process.StartInfo          = processStartInfo;

                // Start the process, don't wait for it to complete
                if (_auditEventRepository != null)
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                         string.Format("Starting process {0} (Task ID={1})", processStartInfo.FileName, taskInstance.TaskId)));
                }
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.UseShellExecute        = false;

                bool started = process.Start();
                errorReader = process.StandardOutput;
                if (!started)
                {
                    if (_auditEventRepository != null)
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                             string.Format("Failed to start process {0}", processStartInfo.FileName)));
                    }
                    string output = errorReader.ReadToEnd();
                    throw new Exception($"Unable to start Task Executor {processStartInfo.FileName}. Output : {output}");
                }

                // Wait for status to change to indicate that something is happening, process will typically set to InProgress immediately
                if (_auditEventRepository != null)
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                         string.Format("Waiting for status change for process {0} (Task ID={1})", processStartInfo.FileName, taskInstance.TaskId)));
                }

                taskResult.Status = WaitForStatusChange(taskInstance.Id, process, TaskInstanceStatues.Starting, waitSpan);

                if (_auditEventRepository != null)
                {
                    int?exitCode = process.HasExited ? process.ExitCode : (int?)null;
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                         string.Format("Waited (upto) {0} for status change for process {1} (Task ID={2}, (TaskInstance ID={3}, Status={4}, ExitCode={5})",
                                                                                                                       waitSpan.ToString(), processStartInfo.FileName, taskInstance.TaskId, taskInstance.Id, taskResult.Status, (exitCode.HasValue ? exitCode.Value.ToString() : "null"))));
                }

                // Wait for completion if requested
                if (_completionTimeout != null && _completionTimeout.TotalMilliseconds > 0 && taskResult.Status == TaskInstanceStatues.InProgress)
                {
                    if (_auditEventRepository != null)
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                             string.Format("Waiting for completion for process {0} (Task ID={1})", processStartInfo.FileName, taskInstance.TaskId)));
                    }
                    taskResult.Status = WaitForCompletion(taskInstance.Id, _completionTimeout);
                    if (_auditEventRepository != null)
                    {
                        _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForInformationMessage(0, 0,
                                                                                                             string.Format("Waited for completion for process {0} (Task ID={1}, Status={2})", processStartInfo.FileName, taskInstance.TaskId, taskResult.Status)));
                    }
                }
            }
            catch (Exception exception)
            {
                if (_auditEventRepository != null)
                {
                    _auditEventRepository.Insert(AuditEventFactory.CreateAuditEventForWarningMessage(0, 0,
                                                                                                     string.Format("Error executing task for Task ID {0}: {1}", taskInstance.TaskId, exception.Message)));
                }
                string output = errorReader?.ReadToEnd();

                taskResult.Status    = TaskInstanceStatues.CompletedError;
                taskResult.Exception = exception;
            }
            return(taskResult);
        }