Adding
This commit is contained in:
+461
@@ -0,0 +1,461 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Collections.RepoApi.Exceptions;
|
||||
using LCU.API.Collections.RepoApi.Models.Filters;
|
||||
using LCU.API.Collections.RepoApi.Models.Requests;
|
||||
using LCU.Shared.Collections.RepoApiLib.Exceptions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.Results;
|
||||
using LCU.Shared.Collections.RepoApiLib.Repositories;
|
||||
using LCU.Shared.Collections.RepoApiLib.WebServices.AutoIMS;
|
||||
using Serilog;
|
||||
using AuctionAssignment = LCU.Shared.Collections.RepoApiLib.Models.AuctionAssignment;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Services
|
||||
{
|
||||
public class AuctionAssignmentService : IAuctionAssignmentService
|
||||
{
|
||||
private readonly IAuctionAssignmentRepository _auctionAssignmentRepository;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IEmailer _emailer;
|
||||
private readonly IAutoImsWebService _autoImsWebService;
|
||||
private readonly IRepoAccountService _repoAccountService;
|
||||
|
||||
public AuctionAssignmentService(
|
||||
IAutoImsWebService autoImsWebService,
|
||||
IRepoAccountService repoAccountService,
|
||||
IAuctionAssignmentRepository auctionAssignmentRepository,
|
||||
IUnitOfWork unitOfWork,
|
||||
IEmailer emailer)
|
||||
{
|
||||
_autoImsWebService = autoImsWebService;
|
||||
_repoAccountService = repoAccountService;
|
||||
_auctionAssignmentRepository = auctionAssignmentRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_emailer = emailer;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<AuctionAssignment>> ListByFilterAsync(AuctionAssignmentFilter filter)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (filter.ReadyForFloorPrice)
|
||||
{
|
||||
return await _auctionAssignmentRepository.ListReadyForFloorPriceAsync();
|
||||
}
|
||||
return await _auctionAssignmentRepository.ListAllAsync(filter.Page, filter.Limit);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failure retrieving AuctionAssignments");
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<AuctionAssignment>> GetListByIdsAsync(IReadOnlyCollection<int> idSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _auctionAssignmentRepository.FindListByIdsAsync(idSet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure retrieving AuctionAssignments for ids: {@idSet}");
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AuctionAssignment> GetByIdAsync(int id)
|
||||
{
|
||||
AuctionAssignment auctionAssignment;
|
||||
try
|
||||
{
|
||||
auctionAssignment = await _auctionAssignmentRepository.FindByIdAsync(id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure retrieving AuctionAssignment with id: {id}");
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
|
||||
if (auctionAssignment == null)
|
||||
{
|
||||
throw new NotFoundException($" AuctionAssignment with {id} not found.");
|
||||
}
|
||||
|
||||
return auctionAssignment;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<AuctionAssignment>> GetByRepoIdAsync(int repoId)
|
||||
{
|
||||
// Ensure the repo exists. If it doesn't, a NFE should be thrown here
|
||||
await _repoAccountService.Get(repoId);
|
||||
try
|
||||
{
|
||||
return await _auctionAssignmentRepository.FindByRepoIdAsync(repoId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure retrieving AuctionAssignments by RepoId with RepoID: {repoId}");
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AuctionAssignmentPostRequest> SaveAsync(AuctionAssignmentPostRequest auctionAssignmentPostRequest)
|
||||
{
|
||||
Collateral primaryCollateral = auctionAssignmentPostRequest.Collaterals
|
||||
.First(collateral => collateral.CollateralId == auctionAssignmentPostRequest.PrimaryCollateralId);
|
||||
|
||||
string auctionCustomerNo;
|
||||
try
|
||||
{
|
||||
auctionCustomerNo = await GetAuctionCustomerNoAsync(auctionAssignmentPostRequest.AuctionAssignment.RepoId.Value, primaryCollateral.RefCollateralId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure retrieving Auction Customer Number with auctionAssignmentPostRequest {auctionAssignmentPostRequest}", auctionAssignmentPostRequest);
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
|
||||
// If active auction already exists, do not create
|
||||
var conflictingAuctionAssignments = await _findActiveAuctionsWithMatchingCollateral(primaryCollateral.RepoId, auctionAssignmentPostRequest.Collaterals);
|
||||
if (conflictingAuctionAssignments!= null && conflictingAuctionAssignments.Any())
|
||||
{
|
||||
throw new DuplicateResourceException("AuctionAssignment");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var auctionAssignmentsToCollaterals = CreateJoiningAuctionAssignmentToCollateralsList(
|
||||
auctionAssignmentPostRequest.AuctionAssignment, auctionAssignmentPostRequest.Collaterals);
|
||||
|
||||
auctionAssignmentPostRequest.AuctionAssignment.AuctionCustomerNo = auctionCustomerNo;
|
||||
auctionAssignmentPostRequest.AuctionAssignment.DateSubmitted = DateTime.Now;
|
||||
auctionAssignmentPostRequest.AuctionAssignment.CollateralVIN = primaryCollateral.Vin;
|
||||
auctionAssignmentPostRequest.AuctionAssignment.AuctionAssignmentToCollaterals = auctionAssignmentsToCollaterals;
|
||||
|
||||
auctionAssignmentPostRequest.AuctionAssignment = await _auctionAssignmentRepository.AddAsync(auctionAssignmentPostRequest.AuctionAssignment);
|
||||
|
||||
await _unitOfWork.CompleteAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure creating AuctionAssignment object: {auctionAssignmentPostRequest.AuctionAssignment}.", auctionAssignmentPostRequest.AuctionAssignment);
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await CreateAutoIMSAuction(primaryCollateral, auctionAssignmentPostRequest.VehicleLocation, auctionAssignmentPostRequest.AuctionAssignment);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure creating AutoIMS Auction with Primary Collateral: {primaryCollateral} Removing AuctionAssignment...", primaryCollateral);
|
||||
|
||||
try { _auctionAssignmentRepository.Remove(auctionAssignmentPostRequest.AuctionAssignment); }
|
||||
catch (Exception ex2) { Log.Error(ex2, $"Failure removing AuctionAssignment : {auctionAssignmentPostRequest.AuctionAssignment} after failed AutoIMS creation.", auctionAssignmentPostRequest.AuctionAssignment); }
|
||||
|
||||
throw new WebException("Failed to add auction assignment to AutoIMS.");
|
||||
}
|
||||
|
||||
return auctionAssignmentPostRequest;
|
||||
}
|
||||
|
||||
public async Task<AuctionAssignment> UpdateAsync(AuctionAssignment auctionAssignment)
|
||||
{
|
||||
var existingAuctionAssignment = await _auctionAssignmentRepository.FindByIdAsync(auctionAssignment.ID);
|
||||
|
||||
if (existingAuctionAssignment == null)
|
||||
{
|
||||
throw new NotFoundException($" Auction Assignment with id {auctionAssignment.ID} not found.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (existingAuctionAssignment.FloorPrice != auctionAssignment.FloorPrice)
|
||||
{
|
||||
await UpdateAuctionFloor(auctionAssignment, existingAuctionAssignment);
|
||||
}
|
||||
|
||||
if (existingAuctionAssignment.SentTitleDocsDate != auctionAssignment.SentTitleDocsDate)
|
||||
{
|
||||
await UpdateTitleSentDate(auctionAssignment, existingAuctionAssignment);
|
||||
}
|
||||
|
||||
if (existingAuctionAssignment.RedeemedDate != auctionAssignment.RedeemedDate)
|
||||
{
|
||||
await UpdateRedeemedDate(auctionAssignment, existingAuctionAssignment);
|
||||
}
|
||||
|
||||
if (existingAuctionAssignment.HoldStatus != auctionAssignment.HoldStatus || existingAuctionAssignment.HoldUntil != auctionAssignment.HoldUntil)
|
||||
{
|
||||
await UpdateHoldData(auctionAssignment, existingAuctionAssignment);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failed to fully update auction assignment with id {auctionAssignment.ID} in AutoIMS");
|
||||
throw new WebException("Failed to fully update auction assignment in AutoIMS.");
|
||||
}
|
||||
|
||||
return auctionAssignment;
|
||||
}
|
||||
|
||||
public async Task<string> GetAuctionCustomerNoAsync(int repoId, string refCollateralId)
|
||||
{
|
||||
RepoAccount repoAccount = await _repoAccountService.Get(repoId);
|
||||
Borrower primaryBorrower = repoAccount.Borrowers.Where((b) => b.OwnershipType == 6).FirstOrDefault();
|
||||
|
||||
if (primaryBorrower == null)
|
||||
{
|
||||
throw new NotFoundException($"Primary borrower for Repo Account {repoAccount.AccountNo} not found.");
|
||||
}
|
||||
|
||||
return primaryBorrower.IndividualId + '-' + refCollateralId;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to create an Auction through AutoIMS.
|
||||
*
|
||||
* It does not catch and will throw if anything goes wrong.
|
||||
* Assume lack of exception equals success.
|
||||
*/
|
||||
public async Task<WebServiceResponse> CreateAutoIMSAuction(
|
||||
Collateral collateral,
|
||||
VehicleLocation vehicleLocation,
|
||||
AuctionAssignment auctionAssignment)
|
||||
{
|
||||
|
||||
Vehicle vehicle = new Vehicle()
|
||||
{
|
||||
ClientAccountNumber = auctionAssignment.AuctionCustomerNo,
|
||||
VIN = collateral.Vin,
|
||||
Make = collateral.Make,
|
||||
Model = collateral.Model,
|
||||
ModelYear = collateral.Year.GetValueOrDefault(),
|
||||
BodyStyle = collateral.BodyStyle,
|
||||
Classification = collateral.VehicleType.GetValueOrDefault(),
|
||||
ClientField1 = auctionAssignment.ID + "",
|
||||
AuctionAssignment = new Shared.Collections.RepoApiLib.WebServices.AutoIMS.AuctionAssignment()
|
||||
{
|
||||
AuctionID = auctionAssignment.AuctionId,
|
||||
PickupDate = auctionAssignment.AvailablePickupDate.GetValueOrDefault().ToString("yyyy-MM-dd"),
|
||||
LegalSaleDate = auctionAssignment.LegalSaleDate.GetValueOrDefault().ToString("yyyy-MM-dd"),
|
||||
PickupOrDropOffNote = auctionAssignment.AuctionNotes,
|
||||
CleaningLevelRequested = auctionAssignment.CleaningLevel,
|
||||
},
|
||||
VehicleLocation = vehicleLocation,
|
||||
};
|
||||
|
||||
return await _autoImsWebService.PostVehicleAsync<Vehicle>(vehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to remove an Auction through AutoIMS.
|
||||
*
|
||||
* It does not catch and will throw if anything goes wrong.
|
||||
* Assume lack of exception equals success.
|
||||
*/
|
||||
public async Task<WebServiceResponse> RemoveAuctionFromAutoIMS(AuctionAssignment auctionAssignment)
|
||||
{
|
||||
return await _autoImsWebService.RemoveFromAuction(auctionAssignment.AuctionCustomerNo, auctionAssignment.CollateralVIN);
|
||||
}
|
||||
|
||||
public IEnumerable<AuctionAssignmentToCollateral> CreateJoiningAuctionAssignmentToCollateralsList(AuctionAssignment auctionAssignment, IEnumerable<Collateral> collaterals)
|
||||
{
|
||||
return (from collateral in collaterals
|
||||
select new AuctionAssignmentToCollateral
|
||||
{
|
||||
AuctionAssignment = auctionAssignment,
|
||||
Collateral = collateral
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to call AutoIMS with an auction floor, and will not update the
|
||||
* floor related values unless it succeeds
|
||||
*/
|
||||
public async Task UpdateAuctionFloor(AuctionAssignment auctionAssignmentInput,
|
||||
AuctionAssignment existingAssignment)
|
||||
{
|
||||
FloorPriceVehicle vehicle = new FloorPriceVehicle();
|
||||
vehicle.ClientAccountNumber = auctionAssignmentInput.AuctionCustomerNo;
|
||||
vehicle.VIN = auctionAssignmentInput.CollateralVIN;
|
||||
vehicle.AuctionAssignment.FloorPrice = auctionAssignmentInput.FloorPrice ?? 0;
|
||||
|
||||
WebServiceResponse response = await _autoImsWebService.PostVehicleAsync<FloorPriceVehicle>(vehicle);
|
||||
|
||||
existingAssignment.FloorPriceResponseCode = response?.Status.Code;
|
||||
existingAssignment.FloorPriceResponseDescription = response?.Status.Description;
|
||||
|
||||
if (response?.Status.ValidationError?.Any() ?? false)
|
||||
{
|
||||
foreach (var item in response.Status.ValidationError)
|
||||
{
|
||||
existingAssignment.FloorPriceSubmissionErrors +=
|
||||
"Code: " + item.Code + " Message: " + item.Message + "|";
|
||||
}
|
||||
|
||||
}
|
||||
else if (response?.Status.Code == 1)
|
||||
{
|
||||
// e-mail management on successfully accepted floor price change
|
||||
var isManualFloorSet = existingAssignment.FloorPriceValuesUsed == auctionAssignmentInput.FloorPriceValuesUsed;
|
||||
var repoAccount = await _repoAccountService.FindByAuctionAssignmentId(existingAssignment.ID);
|
||||
await _emailer.SendFloorPriceAcceptedEmail(isManualFloorSet, repoAccount?.AccountNo, existingAssignment.FloorPrice, auctionAssignmentInput.FloorPrice);
|
||||
|
||||
existingAssignment.FloorPrice = auctionAssignmentInput.FloorPrice;
|
||||
existingAssignment.FloorPriceValuesUsed = auctionAssignmentInput.FloorPriceValuesUsed;
|
||||
}
|
||||
|
||||
await _completeAuctionAssignmentUpdateTransaction(existingAssignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to call AutoIMS and set the title sent date, and will not update the
|
||||
* title sent related values unless it succeeds
|
||||
*/
|
||||
public async Task UpdateTitleSentDate(AuctionAssignment auctionAssignmentInput,
|
||||
AuctionAssignment existingAssignment)
|
||||
{
|
||||
WebServiceResponse response = await _autoImsWebService.TitleSent(auctionAssignmentInput.CollateralVIN);
|
||||
|
||||
existingAssignment.TitleSentResponseCode = response?.Status.Code;
|
||||
existingAssignment.TitleSentResponseDescription = response?.Status.Description;
|
||||
|
||||
if (response?.Status.ValidationError?.Any() ?? false)
|
||||
{
|
||||
foreach (var item in response.Status.ValidationError)
|
||||
{
|
||||
existingAssignment.TitleSentSubmissionErrors +=
|
||||
"Code: " + item.Code + " Message: " + item.Message + "|";
|
||||
}
|
||||
|
||||
}
|
||||
else if (response?.Status.Code == 1)
|
||||
{
|
||||
existingAssignment.SentTitleDocsDate = auctionAssignmentInput.SentTitleDocsDate;
|
||||
}
|
||||
|
||||
await _completeAuctionAssignmentUpdateTransaction(existingAssignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to call AutoIMS and set the redeemed date, and will not update the
|
||||
* redeemed date unless it succeeds
|
||||
*/
|
||||
public async Task UpdateRedeemedDate(AuctionAssignment auctionAssignmentInput,
|
||||
AuctionAssignment existingAssignment)
|
||||
{
|
||||
WebServiceResponse response = await _autoImsWebService.Redeem(auctionAssignmentInput.CollateralVIN);
|
||||
|
||||
if (response?.Status.ValidationError?.Any() ?? false)
|
||||
{
|
||||
foreach (var item in response.Status.ValidationError)
|
||||
{
|
||||
// There are no database columns for redemption submission errors so log the error
|
||||
Log.Error($"Redemption submission error. Code: {item.Code} Message: {item.Message} | { auctionAssignmentInput}");
|
||||
}
|
||||
|
||||
}
|
||||
else if (response?.Status.Code == 1)
|
||||
{
|
||||
existingAssignment.RedeemedDate = auctionAssignmentInput.RedeemedDate;
|
||||
}
|
||||
|
||||
await _completeAuctionAssignmentUpdateTransaction(existingAssignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to call AutoIMS to place a hold, and will not update the
|
||||
* hold related values unless it succeeds
|
||||
*/
|
||||
public async Task UpdateHoldData(AuctionAssignment auctionAssignmentInput,
|
||||
AuctionAssignment existingAssignment)
|
||||
{
|
||||
var holdStatus = auctionAssignmentInput.HoldStatus ?? 0;
|
||||
var holdUntil = auctionAssignmentInput.HoldUntil ?? DateTime.MinValue;
|
||||
|
||||
WebServiceResponse response = await _autoImsWebService.PlaceHold(auctionAssignmentInput.CollateralVIN, holdStatus, holdUntil);
|
||||
|
||||
if (response?.Status.ValidationError?.Any() ?? false)
|
||||
{
|
||||
foreach (var item in response.Status.ValidationError)
|
||||
{
|
||||
existingAssignment.SubmissionErrors +=
|
||||
"Code: " + item.Code + " Message: " + item.Message + "|";
|
||||
}
|
||||
|
||||
}
|
||||
else if (response?.Status.Code == 1)
|
||||
{
|
||||
existingAssignment.HoldStatus = auctionAssignmentInput.HoldStatus;
|
||||
existingAssignment.HoldUntil = auctionAssignmentInput.HoldUntil;
|
||||
}
|
||||
|
||||
await _completeAuctionAssignmentUpdateTransaction(existingAssignment);
|
||||
}
|
||||
|
||||
public async Task<AuctionAssignment> RemoveAuction(int id)
|
||||
{
|
||||
var auctionAssignment = await _auctionAssignmentRepository.FindByIdAsync(id);
|
||||
|
||||
if (auctionAssignment == null)
|
||||
{
|
||||
throw new NotFoundException($" Auction Assignment with id {id} not found.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await RemoveAuctionFromAutoIMS(auctionAssignment);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failed to remove auction assignment from AutoIMS {auctionAssignment.ID}");
|
||||
throw new WebException("Failed to remove auction assignment from AutoIMS.");
|
||||
}
|
||||
|
||||
auctionAssignment.IsActive = false;
|
||||
await _completeAuctionAssignmentUpdateTransaction(auctionAssignment);
|
||||
|
||||
return auctionAssignment;
|
||||
}
|
||||
|
||||
private async Task _completeAuctionAssignmentUpdateTransaction(AuctionAssignment auctionAssignment)
|
||||
{
|
||||
try
|
||||
{
|
||||
_auctionAssignmentRepository.Update(auctionAssignment);
|
||||
await _unitOfWork.CompleteAsync();
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
Log.Error(ex, $"SQL Failure updating Auction Assignment: {auctionAssignment}", auctionAssignment);
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Failure updating Auction Assignment: {auctionAssignment}", auctionAssignment);
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<AuctionAssignment>> _findActiveAuctionsWithMatchingCollateral(int repoId, IEnumerable<Collateral> collaterals)
|
||||
{
|
||||
var assignments = await _auctionAssignmentRepository.FindByRepoIdAsync(repoId);
|
||||
if (assignments != null && assignments.Any())
|
||||
{
|
||||
return assignments.Where(auctionAssignment => auctionAssignment.IsActive == true &&
|
||||
auctionAssignment.AuctionAssignmentToCollaterals.Any(aa2c => collaterals
|
||||
.Select(collateral => collateral.CollateralId)
|
||||
.Contains(aa2c.CollateralId)));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user