Optimized the Manage infra API in Project Controller
This commit is contained in:
parent
57b7f941e6
commit
eabd31f8cf
@ -95,6 +95,13 @@ namespace Marco.Pms.CacheHelper
|
|||||||
var result = await _projetCollection.DeleteOneAsync(filter);
|
var result = await _projetCollection.DeleteOneAsync(filter);
|
||||||
return result.DeletedCount > 0;
|
return result.DeletedCount > 0;
|
||||||
}
|
}
|
||||||
|
public async Task<bool> RemoveProjectsFromCacheAsync(List<Guid> projectIds)
|
||||||
|
{
|
||||||
|
var stringIds = projectIds.Select(id => id.ToString()).ToList();
|
||||||
|
var filter = Builders<ProjectMongoDB>.Filter.In(p => p.Id, stringIds);
|
||||||
|
var result = await _projetCollection.DeleteManyAsync(filter);
|
||||||
|
return result.DeletedCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------- Project InfraStructure -------------------------------------------------------
|
// ------------------------------------------------------- Project InfraStructure -------------------------------------------------------
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
|
|
||||||
namespace Marco.Pms.Model.Dtos.Project
|
namespace Marco.Pms.Model.Dtos.Project
|
||||||
{
|
{
|
||||||
public class BuildingDot
|
public class BuildingDto
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
|
|
||||||
namespace Marco.Pms.Model.Dtos.Project
|
namespace Marco.Pms.Model.Dtos.Project
|
||||||
{
|
{
|
||||||
public class FloorDot
|
public class FloorDto
|
||||||
{
|
{
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
namespace Marco.Pms.Model.Dtos.Project
|
|
||||||
{
|
|
||||||
public class InfraDot
|
|
||||||
{
|
|
||||||
public BuildingDot? Building { get; set; }
|
|
||||||
public FloorDot? Floor { get; set; }
|
|
||||||
public WorkAreaDot? WorkArea { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
9
Marco.Pms.Model/Dtos/Projects/InfraDto.cs
Normal file
9
Marco.Pms.Model/Dtos/Projects/InfraDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Project
|
||||||
|
{
|
||||||
|
public class InfraDto
|
||||||
|
{
|
||||||
|
public BuildingDto? Building { get; set; }
|
||||||
|
public FloorDto? Floor { get; set; }
|
||||||
|
public WorkAreaDto? WorkArea { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
|
|
||||||
namespace Marco.Pms.Model.Dtos.Project
|
namespace Marco.Pms.Model.Dtos.Project
|
||||||
{
|
{
|
||||||
public class WorkAreaDot
|
public class WorkAreaDto
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
@ -5,7 +5,7 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
{
|
{
|
||||||
public static class BuildingMapper
|
public static class BuildingMapper
|
||||||
{
|
{
|
||||||
public static Building ToBuildingFromBuildingDto(this BuildingDot model, Guid tenantId)
|
public static Building ToBuildingFromBuildingDto(this BuildingDto model, Guid tenantId)
|
||||||
{
|
{
|
||||||
return new Building
|
return new Building
|
||||||
{
|
{
|
||||||
@ -20,7 +20,7 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
|
|
||||||
public static class FloorMapper
|
public static class FloorMapper
|
||||||
{
|
{
|
||||||
public static Floor ToFloorFromFloorDto(this FloorDot model, Guid tenantId)
|
public static Floor ToFloorFromFloorDto(this FloorDto model, Guid tenantId)
|
||||||
{
|
{
|
||||||
return new Floor
|
return new Floor
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
|
|
||||||
public static class WorAreaMapper
|
public static class WorAreaMapper
|
||||||
{
|
{
|
||||||
public static WorkArea ToWorkAreaFromWorkAreaDto(this WorkAreaDot model, Guid tenantId)
|
public static WorkArea ToWorkAreaFromWorkAreaDto(this WorkAreaDto model, Guid tenantId)
|
||||||
{
|
{
|
||||||
return new WorkArea
|
return new WorkArea
|
||||||
{
|
{
|
||||||
|
8
Marco.Pms.Model/Utilities/ServiceResponse.cs
Normal file
8
Marco.Pms.Model/Utilities/ServiceResponse.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Utilities
|
||||||
|
{
|
||||||
|
public class ServiceResponse
|
||||||
|
{
|
||||||
|
public object? Notification { get; set; }
|
||||||
|
public ApiResponse<object> Response { get; set; } = ApiResponse<object>.ErrorResponse("");
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Dtos.Project;
|
using Marco.Pms.Model.Dtos.Project;
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Mapper;
|
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Projects;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Projects;
|
|
||||||
using Marco.Pms.Services.Helpers;
|
using Marco.Pms.Services.Helpers;
|
||||||
using Marco.Pms.Services.Service;
|
using Marco.Pms.Services.Service;
|
||||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
@ -359,6 +357,30 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
||||||
|
|
||||||
|
[HttpPost("manage-infra")]
|
||||||
|
public async Task<IActionResult> ManageProjectInfra(List<InfraDto> infraDtos)
|
||||||
|
{
|
||||||
|
// --- Step 1: Input Validation ---
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 2: Prepare data without I/O ---
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var serviceResponse = await _projectServices.ManageProjectInfraAsync(infraDtos, tenantId, loggedInEmployee);
|
||||||
|
var response = serviceResponse.Response;
|
||||||
|
var notification = serviceResponse.Notification;
|
||||||
|
if (notification != null)
|
||||||
|
{
|
||||||
|
await _signalR.SendNotificationAsync(notification);
|
||||||
|
}
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("task")]
|
[HttpPost("task")]
|
||||||
public async Task<IActionResult> CreateProjectTask([FromBody] List<WorkItemDto> workItemDtos)
|
public async Task<IActionResult> CreateProjectTask([FromBody] List<WorkItemDto> workItemDtos)
|
||||||
{
|
{
|
||||||
@ -439,134 +461,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("manage-infra")]
|
|
||||||
public async Task<IActionResult> ManageProjectInfra(List<InfraDot> infraDots)
|
|
||||||
{
|
|
||||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
||||||
|
|
||||||
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 = item.Building.ToBuildingFromBuildingDto(tenantId);
|
|
||||||
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 = item.Floor.ToFloorFromFloorDto(tenantId);
|
|
||||||
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 = item.WorkArea.ToWorkAreaFromWorkAreaDto(tenantId);
|
|
||||||
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 };
|
|
||||||
|
|
||||||
await _signalR.SendNotificationAsync(notification);
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(responseData, responseMessage, 200));
|
|
||||||
}
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid details.", "Infra Details are not valid.", 400));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -478,6 +478,18 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task RemoveProjectsAsync(List<Guid> projectIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _projectCache.RemoveProjectsFromCacheAsync(projectIds);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error occured while deleting project list from to Cache");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------ Project Infrastructure Cache ---------------------------------------
|
// ------------------------------------ Project Infrastructure Cache ---------------------------------------
|
||||||
|
|
||||||
|
@ -51,6 +51,9 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
CreateMap<ProjectsAllocationDto, ProjectAllocation>();
|
CreateMap<ProjectsAllocationDto, ProjectAllocation>();
|
||||||
CreateMap<ProjectAllocation, ProjectAllocationVM>();
|
CreateMap<ProjectAllocation, ProjectAllocationVM>();
|
||||||
|
|
||||||
|
CreateMap<BuildingDto, Building>();
|
||||||
|
CreateMap<FloorDto, Floor>();
|
||||||
|
CreateMap<WorkAreaDto, WorkArea>();
|
||||||
CreateMap<WorkItemDto, WorkItem>()
|
CreateMap<WorkItemDto, WorkItem>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Description,
|
dest => dest.Description,
|
||||||
|
@ -1033,83 +1033,360 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> CreateProjectTask1(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> ManageProjectInfra(List<InfraDto> infraDots, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
_logger.LogInfo("CreateProjectTask called with {Count} items", workItemDtos?.Count ?? 0);
|
var responseData = new InfraVM { };
|
||||||
|
string responseMessage = "";
|
||||||
// Validate request
|
|
||||||
if (workItemDtos == null || !workItemDtos.Any())
|
|
||||||
{
|
|
||||||
_logger.LogWarning("No work items provided in the request.");
|
|
||||||
return ApiResponse<object>.ErrorResponse("Invalid details.", "Work Item details are not valid.", 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
var workItemsToCreate = new List<WorkItem>();
|
|
||||||
var workItemsToUpdate = new List<WorkItem>();
|
|
||||||
var responseList = new List<WorkItemVM>();
|
|
||||||
string message = "";
|
string message = "";
|
||||||
List<Guid> workAreaIds = new List<Guid>();
|
List<Guid> projectIds = new List<Guid>();
|
||||||
var workItemIds = workItemDtos.Where(wi => wi.Id != null && wi.Id != Guid.Empty).Select(wi => wi.Id).ToList();
|
if (infraDots != null)
|
||||||
var workItems = await _context.WorkItems.AsNoTracking().Where(wi => workItemIds.Contains(wi.Id)).ToListAsync();
|
|
||||||
|
|
||||||
foreach (var itemDto in workItemDtos)
|
|
||||||
{
|
{
|
||||||
var workItem = _mapper.Map<WorkItem>(itemDto);
|
foreach (var item in infraDots)
|
||||||
workItem.TenantId = tenantId;
|
|
||||||
var workArea = await _context.WorkAreas.Include(a => a.Floor).FirstOrDefaultAsync(a => a.Id == workItem.WorkAreaId) ?? new WorkArea();
|
|
||||||
|
|
||||||
Building building = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == (workArea.Floor != null ? workArea.Floor.BuildingId : Guid.Empty)) ?? new Building();
|
|
||||||
|
|
||||||
if (itemDto.Id != null && itemDto.Id != Guid.Empty)
|
|
||||||
{
|
{
|
||||||
// Update existing
|
if (item.Building != null)
|
||||||
workItemsToUpdate.Add(workItem);
|
|
||||||
message = $"Task Updated in Building: {building.Name}, on Floor: {workArea.Floor?.FloorName}, in Area: {workArea.AreaName} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}";
|
|
||||||
var existingWorkItem = workItems.FirstOrDefault(wi => wi.Id == workItem.Id);
|
|
||||||
if (existingWorkItem != null)
|
|
||||||
{
|
{
|
||||||
double plannedWork = workItem.PlannedWork - existingWorkItem.PlannedWork;
|
|
||||||
double completedWork = workItem.CompletedWork - existingWorkItem.CompletedWork;
|
Building building = _mapper.Map<Building>(item.Building);
|
||||||
await _cache.UpdatePlannedAndCompleteWorksInBuilding(workArea.Id, plannedWork, completedWork);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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.
|
||||||
|
if (infraDtos == null || !infraDtos.Any())
|
||||||
|
{
|
||||||
|
return new ServiceResponse
|
||||||
{
|
{
|
||||||
// Create new
|
Response = ApiResponse<object>.ErrorResponse("Invalid details.", "No infrastructure details were provided.", 400)
|
||||||
workItem.Id = Guid.NewGuid();
|
};
|
||||||
workItemsToCreate.Add(workItem);
|
}
|
||||||
message = $"Task Added in Building: {building.Name}, on Floor: {workArea.Floor?.FloorName}, in Area: {workArea.AreaName} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}";
|
|
||||||
await _cache.UpdatePlannedAndCompleteWorksInBuilding(workArea.Id, workItem.PlannedWork, workItem.CompletedWork);
|
var responseData = new InfraVM();
|
||||||
|
var messages = new List<string>();
|
||||||
|
var projectIds = new HashSet<Guid>(); // Use HashSet for automatic duplicate handling.
|
||||||
|
var cacheUpdateTasks = new List<Task>();
|
||||||
|
|
||||||
|
// --- Pre-fetch parent entities to avoid N+1 query problem ---
|
||||||
|
// 2. Gather all parent IDs needed for validation and context.
|
||||||
|
var requiredBuildingIds = infraDtos
|
||||||
|
.Where(i => i.Floor?.BuildingId != null)
|
||||||
|
.Select(i => i.Floor!.BuildingId)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var requiredFloorIds = infraDtos
|
||||||
|
.Where(i => i.WorkArea?.FloorId != null)
|
||||||
|
.Select(i => i.WorkArea!.FloorId)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 3. Fetch all required parent entities in single batch queries.
|
||||||
|
var buildingsDict = await _context.Buildings
|
||||||
|
.Where(b => requiredBuildingIds.Contains(b.Id))
|
||||||
|
.ToDictionaryAsync(b => b.Id);
|
||||||
|
|
||||||
|
var floorsDict = await _context.Floor
|
||||||
|
.Include(f => f.Building) // Eagerly load Building for later use
|
||||||
|
.Where(f => requiredFloorIds.Contains(f.Id))
|
||||||
|
.ToDictionaryAsync(f => f.Id);
|
||||||
|
// --- End Pre-fetching ---
|
||||||
|
|
||||||
|
// 4. Process all entities and add them to the context's change tracker.
|
||||||
|
foreach (var item in infraDtos)
|
||||||
|
{
|
||||||
|
if (item.Building != null)
|
||||||
|
{
|
||||||
|
ProcessBuilding(item.Building, tenantId, responseData, messages, projectIds, cacheUpdateTasks);
|
||||||
|
}
|
||||||
|
if (item.Floor != null)
|
||||||
|
{
|
||||||
|
ProcessFloor(item.Floor, tenantId, responseData, messages, projectIds, cacheUpdateTasks, buildingsDict);
|
||||||
|
}
|
||||||
|
if (item.WorkArea != null)
|
||||||
|
{
|
||||||
|
ProcessWorkArea(item.WorkArea, tenantId, responseData, messages, projectIds, cacheUpdateTasks, floorsDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Save all changes to the database in a single transaction.
|
||||||
|
var changedRecordCount = await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// If no changes were actually made, we can exit early.
|
||||||
|
if (changedRecordCount == 0)
|
||||||
|
{
|
||||||
|
return new ServiceResponse
|
||||||
|
{
|
||||||
|
Response = ApiResponse<object>.SuccessResponse(responseData, "No changes detected in the provided infrastructure details.", 200)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Execute all cache updates concurrently after the DB save is successful.
|
||||||
|
await Task.WhenAll(cacheUpdateTasks);
|
||||||
|
|
||||||
|
// 7. Consolidate messages and create notification payload.
|
||||||
|
string finalResponseMessage = messages.LastOrDefault() ?? "Infrastructure managed successfully.";
|
||||||
|
string logMessage = $"{string.Join(", ", messages)} by {loggedInEmployee.FirstName} {loggedInEmployee.LastName}";
|
||||||
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Infra", ProjectIds = projectIds.ToList(), Message = logMessage };
|
||||||
|
|
||||||
|
// TODO: Dispatch the 'notification' object to your notification service.
|
||||||
|
|
||||||
|
return new ServiceResponse
|
||||||
|
{
|
||||||
|
Notification = notification,
|
||||||
|
Response = ApiResponse<object>.SuccessResponse(responseData, finalResponseMessage, 200)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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);
|
||||||
}
|
}
|
||||||
|
|
||||||
responseList.Add(new WorkItemVM
|
// --- Step 5: Process all logic IN MEMORY, tracking changes ---
|
||||||
|
|
||||||
|
// Process Buildings
|
||||||
|
var createdBuildings = new List<Building>();
|
||||||
|
foreach (var dto in buildingsToCreateDto)
|
||||||
{
|
{
|
||||||
WorkItemId = workItem.Id,
|
var newBuilding = _mapper.Map<Building>(dto);
|
||||||
WorkItem = workItem
|
newBuilding.TenantId = tenantId;
|
||||||
});
|
createdBuildings.Add(newBuilding);
|
||||||
workAreaIds.Add(workItem.WorkAreaId);
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
// Apply DB changes
|
catch (Exception ex)
|
||||||
if (workItemsToCreate.Any())
|
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Adding {Count} new work items", workItemsToCreate.Count);
|
_logger.LogError(ex, "An unexpected error occurred in ManageProjectInfraAsync.");
|
||||||
await _context.WorkItems.AddRangeAsync(workItemsToCreate);
|
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An unexpected error occurred.", 500);
|
||||||
await _cache.ManageWorkItemDetails(workItemsToCreate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workItemsToUpdate.Any())
|
|
||||||
{
|
|
||||||
_logger.LogInfo("Updating {Count} existing work items", workItemsToUpdate.Count);
|
|
||||||
_context.WorkItems.UpdateRange(workItemsToUpdate);
|
|
||||||
await _cache.ManageWorkItemDetails(workItemsToUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
_logger.LogInfo("CreateProjectTask completed successfully. Created: {Created}, Updated: {Updated}", workItemsToCreate.Count, workItemsToUpdate.Count);
|
|
||||||
|
|
||||||
return ApiResponse<object>.SuccessResponse(responseList, message, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1211,12 +1488,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
_logger.LogInfo("Successfully saved {CreatedCount} new and {UpdatedCount} updated work items.", workItemsToCreate.Count, workItemsToModify.Count);
|
_logger.LogInfo("Successfully saved {CreatedCount} new and {UpdatedCount} updated work items.", workItemsToCreate.Count, workItemsToModify.Count);
|
||||||
|
|
||||||
// --- Step 5: Update Cache and SignalR AFTER successful DB save (non-blocking) ---
|
// --- Step 5: Update Cache and SignalR AFTER successful DB save ---
|
||||||
var allAffectedItems = workItemsToCreate.Concat(workItemsToModify).ToList();
|
var allAffectedItems = workItemsToCreate.Concat(workItemsToModify).ToList();
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
await UpdateCacheAndNotify(workDeltaForCache, allAffectedItems);
|
||||||
await UpdateCacheAndNotify(workDeltaForCache, allAffectedItems);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (DbUpdateException ex)
|
catch (DbUpdateException ex)
|
||||||
@ -1291,133 +1566,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
// return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
// return Ok(ApiResponse<object>.SuccessResponse(new { }, "Task deleted successfully", 200));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//public async Task<IActionResult> ManageProjectInfra(List<InfraDot> infraDots)
|
|
||||||
//{
|
|
||||||
// var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
|
||||||
|
|
||||||
// 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 = item.Building.ToBuildingFromBuildingDto(tenantId);
|
|
||||||
// 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 = item.Floor.ToFloorFromFloorDto(tenantId);
|
|
||||||
// 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 = item.WorkArea.ToWorkAreaFromWorkAreaDto(tenantId);
|
|
||||||
// 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 };
|
|
||||||
|
|
||||||
// await _signalR.SendNotificationAsync(notification);
|
|
||||||
// return Ok(ApiResponse<object>.SuccessResponse(responseData, responseMessage, 200));
|
|
||||||
// }
|
|
||||||
// return BadRequest(ApiResponse<object>.ErrorResponse("Invalid details.", "Infra Details are not valid.", 400));
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
@ -1663,6 +1811,82 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ProcessBuilding(BuildingDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks)
|
||||||
|
{
|
||||||
|
Building building = _mapper.Map<Building>(dto);
|
||||||
|
building.TenantId = tenantId;
|
||||||
|
|
||||||
|
bool isNew = dto.Id == null;
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_context.Buildings.Add(building);
|
||||||
|
messages.Add("Building Added");
|
||||||
|
cacheTasks.Add(_cache.AddBuildngInfra(building.ProjectId, building));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Buildings.Update(building);
|
||||||
|
messages.Add("Building Updated");
|
||||||
|
cacheTasks.Add(_cache.UpdateBuildngInfra(building.ProjectId, building));
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData.building = building;
|
||||||
|
projectIds.Add(building.ProjectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessFloor(FloorDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Building> buildings)
|
||||||
|
{
|
||||||
|
Floor floor = _mapper.Map<Floor>(dto);
|
||||||
|
floor.TenantId = tenantId;
|
||||||
|
|
||||||
|
// Use the pre-fetched dictionary for parent lookup.
|
||||||
|
Building? parentBuilding = buildings.TryGetValue(dto.BuildingId, out var b) ? b : null;
|
||||||
|
|
||||||
|
bool isNew = dto.Id == null;
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_context.Floor.Add(floor);
|
||||||
|
messages.Add($"Floor Added in Building: {parentBuilding?.Name ?? "Unknown"}");
|
||||||
|
cacheTasks.Add(_cache.AddBuildngInfra(parentBuilding?.ProjectId ?? Guid.Empty, floor: floor));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Floor.Update(floor);
|
||||||
|
messages.Add($"Floor Updated in Building: {parentBuilding?.Name ?? "Unknown"}");
|
||||||
|
cacheTasks.Add(_cache.UpdateBuildngInfra(parentBuilding?.ProjectId ?? Guid.Empty, floor: floor));
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData.floor = floor;
|
||||||
|
if (parentBuilding != null) projectIds.Add(parentBuilding.ProjectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessWorkArea(WorkAreaDto dto, Guid tenantId, InfraVM responseData, List<string> messages, ISet<Guid> projectIds, List<Task> cacheTasks, IDictionary<Guid, Floor> floors)
|
||||||
|
{
|
||||||
|
WorkArea workArea = _mapper.Map<WorkArea>(dto);
|
||||||
|
workArea.TenantId = tenantId;
|
||||||
|
|
||||||
|
// Use the pre-fetched dictionary for parent lookup.
|
||||||
|
Floor? parentFloor = floors.TryGetValue(dto.FloorId, out var f) ? f : null;
|
||||||
|
var parentBuilding = parentFloor?.Building;
|
||||||
|
|
||||||
|
bool isNew = dto.Id == null;
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_context.WorkAreas.Add(workArea);
|
||||||
|
messages.Add($"Work Area Added in Building: {parentBuilding?.Name ?? "Unknown"}, on Floor: {parentFloor?.FloorName ?? "Unknown"}");
|
||||||
|
cacheTasks.Add(_cache.AddBuildngInfra(parentBuilding?.ProjectId ?? Guid.Empty, workArea: workArea, buildingId: parentBuilding?.Id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.WorkAreas.Update(workArea);
|
||||||
|
messages.Add($"Work Area Updated in Building: {parentBuilding?.Name ?? "Unknown"}, on Floor: {parentFloor?.FloorName ?? "Unknown"}");
|
||||||
|
cacheTasks.Add(_cache.UpdateBuildngInfra(parentBuilding?.ProjectId ?? Guid.Empty, workArea: workArea, buildingId: parentBuilding?.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData.workArea = workArea;
|
||||||
|
if (parentBuilding != null) projectIds.Add(parentBuilding.ProjectId);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee);
|
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<ApiResponse<List<WorkItemVM>>> CreateProjectTaskAsync(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user