Files
monorepo/LCU.API.Operations.IncentiveAPI/LCU.API.Internal.Operations.IncentiveApi/Services/Temenos/ImportIndirectVehicleSalesService.cs
T
2026-04-23 16:27:51 +00:00

240 lines
10 KiB
C#

using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;
using System.IO;
using LCU.API.Internal.Operations.IncentiveApi.Services.MicroApiServices;
using LCU.API.Internal.Operations.IncentiveApi.Models.Temenos;
using LCU.Library.Internal.ApiResponse.Services;
using LCU.Library.Internal.Exceptions;
using LCU.Library.Internal.IncentiveApiModels.Requests;
using LCU.Library.Internal.IncentiveApiModels.Results;
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
using LCU.Library.Internal.IncentiveApiModels.Entities;
using LCU.Library.Internal.IncentiveApiModels.Enums;
using LCU.API.Internal.Operations.IncentiveApi.Services.Transformations;
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Temenos;
public class ImportIndirectVehicleSalesService : IImportIndirectVehicleSalesService
{
private readonly IUserRepository _userRepository;
private readonly IActivityService _activityService;
private readonly IFileOperationsApiService _fileOperationsApiService;
private readonly IDeadActivityService _deadActivityService;
private readonly ProcessResult _importIndirectVehicleSalesResult;
public ImportIndirectVehicleSalesService(IActivityService activityService, IUserRepository userRepository,
IFileOperationsApiService fileOperationsApiService, IDeadActivityService deadActivityService)
{
_activityService = activityService;
_userRepository = userRepository;
_fileOperationsApiService = fileOperationsApiService;
_deadActivityService = deadActivityService;
_importIndirectVehicleSalesResult = new ProcessResult();
}
public async Task HandleImportIndirectVehicleSales(ImportIndirectVehicleSalesRequest request)
{
try
{
var records = await GetIndirectVehicleRecordsForImport(request);
await CreateAndSaveActivities(records);
await QueueReturnResponse.QueueResponse(request, _importIndirectVehicleSalesResult.Success, _importIndirectVehicleSalesResult.MessageStack);
}
catch (Exception exception)
{
var message = $"There was an issue with handling Import Indirect Vehicle Sales. Exception Message: {exception.Message}.";
_importIndirectVehicleSalesResult.MessageStack.Add(message);
_importIndirectVehicleSalesResult.Success = false;
await QueueReturnResponse.QueueResponse(request, _importIndirectVehicleSalesResult.Success, _importIndirectVehicleSalesResult.MessageStack);
}
}
private async Task<List<IndirectVehicleSaleRecord>> GetIndirectVehicleRecordsForImport(ImportIndirectVehicleSalesRequest request)
{
var recordsToImport = new List<IndirectVehicleSaleRecord>();
var directDynamicFileListRequest = request.ToDirectDynamicVehicleFileListRequest(request.DirectDynamicFileName);
var directFiles = await _fileOperationsApiService.BuildDynamicFileList(directDynamicFileListRequest);
var directRecords = new List<DirectVehicleSaleRecord>();
foreach (var file in directFiles)
{
directRecords.AddRange(await GetRecords<DirectVehicleSaleRecord>(request.FinalBasePath + file));
}
if (directRecords.Any())
{
var indirectDynamicFileListRequest = request.ToIndirectDynamicVehicleFileListRequest(request.IndirectDynamicFileName);
var indirectFiles = await _fileOperationsApiService.BuildDynamicFileList(indirectDynamicFileListRequest);
var indirectRecords = new List<IndirectVehicleSaleRecord>();
foreach(var file in indirectFiles)
{
indirectRecords.AddRange(await GetRecords<IndirectVehicleSaleRecord>(request.FinalBasePath + file));
}
recordsToImport = GetIndirectRecordsToImport(directRecords, indirectRecords);
}
return recordsToImport;
}
private async Task CreateAndSaveActivities(List<IndirectVehicleSaleRecord> records)
{
var activities = new List<Activity>();
var deadActivities = new List<DeadActivity>();
foreach (var record in records)
{
var activity = new Activity()
{
Product = Product.Vehicle,
Type = ActivityType.Sale,
State = ActivityState.Accepted,
SourceSystem = SystemType.Temenos,
SourceCreated = DateTime.Parse(record.DisbursedDate),
Accepted = DateTime.Parse(record.DisbursedDate).Date.AddHours(12),
SourceId = record.ApplicationID,
Detail = new ActivityDetail()
{
AccountNumber = record.AccountNumber,
MemberName = record.ApplicantName,
AccountBalance = !string.IsNullOrEmpty(record.AmountFinanced)
? ParseMoneyDouble(record.AmountFinanced)
: ParseMoneyDouble("0.0"),
AccountStatus = record.SubProduct
},
EmployeeEmail = null,
EmployeeId = null,
DepartmentId = -1
};
var employee = await FindEmployee(record.ReferringEmployeeEmail);
if (employee == null)
{
var message = $"Temenos Import, No user for {record.ReferringEmployeeEmail}. Saving as Dead Activity.";
_importIndirectVehicleSalesResult.MessageStack.Add(message);
activity.EmployeeEmail = record.ReferringEmployeeEmail;
deadActivities.Add(new DeadActivity(activity, DeadActivityReason.MissingRequiredField, message));
continue;
}
activity.AppUserId = employee.Id;
activity.EmployeeEmail = employee.AdEmail;
activity.EmployeeId = employee.EmployeeId;
var homeDept = employee.FindHomeDepartment();
if (homeDept == null)
{
var message = $"User has no reliably determinable home department, {employee.EmployeeId}. Saving as Dead Activity.";
_importIndirectVehicleSalesResult.MessageStack.Add(message);
deadActivities.Add(new DeadActivity(activity, DeadActivityReason.MissingRequiredField, message));
continue;
}
activity.DepartmentId = homeDept.DepartmentId;
activities.Add(activity);
}
if (activities.Any())
{
await SaveActivities(activities);
}
if (deadActivities.Any())
{
await SaveDeadActivities(deadActivities);
}
_importIndirectVehicleSalesResult.MessageStack.Add($"Imported { activities.Count + deadActivities.Count } indirect vehicle sales.");
}
private async Task<AppUser> FindEmployee(string employeeEmail)
{
try
{
return await _userRepository.FindUserByAdEmailAsync(employeeEmail);
}
catch (Exception exception)
{
_importIndirectVehicleSalesResult.MessageStack.Add($"Error when finding user by email in ImportIndirectVehicleSalesService. Exception message: { exception.Message }");
return null;
}
}
private async Task SaveActivities(List<Activity> activities)
{
try
{
await _activityService.SaveActivityRangeAsync(activities);
}
catch (Exception exception)
{
var message = $"Failed to save activities from ImportIndirectVehicleSalesService. Activities will be lost. Eception Message: {exception.Message}";
_importIndirectVehicleSalesResult.MessageStack.Add(message);
throw new ServiceException($"{message}. Exception: {exception.Message}");
}
}
private async Task SaveDeadActivities(List<DeadActivity> deadActivities)
{
try
{
await _deadActivityService.SaveDeadActivityRange(deadActivities);
}
catch (Exception exception)
{
var message = $"Failed to save dead activities from ImportIndirectVehicleSalesService. Dead Activities will be lost. Eception Message: {exception.Message}";
_importIndirectVehicleSalesResult.MessageStack.Add(message);
throw new ServiceException($"{message}. Exception: {exception.Message}");
}
}
private static List<IndirectVehicleSaleRecord> GetIndirectRecordsToImport(List<DirectVehicleSaleRecord> directRecords, List<IndirectVehicleSaleRecord> indirectRecords)
{
var recordsToImport = new List<IndirectVehicleSaleRecord>();
foreach (var indirectRecord in indirectRecords)
{
if (!recordsToImport.Any(x => x.ApplicationID == indirectRecord.ApplicationID))
{
var directSsnMatches = directRecords.Where(x => x.ApplicantSSN == indirectRecord.ApplicantSSN);
var directCreatedBeforeIndirectMatches = directSsnMatches.Where(x => DateTime.Parse(x.CreatedDate) < DateTime.Parse(indirectRecord.CreatedDate));
if (directCreatedBeforeIndirectMatches.Any())
{
var matchedDirectRecord = directCreatedBeforeIndirectMatches.OrderByDescending(x => DateTime.Parse(x.CreatedDate)).FirstOrDefault();
indirectRecord.ReferringEmployeeEmail = matchedDirectRecord?.ReferringEmployeeEmail;
recordsToImport.Add(indirectRecord);
}
}
}
return recordsToImport;
}
private async Task<List<TResponse>> GetRecords<TResponse>(string filePathAndName)
{
var contents = await _fileOperationsApiService.GetFileContent(filePathAndName);
using var stringReader = new StringReader(contents);
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = "|",
HasHeaderRecord = false
};
using var csv = new CsvReader(stringReader, config);
return csv.GetRecords<TResponse>().ToList();
}
private double? ParseMoneyDouble(string amountFinanced)
{
var parsed = decimal.Parse(amountFinanced, NumberStyles.Currency, new CultureInfo("en-Us"));
return (double)parsed;
}
}