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; } = []; }