Adding
This commit is contained in:
+8
@@ -0,0 +1,8 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Temenos;
|
||||
|
||||
public interface IImportCreditCardSalesService
|
||||
{
|
||||
Task HandleImportCreditCardSales(ImportCreditCardSalesRequest message);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Temenos;
|
||||
|
||||
public interface IImportIndirectVehicleSalesService
|
||||
{
|
||||
Task HandleImportIndirectVehicleSales(ImportIndirectVehicleSalesRequest message);
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
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 ImportCreditCardSalesService : IImportCreditCardSalesService
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IActivityService _activityService;
|
||||
private readonly IFileOperationsApiService _fileOperationsApiService;
|
||||
private readonly IDeadActivityService _deadActivityService;
|
||||
private readonly ProcessResult _importCreditCardResult;
|
||||
|
||||
public ImportCreditCardSalesService(IActivityService activityService, IUserRepository userRepository,
|
||||
IFileOperationsApiService fileOperationsService, IDeadActivityService deadActivityService)
|
||||
{
|
||||
_activityService = activityService;
|
||||
_userRepository = userRepository;
|
||||
_fileOperationsApiService = fileOperationsService;
|
||||
_deadActivityService = deadActivityService;
|
||||
_importCreditCardResult = new ProcessResult();
|
||||
}
|
||||
|
||||
public async Task HandleImportCreditCardSales(ImportCreditCardSalesRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var records = await GetCreditCardSales(request);
|
||||
List<Activity> allActivity = await CreateActivities(records);
|
||||
|
||||
var personalCardCount = 0;
|
||||
var businesCardCount = 0;
|
||||
|
||||
if (allActivity.Any())
|
||||
{
|
||||
await _activityService.SaveActivityRangeAsync(allActivity);
|
||||
personalCardCount = records.Where(x => x.IsPersonal).Count();
|
||||
businesCardCount = records.Where(x => !x.IsPersonal).Count();
|
||||
}
|
||||
|
||||
_importCreditCardResult.MessageStack.Add( $"Imported {personalCardCount} personal and {businesCardCount} business credit cards.");
|
||||
await QueueReturnResponse.QueueResponse(request, _importCreditCardResult.Success, _importCreditCardResult.MessageStack);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var message = $"There was an issue with handling Import Credit Card Sales Exception Message: {exception.Message}.";
|
||||
_importCreditCardResult.MessageStack.Add(message);
|
||||
_importCreditCardResult.Success = false;
|
||||
await QueueReturnResponse.QueueResponse(request, _importCreditCardResult.Success, _importCreditCardResult.MessageStack);
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<TemenosCreditCardSale>> GetCreditCardSales(ImportCreditCardSalesRequest request)
|
||||
{
|
||||
var dynamicFileListRequest = request.ToDynamicCreditCardFileListRequest();
|
||||
|
||||
var files = await _fileOperationsApiService.BuildDynamicFileList(dynamicFileListRequest);
|
||||
var records = new List<TemenosCreditCardSale>();
|
||||
|
||||
foreach (var file in files) {
|
||||
var filePathAndName = request.FinalBasePath + file;
|
||||
var contents = _fileOperationsApiService.GetFileContent(filePathAndName);
|
||||
using var stringReader = new StringReader(contents.Result);
|
||||
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
||||
{
|
||||
Delimiter = "|",
|
||||
HasHeaderRecord = false
|
||||
};
|
||||
|
||||
using var csv = new CsvReader(stringReader, config);
|
||||
records.AddRange(csv.GetRecords<TemenosCreditCardSale>().ToList());
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
private async Task<List<Activity>> CreateActivities(IEnumerable<TemenosCreditCardSale> records)
|
||||
{
|
||||
var activities = new List<Activity>();
|
||||
var deadActivities = new List<DeadActivity>();
|
||||
|
||||
foreach (var record in records)
|
||||
{
|
||||
string email = string.IsNullOrEmpty(record.ReferringEmployeeEmail) ? null : record.ReferringEmployeeEmail.Trim();
|
||||
var employee = string.IsNullOrEmpty(email) ? null : await FindEmployee(email);
|
||||
|
||||
if (employee == null)
|
||||
{
|
||||
email = string.IsNullOrEmpty(record.LOResponsibleEmployeeEmail) ? null : record.LOResponsibleEmployeeEmail.Trim();
|
||||
employee = string.IsNullOrEmpty(email) ? null : await FindEmployee(email);
|
||||
}
|
||||
|
||||
if (employee == null
|
||||
&& (!string.IsNullOrWhiteSpace(record.LODirectLoanOfficer)
|
||||
&& record.LODirectLoanOfficer.Contains(',')))
|
||||
{
|
||||
var lastName = record.LODirectLoanOfficer?.Split(',')[0].Trim();
|
||||
var firstName = record.LODirectLoanOfficer?.Split(',')[1].Trim();
|
||||
email = string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)
|
||||
? null
|
||||
: $"{firstName}{lastName}@landmarkcu.com";
|
||||
employee = string.IsNullOrEmpty(email) ? null : await FindEmployee(email);
|
||||
}
|
||||
|
||||
if (employee == null)
|
||||
{
|
||||
_importCreditCardResult.MessageStack.Add($"Action Import, No user for {email} email. Saving as Dead Activity.");
|
||||
deadActivities.Add(record.CreateDeadActivity(DeadActivityReason.MissingRequiredField, $"Action Import, No user for {email} email", email));
|
||||
continue;
|
||||
}
|
||||
|
||||
var homeDept = employee.FindHomeDepartment();
|
||||
if (homeDept == null)
|
||||
{
|
||||
_importCreditCardResult.MessageStack.Add($"User has no reliably determinable home department, {employee.EmployeeId}. Saving as Dead Activity.");
|
||||
deadActivities.Add(
|
||||
record.CreateDeadActivity(DeadActivityReason.MissingRequiredField,
|
||||
$"User has no reliably determinable home department, {employee.EmployeeId}", email, employee.EmployeeId));
|
||||
continue;
|
||||
}
|
||||
|
||||
var activity = record.CreateActivity(employee);
|
||||
|
||||
if (activities.Any(x => x.SourceId == activity.SourceId))
|
||||
{
|
||||
_importCreditCardResult.MessageStack.Add($"Duplicate activity in Temenos credit card file for Incentive Manager, sourceId is {activity.SourceId}");
|
||||
continue;
|
||||
}
|
||||
activities.Add(activity);
|
||||
}
|
||||
|
||||
if (deadActivities.Any())
|
||||
{
|
||||
await SaveDeadActivities(deadActivities);
|
||||
}
|
||||
|
||||
return activities;
|
||||
}
|
||||
|
||||
private async Task SaveDeadActivities(List<DeadActivity> deadActivities)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _deadActivityService.SaveDeadActivityRange(deadActivities);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_importCreditCardResult.MessageStack.Add($"Failed to SaveDeadActivities in ImportCreditCardSalesService. Dead Activities will be lost. Exception message:{exception.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AppUser> FindEmployee(string employeeEmail)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _userRepository.FindUserByAdEmailAsync(employeeEmail);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_importCreditCardResult.MessageStack.Add($"Error to FindEmployee email in ImportCreditCardSalesService. Exception messge:{exception.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
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);
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user