Adding
This commit is contained in:
+94
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using LCU.API.Collections.RepoApi.Configuration;
|
||||
using Serilog;
|
||||
using WinSCP;
|
||||
using SessionOptions = WinSCP.SessionOptions;
|
||||
using TransferMode = WinSCP.TransferMode;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AuctionFtpClientService : IAuctionFtpClientService
|
||||
{
|
||||
private readonly SessionOptions _sessionOptions;
|
||||
private readonly RepoApiConfiguration _configuration;
|
||||
|
||||
public AuctionFtpClientService(RepoApiConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_sessionOptions = new SessionOptions()
|
||||
{
|
||||
Protocol = Protocol.Sftp,
|
||||
HostName = configuration.FtpConfiguration.HostName,
|
||||
UserName = configuration.FtpConfiguration.UserName,
|
||||
PortNumber = configuration.FtpConfiguration.Port,
|
||||
SshHostKeyFingerprint = configuration.FtpConfiguration.SshHostKeyFingerprint,
|
||||
SshPrivateKeyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||
configuration.FtpConfiguration.SshPrivateKeyPath)
|
||||
};
|
||||
}
|
||||
|
||||
public Dictionary<FileInfo, string> Download()
|
||||
{
|
||||
var fileResults = new Dictionary<FileInfo, string>();
|
||||
using (Session session = new Session())
|
||||
{
|
||||
TransferOperationResult transferResult = null;
|
||||
try
|
||||
{
|
||||
session.ExecutablePath = _configuration.FtpConfiguration.ExecutablePath;
|
||||
session.Open(_sessionOptions);
|
||||
}
|
||||
catch (WinSCP.SessionLocalException wsle)
|
||||
{
|
||||
Log.Error(wsle, "Failed to open FTP session, WINSCP likely missing");
|
||||
return fileResults;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex,"Failed to open FTP session");
|
||||
return fileResults;
|
||||
}
|
||||
|
||||
TransferOptions transferOptions = new TransferOptions();
|
||||
transferOptions.TransferMode = TransferMode.Automatic;
|
||||
transferOptions.PreserveTimestamp = true;
|
||||
|
||||
RemoteDirectoryInfo directory = session.ListDirectory(_configuration.RemoteFilePath);
|
||||
|
||||
foreach (RemoteFileInfo fileInfo in directory.Files)
|
||||
{
|
||||
string localFileName = Path.Combine(_configuration.LocalDirectoryPath, fileInfo.Name);
|
||||
var remoteFileName = Path.Combine(_configuration.RemoteFilePath, fileInfo.Name);
|
||||
|
||||
FileInfo thisFileInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!fileInfo.IsDirectory && !File.Exists(localFileName))
|
||||
{
|
||||
thisFileInfo = new FileInfo(localFileName);
|
||||
fileResults.Add(thisFileInfo, "success");
|
||||
|
||||
transferResult = session.GetFiles(remoteFileName, localFileName, true, transferOptions);
|
||||
|
||||
// Throw on any error
|
||||
transferResult.Check();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Exception while FTP'ing files ");
|
||||
if (thisFileInfo != null)
|
||||
{
|
||||
fileResults[thisFileInfo] = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.Shared.Collections.RepoApiLib.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Persistence;
|
||||
using LCU.Shared.Collections.RepoApiLib.Repositories;
|
||||
using LCU.Shared.Collections.RepoApiLib.WebServices.AutoIMS;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
using AuctionAssignment = LCU.Shared.Collections.RepoApiLib.Models.AuctionAssignment;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AuctionProcessorDao : IAuctionProcessorDao
|
||||
{
|
||||
private readonly IImsAutoFileDataRepository _imsAutoFileDataRepository;
|
||||
private readonly IAutoImsWebService _autoImsWebService;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly AppDbContext _context;
|
||||
private readonly string statusTypeRepo = "REPO";
|
||||
private readonly string statusTypeSold = "SOLD";
|
||||
private readonly string statusTypeRedeemed = "REDEEMED";
|
||||
|
||||
public AuctionProcessorDao(
|
||||
IImsAutoFileDataRepository imsAutoFileDataRepository,
|
||||
IAutoImsWebService autoImsWebService,
|
||||
AppDbContext context,
|
||||
IUnitOfWork unitOfWork
|
||||
)
|
||||
{
|
||||
_context = context;
|
||||
_unitOfWork = unitOfWork;
|
||||
_imsAutoFileDataRepository = imsAutoFileDataRepository;
|
||||
_autoImsWebService = autoImsWebService;
|
||||
}
|
||||
|
||||
public string UpdateAutoImsFromAuctionData(ImsAutoFileData item)
|
||||
{
|
||||
try
|
||||
{
|
||||
WebServiceResponse response = null;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
response = await _autoImsWebService.UpdateAuctionIdentifyingValuesAsync(
|
||||
item.AuctionCustomerNo,
|
||||
item.VIN,
|
||||
item.AuctionAssignmentId.ToString());
|
||||
}).Wait();
|
||||
return "Updated AutoIMS with Landmark identifiers.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "UpdateAutoIMS From Auction Failure");
|
||||
return "Failure Updating AutoIMS with Landmark identifiers.";
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFormattedVin(string vin)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(vin)
|
||||
? vin.Trim().PadLeft(17, '0').ToUpper()
|
||||
: null;
|
||||
}
|
||||
|
||||
public RepoAccount FindByAuctionCustomerNoAndVinAsync(string auctionCustomerNo, string unformattedVin)
|
||||
{
|
||||
List<RepoAccount> repos = FindRepoByStatus(auctionCustomerNo, unformattedVin, statusTypeRepo);
|
||||
|
||||
|
||||
if (!repos.Any())
|
||||
{
|
||||
repos = FindRepoByStatus(auctionCustomerNo, unformattedVin, statusTypeSold);
|
||||
}
|
||||
|
||||
if (!repos.Any())
|
||||
{
|
||||
repos = FindRepoByStatus(auctionCustomerNo, unformattedVin, statusTypeRedeemed);
|
||||
}
|
||||
|
||||
/*
|
||||
Currently we cannot error on multiple rows returned because we can have duplicate repos in the database
|
||||
We will need to perform extensive data cleanup before this can be enabled
|
||||
*/
|
||||
// if (repos.Count > 1)
|
||||
// {
|
||||
// throw new Exception($"Multiple Auction Assignments Returned For: AuctionCustomerNo:{auctionCustomerNo} | VIN:{vin}");
|
||||
// }
|
||||
|
||||
return repos.FirstOrDefault();
|
||||
}
|
||||
|
||||
public ImsAutoFileData UpdateExistingFile(ImsAutoFileData existingAuctionFile, ImsAutoFileData imsAutoFileData)
|
||||
{
|
||||
_context.Entry(existingAuctionFile).CurrentValues.SetValues(imsAutoFileData);
|
||||
imsAutoFileData.DateReceivedFromAutoIMS = existingAuctionFile.DateReceivedFromAutoIMS;
|
||||
imsAutoFileData.CollateralImagePath =
|
||||
_autoImsWebService.GetCollateralImage(imsAutoFileData.ConditionReportLink);
|
||||
_imsAutoFileDataRepository.Update(existingAuctionFile);
|
||||
_unitOfWork.CompleteAsync().GetAwaiter().GetResult();
|
||||
return imsAutoFileData;
|
||||
}
|
||||
|
||||
public ImsAutoFileData CreateImsAuctionFileData(ImsAutoFileData imsAutoFileData)
|
||||
{
|
||||
imsAutoFileData.DateReceivedFromAutoIMS = DateTime.Now;
|
||||
imsAutoFileData.CollateralImagePath =
|
||||
_autoImsWebService.GetCollateralImage(imsAutoFileData.ConditionReportLink);
|
||||
Add(imsAutoFileData);
|
||||
_unitOfWork.CompleteAsync().GetAwaiter().GetResult();
|
||||
|
||||
return imsAutoFileData;
|
||||
}
|
||||
|
||||
public void Add(ImsAutoFileData assignment)
|
||||
{
|
||||
_context.ImsAutoFileData.Add(assignment);
|
||||
}
|
||||
|
||||
public ImsAutoFileData FindByAuctionAssignmentIdAsync(int auctionAssignmentId)
|
||||
{
|
||||
return _context.ImsAutoFileData.AsNoTracking()
|
||||
.FirstOrDefault(x => x.AuctionAssignmentId == auctionAssignmentId);
|
||||
}
|
||||
|
||||
public ImsAutoFileData GetNonConformingImsFileRecord(string vin, string auctionCustomerNo)
|
||||
{
|
||||
ImsAutoFileData imsAutoFile = null;
|
||||
|
||||
// Allow for vehicle brought back to auction after sale. it happens!
|
||||
DateTime withinThirtyDays = DateTime.Now.AddDays(-30);
|
||||
imsAutoFile = _context.ImsAutoFileData.AsNoTracking().FirstOrDefault(x =>
|
||||
(x.VIN.Trim() == vin && x.AuctionCustomerNo == auctionCustomerNo
|
||||
&& (x.SoldDate == null || x.SoldDate >= withinThirtyDays)));
|
||||
|
||||
return imsAutoFile;
|
||||
}
|
||||
|
||||
|
||||
public ImsAutoFileData FindImsAuctionFileData(int auctionAssignmentId, string customerNo, string VIN)
|
||||
{
|
||||
var existingAuctionFile = FindByAuctionAssignmentIdAsync(auctionAssignmentId) ?? GetNonConformingImsFileRecord(VIN, customerNo);
|
||||
return existingAuctionFile;
|
||||
}
|
||||
|
||||
public AuctionAssignment FindByIdAsync(int id)
|
||||
{
|
||||
return _context.AuctionAssignments.Where(c => c.ID == id).IncludeAll().FirstOrDefault();
|
||||
}
|
||||
|
||||
public AuctionAssignment FindByAuctionCustomerNoAndVin(string auctionCustomerNo, string vin)
|
||||
{
|
||||
List<AuctionAssignment> auctionAssignments = FindAuctionByStatus(auctionCustomerNo, vin, statusTypeRepo);
|
||||
|
||||
if(!auctionAssignments.Any())
|
||||
{
|
||||
auctionAssignments = FindAuctionByStatus(auctionCustomerNo, vin, statusTypeSold);
|
||||
}
|
||||
|
||||
if (!auctionAssignments.Any())
|
||||
{
|
||||
auctionAssignments = FindAuctionByStatus(auctionCustomerNo, vin, statusTypeRedeemed);
|
||||
}
|
||||
|
||||
return auctionAssignments.FirstOrDefault();
|
||||
}
|
||||
|
||||
public AuctionAssignment FindAuctionAssignment(ImsAutoFileData item)
|
||||
{
|
||||
var auctionAssignment
|
||||
= /* FindByIdAsync(item.AuctionAssignmentId) this can't be used because old numbers will exist at first. ??*/
|
||||
FindByAuctionCustomerNoAndVin(item.AuctionCustomerNo, item.VIN);
|
||||
|
||||
if (auctionAssignment == null)
|
||||
{
|
||||
throw new Exception("Auction assignment not found for Individual/VIN " + item.AuctionCustomerNo);
|
||||
}
|
||||
|
||||
return auctionAssignment;
|
||||
}
|
||||
|
||||
public RepoAccount FindRepoForImsAuctionItem(ImsAutoFileData item)
|
||||
{
|
||||
RepoAccount repo = null;
|
||||
|
||||
// GJF, this can't be used because old numbers will exist at first....
|
||||
// if (item.AuctionAssignmentId > 0) {
|
||||
// repo = await _repoAccountRepository.FindByAuctionAssignmentIdAsync(item.AuctionAssignmentId);
|
||||
// }
|
||||
|
||||
repo = FindByAuctionCustomerNoAndVinAsync(item.AuctionCustomerNo, item.VIN);
|
||||
|
||||
if (repo == null)
|
||||
{
|
||||
throw new Exception("Repo Account not found for Individual/VIN " + item.AuctionCustomerNo);
|
||||
}
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<AuctionAssignment> ListReadyForFloorPrice()
|
||||
{
|
||||
var temp = (from x in _context.AuctionAssignments
|
||||
where (x.FloorPrice ?? 0) == 0 && x.AutoIMS != null && x.AutoIMS.SoldDate == null &&
|
||||
(x.AutoIMS.StatedMileage ?? -1) > 1 && x.AutoIMS.ScheduledSaleDate != null &&
|
||||
x.AutoIMS.ScheduledSaleDate > DateTime.Now.Date &&
|
||||
x.RedeemedDate == null &&
|
||||
((x.AutoIMS.ApprovedVehicleGrade ?? 0) > 0 || (x.AutoIMS.VehicleGrade ?? 0) > 0)
|
||||
select x).OrderByDescending(x => x.ID);
|
||||
|
||||
return temp.IncludeAll().ToList();
|
||||
}
|
||||
|
||||
private List<RepoAccount> FindRepoByStatus(string auctionCustomerNo, string unformattedVin, string statusType)
|
||||
{
|
||||
return (from account in _context.RepoAccounts
|
||||
join collateral in _context.Collaterals on account.RepoId equals collateral.RepoId
|
||||
join auctionAssignment in _context.AuctionAssignments on account.RepoId equals auctionAssignment.RepoId
|
||||
where GetFormattedVin(collateral.Vin) == GetFormattedVin(unformattedVin)
|
||||
&& (auctionAssignment.AuctionCustomerNo == auctionCustomerNo || string.IsNullOrWhiteSpace(auctionCustomerNo))
|
||||
&& account.Status == statusType
|
||||
select account).ToList();
|
||||
}
|
||||
|
||||
private List<AuctionAssignment> FindAuctionByStatus(string auctionCustomerNo, string vin, string statusType)
|
||||
{
|
||||
return (from auctionAssignment in _context.AuctionAssignments
|
||||
join account in _context.RepoAccounts on auctionAssignment.RepoId equals account.RepoId
|
||||
join collateral in _context.Collaterals on account.RepoId equals collateral.RepoId
|
||||
where GetFormattedVin(collateral.Vin) == GetFormattedVin(vin)
|
||||
&& (auctionAssignment.AuctionCustomerNo == auctionCustomerNo || string.IsNullOrWhiteSpace(auctionCustomerNo))
|
||||
&& account.Status == statusType
|
||||
select auctionAssignment).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.AutoIms;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AutoImsAuctionProcessorService : IAutoImsAuctionProcessorService
|
||||
{
|
||||
private readonly IAuctionProcessorDao _auctionProcessorDao;
|
||||
|
||||
public AutoImsAuctionProcessorService(IAuctionProcessorDao auctionProcessorDao)
|
||||
{
|
||||
_auctionProcessorDao = auctionProcessorDao;
|
||||
}
|
||||
|
||||
public ImportResultRow ImportSingleAutoImsAuction(ImsAutoFileData incomingAutoImsData)
|
||||
{
|
||||
AuctionAssignment auctionAssignment;
|
||||
var result = new ImportResultRow()
|
||||
{
|
||||
Success = true,
|
||||
Description = incomingAutoImsData.Description,
|
||||
Messages = new List<string>()
|
||||
};
|
||||
|
||||
incomingAutoImsData.VIN = incomingAutoImsData.VIN.Trim();
|
||||
if (incomingAutoImsData.VIN.Length != 17) // must be 17. Auction may add as less than 17 characters.
|
||||
{
|
||||
Log.Error($"Vin Length Not Correct, {incomingAutoImsData.AuctionCustomerNo}, {incomingAutoImsData.VIN}, Skipping.");
|
||||
result.Success = false;
|
||||
result.Messages.Add("Invalid VIN, this row has been skipped.");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool requiresAutoImsUpdate =
|
||||
string.IsNullOrWhiteSpace(incomingAutoImsData.AuctionCustomerNo) ||
|
||||
incomingAutoImsData.AuctionAssignmentId == 0;
|
||||
|
||||
try
|
||||
{
|
||||
result.RepoAccount = _auctionProcessorDao.FindRepoForImsAuctionItem(incomingAutoImsData);
|
||||
auctionAssignment = _auctionProcessorDao.FindAuctionAssignment(incomingAutoImsData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Success = false;
|
||||
result.Messages.Add("Failed to load required data => " + ex.Message);
|
||||
return result;
|
||||
}
|
||||
|
||||
RepoAccount repo = result.RepoAccount;
|
||||
// Always re-assign these fields, carried from previous system.
|
||||
incomingAutoImsData.RepoId = auctionAssignment.RepoId ?? 0;
|
||||
incomingAutoImsData.AuctionCustomerNo = auctionAssignment.AuctionCustomerNo;
|
||||
incomingAutoImsData.AuctionAssignmentId = auctionAssignment.ID;
|
||||
|
||||
ImsAutoFileData existingAuctionFile = auctionAssignment.AutoIMS;
|
||||
if (existingAuctionFile == null)
|
||||
{
|
||||
existingAuctionFile = _auctionProcessorDao.FindImsAuctionFileData(auctionAssignment.ID,
|
||||
incomingAutoImsData.AuctionCustomerNo,
|
||||
incomingAutoImsData.VIN);
|
||||
}
|
||||
|
||||
if (existingAuctionFile == null)
|
||||
{
|
||||
result.Messages.Add("New Entry Created.");
|
||||
existingAuctionFile = _auctionProcessorDao.CreateImsAuctionFileData(incomingAutoImsData);
|
||||
if (existingAuctionFile.AssignmentAccepted != null)
|
||||
{
|
||||
result.Messages.Add("Auction accepted by Auto IMS on " + existingAuctionFile.AssignmentAccepted);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Messages.Add("Updated existing IMS Auction Entry.");
|
||||
existingAuctionFile = _auctionProcessorDao.UpdateExistingFile(existingAuctionFile, incomingAutoImsData);
|
||||
}
|
||||
|
||||
result = CheckAuctionGates(existingAuctionFile, result);
|
||||
|
||||
// update autoims with customer number and auction assignment id when not added through our interface.
|
||||
if (requiresAutoImsUpdate)
|
||||
{
|
||||
result.Messages.Add(
|
||||
_auctionProcessorDao.UpdateAutoImsFromAuctionData(existingAuctionFile));
|
||||
}
|
||||
|
||||
result.Data = existingAuctionFile;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImportResultRow CheckAuctionGates(ImsAutoFileData existingAuctionFile, ImportResultRow result)
|
||||
{
|
||||
if (existingAuctionFile.VehicleGrade > 0)
|
||||
{
|
||||
result.Messages.Add("Grade present: " + existingAuctionFile.VehicleGrade + ".");
|
||||
}
|
||||
|
||||
if (existingAuctionFile.FloorPriceAccepted > 0)
|
||||
{
|
||||
result.Messages.Add("Accepted Floor Price present: $" +
|
||||
existingAuctionFile.FloorPriceAccepted + ".");
|
||||
}
|
||||
|
||||
if (existingAuctionFile.SoldDate != null)
|
||||
{
|
||||
result.Messages.Add("Auction Sold:" + existingAuctionFile.SoldDate + ".");
|
||||
}
|
||||
|
||||
if (existingAuctionFile.FundsSent != null)
|
||||
{
|
||||
result.Messages.Add("Funds Send Date received: " + existingAuctionFile.FundsSent + ".");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Configuration;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AutoImsDownloaderService : IAutoImsDownloaderService
|
||||
{
|
||||
private readonly RepoApiConfiguration _configuration;
|
||||
private readonly IAuctionFtpClientService _auctionFtpClientService;
|
||||
|
||||
public AutoImsDownloaderService(IAuctionFtpClientService auctionFtpClientService,
|
||||
RepoApiConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_auctionFtpClientService = auctionFtpClientService;
|
||||
}
|
||||
|
||||
public Dictionary<FileInfo, string> DownLoadAuctionFiles()
|
||||
{
|
||||
var fileResults = _auctionFtpClientService.Download();
|
||||
return fileResults;
|
||||
}
|
||||
|
||||
public Dictionary<FileInfo, string> CombineWithLocalFiles(Dictionary<FileInfo, string> fileResults)
|
||||
{
|
||||
// check if there are any files in the folder already that are not in our downloaded list.
|
||||
string[] fileEntries = Directory.GetFiles(_configuration.LocalDirectoryPath);
|
||||
|
||||
foreach (string file in fileEntries)
|
||||
{
|
||||
var newFile = new FileInfo(file);
|
||||
Log.Information($"Auto IMS Job Added file: {file}");
|
||||
|
||||
if (fileResults.Keys.All(x => x.Name != newFile.Name))
|
||||
{
|
||||
fileResults.Add(newFile, "success");
|
||||
}
|
||||
}
|
||||
|
||||
return fileResults;
|
||||
}
|
||||
|
||||
public IEnumerable<FileInfo> ConvertToFileList(Dictionary<FileInfo, string> fileResults)
|
||||
{
|
||||
if (fileResults.Any(x => x.Value != "success"))
|
||||
{
|
||||
foreach (var file in fileResults.Where(x => x.Value != "success"))
|
||||
{
|
||||
Log.Information($"File Downloads failed: {file.Key} - {file.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
if (fileResults.Any(x => x.Value == "success"))
|
||||
{
|
||||
var ascendingOrderOfFiles = fileResults.Where(x => x.Value == "success")
|
||||
.OrderBy(x => x.Key.LastWriteTime).Select(x => x.Key).ToList();
|
||||
return ascendingOrderOfFiles;
|
||||
}
|
||||
|
||||
Log.Information("No files found from AutoIMS.");
|
||||
return new List<FileInfo>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.AutoIms;
|
||||
using LCU.Shared.Collections.RepoApiLib.Repositories;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AutoImsImporterService : IAutoImsImporterService
|
||||
{
|
||||
private readonly IAuctionAssignmentRepository _auctionAssignmentRepository;
|
||||
private readonly IAutoImsNoteProcessorService _autoImsNoteProcessorService;
|
||||
private readonly IAutoImsAuctionProcessorService _autoImsAuctionProcessorService;
|
||||
private readonly IFloorPricingService _floorPricingService;
|
||||
private readonly IAuctionAssignmentService _auctionAssignmentService;
|
||||
|
||||
public AutoImsImporterService(
|
||||
IAuctionAssignmentRepository auctionAssignmentRepository,
|
||||
IAutoImsNoteProcessorService autoImsNoteProcessorService,
|
||||
IAutoImsAuctionProcessorService autoImsAuctionProcessorService, IFloorPricingService floorPricingService,
|
||||
IAuctionAssignmentService auctionAssignmentService)
|
||||
{
|
||||
_autoImsAuctionProcessorService = autoImsAuctionProcessorService;
|
||||
_floorPricingService = floorPricingService;
|
||||
_auctionAssignmentService = auctionAssignmentService;
|
||||
_autoImsNoteProcessorService = autoImsNoteProcessorService;
|
||||
_auctionAssignmentRepository = auctionAssignmentRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of notes comes from AutoIMS and must be inserted (But not updated).
|
||||
* Duplicates/Existing are checked for based on writer, time and text.
|
||||
*/
|
||||
public IReadOnlyCollection<AuctionAssignmentNote> ImportNotesToDatabase(IEnumerable<AuctionAssignmentNote> data)
|
||||
{
|
||||
List<AuctionAssignmentNote> savedData = new List<AuctionAssignmentNote>();
|
||||
foreach (var item in data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _autoImsNoteProcessorService.ImportSingleNoteRow(item);
|
||||
if (result != null)
|
||||
{
|
||||
savedData.Add(result);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Error processing notes for auction accountNo: {item.AuctionCustomerNo}");
|
||||
}
|
||||
}
|
||||
|
||||
return savedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each row in the Data file is an ImsAutoAuctionData row used to track the status of
|
||||
* a Repo at auction and assist in setting the floor.
|
||||
*/
|
||||
public IReadOnlyCollection<ImportResultRow> ImportDataFile(IEnumerable<ImsAutoFileData> models)
|
||||
{
|
||||
List<ImportResultRow> savedData = new List<ImportResultRow>();
|
||||
foreach (var item in models)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _autoImsAuctionProcessorService.ImportSingleAutoImsAuction(item);
|
||||
if (result != null)
|
||||
{
|
||||
savedData.Add(result);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Error processing data for auction account with repoId: {item.RepoId}");
|
||||
}
|
||||
}
|
||||
|
||||
return savedData;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<ImportResultRow> SetAllAvailableFloors()
|
||||
{
|
||||
var list = new List<ImportResultRow>();
|
||||
var auctionAssignments =
|
||||
_auctionAssignmentRepository.ListReadyForFloorPriceAsync()
|
||||
.ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
|
||||
|
||||
if (auctionAssignments.Items != null && auctionAssignments.Items.Any())
|
||||
{
|
||||
foreach (var auctionAssignment in auctionAssignments.Items)
|
||||
{
|
||||
var result = new ImportResultRow() {Messages = new List<string>()};
|
||||
var floorPriceCalculationResultSet = _floorPricingService.DetermineFloorPrice(auctionAssignment.ID);
|
||||
|
||||
if (floorPriceCalculationResultSet?.PrimaryResult != null)
|
||||
{
|
||||
result.Messages.Add("Floor Price Results Generated for Account " + auctionAssignment.RepoId);
|
||||
if (floorPriceCalculationResultSet.PrimaryResult.Success)
|
||||
{
|
||||
result.Messages.Add("Floor Price Results SUCCESS for Account " + auctionAssignment.RepoId);
|
||||
auctionAssignment.FloorPrice = floorPriceCalculationResultSet.PrimaryResult.FloorPrice;
|
||||
auctionAssignment.FloorPriceValuesUsed =
|
||||
floorPriceCalculationResultSet.FloorPriceValuesUsed;
|
||||
var updated = _auctionAssignmentService.UpdateAsync(auctionAssignment).GetAwaiter()
|
||||
.GetResult();
|
||||
Log.Information($"Auction Floor Set Id:{updated.ID}, FloorPrice:{updated.FloorPrice}, Skipping.");
|
||||
result.Messages.Add(
|
||||
$"Floor price set for {auctionAssignment.RepoId} to {auctionAssignment.FloorPrice}");
|
||||
result.Success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Messages.Add("Floor Price Results FAILURE for Account " + auctionAssignment.RepoId);
|
||||
result.Messages.Add("Reason: " +
|
||||
floorPriceCalculationResultSet.PrimaryResult.FailureReason);
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Information("SetAllAvailableFloors: No floors to set.");
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Repositories;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class AutoImsNoteProcessorService : IAutoImsNoteProcessorService
|
||||
{
|
||||
private readonly IAuctionAssignmentNoteRepository _auctionAssignmentNoteRepository;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
public AutoImsNoteProcessorService(IAuctionAssignmentNoteRepository auctionAssignmentNoteRepository,
|
||||
IUnitOfWork unitOfWork
|
||||
)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_auctionAssignmentNoteRepository = auctionAssignmentNoteRepository;
|
||||
}
|
||||
|
||||
public AuctionAssignmentNote ImportSingleNoteRow(AuctionAssignmentNote item)
|
||||
{
|
||||
var dateWritten = item.DateWritten ?? DateTime.Now;
|
||||
var existing =
|
||||
_auctionAssignmentNoteRepository.FindConflictingNotes(dateWritten, item.Text, item.Writer)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
if (!existing.Any())
|
||||
{
|
||||
item.DateWritten = dateWritten;
|
||||
Log.Information("Saving Note.");
|
||||
_auctionAssignmentNoteRepository.AddAsync(item);
|
||||
_unitOfWork.CompleteAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Information($"Note already exists, customerNo: {item.AuctionCustomerNo} on writeDate: {item.DateWritten}");
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAuctionFtpClientService
|
||||
{
|
||||
Dictionary<FileInfo, string> Download();
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAuctionProcessorDao
|
||||
{
|
||||
string UpdateAutoImsFromAuctionData(ImsAutoFileData item);
|
||||
|
||||
RepoAccount FindByAuctionCustomerNoAndVinAsync(string auctionCustomerNo,
|
||||
string unformattedVin);
|
||||
|
||||
ImsAutoFileData UpdateExistingFile(ImsAutoFileData existingAuctionFile, ImsAutoFileData imsAutoFileData);
|
||||
ImsAutoFileData CreateImsAuctionFileData(ImsAutoFileData imsAutoFileData);
|
||||
void Add(ImsAutoFileData assignment);
|
||||
ImsAutoFileData FindByAuctionAssignmentIdAsync(int auctionAssignmentId);
|
||||
ImsAutoFileData GetNonConformingImsFileRecord(string vin, string auctionCustomerNo);
|
||||
ImsAutoFileData FindImsAuctionFileData(int auctionAssignmentId, string customerNo, string VIN);
|
||||
AuctionAssignment FindByIdAsync(int id);
|
||||
AuctionAssignment FindByAuctionCustomerNoAndVin(string auctionCustomerNo, string vin);
|
||||
AuctionAssignment FindAuctionAssignment(ImsAutoFileData item);
|
||||
RepoAccount FindRepoForImsAuctionItem(ImsAutoFileData item);
|
||||
IReadOnlyCollection<AuctionAssignment> ListReadyForFloorPrice();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.AutoIms;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAutoImsAuctionProcessorService
|
||||
{
|
||||
ImportResultRow ImportSingleAutoImsAuction(ImsAutoFileData item);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAutoImsDownloaderService
|
||||
{
|
||||
Dictionary<FileInfo, string> DownLoadAuctionFiles();
|
||||
Dictionary<FileInfo, string> CombineWithLocalFiles(Dictionary<FileInfo, string> fileResults);
|
||||
IEnumerable<FileInfo> ConvertToFileList(Dictionary<FileInfo, string> fileResults);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.AutoIms;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAutoImsImporterService
|
||||
{
|
||||
IReadOnlyCollection<AuctionAssignmentNote> ImportNotesToDatabase(IEnumerable<AuctionAssignmentNote> data);
|
||||
IReadOnlyCollection<ImportResultRow> ImportDataFile(IEnumerable<ImsAutoFileData> models);
|
||||
IReadOnlyCollection<ImportResultRow> SetAllAvailableFloors();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IAutoImsNoteProcessorService
|
||||
{
|
||||
AuctionAssignmentNote ImportSingleNoteRow(AuctionAssignmentNote item);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IImsAutoFileDataConverter
|
||||
{
|
||||
ImsAutoFileData SetFieldByName(ImsAutoFileData input, string fieldName, string value);
|
||||
IReadOnlyCollection<ImsAutoFileData> CsvToImsAutoFileData(Stream file);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public interface IImsAutoFileNoteConverter
|
||||
{
|
||||
IEnumerable<AuctionAssignmentNote> CsvToImsAutoFileNotes(Stream file);
|
||||
IEnumerable<AuctionAssignmentNote> CompressIdentifyingRows(IEnumerable<AuctionAssignmentNote> csvNotes);
|
||||
AuctionAssignmentNote SetFieldByName(AuctionAssignmentNote input, string fieldName, string value);
|
||||
}
|
||||
}
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using LCU.API.Collections.RepoApi.Configuration;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using NotVisualBasic.FileIO;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class ImsAutoFileDataConverter : IImsAutoFileDataConverter
|
||||
{
|
||||
private readonly RepoApiConfiguration _configuration;
|
||||
|
||||
public ImsAutoFileDataConverter( RepoApiConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<ImsAutoFileData> CsvToImsAutoFileData(Stream file)
|
||||
{
|
||||
List<ImsAutoFileData> listOfObjects = new List<ImsAutoFileData>();
|
||||
using (CsvTextFieldParser tfp = new CsvTextFieldParser(file))
|
||||
{
|
||||
// Get Some Column Names
|
||||
string[] columns = tfp.ReadFields();
|
||||
|
||||
while (!tfp.EndOfData)
|
||||
{
|
||||
var fields = tfp.ReadFields();
|
||||
|
||||
if (!fields[0].Contains("------") && (fields.Any(x => x.Trim().Length > 0)))
|
||||
{
|
||||
var obj = new ImsAutoFileData();
|
||||
|
||||
for (var i = 0; i < fields.Length; i++)
|
||||
{
|
||||
obj = SetFieldByName(obj, columns[i].Trim(), fields[i]);
|
||||
}
|
||||
|
||||
listOfObjects.Add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return listOfObjects;
|
||||
}
|
||||
|
||||
public ImsAutoFileData SetFieldByName(ImsAutoFileData input, string fieldName, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (fieldName)
|
||||
{
|
||||
case "Announced Conditions":
|
||||
input.AnnouncedConditions = value.Trim();
|
||||
break;
|
||||
case "Arbitration Reason":
|
||||
input.ArbitrationReason = value.Trim();
|
||||
break;
|
||||
case "As Is 100K Miles":
|
||||
input.AsIs100KMiles = (value.Trim() == "Yes");
|
||||
break;
|
||||
case "Assignment Accepted":
|
||||
input.AssignmentAccepted =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Auction Age":
|
||||
input.AuctionAge = !string.IsNullOrWhiteSpace(value) ? NumbersOnly<int>(value) : (int?) null;
|
||||
break;
|
||||
case "Auction Guide Book Price":
|
||||
input.AuctionGuideBookPrice = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Buyer ID":
|
||||
input.BuyerId = value.Trim();
|
||||
break;
|
||||
case "Buyer Name":
|
||||
input.BuyerName = value.Trim();
|
||||
break;
|
||||
case "Charge Amount":
|
||||
input.ChargeAmount = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Check Amount":
|
||||
input.CheckAmount = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Client Age":
|
||||
input.ClientAge = !string.IsNullOrWhiteSpace(value) ? NumbersOnly<int>(value) : (int?) null;
|
||||
break;
|
||||
case "Client Cancelled":
|
||||
input.ClientCancelled =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Collision Damage":
|
||||
input.CollisionDamage = value.Trim();
|
||||
break;
|
||||
case "Inspected Date":
|
||||
input.InspectedDate = !string.IsNullOrEmpty(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Date of Loss":
|
||||
input.DateofLoss = !string.IsNullOrEmpty(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Date Picked Up":
|
||||
input.DatePickedUp = !string.IsNullOrEmpty(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Date Entered AutoIMS":
|
||||
input.DateEnteredAutoIMS = !string.IsNullOrEmpty(value)
|
||||
? DateTime.Parse(value.Substring(0, value.Trim().Length - 4))
|
||||
: (DateTime?) null;
|
||||
break;
|
||||
case "Days Run":
|
||||
input.DaysRun = !string.IsNullOrWhiteSpace(value) ? NumbersOnly<int>(value) : (int?) null;
|
||||
break;
|
||||
case "Days Run/Highest Bid Recorded by Auction":
|
||||
input.DaysRunHighestBidRecordedbyAuction = value;
|
||||
break;
|
||||
case "Days to Delivery":
|
||||
input.DaystoDelivery =
|
||||
!string.IsNullOrWhiteSpace(value) ? NumbersOnly<int>(value) : (int?) null;
|
||||
break;
|
||||
case "Description":
|
||||
input.Description = value.Trim();
|
||||
break;
|
||||
case "Drivable":
|
||||
input.IsDrivable = !string.IsNullOrWhiteSpace(value)
|
||||
? value == "Yes" ? true : false
|
||||
: (bool?) null;
|
||||
break;
|
||||
case "Floor Price (Accepted)":
|
||||
input.FloorPriceAccepted = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Funds Sent":
|
||||
input.FundsSent = !string.IsNullOrEmpty(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Gross % Floor":
|
||||
input.GrossPercentFloor =
|
||||
!string.IsNullOrWhiteSpace(value) ? NumbersOnly<decimal>(value) : (decimal?) null;
|
||||
break;
|
||||
case "Highest Bid":
|
||||
input.HighestBid = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Mileage":
|
||||
input.StatedMileage = !string.IsNullOrWhiteSpace(value)
|
||||
? int.Parse(value.Replace(",", ""))
|
||||
: (int?) null;
|
||||
break;
|
||||
case "Net % Floor":
|
||||
input.NetPercentFloor = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Other Advance Fees":
|
||||
input.OtherAdvanceFees = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "OTHER Total":
|
||||
input.OTHERTotal = value.Trim();
|
||||
break;
|
||||
case "OTHER: Advanced Other(72)":
|
||||
input.OTHERAdvancedOther = value.Trim();
|
||||
break;
|
||||
case "OTHER: Advanced Storage(71)":
|
||||
input.OTHERAdvancedStorage = value.Trim();
|
||||
break;
|
||||
case "OTHER: Advanced Tow(70)":
|
||||
input.OTHERAdvancedTow = value.Trim();
|
||||
break;
|
||||
case "OTHER: Miscellaneous(41)":
|
||||
input.OTHERMiscellaneous = value.Trim();
|
||||
break;
|
||||
case "Sale Price":
|
||||
input.SalePrice = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Scheduled Sale Date":
|
||||
input.ScheduledSaleDate =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Sold Date":
|
||||
input.SoldDate = !string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Title #":
|
||||
input.TitleNumber = value.Trim();
|
||||
break;
|
||||
case "Title Received":
|
||||
input.TitleReceived =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Title Returned":
|
||||
input.TitleReturned =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Title State":
|
||||
input.TitleState = value.Trim();
|
||||
break;
|
||||
case "Title Status":
|
||||
input.TitleStatus = value.Trim();
|
||||
break;
|
||||
case "Title Status from Auction":
|
||||
input.TitleStatusfromAuction = value.Trim();
|
||||
break;
|
||||
case "Total Charges":
|
||||
input.TotalCharges = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Vehicle Grade (Approved CR)":
|
||||
input.ApprovedVehicleGrade = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Operable":
|
||||
input.IsOperable = !string.IsNullOrWhiteSpace(value)
|
||||
? value == "Yes" ? true : false
|
||||
: (bool?) null;
|
||||
break;
|
||||
case "Shipment Date":
|
||||
input.ShipmentDate =
|
||||
!string.IsNullOrWhiteSpace(value) ? DateTime.Parse(value) : (DateTime?) null;
|
||||
break;
|
||||
case "Status":
|
||||
input.Status = value.Trim();
|
||||
break;
|
||||
case "VIN":
|
||||
input.VIN = value.Trim();
|
||||
break;
|
||||
case "Storage Cost":
|
||||
input.StorageCost = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Storage Rate Per Day":
|
||||
input.StorageRatePerDay = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Tow Cost":
|
||||
input.TowCost = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Cn. Acc. #":
|
||||
input.AuctionCustomerNo = value.Trim();
|
||||
break;
|
||||
case "Auction ID":
|
||||
break;
|
||||
case "Vehicle Decimal Grade Code":
|
||||
input.VehicleDecimalGradeCode = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Vehicle Grade":
|
||||
input.VehicleGrade = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Most Recent National Adjusted MMR Price":
|
||||
input.MMRNationalAdjustedPrice = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "Most Recent Regional Adjusted MMR Price":
|
||||
input.MMRRegionalAdjustedPrice = !string.IsNullOrWhiteSpace(value)
|
||||
? NumbersOnly<decimal>(value)
|
||||
: (decimal?) null;
|
||||
break;
|
||||
case "MMR":
|
||||
input.MMR = value.Trim();
|
||||
break;
|
||||
case "External CR Link":
|
||||
input.ConditionReportLink = _configuration.ConditionReportUrl + value;
|
||||
break;
|
||||
case "Open Text 1":
|
||||
input.AuctionAssignmentId =
|
||||
!string.IsNullOrWhiteSpace(value) ? int.Parse(value.Replace(",", "")) : -1;
|
||||
break;
|
||||
default:
|
||||
Log.Error("Got unknown field {0} with value {1} for ImsAutoFileData", fieldName,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failed to set field {fieldName} with value {value} for ImsAutoFileData");
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private static T NumbersOnly<T>(string val)
|
||||
{
|
||||
var formattedStr = Regex.Replace(val.Trim(), "[^0-9\\.]", "");
|
||||
if (string.IsNullOrWhiteSpace(formattedStr))
|
||||
formattedStr = "-1";
|
||||
return (T) Convert.ChangeType(formattedStr, typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using NotVisualBasic.FileIO;
|
||||
using Serilog;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services.AutoIms
|
||||
{
|
||||
public class ImsAutoFileNoteConverter : IImsAutoFileNoteConverter
|
||||
{
|
||||
public ImsAutoFileNoteConverter()
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<AuctionAssignmentNote> CsvToImsAutoFileNotes(Stream file)
|
||||
{
|
||||
List<AuctionAssignmentNote> listOfObjects = new List<AuctionAssignmentNote>();
|
||||
|
||||
using (CsvTextFieldParser tfp = new CsvTextFieldParser(file))
|
||||
{
|
||||
// Get Some Column Names
|
||||
string[] columns = tfp.ReadFields();
|
||||
|
||||
while (!tfp.EndOfData)
|
||||
{
|
||||
var fields = tfp.ReadFields();
|
||||
|
||||
if (!fields[0].Contains("------") && (fields.Any(x => x.Trim().Length > 0)))
|
||||
{
|
||||
var obj = new AuctionAssignmentNote();
|
||||
|
||||
for (var i = 0; i < fields.Length; i++)
|
||||
{
|
||||
obj = SetFieldByName(obj, columns[i].Trim(), fields[i].Trim());
|
||||
}
|
||||
|
||||
listOfObjects.Add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listOfObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the rows with only account and discard them, using the account no to update the other rows.
|
||||
* Each row in the CSV does not have CustomerAccountNo, only the first row of each set.
|
||||
* Further, if a row has a customer account no, it has nothing else.
|
||||
*/
|
||||
public IEnumerable<AuctionAssignmentNote> CompressIdentifyingRows(IEnumerable<AuctionAssignmentNote> csvNotes)
|
||||
{
|
||||
List<AuctionAssignmentNote> data = new List<AuctionAssignmentNote>();
|
||||
string accountNo = String.Empty;
|
||||
|
||||
foreach (var item in csvNotes)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.AuctionCustomerNo) && item.AuctionCustomerNo != accountNo)
|
||||
{
|
||||
accountNo = item.AuctionCustomerNo;
|
||||
// Skip account rows, unless they start showing up with data.
|
||||
if (string.IsNullOrWhiteSpace(item.Text))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(accountNo))
|
||||
{
|
||||
Log.Error($"No Account Number when processing notes row, {item.Text}");
|
||||
return null;
|
||||
}
|
||||
|
||||
item.AuctionCustomerNo = accountNo;
|
||||
data.Add(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Error compressing notes for auction accountNo: {accountNo}");
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public AuctionAssignmentNote SetFieldByName(AuctionAssignmentNote input, string fieldName, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (fieldName)
|
||||
{
|
||||
case "Cn. Acc. #":
|
||||
input.AuctionCustomerNo = value;
|
||||
break;
|
||||
case "Origin":
|
||||
input.Origin = value;
|
||||
break;
|
||||
case "Writer":
|
||||
input.Writer = value;
|
||||
break;
|
||||
case "Type":
|
||||
input.Type = value;
|
||||
break;
|
||||
case "Text":
|
||||
input.Text = value;
|
||||
break;
|
||||
case "Date Written":
|
||||
input.DateWritten = !string.IsNullOrWhiteSpace(value)
|
||||
? DateTime.Parse(value.Substring(0, value.Trim().Length - 4))
|
||||
: (DateTime?) null;
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Error("Got unknown field {fieldName} with value {value} for AuctionAssignmentNote");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to set field {fieldName} with value {value} for AuctionAssignmentNote.");
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user