using LCU.API.Internal.Operations.IncentiveApi.Exceptions; using LCU.Library.Internal.IncentiveApiModels.Entities; using LCU.Library.Internal.IncentiveApiModels.Enums; using LCU.API.Internal.Operations.IncentiveApi.Services.AutoDecision; using LCU.API.Internal.Operations.IncentiveApi.Services.ExternalActivity; using LCU.API.Internal.Operations.IncentiveApi.Models.ExternalActivities; using LCU.API.Internal.Operations.IncentiveApi.Services; namespace LCU.API.Internal.Operations.IncentiveApi.DnaActivityServices; public class DnaActivityProcessingService : IDnaActivityProcessingService { private readonly IActivityService _activityService; private readonly IActivityDecisionService _activityDecisionService; private readonly IExternalActivityService _externalActivityService; private readonly IProcessorHistoryService _processorHistoryService; private readonly IDeadActivityService _deadActivityService; public DnaActivityProcessingService(IActivityService activityService, IProcessorHistoryService processorHistoryService, IActivityDecisionService activityDecisionService, IDeadActivityService deadActivityService, IExternalActivityService externalActivityService) { _activityDecisionService = activityDecisionService; _activityService = activityService; _externalActivityService = externalActivityService; _deadActivityService = deadActivityService; _processorHistoryService = processorHistoryService; } public async Task GetLastActivityProcessedData(Process processName) { var lastActivityProcess = await _processorHistoryService.GetProcessorHistory(processName); if (lastActivityProcess == null) { throw new MissingProcessorRunHistoryException(processName); } return lastActivityProcess; } public async Task> GetFilteredExternalActivities(List activityList) { return await _activityService.FilterExternalActivitiesByExistingSourceId(activityList); } public async Task> HandleMapExternalActivities(List externalActivityList, Product productName, ActivityType activityType) { var mappedActivities = new List(); foreach (var item in externalActivityList) { try { mappedActivities.Add(await _externalActivityService.TryMapExternalActivity(item)); } catch (Exception ex) { Log.Error(ex, $"Could not map activity for item with product {item.GetProductType()} of type {item.GetActivityType()}. Will Try to save as Dead Activity."); await _deadActivityService.SaveDeadActivity(new DeadActivity(item.GetSourceId(), SystemType.Dna, DeadActivityReason.FailureToMap, "Total Mapping Failure. Only SourceID will be saved.")); } } return mappedActivities; } public async Task HandleIncomingActivityDecision(Activity activity, Product productName, ActivityType activityType) { try { var activityId = await _activityService.SaveActivityAsync(activity); var savedActivity = await _activityService.GetActivity(activityId); if (savedActivity.CanAutoDecision()) { var decision = await _activityDecisionService.TryDecisionActivity(activity); await _activityService.ApplyStateChange(decision); } } catch (DeadActivityException ex) { var deadActivity = new DeadActivity(activity, DeadActivityReason.MissingRequiredField, $"{ex.Message}"); deadActivity = await _deadActivityService.SaveDeadActivity(deadActivity); if (deadActivity != null) { Log.Warning($"Activity from Queue was Incomplete product {productName}-{activityType} and sourceId: {activity.SourceId}. Saving as Dead Activity with ID: {deadActivity.Id}"); } } catch (Exception ex) { Log.Fatal(ex, $"Failed to save or update an incoming activity: {productName}-{activityType} and sourceId: {activity.SourceId}. This Activity will be lost. Please investigate."); } } public async Task UpdateProcessorHistory(Process process, long lastProcessedId, DateTime lastProcessedDateTime) { await _processorHistoryService.SaveProcessorHistory(new ProcessorHistoryRecord() { Process = process, LastSuccessfulRunTime = DateTime.UtcNow, LastProcessedRecordId = lastProcessedId, LastProcessedRecordTimestamp = lastProcessedDateTime, }); } }