Ashutosh_Refactor #107
@ -1,7 +1,6 @@
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Dtos.Project;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Services.Helpers;
|
||||
using Marco.Pms.Services.Service;
|
||||
@ -11,7 +10,6 @@ using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace MarcoBMS.Services.Controllers
|
||||
@ -410,55 +408,24 @@ namespace MarcoBMS.Services.Controllers
|
||||
[HttpDelete("task/{id}")]
|
||||
public async Task<IActionResult> DeleteProjectTask(Guid id)
|
||||
{
|
||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
List<Guid> workAreaIds = new List<Guid>();
|
||||
WorkItem? task = await _context.WorkItems.AsNoTracking().Include(t => t.WorkArea).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId);
|
||||
if (task != null)
|
||||
// --- Step 1: Input Validation ---
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
if (task.CompletedWork == 0)
|
||||
{
|
||||
var assignedTask = await _context.TaskAllocations.Where(t => t.WorkItemId == id).ToListAsync();
|
||||
if (assignedTask.Count == 0)
|
||||
{
|
||||
_context.WorkItems.Remove(task);
|
||||
await _context.SaveChangesAsync();
|
||||
_logger.LogInfo("Task with ID {WorkItemId} has been successfully deleted.", task.Id);
|
||||
|
||||
var floorId = task.WorkArea?.FloorId;
|
||||
var floor = await _context.Floor.Include(f => f.Building).FirstOrDefaultAsync(f => f.Id == floorId);
|
||||
|
||||
|
||||
workAreaIds.Add(task.WorkAreaId);
|
||||
var projectId = floor?.Building?.ProjectId;
|
||||
|
||||
var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "WorkItem", WorkAreaIds = workAreaIds, Message = $"Task Deleted in Building: {floor?.Building?.Name}, on Floor: {floor?.FloorName}, in Area: {task.WorkArea?.AreaName} by {LoggedInEmployee.FirstName} {LoggedInEmployee.LastName}" };
|
||||
await _signalR.SendNotificationAsync(notification);
|
||||
await _cache.DeleteWorkItemByIdAsync(task.Id);
|
||||
if (projectId != null)
|
||||
{
|
||||
await _cache.DeleteProjectByIdAsync(projectId.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Task with ID {WorkItemId} is currently assigned and cannot be deleted.", task.Id);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Task is currently assigned and cannot be deleted.", "Task is currently assigned and cannot be deleted.", 400));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double percentage = (task.CompletedWork / task.PlannedWork) * 100;
|
||||
percentage = Math.Round(percentage, 2);
|
||||
_logger.LogWarning("Task with ID {WorkItemId} is {CompletionPercentage}% complete and cannot be deleted", task.Id, percentage);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse(System.String.Format("Task is {0}% complete and cannot be deleted", percentage), System.String.Format("Task is {0}% complete and cannot be deleted", percentage), 400));
|
||||
|
||||
}
|
||||
var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList();
|
||||
_logger.LogWarning("project Alocation called with invalid model state for list of projects. Errors: {Errors}", string.Join(", ", errors));
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid request data provided.", errors, 400));
|
||||
}
|
||||
else
|
||||
|
||||
// --- Step 2: Prepare data without I/O ---
|
||||
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var serviceResponse = await _projectServices.DeleteProjectTaskAsync(id, tenantId, loggedInEmployee);
|
||||
var response = serviceResponse.Response;
|
||||
var notification = serviceResponse.Notification;
|
||||
if (notification != null)
|
||||
{
|
||||
_logger.LogWarning("Task with ID {WorkItemId} not found ID database", id);
|
||||
await _signalR.SendNotificationAsync(notification);
|
||||
}
|
||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -1033,130 +1033,6 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
||||
|
||||
public async Task<ApiResponse<object>> ManageProjectInfra(List<InfraDto> infraDots, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
var responseData = new InfraVM { };
|
||||
string responseMessage = "";
|
||||
string message = "";
|
||||
List<Guid> projectIds = new List<Guid>();
|
||||
if (infraDots != null)
|
||||
{
|
||||
foreach (var item in infraDots)
|
||||
{
|
||||
if (item.Building != null)
|
||||
{
|
||||
|
||||
Building building = _mapper.Map<Building>(item.Building);
|
||||
building.TenantId = tenantId;
|
||||
|
||||
if (item.Building.Id == null)
|
||||
{
|
||||
//create
|
||||
_context.Buildings.Add(building);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.building = building;
|
||||
responseMessage = "Buliding Added Successfully";
|
||||
message = "Building Added";
|
||||
await _cache.AddBuildngInfra(building.ProjectId, building);
|
||||
}
|
||||
else
|
||||
{
|
||||
//update
|
||||
_context.Buildings.Update(building);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.building = building;
|
||||
responseMessage = "Buliding Updated Successfully";
|
||||
message = "Building Updated";
|
||||
await _cache.UpdateBuildngInfra(building.ProjectId, building);
|
||||
}
|
||||
projectIds.Add(building.ProjectId);
|
||||
}
|
||||
if (item.Floor != null)
|
||||
{
|
||||
Floor floor = _mapper.Map<Floor>(item.Floor);
|
||||
floor.TenantId = tenantId;
|
||||
bool isCreated = false;
|
||||
|
||||
if (item.Floor.Id == null)
|
||||
{
|
||||
//create
|
||||
_context.Floor.Add(floor);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.floor = floor;
|
||||
responseMessage = "Floor Added Successfully";
|
||||
message = "Floor Added";
|
||||
isCreated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//update
|
||||
_context.Floor.Update(floor);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.floor = floor;
|
||||
responseMessage = "Floor Updated Successfully";
|
||||
message = "Floor Updated";
|
||||
}
|
||||
Building? building = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == floor.BuildingId);
|
||||
var projectId = building?.ProjectId ?? Guid.Empty;
|
||||
projectIds.Add(projectId);
|
||||
message = $"{message} in Building: {building?.Name}";
|
||||
if (isCreated)
|
||||
{
|
||||
await _cache.AddBuildngInfra(projectId, floor: floor);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _cache.UpdateBuildngInfra(projectId, floor: floor);
|
||||
}
|
||||
}
|
||||
if (item.WorkArea != null)
|
||||
{
|
||||
WorkArea workArea = _mapper.Map<WorkArea>(item.WorkArea);
|
||||
workArea.TenantId = tenantId;
|
||||
bool isCreated = false;
|
||||
|
||||
if (item.WorkArea.Id == null)
|
||||
{
|
||||
//create
|
||||
_context.WorkAreas.Add(workArea);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.workArea = workArea;
|
||||
responseMessage = "Work Area Added Successfully";
|
||||
message = "Work Area Added";
|
||||
isCreated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//update
|
||||
_context.WorkAreas.Update(workArea);
|
||||
await _context.SaveChangesAsync();
|
||||
responseData.workArea = workArea;
|
||||
responseMessage = "Work Area Updated Successfully";
|
||||
message = "Work Area Updated";
|
||||
}
|
||||
Floor? floor = await _context.Floor.Include(f => f.Building).FirstOrDefaultAsync(f => f.Id == workArea.FloorId);
|
||||
var projectId = floor?.Building?.ProjectId ?? Guid.Empty;
|
||||
projectIds.Add(projectId);
|
||||
message = $"{message} in Building: {floor?.Building?.Name}, on Floor: {floor?.FloorName}";
|
||||
if (isCreated)
|
||||
{
|
||||
await _cache.AddBuildngInfra(projectId, workArea: workArea, buildingId: floor?.BuildingId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _cache.UpdateBuildngInfra(projectId, workArea: workArea, buildingId: floor?.BuildingId);
|
||||
}
|
||||
}
|
||||
}
|
||||
message = $"{message} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}";
|
||||
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Infra", ProjectIds = projectIds, Message = message };
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(responseData, responseMessage, 200);
|
||||
}
|
||||
return ApiResponse<object>.ErrorResponse("Invalid details.", "Infra Details are not valid.", 400);
|
||||
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
// 1. Guard Clause: Handle null or empty input gracefully.
|
||||
@ -1244,151 +1120,6 @@ namespace Marco.Pms.Services.Service
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages a batch of infrastructure changes (creates/updates for Buildings, Floors, and WorkAreas).
|
||||
/// This method is optimized to perform all database operations in a single, atomic transaction.
|
||||
/// </summary>
|
||||
public async Task<ApiResponse<object>> ManageProjectInfraAsync1(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
// --- Step 1: Input Validation ---
|
||||
if (infraDtos == null || !infraDtos.Any())
|
||||
{
|
||||
_logger.LogWarning("ManageProjectInfraAsync called with null or empty DTO list.");
|
||||
return ApiResponse<object>.ErrorResponse("Invalid details.", "Infrastructure data cannot be empty.", 400);
|
||||
}
|
||||
|
||||
_logger.LogInfo("Begin ManageProjectInfraAsync for {DtoCount} items, TenantId: {TenantId}, User: {UserId}", infraDtos.Count, tenantId, loggedInEmployee.Id);
|
||||
|
||||
// --- Step 2: Categorize DTOs by Type and Action ---
|
||||
var buildingsToCreateDto = infraDtos.Where(i => i.Building != null && i.Building.Id == null).Select(i => i.Building!).ToList();
|
||||
var buildingsToUpdateDto = infraDtos.Where(i => i.Building != null && i.Building.Id != null).Select(i => i.Building!).ToList();
|
||||
var floorsToCreateDto = infraDtos.Where(i => i.Floor != null && i.Floor.Id == null).Select(i => i.Floor!).ToList();
|
||||
var floorsToUpdateDto = infraDtos.Where(i => i.Floor != null && i.Floor.Id != null).Select(i => i.Floor!).ToList();
|
||||
var workAreasToCreateDto = infraDtos.Where(i => i.WorkArea != null && i.WorkArea.Id == null).Select(i => i.WorkArea!).ToList();
|
||||
var workAreasToUpdateDto = infraDtos.Where(i => i.WorkArea != null && i.WorkArea.Id != null).Select(i => i.WorkArea!).ToList();
|
||||
|
||||
_logger.LogDebug("Categorized DTOs...");
|
||||
|
||||
try
|
||||
{
|
||||
// --- Step 3: Fetch all required existing data in bulk ---
|
||||
|
||||
// Fetch existing entities to be updated
|
||||
var buildingIdsToUpdate = buildingsToUpdateDto.Select(d => d.Id!.Value).ToList();
|
||||
var existingBuildings = await _context.Buildings.Where(b => buildingIdsToUpdate.Contains(b.Id) && b.TenantId == tenantId).ToDictionaryAsync(b => b.Id);
|
||||
|
||||
var floorIdsToUpdate = floorsToUpdateDto.Select(d => d.Id!.Value).ToList();
|
||||
var existingFloors = await _context.Floor.Include(f => f.Building).Where(f => floorIdsToUpdate.Contains(f.Id) && f.TenantId == tenantId).ToDictionaryAsync(f => f.Id);
|
||||
|
||||
var workAreaIdsToUpdate = workAreasToUpdateDto.Select(d => d.Id!.Value).ToList();
|
||||
var existingWorkAreas = await _context.WorkAreas.Include(wa => wa.Floor!.Building).Where(wa => workAreaIdsToUpdate.Contains(wa.Id) && wa.TenantId == tenantId).ToDictionaryAsync(wa => wa.Id);
|
||||
|
||||
// Fetch parent entities for items being created to get their ProjectIds
|
||||
var buildingIdsForNewFloors = floorsToCreateDto.Select(f => f.BuildingId).ToList();
|
||||
var parentBuildingsForNewFloors = await _context.Buildings.Where(b => buildingIdsForNewFloors.Contains(b.Id)).ToDictionaryAsync(b => b.Id);
|
||||
|
||||
var floorIdsForNewWorkAreas = workAreasToCreateDto.Select(wa => wa.FloorId).ToList();
|
||||
var parentFloorsForNewWorkAreas = await _context.Floor.Include(f => f.Building).Where(f => floorIdsForNewWorkAreas.Contains(f.Id)).ToDictionaryAsync(f => f.Id);
|
||||
|
||||
_logger.LogInfo("Fetched existing entities and parents for new items.");
|
||||
|
||||
// --- Step 4: Aggregate all affected ProjectIds for Security Check ---
|
||||
var affectedProjectIds = new HashSet<Guid>();
|
||||
|
||||
// From buildings being created/updated
|
||||
buildingsToCreateDto.ForEach(b => affectedProjectIds.Add(b.ProjectId));
|
||||
foreach (var b in existingBuildings.Values) { affectedProjectIds.Add(b.ProjectId); }
|
||||
|
||||
// From floors being created/updated
|
||||
foreach (var f in floorsToCreateDto) { if (parentBuildingsForNewFloors.TryGetValue(f.BuildingId, out var b)) affectedProjectIds.Add(b.ProjectId); }
|
||||
foreach (var f in existingFloors.Values) { if (f.Building != null) affectedProjectIds.Add(f.Building.ProjectId); }
|
||||
|
||||
// From work areas being created/updated
|
||||
foreach (var wa in workAreasToCreateDto) { if (parentFloorsForNewWorkAreas.TryGetValue(wa.FloorId, out var f) && f.Building != null) affectedProjectIds.Add(f.Building.ProjectId); }
|
||||
foreach (var wa in existingWorkAreas.Values) { if (wa.Floor?.Building != null) affectedProjectIds.Add(wa.Floor.Building.ProjectId); }
|
||||
|
||||
// Security Check against the complete list of affected projects
|
||||
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageProjectInfra, loggedInEmployee.Id);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access DENIED for user {UserId} trying to manage infrastructure for projects.", loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to manage infrastructure for one or more of the specified projects.", 403);
|
||||
}
|
||||
|
||||
// --- Step 5: Process all logic IN MEMORY, tracking changes ---
|
||||
|
||||
// Process Buildings
|
||||
var createdBuildings = new List<Building>();
|
||||
foreach (var dto in buildingsToCreateDto)
|
||||
{
|
||||
var newBuilding = _mapper.Map<Building>(dto);
|
||||
newBuilding.TenantId = tenantId;
|
||||
createdBuildings.Add(newBuilding);
|
||||
}
|
||||
foreach (var dto in buildingsToUpdateDto) { if (existingBuildings.TryGetValue(dto.Id!.Value, out var b)) _mapper.Map(dto, b); }
|
||||
|
||||
// Process Floors
|
||||
var createdFloors = new List<Floor>();
|
||||
foreach (var dto in floorsToCreateDto)
|
||||
{
|
||||
var newFloor = _mapper.Map<Floor>(dto);
|
||||
newFloor.TenantId = tenantId;
|
||||
createdFloors.Add(newFloor);
|
||||
}
|
||||
foreach (var dto in floorsToUpdateDto) { if (existingFloors.TryGetValue(dto.Id!.Value, out var f)) _mapper.Map(dto, f); }
|
||||
|
||||
// Process WorkAreas
|
||||
var createdWorkAreas = new List<WorkArea>();
|
||||
foreach (var dto in workAreasToCreateDto)
|
||||
{
|
||||
var newWorkArea = _mapper.Map<WorkArea>(dto);
|
||||
newWorkArea.TenantId = tenantId;
|
||||
createdWorkAreas.Add(newWorkArea);
|
||||
}
|
||||
foreach (var dto in workAreasToUpdateDto) { if (existingWorkAreas.TryGetValue(dto.Id!.Value, out var wa)) _mapper.Map(dto, wa); }
|
||||
|
||||
// --- Step 6: Save all database changes in a SINGLE TRANSACTION ---
|
||||
if (createdBuildings.Any()) _context.Buildings.AddRange(createdBuildings);
|
||||
if (createdFloors.Any()) _context.Floor.AddRange(createdFloors);
|
||||
if (createdWorkAreas.Any()) _context.WorkAreas.AddRange(createdWorkAreas);
|
||||
|
||||
if (_context.ChangeTracker.HasChanges())
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
_logger.LogInfo("Database save successful.");
|
||||
}
|
||||
|
||||
// --- Step 7: Update Cache using the aggregated ProjectIds (Non-blocking) ---
|
||||
var finalProjectIds = affectedProjectIds.ToList();
|
||||
if (finalProjectIds.Any())
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInfo("Queuing background cache update for {ProjectCount} projects.", finalProjectIds.Count);
|
||||
// Assuming your cache service has a method to handle this.
|
||||
await _cache.RemoveProjectsAsync(finalProjectIds);
|
||||
_logger.LogInfo("Background cache update task completed for projects: {ProjectIds}", string.Join(", ", finalProjectIds));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred during the background cache update task for projects: {ProjectIds}", string.Join(", ", finalProjectIds));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- Step 8: Prepare and return a clear response ---
|
||||
var responseVm = new { /* ... as before ... */ };
|
||||
return ApiResponse<object>.SuccessResponse(responseVm, "Infrastructure changes processed successfully.", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An unexpected error occurred in ManageProjectInfraAsync.");
|
||||
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An unexpected error occurred.", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates or updates a batch of work items.
|
||||
/// This method is optimized to perform all database operations in a single, atomic transaction.
|
||||
@ -1512,60 +1243,88 @@ namespace Marco.Pms.Services.Service
|
||||
return ApiResponse<List<WorkItemVM>>.SuccessResponse(responseList, message, 200);
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
// 1. Fetch the task and its parent data in a single query.
|
||||
// This is still a major optimization, avoiding a separate query for the floor/building.
|
||||
WorkItem? task = await _context.WorkItems
|
||||
.AsNoTracking() // Use AsNoTracking because we will re-attach for deletion later.
|
||||
.Include(t => t.WorkArea)
|
||||
.ThenInclude(wa => wa!.Floor)
|
||||
.ThenInclude(f => f!.Building)
|
||||
.FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId);
|
||||
|
||||
//public async Task<IActionResult> DeleteProjectTask(Guid id)
|
||||
//{
|
||||
// var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
// List<Guid> workAreaIds = new List<Guid>();
|
||||
// WorkItem? task = await _context.WorkItems.AsNoTracking().Include(t => t.WorkArea).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId);
|
||||
// if (task != null)
|
||||
// {
|
||||
// if (task.CompletedWork == 0)
|
||||
// {
|
||||
// var assignedTask = await _context.TaskAllocations.Where(t => t.WorkItemId == id).ToListAsync();
|
||||
// if (assignedTask.Count == 0)
|
||||
// {
|
||||
// _context.WorkItems.Remove(task);
|
||||
// await _context.SaveChangesAsync();
|
||||
// _logger.LogInfo("Task with ID {WorkItemId} has been successfully deleted.", task.Id);
|
||||
// 2. Guard Clause: Handle non-existent task.
|
||||
if (task == null)
|
||||
{
|
||||
_logger.LogWarning("Attempted to delete a non-existent task with ID {WorkItemId}", id);
|
||||
return new ServiceResponse
|
||||
{
|
||||
Response = ApiResponse<object>.ErrorResponse("Task not found.", $"A task with ID {id} was not found.", 404)
|
||||
};
|
||||
}
|
||||
|
||||
// var floorId = task.WorkArea?.FloorId;
|
||||
// var floor = await _context.Floor.Include(f => f.Building).FirstOrDefaultAsync(f => f.Id == floorId);
|
||||
// 3. Guard Clause: Prevent deletion if work has started.
|
||||
if (task.CompletedWork > 0)
|
||||
{
|
||||
double percentage = Math.Round((task.CompletedWork / task.PlannedWork) * 100, 2);
|
||||
_logger.LogWarning("Task with ID {WorkItemId} is {CompletionPercentage}% complete and cannot be deleted.", task.Id, percentage);
|
||||
return new ServiceResponse
|
||||
{
|
||||
Response = ApiResponse<object>.ErrorResponse($"Task is {percentage}% complete and cannot be deleted.", "Deletion failed because the task has progress.", 400)
|
||||
};
|
||||
}
|
||||
|
||||
// 4. Guard Clause: Efficiently check if the task is assigned in a separate, optimized query.
|
||||
// AnyAsync() is highly efficient and translates to a `SELECT TOP 1` or `EXISTS` in SQL.
|
||||
bool isAssigned = await _context.TaskAllocations.AnyAsync(t => t.WorkItemId == id);
|
||||
if (isAssigned)
|
||||
{
|
||||
_logger.LogWarning("Task with ID {WorkItemId} is currently assigned and cannot be deleted.", task.Id);
|
||||
return new ServiceResponse
|
||||
{
|
||||
Response = ApiResponse<object>.ErrorResponse("Task is currently assigned and cannot be deleted.", "Deletion failed because the task is assigned to an employee.", 400)
|
||||
};
|
||||
}
|
||||
|
||||
// workAreaIds.Add(task.WorkAreaId);
|
||||
// var projectId = floor?.Building?.ProjectId;
|
||||
// --- Success Path: All checks passed, proceed with deletion ---
|
||||
|
||||
// var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "WorkItem", WorkAreaIds = workAreaIds, Message = $"Task Deleted in Building: {floor?.Building?.Name}, on Floor: {floor?.FloorName}, in Area: {task.WorkArea?.AreaName} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}" };
|
||||
// await _signalR.SendNotificationAsync(notification);
|
||||
// await _cache.DeleteWorkItemByIdAsync(task.Id);
|
||||
// if (projectId != null)
|
||||
// {
|
||||
// await _cache.DeleteProjectByIdAsync(projectId.Value);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _logger.LogWarning("Task with ID {WorkItemId} is currently assigned and cannot be deleted.", task.Id);
|
||||
// return BadRequest(ApiResponse<object>.ErrorResponse("Task is currently assigned and cannot be deleted.", "Task is currently assigned and cannot be deleted.", 400));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// double percentage = (task.CompletedWork / task.PlannedWork) * 100;
|
||||
// percentage = Math.Round(percentage, 2);
|
||||
// _logger.LogWarning("Task with ID {WorkItemId} is {CompletionPercentage}% complete and cannot be deleted", task.Id, percentage);
|
||||
// return BadRequest(ApiResponse<object>.ErrorResponse(System.String.Format("Task is {0}% complete and cannot be deleted", percentage), System.String.Format("Task is {0}% complete and cannot be deleted", percentage), 400));
|
||||
var building = task.WorkArea?.Floor?.Building;
|
||||
var notification = new
|
||||
{
|
||||
LoggedInUserId = loggedInEmployee.Id,
|
||||
Keyword = "WorkItem",
|
||||
WorkAreaIds = new[] { task.WorkAreaId },
|
||||
Message = $"Task Deleted in Building: {building?.Name ?? "N/A"}, on Floor: {task.WorkArea?.Floor?.FloorName ?? "N/A"}, in Area: {task.WorkArea?.AreaName ?? "N/A"} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}"
|
||||
};
|
||||
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _logger.LogWarning("Task with ID {WorkItemId} not found ID database", id);
|
||||
// }
|
||||
// return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
||||
//}
|
||||
// 5. Perform the database deletion.
|
||||
// We must attach a new instance or the original one without AsNoTracking.
|
||||
// Since we used AsNoTracking, we create a 'stub' entity for deletion.
|
||||
// This is more efficient than re-querying.
|
||||
_context.WorkItems.Remove(new WorkItem { Id = task.Id });
|
||||
await _context.SaveChangesAsync();
|
||||
_logger.LogInfo("Task with ID {WorkItemId} has been successfully deleted.", task.Id);
|
||||
|
||||
// 6. Perform cache operations concurrently.
|
||||
var cacheTasks = new List<Task>
|
||||
{
|
||||
_cache.DeleteWorkItemByIdAsync(task.Id)
|
||||
};
|
||||
|
||||
if (building?.ProjectId != null)
|
||||
{
|
||||
cacheTasks.Add(_cache.DeleteProjectByIdAsync(building.ProjectId));
|
||||
}
|
||||
await Task.WhenAll(cacheTasks);
|
||||
|
||||
// 7. Return the final success response.
|
||||
return new ServiceResponse
|
||||
{
|
||||
Notification = notification,
|
||||
Response = ApiResponse<object>.SuccessResponse(new { id = task.Id }, "Task deleted successfully.", 200)
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Helper Functions ===================================================================
|
||||
|
@ -23,6 +23,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<List<WorkItemVM>>> CreateProjectTaskAsync(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user