diff --git a/Marco.Pms.CacheHelper/ProjectCache.cs b/Marco.Pms.CacheHelper/ProjectCache.cs index f60884f..6f5a3d3 100644 --- a/Marco.Pms.CacheHelper/ProjectCache.cs +++ b/Marco.Pms.CacheHelper/ProjectCache.cs @@ -1,4 +1,5 @@ using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.Master; using Marco.Pms.Model.MongoDBModels; using Marco.Pms.Model.Projects; using Microsoft.EntityFrameworkCore; @@ -434,10 +435,129 @@ namespace Marco.Pms.CacheHelper return buildings; } + public async Task UpdatePlannedAndCompleteWorksInBuildingFromCache(Guid workAreaId, double plannedWork, double completedWork) + { + var filter = Builders.Filter.Eq("Buildings.Floors.WorkAreas._id", workAreaId.ToString()); + var project = await _projetCollection.Find(filter).FirstOrDefaultAsync(); + + string? selectedBuildingId = null; + string? selectedFloorId = null; + string? selectedWorkAreaId = null; + + foreach (var building in project.Buildings) + { + foreach (var floor in building.Floors) + { + foreach (var area in floor.WorkAreas) + { + if (area.Id == workAreaId.ToString()) + { + selectedWorkAreaId = area.Id; + selectedFloorId = floor.Id; + selectedBuildingId = building.Id; + } + } + } + } + + var arrayFilters = new List + { + new JsonArrayFilterDefinition("{ 'b._id': '" + selectedBuildingId + "' }"), + new JsonArrayFilterDefinition("{ 'f._id': '" + selectedFloorId + "' }"), + new JsonArrayFilterDefinition("{ 'a._id': '" + selectedWorkAreaId + "' }") + }; + var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters }; + var update = Builders.Update + .Inc("Buildings.$[b].Floors.$[f].WorkAreas.$[a].PlannedWork", plannedWork) + .Inc("Buildings.$[b].Floors.$[f].WorkAreas.$[a].CompletedWork", completedWork) + .Inc("Buildings.$[b].Floors.$[f].PlannedWork", plannedWork) + .Inc("Buildings.$[b].Floors.$[f].CompletedWork", completedWork) + .Inc("Buildings.$[b].PlannedWork", plannedWork) + .Inc("Buildings.$[b].CompletedWork", completedWork) + .Inc("PlannedWork", plannedWork) + .Inc("CompletedWork", completedWork); + var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions); + + } // ------------------------------------------------------- WorkItem ------------------------------------------------------- + public async Task ManageWorkItemDetailsToCache(List workItems) + { + var activityIds = workItems.Select(wi => wi.ActivityId).ToList(); + var workCategoryIds = workItems.Select(wi => wi.WorkCategoryId).ToList(); + // fetching Activity master + var activities = await _context.ActivityMasters.Where(a => activityIds.Contains(a.Id)).ToListAsync() ?? new List(); + // Fetching Work Category + var workCategories = await _context.WorkCategoryMasters.Where(wc => workCategoryIds.Contains(wc.Id)).ToListAsync() ?? new List(); + + foreach (WorkItem workItem in workItems) + { + var activity = activities.FirstOrDefault(a => a.Id == workItem.ActivityId) ?? new ActivityMaster(); + var workCategory = workCategories.FirstOrDefault(a => a.Id == workItem.WorkCategoryId) ?? new WorkCategoryMaster(); + + var filter = Builders.Filter.Eq(p => p.Id, workItem.Id.ToString()); + var updates = Builders.Update.Combine( + Builders.Update.Set(r => r.WorkAreaId, workItem.WorkAreaId.ToString()), + Builders.Update.Set(r => r.ParentTaskId, (workItem.ParentTaskId != null ? workItem.ParentTaskId.ToString() : null)), + Builders.Update.Set(r => r.PlannedWork, workItem.PlannedWork), + Builders.Update.Set(r => r.TodaysAssigned, 0), + Builders.Update.Set(r => r.CompletedWork, workItem.CompletedWork), + Builders.Update.Set(r => r.Description, workItem.Description), + Builders.Update.Set(r => r.TaskDate, workItem.TaskDate), + Builders.Update.Set(r => r.ActivityMaster, new ActivityMasterMongoDB + { + Id = activity.Id.ToString(), + ActivityName = activity.ActivityName, + UnitOfMeasurement = activity.UnitOfMeasurement + }), + Builders.Update.Set(r => r.WorkCategoryMaster, new WorkCategoryMasterMongoDB + { + Id = workCategory.Id.ToString(), + Name = workCategory.Name, + Description = workCategory.Description, + }) + ); + var options = new UpdateOptions { IsUpsert = true }; + var result = await _taskCollection.UpdateOneAsync(filter, updates, options); + } + } + public async Task> GetWorkItemDetailsByWorkAreaFromCache(Guid workAreaId) + { + var filter = Builders.Filter.Eq(p => p.WorkAreaId, workAreaId.ToString()); + + var options = new UpdateOptions { IsUpsert = true }; + var workItems = await _taskCollection + .Find(filter) + .ToListAsync(); + return workItems; + } + public async Task GetWorkItemDetailsByIdFromCache(Guid id) + { + var filter = Builders.Filter.Eq(p => p.Id, id.ToString()); + + var options = new UpdateOptions { IsUpsert = true }; + var workItem = await _taskCollection + .Find(filter) + .FirstOrDefaultAsync(); + return workItem; + } + public async Task UpdatePlannedAndCompleteWorksInWorkItem(Guid id, double plannedWork = 0, double completedWork = 0, double todaysAssigned = 0) + { + var filter = Builders.Filter.Eq(p => p.Id, id.ToString()); + var updates = Builders.Update + .Inc("PlannedWork", plannedWork) + .Inc("CompletedWork", completedWork) + .Inc("TodaysAssigned", todaysAssigned); + + var result = await _taskCollection.UpdateOneAsync(filter, updates); + if (result.ModifiedCount > 0) + { + return true; + } + return false; + } } } diff --git a/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs index 37218b7..cc77d96 100644 --- a/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs @@ -2,7 +2,7 @@ { public class ActivityMasterMongoDB { - public string? Id { get; set; } + public string Id { get; set; } = string.Empty; public string? ActivityName { get; set; } public string? UnitOfMeasurement { get; set; } } diff --git a/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs b/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs index 87ccb8d..64ccbce 100644 --- a/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs @@ -7,7 +7,7 @@ public string? Description { get; set; } public double PlannedWork { get; set; } public double CompletedWork { get; set; } - public List? Floors { get; set; } + public List Floors { get; set; } = new List(); } public class BuildingMongoDBVM { diff --git a/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs b/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs index ae3975f..57257a4 100644 --- a/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs @@ -6,7 +6,7 @@ public string? FloorName { get; set; } public double PlannedWork { get; set; } public double CompletedWork { get; set; } - public List? WorkAreas { get; set; } + public List WorkAreas { get; set; } = new List(); } public class FloorMongoDBVM diff --git a/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs b/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs index 8b1612c..7f3a557 100644 --- a/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs @@ -7,7 +7,7 @@ public string? ShortName { get; set; } public string? ProjectAddress { get; set; } public string? ContactPerson { get; set; } - public List? Buildings { get; set; } + public List Buildings { get; set; } = new List(); public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } public StatusMasterMongoDB? ProjectStatus { get; set; } diff --git a/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs index aef0ada..4ea4682 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs @@ -2,7 +2,7 @@ { public class WorkCategoryMasterMongoDB { - public string? Id { get; set; } + public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; } diff --git a/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs b/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs index 71638a3..850300d 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs @@ -6,7 +6,7 @@ public string WorkAreaId { get; set; } = string.Empty; public ActivityMasterMongoDB? ActivityMaster { get; set; } public WorkCategoryMasterMongoDB? WorkCategoryMaster { get; set; } - public string? ParentTaskId { get; set; } + public string? ParentTaskId { get; set; } = null; public double PlannedWork { get; set; } = 0; public double TodaysAssigned { get; set; } = 0; public double CompletedWork { get; set; } = 0; diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index a440c21..3ae76ed 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -734,16 +734,45 @@ namespace MarcoBMS.Services.Controllers } // Step 4: Fetch WorkItems with related Activity and Work Category data - var workItems = await _context.WorkItems - .Include(wi => wi.ActivityMaster) - .Include(wi => wi.WorkCategoryMaster) - .Where(wi => wi.WorkAreaId == workAreaId) - .ToListAsync(); + var workItemVMs = await _cache.GetWorkItemDetailsByWorkArea(workAreaId); + if (workItemVMs == null) + { + var workItems = await _context.WorkItems + .Include(wi => wi.ActivityMaster) + .Include(wi => wi.WorkCategoryMaster) + .Where(wi => wi.WorkAreaId == workAreaId) + .ToListAsync(); - _logger.LogInfo("{Count} work items fetched successfully for WorkAreaId: {WorkAreaId}", workItems.Count, workAreaId); + workItemVMs = workItems.Select(wi => new WorkItemMongoDB + { + Id = wi.Id.ToString(), + WorkAreaId = wi.WorkAreaId.ToString(), + ParentTaskId = wi.ParentTaskId.ToString(), + ActivityMaster = new ActivityMasterMongoDB + { + Id = wi.ActivityId.ToString(), + ActivityName = wi.ActivityMaster != null ? wi.ActivityMaster.ActivityName : null, + UnitOfMeasurement = wi.ActivityMaster != null ? wi.ActivityMaster.UnitOfMeasurement : null + }, + WorkCategoryMaster = new WorkCategoryMasterMongoDB + { + Id = wi.ActivityId.ToString(), + Name = wi.WorkCategoryMaster != null ? wi.WorkCategoryMaster.Name : "", + Description = wi.WorkCategoryMaster != null ? wi.WorkCategoryMaster.Description : "" + }, + PlannedWork = wi.PlannedWork, + CompletedWork = wi.CompletedWork, + Description = wi.Description, + TaskDate = wi.TaskDate, + }).ToList(); + + await _cache.ManageWorkItemDetails(workItems); + } + + _logger.LogInfo("{Count} work items fetched successfully for WorkAreaId: {WorkAreaId}", workItemVMs.Count, workAreaId); // Step 5: Return result - return Ok(ApiResponse.SuccessResponse(workItems, $"{workItems.Count} records of tasks fetched successfully", 200)); + return Ok(ApiResponse.SuccessResponse(workItemVMs, $"{workItemVMs.Count} records of tasks fetched successfully", 200)); } [HttpPost("task")] @@ -765,6 +794,8 @@ namespace MarcoBMS.Services.Controllers var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); string message = ""; List projectIds = new List(); + var workItemIds = workItemDtos.Where(wi => wi.Id != null && wi.Id != Guid.Empty).Select(wi => wi.Id).ToList(); + var workItems = await _context.WorkItems.AsNoTracking().Where(wi => workItemIds.Contains(wi.Id)).ToListAsync(); foreach (var itemDto in workItemDtos) { @@ -778,6 +809,28 @@ namespace MarcoBMS.Services.Controllers // Update existing 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); + double plannedWork = 0; + double completedWork = 0; + if (existingWorkItem != null) + { + if (existingWorkItem.PlannedWork != workItem.PlannedWork && existingWorkItem.CompletedWork != workItem.CompletedWork) + { + plannedWork = workItem.PlannedWork - existingWorkItem.PlannedWork; + completedWork = workItem.CompletedWork - existingWorkItem.CompletedWork; + } + else if (existingWorkItem.PlannedWork == workItem.PlannedWork && existingWorkItem.CompletedWork != workItem.CompletedWork) + { + plannedWork = 0; + completedWork = workItem.CompletedWork - existingWorkItem.CompletedWork; + } + else if (existingWorkItem.PlannedWork != workItem.PlannedWork && existingWorkItem.CompletedWork == workItem.CompletedWork) + { + plannedWork = workItem.PlannedWork - existingWorkItem.PlannedWork; + completedWork = 0; + } + await _cache.UpdatePlannedAndCompleteWorksInBuilding(workArea.Id, plannedWork, completedWork); + } } else { @@ -785,6 +838,7 @@ namespace MarcoBMS.Services.Controllers 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); } responseList.Add(new WorkItemVM @@ -793,6 +847,7 @@ namespace MarcoBMS.Services.Controllers WorkItem = workItem }); projectIds.Add(building.ProjectId); + } string responseMessage = ""; // Apply DB changes @@ -801,7 +856,7 @@ namespace MarcoBMS.Services.Controllers _logger.LogInfo("Adding {Count} new work items", workItemsToCreate.Count); await _context.WorkItems.AddRangeAsync(workItemsToCreate); responseMessage = "Task Added Successfully"; - + await _cache.ManageWorkItemDetails(workItemsToCreate); } if (workItemsToUpdate.Any()) @@ -809,7 +864,7 @@ namespace MarcoBMS.Services.Controllers _logger.LogInfo("Updating {Count} existing work items", workItemsToUpdate.Count); _context.WorkItems.UpdateRange(workItemsToUpdate); responseMessage = "Task Updated Successfully"; - + await _cache.ManageWorkItemDetails(workItemsToUpdate); } await _context.SaveChangesAsync(); diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 6ff9cfe..ecce8ab 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -109,6 +109,71 @@ namespace Marco.Pms.Services.Helpers return null; } } + public async Task UpdatePlannedAndCompleteWorksInBuilding(Guid workAreaId, double plannedWork = 0, double completedWork = 0) + { + try + { + await _projectCache.UpdatePlannedAndCompleteWorksInBuildingFromCache(workAreaId, plannedWork, completedWork); + } + catch (Exception ex) + { + _logger.LogWarning("Error occured while updating planned work and completed work in building infra form Cache: {Error}", ex.Message); + } + } + + // ------------------------------------------------------- WorkItem ------------------------------------------------------- + + public async Task ManageWorkItemDetails(List workItems) + { + try + { + await _projectCache.ManageWorkItemDetailsToCache(workItems); + } + catch (Exception ex) + { + _logger.LogWarning("Error occured while saving workItems form Cache: {Error}", ex.Message); + } + } + public async Task?> GetWorkItemDetailsByWorkArea(Guid workAreaId) + { + try + { + var workItems = await _projectCache.GetWorkItemDetailsByWorkAreaFromCache(workAreaId); + if (workItems.Count > 0) + { + return workItems; + } + else + { + return null; + } + } + catch (Exception ex) + { + _logger.LogWarning("Error occured while fetching list of workItems form Cache: {Error}", ex.Message); + return null; + } + } + public async Task GetWorkItemDetailsById(Guid id) + { + try + { + var workItem = await _projectCache.GetWorkItemDetailsByIdFromCache(id); + if (workItem.Id != "") + { + return workItem; + } + else + { + return null; + } + } + catch (Exception ex) + { + _logger.LogWarning("Error occured while fetching list of workItems form Cache: {Error}", ex.Message); + return null; + } + } // ------------------------------------ Employee Profile Cache --------------------------------------- diff --git a/Marco.Pms.Services/appsettings.Development.json b/Marco.Pms.Services/appsettings.Development.json index 5f5e19d..030c450 100644 --- a/Marco.Pms.Services/appsettings.Development.json +++ b/Marco.Pms.Services/appsettings.Development.json @@ -48,6 +48,6 @@ }, "MongoDB": { "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", - "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches" + "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500" } }