Merge master into dev: quote stat cards Converted fix
This commit is contained in:
@@ -33,10 +33,17 @@ public interface IQuoteRepository : IRepository<Quote>
|
||||
|
||||
/// <summary>
|
||||
/// Returns aggregate stat counts and total value for the Index view stat cards, scoped to the
|
||||
/// current company by the global query filter. Pass status ID sets (derived from QuoteStatusLookup)
|
||||
/// to classify open vs. approved/converted quotes.
|
||||
/// given <paramref name="companyId"/> (explicit predicate for defense in depth, in addition to
|
||||
/// the global query filter). Pass status ID sets (derived from QuoteStatusLookup) to classify
|
||||
/// open vs. approved/converted quotes.
|
||||
/// <para>
|
||||
/// <paramref name="excludedStatusId"/> drops quotes in that status (Converted) from every card so
|
||||
/// the stat strip reflects the same population as the default Index list, which hides Converted
|
||||
/// quotes. Without this, a converted quote (which cannot be deleted while a job is linked) inflates
|
||||
/// TotalValue and the approved count even though it never appears in the list.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
Task<QuoteIndexStats> GetIndexStatsAsync(List<int> openStatusIds, List<int> approvedConvertedStatusIds);
|
||||
Task<QuoteIndexStats> GetIndexStatsAsync(int companyId, List<int> openStatusIds, List<int> approvedConvertedStatusIds, int? excludedStatusId = null);
|
||||
|
||||
/// <summary>
|
||||
/// Loads quote items with their coat passes (InventoryItem + Vendor) and prep services for
|
||||
|
||||
@@ -69,10 +69,21 @@ public class QuoteRepository : Repository<Quote>, IQuoteRepository
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<QuoteIndexStats> GetIndexStatsAsync(List<int> openStatusIds, List<int> approvedConvertedStatusIds)
|
||||
public async Task<QuoteIndexStats> GetIndexStatsAsync(int companyId, List<int> openStatusIds, List<int> approvedConvertedStatusIds, int? excludedStatusId = null)
|
||||
{
|
||||
var stats = await _context.Quotes
|
||||
.Where(q => !q.IsDeleted)
|
||||
// Explicit CompanyId predicate (defense in depth) on top of the global tenant filter.
|
||||
var query = _context.Quotes
|
||||
.Where(q => q.CompanyId == companyId && !q.IsDeleted);
|
||||
|
||||
// Exclude the same status the default Index list hides (Converted) so the stat strip and the
|
||||
// visible list summarize the identical population — a converted quote left behind by a blocked
|
||||
// delete must not inflate the cards while being invisible in the list.
|
||||
if (excludedStatusId.HasValue)
|
||||
{
|
||||
query = query.Where(q => q.QuoteStatusId != excludedStatusId.Value);
|
||||
}
|
||||
|
||||
var stats = await query
|
||||
.Select(q => new { q.QuoteStatusId, q.Total })
|
||||
.ToListAsync();
|
||||
|
||||
|
||||
@@ -248,7 +248,10 @@ public class QuotesController : Controller
|
||||
var approvedConvertedIds = quoteStatuses
|
||||
.Where(s => s.StatusCode == AppConstants.StatusCodes.Quote.Approved || s.StatusCode == AppConstants.StatusCodes.Quote.Converted)
|
||||
.Select(s => s.Id).ToList();
|
||||
var indexStats = await _unitOfWork.Quotes.GetIndexStatsAsync(draftSentIds, approvedConvertedIds);
|
||||
// Exclude Converted from the stat cards so they match the default list (which hides Converted).
|
||||
var convertedStatusId = quoteStatuses
|
||||
.FirstOrDefault(s => s.StatusCode == AppConstants.StatusCodes.Quote.Converted)?.Id;
|
||||
var indexStats = await _unitOfWork.Quotes.GetIndexStatsAsync(companyId, draftSentIds, approvedConvertedIds, convertedStatusId);
|
||||
ViewBag.StatOpenCount = indexStats.OpenCount;
|
||||
ViewBag.StatApprovedCount = indexStats.ApprovedConvertedCount;
|
||||
ViewBag.StatTotalValue = indexStats.TotalValue;
|
||||
|
||||
Reference in New Issue
Block a user