Files
2026-04-20 14:47:24 -05:00

356 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
using LCU.API.Collections.RepoApi.Exceptions;
using LCU.API.Collections.RepoApi.Models;
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.Producer;
using LCU.Shared.Collections.RepoApiLib.Models.Results;
using LCU.Shared.Collections.RepoApiLib.Repositories;
using Serilog;
namespace LCU.API.Collections.RepoApi.Services
{
public class RepoAccountService : IRepoAccountService
{
private readonly IRepoAccountRepository _repoAccountRepository;
private readonly IRepoStatusChangeRepository _repoStatusChangeRepository;
private readonly IRepoManualStatusRepository _repoManualStatusRepository;
private readonly IUnitOfWork _unitOfWork;
public RepoAccountService(
IRepoAccountRepository repoAccountRepository,
IRepoStatusChangeRepository repoStatusChangeRepository,
IRepoManualStatusRepository repoManualStatusRepository,
IUnitOfWork unitOfWork)
{
_repoAccountRepository = repoAccountRepository;
_repoStatusChangeRepository = repoStatusChangeRepository;
_repoManualStatusRepository = repoManualStatusRepository;
_unitOfWork = unitOfWork;
}
public async Task<PagedResult<RepoAccount>> ListAll(PageFilter pageFilter, RepoAccountPostFilter repoAccountFilter)
{
try
{
return await _repoAccountRepository.ListAsync(
repoAccountFilter != null ? repoAccountFilter.RepoIdList : new List<int?>(),
pageFilter.Page,
pageFilter.Limit,
repoAccountFilter?.Status,
repoAccountFilter?.AuctionHouseId,
repoAccountFilter?.RepoCompanyId,
repoAccountFilter?.OnlyOpenAccounts);
}
catch (Exception ex)
{
Log.Error(ex, "Failure retrieving RepoAccounts");
throw new ServerErrorException();
}
}
public async Task<RepoAccount> FindByAuctionAssignmentId(int auctionAssignmentId)
{
try
{
return await _repoAccountRepository.FindByAuctionAssignmentIdAsync(auctionAssignmentId);
}
catch (Exception ex)
{
Log.Error(ex, "Failure retrieving RepoAccount");
throw new ServerErrorException();
}
}
public async Task<RepoAccount> SaveAsync(RepoAccount repoAccount)
{
try
{
var newAccount = await _repoAccountRepository.AddAsync(repoAccount);
RepoStatusChange change = new RepoStatusChange()
{
RepoId = newAccount.RepoId,
ChangedBy = "System",
StatusFrom = "None",
StatusTo = repoAccount.Status,
ChangedDate = DateTime.Now
};
await _repoStatusChangeRepository.AddAsync(change);
await _unitOfWork.CompleteAsync();
return repoAccount;
}
catch (Exception ex)
{
Log.Error(ex, $"Failure saving Repo Account: {repoAccount}", repoAccount);
throw new ServerErrorException();
}
}
public async Task<RepoAccount> Get(int id)
{
RepoAccount repoAccount;
try
{
repoAccount = await _repoAccountRepository.FindByIdAsync(id);
}
catch (Exception ex)
{
Log.Error(ex, $"Failure retrieving Repo Account with id: {id}");
throw new ServerErrorException();
}
if (repoAccount == null)
{
throw new NotFoundException($" Repo Accounts with id {id} not found.");
}
return repoAccount;
}
public async Task<IReadOnlyCollection<RepoAccount>> GetByAccountNo(string accountNo)
{
IReadOnlyCollection<RepoAccount> repoAccounts;
try
{
repoAccounts = await _repoAccountRepository.FindByAccountNoAsync(accountNo);
}
catch (Exception ex)
{
Log.Error(ex, $"Failure retrieving Repo Account by accountNo with accountNo: {accountNo}");
throw new ServerErrorException();
}
if (repoAccounts == null || !repoAccounts.Any())
{
throw new NotFoundException($" Repo Accounts with id {accountNo} not found.");
}
return repoAccounts;
}
public async Task<RepoAccount> UpdateAsync(RepoAccount repoAccount, AppUser currentUser)
{
var existingRepoAccount = await _repoAccountRepository.FindByIdAsync(repoAccount.RepoId);
if (existingRepoAccount == null)
{
throw new NotFoundException($"Repo Account with repoId {repoAccount.RepoId} not found.");
}
var originalStatus = existingRepoAccount.Status;
existingRepoAccount.AccountLastProcessed = repoAccount.AccountLastProcessed;
existingRepoAccount.AccountNo = repoAccount.AccountNo;
existingRepoAccount.AccountTypeCode = repoAccount.AccountTypeCode;
existingRepoAccount.Balance = repoAccount.Balance;
existingRepoAccount.Bankruptcy = repoAccount.Bankruptcy;
existingRepoAccount.Borrowers = repoAccount.Borrowers;
existingRepoAccount.Branch = repoAccount.Branch;
// Only one field can change in collaterals when updating the account.
if (existingRepoAccount.Collaterals != null)
{
foreach (var collateral in existingRepoAccount.Collaterals)
{
var newCollateral =
repoAccount.Collaterals.FirstOrDefault(x => x.CollateralId == collateral.CollateralId);
if (newCollateral != null)
{
collateral.RetitledInLandmarkName = newCollateral.RetitledInLandmarkName;
}
}
}
// existingRepoAccount.Collaterals = repoAccount.Collaterals; This will fail, save separately.
existingRepoAccount.Collector = repoAccount.Collector;
existingRepoAccount.CurrentDelinquentAmount = repoAccount.CurrentDelinquentAmount;
existingRepoAccount.DateClosed = repoAccount.DateClosed;
existingRepoAccount.DateFirstDelinquent = repoAccount.DateFirstDelinquent;
existingRepoAccount.DateFirstIntellect = repoAccount.DateFirstIntellect;
existingRepoAccount.DaysDelinquent = repoAccount.DaysDelinquent;
existingRepoAccount.DelinquentAmount = repoAccount.DelinquentAmount;
existingRepoAccount.DueToPayDate = repoAccount.DueToPayDate;
existingRepoAccount.LastPaymentDate = repoAccount.LastPaymentDate;
existingRepoAccount.LoanNo = repoAccount.LoanNo;
existingRepoAccount.LstPmtAmt = repoAccount.LstPmtAmt;
existingRepoAccount.ManualRedemptionDate = repoAccount.ManualRedemptionDate;
existingRepoAccount.MemberNo = repoAccount.MemberNo;
existingRepoAccount.O4RDate = repoAccount.O4RDate;
existingRepoAccount.OrigAmount = repoAccount.OrigAmount;
existingRepoAccount.OrigAccountTypeCode = repoAccount.OrigAccountTypeCode;
existingRepoAccount.PaidSkipAmount = repoAccount.PaidSkipAmount;
existingRepoAccount.PrimaryIndividualId = repoAccount.PrimaryIndividualId;
existingRepoAccount.RedemptionExpiredDate = repoAccount.RedemptionExpiredDate;
existingRepoAccount.RefundStatus = repoAccount.RefundStatus;
existingRepoAccount.RequiredPaymentAmount = repoAccount.RequiredPaymentAmount;
existingRepoAccount.ReferenceId = repoAccount.ReferenceId;
existingRepoAccount.ReferenceCaseId = repoAccount.ReferenceCaseId;
existingRepoAccount.ReferenceStatus = repoAccount.ReferenceStatus;
existingRepoAccount.Status = repoAccount.Status;
existingRepoAccount.SubStatus = repoAccount.SubStatus;
existingRepoAccount.WrittenOffDate = repoAccount.WrittenOffDate;
existingRepoAccount.SixtyPlusCollectorId = repoAccount.SixtyPlusCollectorId;
try
{
_repoAccountRepository.Update(existingRepoAccount);
if (originalStatus != repoAccount.Status)
{
var change = new RepoStatusChange()
{
RepoId = repoAccount.RepoId,
ChangedBy = currentUser.FirstName + " " + currentUser.LastName,
StatusFrom = originalStatus,
StatusTo = repoAccount.Status,
ChangedDate = DateTime.Now
};
await _repoStatusChangeRepository.AddAsync(change);
}
await _unitOfWork.CompleteAsync();
return await _repoAccountRepository.FindByIdAsync(repoAccount.RepoId);
}
catch (SqlException ex)
{
Log.Error(ex, $"SQL Failure updating Repo Account: {repoAccount}", repoAccount);
throw new ServerErrorException();
}
catch (Exception ex)
{
Log.Error(ex, $"Failure updating Repo Account: {repoAccount}", repoAccount);
throw new ServerErrorException();
}
}
public async Task<RepoAccount> DeleteAsync(int id)
{
RepoAccount existingRepoAccount;
try
{
existingRepoAccount = await _repoAccountRepository.FindByIdAsync(id);
}
catch(Exception ex)
{
Log.Error(ex, $"Error finding an existing repo to delete with account ID: {id}");
throw new ServerErrorException();
}
if (existingRepoAccount == null)
{
throw new NotFoundException($" Repo Account with id {id} not found.");
}
try
{
_repoAccountRepository.Remove(existingRepoAccount);
await _unitOfWork.CompleteAsync();
return existingRepoAccount;
}
catch (SqlException ex)
{
Log.Error(ex, $"SQL Failure deleting Repo Account with id: {id}", id);
throw new ServerErrorException();
}
catch (Exception ex)
{
Log.Error(ex, $"Failure deleting Repo Account with id: {id}", id);
throw new ServerErrorException();
}
}
public async Task<IReadOnlyCollection<ProcessingItem>> GetItemsForProcessing()
{
try
{
var watchStatus = await _repoManualStatusRepository.ListWatchStatusesAsync();
var repoAccountNos = await _repoAccountRepository.GetItemsForProcessing(watchStatus);
return repoAccountNos;
}
catch (Exception ex)
{
Log.Error(ex, "Failure getting Repo Account Nos for polling");
throw new ServerErrorException();
}
}
public async Task<IReadOnlyCollection<RepoAccount>> SearchRepoAccounts(string searchPhrase, int maxAllowedResults)
{
try
{
var matchedRepoAccounts = await _repoAccountRepository.SearchRepoAccounts(searchPhrase, maxAllowedResults);
return matchedRepoAccounts;
}
catch (MaxItemException ex)
{
Log.Error(ex, $"Search Phrase Returned More Items Than Max (${maxAllowedResults}) searchPhrase:{searchPhrase}", searchPhrase);
throw new MaxItemException(ex.ItemCount);
}
catch (Exception ex)
{
Log.Error(ex, $"Failure Searching For Repo Accounts searchPhrase: {searchPhrase}", searchPhrase);
throw new ServerErrorException();
}
}
public async Task<RepoAccount> GetNewestOpenAccount(string accountNo)
{
IReadOnlyCollection<RepoAccount> repoAccounts;
try
{
repoAccounts = await _repoAccountRepository.FindByAccountNoAsync(accountNo);
}
catch (Exception ex)
{
Log.Error(ex, $"Failure retrieving Repo Account by accountNo with accountNo: {accountNo}");
throw new ServerErrorException();
}
if (repoAccounts == null || !repoAccounts.Any())
{
// You can't throw here, it's not an exception case, there simply isn't an account. (404)
Log.Debug($" Repo Accounts with id {accountNo} not found.");
return null;
}
return SelectFirstOpenAccount(repoAccounts);
}
/**
* Attempts to select the repo account that should be updated. Since we have to go by AccountNo and there
* may be more than one. Try to return an open account, and log if it detects more than one.
*/
public RepoAccount SelectFirstOpenAccount(IReadOnlyCollection<RepoAccount> repoAccounts)
{
if (repoAccounts.Count == 1)
{
return repoAccounts.First();
}
RepoAccount openAccount = null;
foreach (var repoAccount in repoAccounts.OrderBy(x => x.RepoId))
{
if (repoAccount.DateClosed == null)
{
if (openAccount != null)
{
Log.Fatal($"Multiple -OPEN- Repos with AccountNo: {openAccount.AccountNo}, {openAccount.RepoId} / {repoAccount.RepoId}");
return openAccount;
}
openAccount = repoAccount;
}
}
if (openAccount != null)
{
return openAccount;
}
return repoAccounts.OrderByDescending(x => x.DateClosed).ToList().FirstOrDefault();
}
}
}