Files
monorepo/LCU.API.Operations.IncentiveAPI/LCU.API.Internal.Operations.IncentiveApi/Services/GapInsuranceActivityService.cs
T
2026-03-17 09:53:09 -05:00

244 lines
10 KiB
C#

using LCU.Library.Internal.IncentiveApiModels.Entities;
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
using LCU.Library.Internal.IncentiveApiModels.Enums;
using LCU.Library.Internal.IncentiveApiModels.Common;
namespace LCU.API.Internal.Operations.IncentiveApi.Services;
public class GapInsuranceActivityService : IGapInsuranceActivityService
{
private readonly IActivityDetailService _activityDetailService;
private readonly IActivityRepository _activityRepository;
private readonly IActivityService _activityService;
private readonly IUnitOfWork _unitOfWork;
public GapInsuranceActivityService(
IActivityDetailService activityDetailService,
IActivityRepository activityRepository,
IActivityService activityService,
IUnitOfWork unitOfWork
)
{
_activityDetailService = activityDetailService;
_activityRepository = activityRepository;
_activityService = activityService;
_unitOfWork = unitOfWork;
}
public async Task<int> MatchOrRemoveGapAccessories(MonthRange monthRange = null)
{
var updateCount = 0;
monthRange ??= new MonthRange(DateTime.UtcNow.AddMonths(-3), DateTime.UtcNow);
var gapEligibleActivities = await _activityRepository.FindGapInsuranceEligible(monthRange);
if (!gapEligibleActivities.Any())
{
return updateCount;
}
var matchedGapEligibleActivities = gapEligibleActivities.Where(x => x.HasActiveGapAccessory()).ToList();
var matchedGapAccessoryActivities = await GetMatchingGapAccessoryActivities(matchedGapEligibleActivities);
matchedGapEligibleActivities = await ValidateMatchedActivityAccessories(matchedGapEligibleActivities, matchedGapAccessoryActivities);
var unmatchedGapEligibleActivities = gapEligibleActivities.Except(matchedGapEligibleActivities).ToList();
var gapActivities = await _activityRepository.GetFilteredActivities(monthRange, Product.GAPInsurance, ActivityState.Accepted);
foreach (var activity in unmatchedGapEligibleActivities)
{
try
{
updateCount += await TryMatchGapEligibleActivityWithAccessory(activity, gapActivities) != null ? 2 : 0;
}
catch (Exception error)
{
Log.Error(error, $"MatchOrRemoveGapAccessories failed processing Activity Id: {activity.Id}");
}
}
return updateCount;
}
private async Task<Activity?> TryMatchGapEligibleActivityWithAccessory(Activity gapEligibleActivity, List<Activity> gapActivities)
{
if (gapActivities.Count <= 0)
{
return null;
}
var matchingGapAccessories = gapActivities
.Where(x => x.Detail.AccountNumber.Equals(gapEligibleActivity.Detail.AccountNumber, StringComparison.CurrentCultureIgnoreCase))
.ToList();
if (matchingGapAccessories.Count <= 0)
{
return null;
}
if (matchingGapAccessories.Count > 1)
{
throw new Exception(
$"Multiple matching GAP Accessory Activities found for Activity Id: {gapEligibleActivity.Id} using AccountNumber: {gapEligibleActivity.Detail.AccountNumber}");
}
var matchedAccessoryActivity = matchingGapAccessories.First();
return await MatchGapAccessory(gapEligibleActivity, matchedAccessoryActivity);
}
private async Task<Activity> MatchGapAccessory(Activity parentActivity, Activity accessoryActivity)
{
var addedDateTime = accessoryActivity.Accepted.Date.AddHours(12);
await ApplyMatchedChangeUpdates(parentActivity, accessoryActivity, addedDateTime);
await ApplyMatchedChangeUpdates(accessoryActivity, parentActivity, addedDateTime);
await _unitOfWork.CompleteAsync();
return parentActivity;
}
private async Task ApplyMatchedChangeUpdates(Activity targetActivity, Activity linkedActivity, DateTime addedDateTime)
{
targetActivity.Detail.GapInsuranceAddDate = addedDateTime;
targetActivity.MatchingGapInsuranceActivityId = linkedActivity.Id;
await _activityDetailService.SaveActivityDetailUpdate(new ActivityDetailUpdate
{
ActivityDetailId = targetActivity.Detail.Id,
Note = $"GapInsuranceAddDate has changed from NULL to {addedDateTime}"
});
if (targetActivity.Detail.GapInsuranceRemoveDate != null)
{
targetActivity.Detail.GapInsuranceRemoveDate = null;
await _activityDetailService.SaveActivityDetailUpdate(new ActivityDetailUpdate
{
ActivityDetailId = targetActivity.Detail.Id,
Note = $"GapInsuranceRemoveDate has changed from {targetActivity.Detail.GapInsuranceRemoveDate} to NULL"
});
}
await _activityService.ApplyStateChange(new ActivityStateChange
{
ActivityId = targetActivity.Id,
ActivityMatchId = linkedActivity.Id,
Note = $"Matched {linkedActivity.Product} Activity Id: {linkedActivity.Id} Added",
State = targetActivity.State
}, false);
}
private async Task<List<Activity>> ValidateMatchedActivityAccessories(List<Activity> matchedActivities, List<Activity> accessoryActivities)
{
var accessoryRemovedActivities = new List<Activity>();
foreach (var parentActivity in matchedActivities)
{
try
{
var accessoryActivity = accessoryActivities.FirstOrDefault(x => x.MatchingGapInsuranceActivityId == parentActivity.Id) == null
? await _activityRepository.GetActivityById(parentActivity.MatchingGapInsuranceActivityId)
: accessoryActivities.FirstOrDefault(x => x.MatchingGapInsuranceActivityId == parentActivity.Id);
if (accessoryActivity == null && parentActivity.Detail.GapInsuranceRemoveDate == null)
{
accessoryRemovedActivities.Add(await RemoveMissingGapAccessory(parentActivity));
continue;
}
if (parentActivity?.State == ActivityState.Accepted && accessoryActivity?.State == ActivityState.Accepted)
{
continue;
}
accessoryRemovedActivities.Add(await RemoveGapAccessory(parentActivity, accessoryActivity));
}
catch (Exception ex)
{
var parentActivityId = parentActivity != null ? parentActivity.Id.ToString() : "NULL";
Log.Error(ex, $"Failed to validate matched GAP accessory for Activity Id:{parentActivityId}");
}
}
Log.Information($"Removed GAP Accessory From {accessoryRemovedActivities.Count} Activities");
return matchedActivities.Except(accessoryRemovedActivities).ToList();
}
private async Task<Activity> RemoveGapAccessory(Activity parentActivity, Activity accessoryActivity)
{
var removedDate = await DetermineRemovedDate(parentActivity, accessoryActivity);
await ApplyRemovalChangeUpdates(parentActivity, accessoryActivity, removedDate);
await ApplyRemovalChangeUpdates(accessoryActivity, parentActivity, removedDate);
await _unitOfWork.CompleteAsync();
return parentActivity.State == ActivityState.Accepted ? parentActivity : null;
}
private async Task ApplyRemovalChangeUpdates(Activity targetActivity, Activity linkedActivity, DateTime removedDateTime)
{
targetActivity.Detail.GapInsuranceRemoveDate = removedDateTime;
targetActivity.MatchingGapInsuranceActivityId = 0;
await _activityDetailService.SaveActivityDetailUpdate(new ActivityDetailUpdate
{
ActivityDetailId = targetActivity.Detail.Id,
Note = $"GapInsuranceRemoveDate has changed from NULL to {removedDateTime}"
});
await _activityService.ApplyStateChange(new ActivityStateChange
{
ActivityId = targetActivity.Id,
ActivityMatchId = linkedActivity.Id,
Note = $"Matched {linkedActivity.Product} Activity Id: {linkedActivity.Id} Removed",
State = targetActivity.State
}, false);
}
private static async Task<DateTime> DetermineRemovedDate(Activity parentActivity, Activity accessoryActivity)
{
if (parentActivity.State == ActivityState.Accepted && accessoryActivity.State != ActivityState.Accepted)
{
return await Task.FromResult(accessoryActivity.Accepted.Date.AddHours(12));
}
if (parentActivity.State != ActivityState.Accepted && accessoryActivity.State == ActivityState.Accepted)
{
return await Task.FromResult(parentActivity.Accepted.Date.AddHours(12));
}
return await Task.FromResult(parentActivity.LastUpdated <= accessoryActivity.LastUpdated
? parentActivity.Accepted.Date.AddHours(12)
: accessoryActivity.Accepted.Date.AddHours(12));
}
private async Task<Activity?> RemoveMissingGapAccessory(Activity activity)
{
Log.Warning($"Unable To Find GAP Accessory Activity Id: {activity.MatchingGapInsuranceActivityId}, Removing GAP Accessory From Activity Id: {activity.Id}");
var removeDate = DateTime.Now.Date.AddHours(12);
activity.MatchingGapInsuranceActivityId = 0;
activity.Detail.GapInsuranceRemoveDate = removeDate;
await _activityDetailService.SaveActivityDetailUpdate(new ActivityDetailUpdate
{
ActivityDetailId = activity.Detail.Id,
Note = $"GapInsuranceRemoveDate has changed from NULL to {removeDate}"
});
var activityStateChange = new ActivityStateChange
{
ActivityId = activity.Id,
Note = $"{Product.GAPInsurance} Accessory Activity Removed, Accessory Activity Not Found",
State = activity.State
};
await _activityService.ApplyStateChange(activityStateChange);
return activity.State == ActivityState.Accepted ? activity : null;
}
private async Task<List<Activity>> GetMatchingGapAccessoryActivities(IReadOnlyCollection<Activity> matchedActivities)
{
if (!matchedActivities.Any())
{
return new List<Activity>();
}
var ids = matchedActivities
.Select(activity => activity.MatchingGapInsuranceActivityId)
.ToList();
return await _activityRepository.FindById(ids);
}
}