Added the APi to get count of pending expenses
This commit is contained in:
parent
548e714ea9
commit
590476a8aa
@ -801,11 +801,18 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return await _permission.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
return await _permission.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
await Task.WhenAll(hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask); // [Parallel Await]
|
var hasManagePermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await _permission.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask, hasManagePermissionTask); // [Parallel Await]
|
||||||
|
|
||||||
var hasReviewPermission = hasReviewPermissionTask.Result;
|
var hasReviewPermission = hasReviewPermissionTask.Result;
|
||||||
var hasApprovePermission = hasApprovePermissionTask.Result;
|
var hasApprovePermission = hasApprovePermissionTask.Result;
|
||||||
var hasProcessPermission = hasProcessPermissionTask.Result;
|
var hasProcessPermission = hasProcessPermissionTask.Result;
|
||||||
|
var hasManagePermission = hasManagePermissionTask.Result;
|
||||||
|
|
||||||
_logger.LogInfo(
|
_logger.LogInfo(
|
||||||
"Permissions resolved: Review={Review}, Approve={Approve}, Process={Process}",
|
"Permissions resolved: Review={Review}, Approve={Approve}, Process={Process}",
|
||||||
@ -813,61 +820,92 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
// Build base query: read-only, tenant-scoped
|
// Build base query: read-only, tenant-scoped
|
||||||
var baseQuery = _context.Expenses
|
var baseQuery = _context.Expenses
|
||||||
.AsNoTracking() // Reduce tracking overhead for read-only list
|
|
||||||
.Where(e => e.IsActive && e.TenantId == tenantId); // [Base Filter]
|
|
||||||
|
|
||||||
// Important: fix operator precedence by grouping OR conditions
|
|
||||||
// Pending means Draft always, plus role-gated statuses
|
|
||||||
var pendingQuery = baseQuery
|
|
||||||
.Include(e => e.PaidBy)
|
|
||||||
.Include(e => e.CreatedBy)
|
|
||||||
.Include(e => e.ProcessedBy)
|
|
||||||
.Include(e => e.ApprovedBy)
|
|
||||||
.Include(e => e.ReviewedBy)
|
|
||||||
.Include(e => e.PaymentMode)
|
|
||||||
.Include(e => e.Project)
|
|
||||||
.Include(e => e.PaymentMode)
|
|
||||||
.Include(e => e.ExpensesType)
|
|
||||||
.Include(e => e.Status)
|
.Include(e => e.Status)
|
||||||
.AsNoTracking()
|
.AsNoTracking() // Reduce tracking overhead for read-only list
|
||||||
.Where(e =>
|
.Where(e => e.IsActive && e.TenantId == tenantId && e.StatusId != Processed && e.Status != null); // [Base Filter]
|
||||||
(e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id)
|
|
||||||
|| (hasReviewPermission && e.StatusId == Review)
|
|
||||||
|| (hasApprovePermission && e.StatusId == Approve)
|
|
||||||
|| (hasProcessPermission && e.StatusId == ProcessPending)); // [Correct Precedence]
|
|
||||||
|
|
||||||
// Project to DTO in SQL to avoid heavy Include graph.
|
// Project to DTO in SQL to avoid heavy Include graph.
|
||||||
if (projectId.HasValue)
|
if (projectId.HasValue)
|
||||||
pendingQuery = pendingQuery.Where(e => e.ProjectId == projectId);
|
baseQuery = baseQuery.Where(e => e.ProjectId == projectId);
|
||||||
|
|
||||||
// Prefer ProjectTo when profiles exist; otherwise project minimal fields
|
// Prefer ProjectTo when profiles exist; otherwise project minimal fields
|
||||||
var response = await pendingQuery
|
var expenses = await baseQuery
|
||||||
.Where(e => e.Status != null && e.ExpensesType != null && e.PaymentMode != null && e.Project != null && e.CreatedBy != null)
|
|
||||||
.Select(e => new
|
|
||||||
{
|
|
||||||
Id = e.Id,
|
|
||||||
Amount = e.Amount,
|
|
||||||
TransactionDate = e.TransactionDate,
|
|
||||||
StatusId = e.StatusId,
|
|
||||||
StatusName = e.Status!.Name,
|
|
||||||
ExpenseTypeName = e.ExpensesType!.Name,
|
|
||||||
PaymentModeName = e.PaymentMode!.Name,
|
|
||||||
ProjectName = e.Project!.Name,
|
|
||||||
CreatedByName = $"{e.CreatedBy!.FirstName} {e.CreatedBy.LastName}",
|
|
||||||
ReviewedByName = e.ReviewedBy != null ? $"{e.ReviewedBy.FirstName} {e.ReviewedBy.LastName}" : null,
|
|
||||||
ApprovedByName = e.ApprovedBy != null ? $"{e.ApprovedBy.FirstName} {e.ApprovedBy.LastName}" : null,
|
|
||||||
ProcessedByName = e.ProcessedBy != null ? $"{e.ProcessedBy.FirstName} {e.ProcessedBy.LastName}" : null,
|
|
||||||
PaidByName = e.PaidBy != null ? $"{e.PaidBy.FirstName} {e.PaidBy.LastName}" : null
|
|
||||||
})
|
|
||||||
.OrderByDescending(x => x.TransactionDate)
|
|
||||||
.ToListAsync(); // Single round-trip; no Include needed for this shape
|
.ToListAsync(); // Single round-trip; no Include needed for this shape
|
||||||
|
|
||||||
|
var draftExpenses = expenses.Where(e => e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id).ToList();
|
||||||
|
var reviewExpenses = expenses.Where(e => (hasReviewPermission || e.CreatedById == loggedInEmployee.Id) && e.StatusId == Review).ToList();
|
||||||
|
var approveExpenses = expenses.Where(e => (hasApprovePermission || e.CreatedById == loggedInEmployee.Id) && e.StatusId == Approve).ToList();
|
||||||
|
var processPendingExpenses = expenses.Where(e => (hasProcessPermission || e.CreatedById == loggedInEmployee.Id) && e.StatusId == ProcessPending).ToList();
|
||||||
|
var submitedExpenses = expenses.Where(e => e.StatusId != Draft && e.CreatedById == loggedInEmployee.Id).ToList();
|
||||||
|
|
||||||
|
if (hasManagePermission)
|
||||||
|
{
|
||||||
|
var response = new
|
||||||
|
{
|
||||||
|
Draft = new
|
||||||
|
{
|
||||||
|
Count = draftExpenses.Count,
|
||||||
|
TotalAmount = draftExpenses.Sum(e => e.Amount)
|
||||||
|
},
|
||||||
|
ReviewPending = new
|
||||||
|
{
|
||||||
|
Count = reviewExpenses.Count,
|
||||||
|
TotalAmount = reviewExpenses.Sum(e => e.Amount)
|
||||||
|
},
|
||||||
|
ApprovePending = new
|
||||||
|
{
|
||||||
|
Count = approveExpenses.Count,
|
||||||
|
TotalAmount = approveExpenses.Sum(e => e.Amount)
|
||||||
|
},
|
||||||
|
ProcessPending = new
|
||||||
|
{
|
||||||
|
Count = processPendingExpenses.Count,
|
||||||
|
TotalAmount = processPendingExpenses.Sum(e => e.Amount)
|
||||||
|
},
|
||||||
|
Submited = new
|
||||||
|
{
|
||||||
|
Count = submitedExpenses.Count,
|
||||||
|
TotalAmount = submitedExpenses.Sum(e => e.Amount)
|
||||||
|
}
|
||||||
|
};
|
||||||
_logger.LogInfo(
|
_logger.LogInfo(
|
||||||
"GetPendingExpenseListAsync completed. TenantId={TenantId}, Count={Count}",
|
"GetPendingExpenseListAsync completed. TenantId={TenantId}",
|
||||||
tenantId, response.Count); // [Completion Log]
|
tenantId); // [Completion Log]
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Pending Expenses fetched successfully", 200)); // [Success Response]
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Pending Expenses fetched successfully", 200)); // [Success Response]
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var response = new
|
||||||
|
{
|
||||||
|
Draft = new
|
||||||
|
{
|
||||||
|
Count = draftExpenses.Count
|
||||||
|
},
|
||||||
|
ReviewPending = new
|
||||||
|
{
|
||||||
|
Count = reviewExpenses.Count
|
||||||
|
},
|
||||||
|
ApprovePending = new
|
||||||
|
{
|
||||||
|
Count = approveExpenses.Count
|
||||||
|
},
|
||||||
|
ProcessPending = new
|
||||||
|
{
|
||||||
|
Count = processPendingExpenses.Count
|
||||||
|
},
|
||||||
|
Submited = new
|
||||||
|
{
|
||||||
|
Count = submitedExpenses.Count
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_logger.LogInfo(
|
||||||
|
"GetPendingExpenseListAsync completed. TenantId={TenantId}",
|
||||||
|
tenantId); // [Completion Log]
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Pending Expenses fetched successfully", 200)); // [Success Response]
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("GetPendingExpenseListAsync canceled by client. TenantId={TenantId}", tenantId); // [Cancel Log]
|
_logger.LogWarning("GetPendingExpenseListAsync canceled by client. TenantId={TenantId}", tenantId); // [Cancel Log]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user