Added proper logs to all Expesne APIs

This commit is contained in:
ashutosh.nehete 2025-07-23 18:02:12 +05:30
parent ae1222bb96
commit 8b5b0aed4c

View File

@ -56,6 +56,7 @@ namespace Marco.Pms.Services.Service
_mapper = mapper;
}
#region =================================================================== Get Functions ===================================================================
/// <summary>
/// Retrieves a paginated list of expenses based on user permissions and optional filters.
@ -159,9 +160,6 @@ namespace Marco.Pms.Services.Service
{
expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById));
}
}
// 4. --- Apply Ordering and Pagination ---
@ -247,11 +245,13 @@ namespace Marco.Pms.Services.Service
expenseDetails = await _cache.AddExpenseByIdAsync(id, tenantId);
if (expenseDetails == null)
{
_logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id);
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
}
}
var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails);
_logger.LogInfo("Employee {EmployeeId} successfully fetched expense details with ID {ExpenseId}", loggedInEmployee.Id, vm.Id);
return ApiResponse<object>.SuccessResponse(vm, "Successfully fetched the details of expense", 200);
}
@ -272,13 +272,12 @@ namespace Marco.Pms.Services.Service
}, 500);
}
}
public async Task<ApiResponse<object>> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId)
{
try
{
var supplerNameList = await _context.Expenses.Where(e => e.TenantId == tenantId).Select(e => e.SupplerName).Distinct().ToListAsync();
_logger.LogInfo("Employee {EmployeeId} fetched list of organizations in a tenant {TenantId}", loggedInEmployee.Id, tenantId);
_logger.LogInfo("Employee {EmployeeId} fetched list of suppler names from expenses in a tenant {TenantId}", loggedInEmployee.Id, tenantId);
return ApiResponse<object>.SuccessResponse(supplerNameList, $"{supplerNameList.Count} records of suppler names fetched from expense", 200);
}
catch (DbUpdateException dbEx)
@ -299,6 +298,10 @@ namespace Marco.Pms.Services.Service
}
}
#endregion
#region =================================================================== Post Functions ===================================================================
/// <summary>
/// Creates a new expense entry along with its bill attachments.
/// This operation is transactional and performs validations and file uploads concurrently for optimal performance
@ -633,6 +636,8 @@ namespace Marco.Pms.Services.Service
UpdatedAt = DateTime.UtcNow
}, Collection);
var cacheUpdateTask = _cache.ReplaceExpenseAsync(existingExpense);
// Task to get all possible next statuses from the *new* current state to help the UI.
// NOTE: This now fetches a list of all possible next states, which is more useful for a UI.
var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t =>
@ -650,7 +655,7 @@ namespace Marco.Pms.Services.Service
});
}).Unwrap();
await Task.WhenAll(mongoDBTask, getNextStatusesTask);
await Task.WhenAll(mongoDBTask, getNextStatusesTask, cacheUpdateTask);
var nextPossibleStatuses = await getNextStatusesTask;
@ -677,6 +682,11 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.SuccessResponse(response, "Status updated, but a post-processing error occurred.");
}
}
#endregion
#region =================================================================== Put Functions ===================================================================
public async Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId)
{
var existingExpense = await _context.Expenses
@ -696,6 +706,7 @@ namespace Marco.Pms.Services.Service
if (existingExpense == null)
{
_logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but not found in database", id);
return ApiResponse<object>.ErrorResponse("Expense not found", "Expense not found", 404);
}
@ -722,14 +733,73 @@ namespace Marco.Pms.Services.Service
if (newBillAttachments.Any())
{
await ProcessAndUploadAttachmentsAsync(newBillAttachments, existingExpense, loggedInEmployee.Id, tenantId);
await _context.SaveChangesAsync();
try
{
await _context.SaveChangesAsync();
_logger.LogInfo("{Count} New attachments added while updating expense {ExpenseId} by employee {EmployeeId}",
newBillAttachments.Count, existingExpense.Id, loggedInEmployee.Id);
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while adding new attachments during updating expense");
return ApiResponse<object>.ErrorResponse("Databsae Exception", new
{
Message = dbEx.Message,
StackTrace = dbEx.StackTrace,
Source = dbEx.Source,
InnerException = new
{
Message = dbEx.InnerException?.Message,
StackTrace = dbEx.InnerException?.StackTrace,
Source = dbEx.InnerException?.Source,
}
}, 500);
}
}
var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList();
if (deleteBillAttachments.Any())
{
var documentIds = deleteBillAttachments.Select(d => d.DocumentId!.Value).ToList();
await DeleteAttachemnts(documentIds);
try
{
await DeleteAttachemnts(documentIds);
_logger.LogInfo("{Count} Attachments deleted while updating expense {ExpenseId} by employee {EmployeeId}",
deleteBillAttachments.Count, existingExpense.Id, loggedInEmployee.Id);
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense");
return ApiResponse<object>.ErrorResponse("Databsae Exception", new
{
Message = dbEx.Message,
StackTrace = dbEx.StackTrace,
Source = dbEx.Source,
InnerException = new
{
Message = dbEx.InnerException?.Message,
StackTrace = dbEx.InnerException?.StackTrace,
Source = dbEx.InnerException?.Source,
}
}, 500);
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception occured while deleting attachments during updating expense");
return ApiResponse<object>.ErrorResponse("Exception occured while deleting attachments during updating expense ", new
{
Message = ex.Message,
StackTrace = ex.StackTrace,
Source = ex.Source,
InnerException = new
{
Message = ex.InnerException?.Message,
StackTrace = ex.InnerException?.StackTrace,
Source = ex.InnerException?.Source,
}
}, 500);
}
}
}
@ -791,6 +861,11 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.SuccessResponse(response, "Status updated, but a post-processing error occurred.");
}
}
#endregion
#region =================================================================== Delete Functions ===================================================================
public async Task<ApiResponse<object>> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId)
{
var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id && e.TenantId == tenantId);
@ -811,7 +886,16 @@ namespace Marco.Pms.Services.Service
var existingExpense = await expenseQuery.FirstOrDefaultAsync();
if (existingExpense == null)
{
return ApiResponse<object>.ErrorResponse("Expense cannot be deleted", "Expense cannot be deleted", 400);
var message = hasAprrovePermission ? "Expenses not found" : "Expense cannot be deleted";
if (hasAprrovePermission)
{
_logger.LogWarning("Employee {EmployeeId} attempted to delete expense {ExpenseId}, but not found in database", loggedInEmployee.Id, id);
}
else
{
_logger.LogWarning("Employee {EmployeeId} attempted to delete expense {ExpenseId}, Which is created by another employee", loggedInEmployee.Id, id);
}
return ApiResponse<object>.ErrorResponse(message, message, 400);
}
var documentIds = await _context.BillAttachments
.Where(ba => ba.ExpensesId == existingExpense.Id)
@ -824,10 +908,11 @@ namespace Marco.Pms.Services.Service
try
{
await _context.SaveChangesAsync();
_logger.LogInfo("Employeee {EmployeeId} successfully deleted the expense {EmpenseId}", loggedInEmployee.Id, id);
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while adding expense");
_logger.LogError(dbEx, "Databsae Exception occured while deleting expense");
return ApiResponse<object>.ErrorResponse("Databsae Exception", new
{
Message = dbEx.Message,
@ -841,27 +926,64 @@ namespace Marco.Pms.Services.Service
}
}, 500);
}
var attachmentDeletionTask = Task.Run(async () =>
try
{
await DeleteAttachemnts(documentIds);
});
var attachmentDeletionTask = Task.Run(async () =>
{
await DeleteAttachemnts(documentIds);
});
var cacheTask = Task.Run(async () =>
{
await _cache.DeleteExpenseAsync(id, tenantId);
});
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
{
EntityId = existingExpense.Id.ToString(),
UpdatedById = loggedInEmployee.Id.ToString(),
OldObject = existingEntityBson,
UpdatedAt = DateTime.UtcNow
}, Collection);
var cacheTask = Task.Run(async () =>
{
await _cache.DeleteExpenseAsync(id, tenantId);
});
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
{
EntityId = existingExpense.Id.ToString(),
UpdatedById = loggedInEmployee.Id.ToString(),
OldObject = existingEntityBson,
UpdatedAt = DateTime.UtcNow
}, Collection);
await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask);
await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask);
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense");
return ApiResponse<object>.ErrorResponse("Databsae Exception", new
{
Message = dbEx.Message,
StackTrace = dbEx.StackTrace,
Source = dbEx.Source,
InnerException = new
{
Message = dbEx.InnerException?.Message,
StackTrace = dbEx.InnerException?.StackTrace,
Source = dbEx.InnerException?.Source,
}
}, 500);
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception occured while deleting attachments during updating expense");
return ApiResponse<object>.ErrorResponse("Exception occured while deleting attachments during updating expense ", new
{
Message = ex.Message,
StackTrace = ex.StackTrace,
Source = ex.Source,
InnerException = new
{
Message = ex.InnerException?.Message,
StackTrace = ex.InnerException?.StackTrace,
Source = ex.InnerException?.Source,
}
}, 500);
}
return ApiResponse<object>.SuccessResponse("Success", "Expense Deleted Successfully", 200);
}
#endregion
#region =================================================================== Helper Functions ===================================================================
private async Task<List<ExpenseList>> GetAllExpnesRelatedTables(List<Expenses> model)