Refactor: centralize accounting helpers, status constants, and query deduplication
- AccountingDropdownHelper: wired into BillsController and ExpensesController, replacing 35-40 lines of duplicated DB queries per controller - AppConstants.StatusCodes: added Job.* and Quote.* constants to replace all magic status strings across Jobs, Quotes, Appointments, OvenScheduler, AiQuickQuote, QuoteApproval, and AccountingDropdownHelper - AccountingRules: extracted IsNormalDebitBalance into shared Infrastructure helper; removed duplicate private method from AccountBalanceService and LedgerService (~50 lines deleted) - AccountDataExportController: extracted 9 Fetch*Async methods (superset of includes) so Add*Sheet and Build*Csv no longer duplicate DB queries; each entity is queried once regardless of whether XLSX or CSV format is requested - BillsController.Create and ExpensesController.Create wrapped in ExecuteInTransactionAsync; blob uploads moved after commit to keep financial data atomic and prevent orphaned blobs from rolling back - Number generators (Appointments, CreditMemo, OvenBatch) fixed from full-table GetAllAsync to prefix-filtered FindAsync Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using PowderCoating.Application.DTOs.Scheduling;
|
||||
@@ -6,6 +6,7 @@ using PowderCoating.Application.Interfaces;
|
||||
using PowderCoating.Core.Entities;
|
||||
using PowderCoating.Core.Enums;
|
||||
using PowderCoating.Core.Interfaces;
|
||||
using PowderCoating.Shared.Constants;
|
||||
using PowderCoating.Web.Hubs;
|
||||
|
||||
namespace PowderCoating.Web.Controllers;
|
||||
@@ -27,7 +28,7 @@ public class OvenSchedulerController : Controller
|
||||
/// </summary>
|
||||
private static readonly string[] QueueableStatuses =
|
||||
{
|
||||
"IN_PREPARATION", "SANDBLASTING", "MASKING_TAPING", "CLEANING", "COATING"
|
||||
AppConstants.StatusCodes.Job.InPreparation, AppConstants.StatusCodes.Job.Sandblasting, AppConstants.StatusCodes.Job.MaskingTaping, AppConstants.StatusCodes.Job.Cleaning, AppConstants.StatusCodes.Job.Coating
|
||||
};
|
||||
|
||||
public OvenSchedulerController(
|
||||
@@ -646,7 +647,7 @@ public class OvenSchedulerController : Controller
|
||||
foreach (var batchItem in batch.Items.Where(i => i.Status == OvenBatchItemStatus.Pending))
|
||||
batchItem.Status = OvenBatchItemStatus.InOven;
|
||||
|
||||
var inOvenStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == "IN_OVEN");
|
||||
var inOvenStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == AppConstants.StatusCodes.Job.InOven);
|
||||
if (inOvenStatus != null)
|
||||
{
|
||||
var jobIds = batch.Items.Select(i => i.JobId).Distinct().ToHashSet();
|
||||
@@ -693,8 +694,8 @@ public class OvenSchedulerController : Controller
|
||||
foreach (var batchItem in batch.Items.Where(i => i.Status == OvenBatchItemStatus.InOven))
|
||||
batchItem.Status = OvenBatchItemStatus.Completed;
|
||||
|
||||
var curingStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == "CURING");
|
||||
var coatingStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == "COATING");
|
||||
var curingStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == AppConstants.StatusCodes.Job.Curing);
|
||||
var coatingStatus = await _unitOfWork.JobStatusLookups.FirstOrDefaultAsync(s => s.StatusCode == AppConstants.StatusCodes.Job.Coating);
|
||||
|
||||
var jobIds = batch.Items.Select(i => i.JobId).Distinct().ToList();
|
||||
var allBatchedItems = await _unitOfWork.OvenBatchItems.GetAllAsync(false, i => i.Batch);
|
||||
@@ -771,15 +772,18 @@ public class OvenSchedulerController : Controller
|
||||
/// </summary>
|
||||
private async Task<string> GenerateBatchNumberAsync()
|
||||
{
|
||||
var yearMonth = DateTime.Now.ToString("yyMM");
|
||||
var all = await _unitOfWork.OvenBatches.GetAllAsync(ignoreQueryFilters: true);
|
||||
var prefix = $"OVN-{yearMonth}-";
|
||||
var maxSeq = all
|
||||
.Where(b => b.BatchNumber.StartsWith(prefix))
|
||||
.Select(b => int.TryParse(b.BatchNumber[prefix.Length..], out var n) ? n : 0)
|
||||
.DefaultIfEmpty(0)
|
||||
.Max();
|
||||
return $"{prefix}{(maxSeq + 1):D4}";
|
||||
var prefix = $"OVN-{DateTime.Now:yyMM}-";
|
||||
var last = (await _unitOfWork.OvenBatches.FindAsync(
|
||||
b => b.BatchNumber.StartsWith(prefix), ignoreQueryFilters: true))
|
||||
.OrderByDescending(b => b.BatchNumber)
|
||||
.Select(b => b.BatchNumber)
|
||||
.FirstOrDefault();
|
||||
|
||||
int next = 1;
|
||||
if (last != null && int.TryParse(last[prefix.Length..], out int num))
|
||||
next = num + 1;
|
||||
|
||||
return $"{prefix}{next:D4}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user