using Microsoft.AspNetCore.Mvc.Rendering;
using PowderCoating.Core.Enums;
using PowderCoating.Core.Interfaces;
using PowderCoating.Shared.Constants;
namespace PowderCoating.Web.Helpers;
///
/// Centralizes the repeated DB queries and SelectListItem projections used by the accounting
/// controllers (Bills, Expenses). Each controller assigns only the properties it needs to ViewBag,
/// so the naming mismatch between controllers (BankAccounts vs PaymentAccounts) is harmless.
///
internal static class AccountingDropdownHelper
{
///
/// Loads vendors, accounts, payment methods, and active jobs in a single call.
/// Returns pre-projected SelectListItem collections so controllers avoid duplicating the
/// LINQ-to-SelectListItem transform.
///
internal static async Task LoadAsync(IUnitOfWork unitOfWork)
{
var vendors = await unitOfWork.Vendors.FindAsync(v => v.IsActive);
var allAccounts = await unitOfWork.Accounts.FindAsync(a => a.IsActive);
var jobs = await unitOfWork.Jobs.FindAsync(j =>
j.JobStatus.StatusCode != AppConstants.StatusCodes.Job.Completed &&
j.JobStatus.StatusCode != AppConstants.StatusCodes.Job.Cancelled &&
j.JobStatus.StatusCode != AppConstants.StatusCodes.Job.Delivered);
var accountLabel = (Core.Entities.Account a) => $"{a.AccountNumber} – {a.Name}";
return new AccountingDropdowns
{
Vendors = vendors
.OrderBy(v => v.CompanyName)
.Select(v => new SelectListItem(v.CompanyName, v.Id.ToString()))
.ToList(),
ExpenseAccounts = allAccounts
.Where(a => a.AccountType == AccountType.Expense ||
a.AccountType == AccountType.CostOfGoods)
.OrderBy(a => a.AccountNumber)
.Select(a => new SelectListItem(accountLabel(a), a.Id.ToString()))
.ToList(),
ExpenseAndAssetAccounts = allAccounts
.Where(a => a.AccountType == AccountType.Expense ||
a.AccountType == AccountType.CostOfGoods ||
a.AccountType == AccountType.Asset)
.OrderBy(a => a.AccountNumber)
.Select(a => new SelectListItem(accountLabel(a), a.Id.ToString()))
.ToList(),
ApAccounts = allAccounts
.Where(a => a.AccountSubType == AccountSubType.AccountsPayable)
.OrderBy(a => a.AccountNumber)
.Select(a => new SelectListItem(accountLabel(a), a.Id.ToString()))
.ToList(),
BankAccounts = allAccounts
.Where(a => a.AccountSubType == AccountSubType.Cash ||
a.AccountSubType == AccountSubType.Checking ||
a.AccountSubType == AccountSubType.Savings ||
a.AccountSubType == AccountSubType.CreditCard)
.OrderBy(a => a.AccountNumber)
.Select(a => new SelectListItem(accountLabel(a), a.Id.ToString()))
.ToList(),
PaymentMethods = Enum.GetValues()
.Select(m => new SelectListItem(m.ToString(), ((int)m).ToString()))
.ToList(),
ActiveJobs = jobs
.OrderBy(j => j.JobNumber)
.Select(j => new SelectListItem(
$"{j.JobNumber} – {j.Description ?? "No description"}",
j.Id.ToString()))
.ToList()
};
}
}
internal sealed class AccountingDropdowns
{
public IReadOnlyList Vendors { get; init; } = [];
/// Expense + Cost of Goods accounts (used by Expenses controller).
public IReadOnlyList ExpenseAccounts { get; init; } = [];
/// Expense + Cost of Goods + Asset accounts (used by Bills controller).
public IReadOnlyList ExpenseAndAssetAccounts { get; init; } = [];
/// Accounts Payable accounts (used by Bills controller).
public IReadOnlyList ApAccounts { get; init; } = [];
/// Cash, Checking, Savings, and Credit Card accounts.
public IReadOnlyList BankAccounts { get; init; } = [];
public IReadOnlyList PaymentMethods { get; init; } = [];
public IReadOnlyList ActiveJobs { get; init; } = [];
}