253 lines
11 KiB
C#
253 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using LCU.API.Collections.RepoApi.Models.Responses;
|
|
using LCU.Shared.Collections.RepoApiLib.Models;
|
|
using LCU.Shared.Collections.RepoApiLib.Repositories;
|
|
using Serilog;
|
|
|
|
namespace LCU.API.Collections.RepoApi.Services
|
|
{
|
|
public class FactoidService : IFactoidService
|
|
{
|
|
private readonly IReportingRepository _reportingRepository;
|
|
private readonly IRepoAccountRepository _repoAccountRepository;
|
|
private readonly IImsAutoFileDataRepository _imsAutoFileDataRepository;
|
|
private const string O4RStatus = "O4R";
|
|
private const string RepoStatus = "REPO";
|
|
private const string RedeemedStatus = "REDEEMED";
|
|
|
|
public FactoidService(
|
|
IReportingRepository reportingRepository,
|
|
IRepoAccountRepository repoAccountRepository,
|
|
IImsAutoFileDataRepository imsAutoFileDataRepository)
|
|
{
|
|
_reportingRepository = reportingRepository;
|
|
_repoAccountRepository = repoAccountRepository;
|
|
_imsAutoFileDataRepository = imsAutoFileDataRepository;
|
|
}
|
|
|
|
public int FindAuctionIndex(IReadOnlyCollection<string> auctionHouses, string auctionId)
|
|
{
|
|
if (auctionId != null)
|
|
{
|
|
foreach (var item in auctionHouses.Select((value, index) => new {index, value}))
|
|
{
|
|
if (item.value == auctionId.Trim().ToLower())
|
|
{
|
|
return item.index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return auctionHouses.Count - 1;
|
|
}
|
|
|
|
|
|
public async Task<FactoidResponse> GetCurrentInventory()
|
|
{
|
|
var accountsInRepo = await _repoAccountRepository.FindByCurrentStatus(RepoStatus);
|
|
|
|
var numCollateral = accountsInRepo.Aggregate(0, (total, curAccount) =>
|
|
total += curAccount.Collaterals.Count());
|
|
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = numCollateral.ToString(),
|
|
Name = "Vehicles",
|
|
Description = "Current Inventory (REPO)",
|
|
FontAwesomeIcon = "fa-car",
|
|
Records = accountsInRepo
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetAllAccountsO4R()
|
|
{
|
|
var filteredRepoAccounts = await _reportingRepository.GetAllAccountsInO4R();
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = filteredRepoAccounts.Count().ToString(),
|
|
Name = "Accounts",
|
|
Description = "Total Accounts in O4R",
|
|
FontAwesomeIcon = "fa-car",
|
|
Records = filteredRepoAccounts
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetPercentFloorPrice(DateTime lowDateTime,
|
|
DateTime highDateTime)
|
|
{
|
|
var soldImsAccounts = await _imsAutoFileDataRepository.GetImsSoldRecordsForPeriod(lowDateTime, highDateTime);
|
|
|
|
decimal? percentFloor = 0m;
|
|
if (soldImsAccounts.Count() != 0)
|
|
{
|
|
percentFloor = soldImsAccounts.Select(x => x.GrossPercentFloor).Sum() / soldImsAccounts.Count;
|
|
}
|
|
|
|
var records = await _repoAccountRepository.FindByRepoIdAsync(soldImsAccounts.Select(x => x.RepoId.ToString()).ToList());
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = percentFloor?.ToString("#.#") + "%",
|
|
Name = "Percentage of Floor",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-money",
|
|
Records = records
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetRecentlyRedeemed(DateTime lowDate, DateTime highDate)
|
|
{
|
|
var filteredRepoAccounts = await _repoAccountRepository.FindByStatusChangeInPeriod(RedeemedStatus, lowDate, highDate);
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = filteredRepoAccounts.Count().ToString(),
|
|
Name = "Recently Redeemed",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-calendar",
|
|
Records = filteredRepoAccounts
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetAvgDaysO4RToREPO(DateTime lowDate, DateTime highDate)
|
|
{
|
|
var recentAccountsInREPO = await _repoAccountRepository.FindByStatusChangeInPeriod(RepoStatus, lowDate, highDate);
|
|
var avgDaysO4RtoRepo = GetAverageDaysBetweenStatuses(recentAccountsInREPO, RepoStatus, O4RStatus);
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = avgDaysO4RtoRepo != null ? avgDaysO4RtoRepo.ToString() : "N/A",
|
|
Name = "Avg. Days O4R to Repo",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-calendar",
|
|
Records = recentAccountsInREPO
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetGetAvgDaysDelqToO4R(DateTime lowDate, DateTime highDate)
|
|
{
|
|
IEnumerable<RepoAccount> recentAccountsInO4R = await _repoAccountRepository.FindByStatusChangeInPeriod(O4RStatus, lowDate, highDate);
|
|
|
|
var accountsWithoutDateDelinquent = recentAccountsInO4R.Where(account => account.DaysDelinquent == null);
|
|
if (accountsWithoutDateDelinquent.Count() > 0)
|
|
{
|
|
Log.Error($"Accounts found without DaysDelinquent when added: {accountsWithoutDateDelinquent} ", accountsWithoutDateDelinquent);
|
|
recentAccountsInO4R = recentAccountsInO4R.Except(accountsWithoutDateDelinquent);
|
|
}
|
|
|
|
var totalAccounts = recentAccountsInO4R.Count();
|
|
var avgDaysDelqToO4R = 0;
|
|
if (totalAccounts > 0)
|
|
{
|
|
var delqToO4RSum = recentAccountsInO4R.Aggregate(0, (sum, repoAccount) => sum += repoAccount.DaysDelinquent ?? 0);
|
|
avgDaysDelqToO4R = delqToO4RSum / totalAccounts;
|
|
}
|
|
|
|
return new FactoidResponse()
|
|
{
|
|
CumulativeValue = avgDaysDelqToO4R.ToString(),
|
|
Name = "Avg. Days Dlqt To O4R",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-calendar",
|
|
Records = recentAccountsInO4R.ToList()
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetGetAvgDaysRepoToSold(DateTime lowDate, DateTime highDate)
|
|
{
|
|
var recentAccountsSold = await _repoAccountRepository.FindByStatusChangeInPeriod("SOLD", lowDate, highDate);
|
|
var avgDaysRepoToSold = GetAverageDaysBetweenStatuses(recentAccountsSold, "SOLD", RepoStatus);
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = avgDaysRepoToSold != null ? avgDaysRepoToSold.ToString() : "N/A",
|
|
Name = "Avg. Days Repo to Sold",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-calendar",
|
|
Records = recentAccountsSold
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetCurrentlyOnHold()
|
|
{
|
|
var accountsOnHold = await _repoAccountRepository.GetCurrentAccountsOnHoldAtAuction();
|
|
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = accountsOnHold.Count().ToString(),
|
|
Name = "On Hold at Auction",
|
|
Description = "Accounts",
|
|
FontAwesomeIcon = "fa-car",
|
|
Records = accountsOnHold
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetRecentlyRepoed(DateTime lowDate, DateTime highDate)
|
|
{
|
|
var accountsRecentlyRepoed = await _repoAccountRepository.FindByStatusChangeInPeriod(RepoStatus, lowDate, highDate);
|
|
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = accountsRecentlyRepoed.Count().ToString(),
|
|
Name = "Recently Repoed",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-car",
|
|
Records = accountsRecentlyRepoed
|
|
};
|
|
}
|
|
|
|
public async Task<FactoidResponse> GetRecentlySold(DateTime lowDate, DateTime highDate)
|
|
{
|
|
var accountsRecentlySold = await _repoAccountRepository.FindByStatusChangeInPeriod("SOLD", lowDate, highDate);
|
|
|
|
return new FactoidResponse
|
|
{
|
|
CumulativeValue = accountsRecentlySold.Count().ToString(),
|
|
Name = "Recently Sold",
|
|
Description = "Last 30 Days",
|
|
FontAwesomeIcon = "fa-car",
|
|
Records = accountsRecentlySold
|
|
};
|
|
}
|
|
|
|
// Get the average day difference between two status changes.
|
|
// If the accounts given don't have valid to and from status, those accounts are ignored from the calulcation.
|
|
// However, if calling this array, the accounts SHOULD have valid status changes.
|
|
private int? GetAverageDaysBetweenStatuses(IEnumerable<RepoAccount> repoAccount, string statusTo, string statusFrom)
|
|
{
|
|
IEnumerable<int?> daysBetweenStatuses = repoAccount.Select(
|
|
(account) => GetDaysBetweenStatuses(account, statusTo, statusFrom));
|
|
|
|
var validRepos = daysBetweenStatuses.Aggregate(0, (sum, days) => sum += days != null ? 1 : 0);
|
|
var sumOfDays = daysBetweenStatuses.Aggregate(0, (sum, days) => sum += days != null ? days.Value : 0);
|
|
|
|
if (validRepos == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return sumOfDays / validRepos;
|
|
}
|
|
|
|
// If either status cannot be found, return null, indicating an that days could not be calculated.
|
|
// If both the from status and to status are found, floor their difference of dates.
|
|
private int? GetDaysBetweenStatuses(RepoAccount repoAccount, string newStatus, string oldStatus)
|
|
{
|
|
var fromStatusDate = GetLatestStatusChange(repoAccount, oldStatus)?.ChangedDate;
|
|
var toStatusDate = GetLatestStatusChange(repoAccount, newStatus)?.ChangedDate;
|
|
|
|
if (toStatusDate != null && fromStatusDate != null)
|
|
{
|
|
return (int) Math.Floor(toStatusDate.Value.Subtract(fromStatusDate.Value).TotalDays);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private RepoStatusChange GetLatestStatusChange(RepoAccount repoAccount, string status)
|
|
{
|
|
return (
|
|
from statusChange in repoAccount.RepoStatusChanges
|
|
where string.Equals(statusChange.StatusTo, status, StringComparison.CurrentCultureIgnoreCase)
|
|
select statusChange).LastOrDefault();
|
|
}
|
|
}
|
|
} |