Create API base for delete expense API

This commit is contained in:
ashutosh.nehete 2025-07-23 17:22:19 +05:30
parent 4370d5a350
commit b6dfb30f92
3 changed files with 117 additions and 50 deletions

View File

@ -54,14 +54,6 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
/// <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
/// by leveraging async/await without unnecessary thread-pool switching via Task.Run.
/// </summary>
/// <param name="dto">The data transfer object containing expense details and attachments.</param>
/// <returns>An IActionResult indicating the result of the creation operation.</returns>
[HttpPost("create")] [HttpPost("create")]
public async Task<IActionResult> CreateExpense([FromBody] CreateExpensesDto model) public async Task<IActionResult> CreateExpense([FromBody] CreateExpensesDto model)
{ {
@ -92,8 +84,11 @@ namespace Marco.Pms.Services.Controllers
} }
[HttpDelete("delete/{id}")] [HttpDelete("delete/{id}")]
public void Delete(int id) public async Task<IActionResult> DeleteExpanse(Guid id)
{ {
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.DeleteExpanseAsync(id, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
} }
} }

View File

@ -702,47 +702,9 @@ namespace Marco.Pms.Services.Service
var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList(); var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList();
if (deleteBillAttachments.Any()) if (deleteBillAttachments.Any())
{ {
var documentIds = deleteBillAttachments.Select(d => d.DocumentId).ToList(); var documentIds = deleteBillAttachments.Select(d => d.DocumentId!.Value).ToList();
var attachmentTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
dbContext.BillAttachments.RemoveRange(attachments);
await dbContext.SaveChangesAsync();
});
var documentsTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
if (documents.Any())
{
dbContext.Documents.RemoveRange(documents);
await dbContext.SaveChangesAsync();
List<S3DeletionObject> deletionObject = new List<S3DeletionObject>();
foreach (var document in documents)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.S3Key
});
if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.ThumbS3Key
});
}
}
await _updateLogHelper.PushToS3DeletionAsync(deletionObject);
}
});
await Task.WhenAll(attachmentTask, documentsTask);
await DeleteAttachemnts(documentIds);
} }
} }
@ -805,8 +767,75 @@ namespace Marco.Pms.Services.Service
} }
} }
public void Delete(int id) 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);
var hasAprrovePermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
});
var hasAprrovePermission = await hasAprrovePermissionTask;
if (!hasAprrovePermission)
{
expenseQuery = expenseQuery.Where(e => e.CreatedById == loggedInEmployee.Id);
}
var existingExpense = await expenseQuery.FirstOrDefaultAsync();
if (existingExpense == null)
{
return ApiResponse<object>.ErrorResponse("Expense cannot be deleted", "Expense cannot be deleted", 400);
}
var documentIds = await _context.BillAttachments
.Where(ba => ba.ExpensesId == existingExpense.Id)
.Select(ba => ba.DocumentId)
.ToListAsync();
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense);
_context.Expenses.Remove(existingExpense);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while adding 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 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);
await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask);
return ApiResponse<object>.SuccessResponse("Success", "Expense Deleted Successfully", 200);
} }
#region =================================================================== Helper Functions =================================================================== #region =================================================================== Helper Functions ===================================================================
@ -1085,6 +1114,48 @@ namespace Marco.Pms.Services.Service
return (document, billAttachment); return (document, billAttachment);
} }
private async Task DeleteAttachemnts(List<Guid> documentIds)
{
var attachmentTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
dbContext.BillAttachments.RemoveRange(attachments);
await dbContext.SaveChangesAsync();
});
var documentsTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
if (documents.Any())
{
dbContext.Documents.RemoveRange(documents);
await dbContext.SaveChangesAsync();
List<S3DeletionObject> deletionObject = new List<S3DeletionObject>();
foreach (var document in documents)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.S3Key
});
if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key)
{
deletionObject.Add(new S3DeletionObject
{
Key = document.ThumbS3Key
});
}
}
await _updateLogHelper.PushToS3DeletionAsync(deletionObject);
}
});
await Task.WhenAll(attachmentTask, documentsTask);
}
#endregion #endregion
} }
} }

View File

@ -11,5 +11,6 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
} }
} }