Solved the database transcation error

This commit is contained in:
ashutosh.nehete 2025-07-21 18:39:34 +05:30
parent f9213b6040
commit 1fffde6d7f
2 changed files with 51 additions and 56 deletions

View File

@ -250,8 +250,6 @@ namespace Marco.Pms.Services.Service
public async Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId) public async Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId)
{ {
_logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId);
// The entire operation is wrapped in a transaction to ensure data consistency.
await using var transaction = await _context.Database.BeginTransactionAsync();
try try
{ {
@ -301,7 +299,7 @@ namespace Marco.Pms.Services.Service
.Include(s => s.Status) .Include(s => s.Status)
.Include(s => s.NextStatus) .Include(s => s.NextStatus)
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(es => es.StatusId == Draft && es.Status != null); .Where(es => es.StatusId == Draft && es.Status != null).ToListAsync();
}); });
@ -329,11 +327,10 @@ namespace Marco.Pms.Services.Service
if (paidBy == null) validationErrors.Add("Paid by employee not found"); if (paidBy == null) validationErrors.Add("Paid by employee not found");
if (expenseType == null) validationErrors.Add("Expense Type not found."); if (expenseType == null) validationErrors.Add("Expense Type not found.");
if (paymentMode == null) validationErrors.Add("Payment Mode not found."); if (paymentMode == null) validationErrors.Add("Payment Mode not found.");
if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found."); if (!statusMapping.Any()) validationErrors.Add("Default status 'Draft' not found.");
if (validationErrors.Any()) if (validationErrors.Any())
{ {
await transaction.RollbackAsync();
var errorMessage = string.Join(" ", validationErrors); var errorMessage = string.Join(" ", validationErrors);
_logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage);
return ApiResponse<object>.ErrorResponse("Invalid input data.", errorMessage, 400); return ApiResponse<object>.ErrorResponse("Invalid input data.", errorMessage, 400);
@ -358,14 +355,13 @@ namespace Marco.Pms.Services.Service
// 5. Database Commit // 5. Database Commit
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
// 6. Transaction Commit var status = statusMapping.Select(sm => sm.Status).FirstOrDefault();
await transaction.CommitAsync(); var nextStatus = statusMapping.Select(sm => sm.NextStatus).ToList();
var response = _mapper.Map<ExpenseList>(expense); var response = _mapper.Map<ExpenseList>(expense);
response.PaidBy = _mapper.Map<BasicEmployeeVM>(paidBy); response.PaidBy = _mapper.Map<BasicEmployeeVM>(paidBy);
response.Project = _mapper.Map<ProjectInfoVM>(project); response.Project = _mapper.Map<ProjectInfoVM>(project);
response.Status = _mapper.Map<ExpensesStatusMasterVM>(statusMapping!.Status); response.Status = _mapper.Map<ExpensesStatusMasterVM>(status);
response.NextStatus = _mapper.Map<List<ExpensesStatusMasterVM>>(statusMapping!.NextStatus); response.NextStatus = _mapper.Map<List<ExpensesStatusMasterVM>>(nextStatus);
response.PaymentMode = _mapper.Map<PaymentModeMatserVM>(paymentMode); response.PaymentMode = _mapper.Map<PaymentModeMatserVM>(paymentMode);
response.ExpensesType = _mapper.Map<ExpensesTypeMasterVM>(expenseType); response.ExpensesType = _mapper.Map<ExpensesTypeMasterVM>(expenseType);
@ -374,7 +370,6 @@ namespace Marco.Pms.Services.Service
} }
catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation
{ {
await transaction.RollbackAsync();
_logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId);
return ApiResponse<object>.ErrorResponse("Invalid Request Data.", new return ApiResponse<object>.ErrorResponse("Invalid Request Data.", new
{ {
@ -391,7 +386,6 @@ namespace Marco.Pms.Services.Service
} }
catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure)
{ {
await transaction.RollbackAsync();
_logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId);
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", new return ApiResponse<object>.ErrorResponse("An internal server error occurred.", new
{ {

View File

@ -1,46 +1,47 @@
{ {
"Cors": { "Cors": {
"AllowedOrigins": "https://app.marcoaiot.com", "AllowedOrigins": "https://app.marcoaiot.com",
"AllowedMethods": "*", "AllowedMethods": "*",
"AllowedHeaders": "*" "AllowedHeaders": "*"
}, },
"Environment": { "Environment": {
"Name": "Production", "Name": "Production",
"Title": "" "Title": ""
}, },
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1" "DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1"
}, },
"SmtpSettings": { "SmtpSettings": {
"SmtpServer": "smtp.gmail.com", "SmtpServer": "smtp.gmail.com",
"Port": 587, "Port": 587,
"SenderName": "MarcoAIOT", "SenderName": "MarcoAIOT",
"SenderEmail": "marcoioitsoft@gmail.com", "SenderEmail": "marcoioitsoft@gmail.com",
"Password": "qrtq wfuj hwpp fhqr" "Password": "qrtq wfuj hwpp fhqr"
}, },
"AppSettings": { "AppSettings": {
"WebFrontendUrl": "https://app.marcoaiot.com", "WebFrontendUrl": "https://app.marcoaiot.com",
"ImagesBaseUrl": "https://app.marcoaiot.com" "ImagesBaseUrl": "https://app.marcoaiot.com"
}, },
"Jwt": { "Jwt": {
"Issuer": "https://app.marcoaiot.com", "Issuer": "https://app.marcoaiot.com",
"Audience": "https://app.marcoaiot.com", "Audience": "https://app.marcoaiot.com",
"Key": "sworffishhkjfa9dnfdndfu33infnajfj", "Key": "sworffishhkjfa9dnfdndfu33infnajfj",
"ExpiresInMinutes": 60, "ExpiresInMinutes": 60,
"RefreshTokenExpiresInDays": 7 "RefreshTokenExpiresInDays": 7
}, },
"MailingList": { "MailingList": {
"RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com", "RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com",
"ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com" "ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
}, },
"AWS": { "AWS": {
"AccessKey": "AKIARZDBH3VDMSUUY2FX", "AccessKey": "AKIARZDBH3VDMSUUY2FX",
"SecretKey": "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", "SecretKey": "NTS5XXgZINQbU6ctpNuLXtIY/Qk9GCgD9Rr5yNJP",
"Region": "us-east-1", "Region": "us-east-1",
"BucketName": "testenv-marco-pms-documents" "BucketName": "testenv-marco-pms-documents"
}, },
"MongoDB": { "MongoDB": {
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
"ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches" "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches",
} "ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?authSource=admin&socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500"
}
} }