Storing workItem in cache and changing planned work and completed work for respective project, building, floor, and workarea

This commit is contained in:
ashutosh.nehete 2025-07-07 17:44:58 +05:30
parent d8cf87aee4
commit cbcc3398c3
10 changed files with 256 additions and 16 deletions

View File

@ -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<ProjectMongoDB>.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<ArrayFilterDefinition>
{
new JsonArrayFilterDefinition<BsonDocument>("{ 'b._id': '" + selectedBuildingId + "' }"),
new JsonArrayFilterDefinition<BsonDocument>("{ 'f._id': '" + selectedFloorId + "' }"),
new JsonArrayFilterDefinition<BsonDocument>("{ 'a._id': '" + selectedWorkAreaId + "' }")
};
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var update = Builders<ProjectMongoDB>.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<WorkItem> 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<ActivityMaster>();
// Fetching Work Category
var workCategories = await _context.WorkCategoryMasters.Where(wc => workCategoryIds.Contains(wc.Id)).ToListAsync() ?? new List<WorkCategoryMaster>();
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<WorkItemMongoDB>.Filter.Eq(p => p.Id, workItem.Id.ToString());
var updates = Builders<WorkItemMongoDB>.Update.Combine(
Builders<WorkItemMongoDB>.Update.Set(r => r.WorkAreaId, workItem.WorkAreaId.ToString()),
Builders<WorkItemMongoDB>.Update.Set(r => r.ParentTaskId, (workItem.ParentTaskId != null ? workItem.ParentTaskId.ToString() : null)),
Builders<WorkItemMongoDB>.Update.Set(r => r.PlannedWork, workItem.PlannedWork),
Builders<WorkItemMongoDB>.Update.Set(r => r.TodaysAssigned, 0),
Builders<WorkItemMongoDB>.Update.Set(r => r.CompletedWork, workItem.CompletedWork),
Builders<WorkItemMongoDB>.Update.Set(r => r.Description, workItem.Description),
Builders<WorkItemMongoDB>.Update.Set(r => r.TaskDate, workItem.TaskDate),
Builders<WorkItemMongoDB>.Update.Set(r => r.ActivityMaster, new ActivityMasterMongoDB
{
Id = activity.Id.ToString(),
ActivityName = activity.ActivityName,
UnitOfMeasurement = activity.UnitOfMeasurement
}),
Builders<WorkItemMongoDB>.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<List<WorkItemMongoDB>> GetWorkItemDetailsByWorkAreaFromCache(Guid workAreaId)
{
var filter = Builders<WorkItemMongoDB>.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<WorkItemMongoDB> GetWorkItemDetailsByIdFromCache(Guid id)
{
var filter = Builders<WorkItemMongoDB>.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<bool> UpdatePlannedAndCompleteWorksInWorkItem(Guid id, double plannedWork = 0, double completedWork = 0, double todaysAssigned = 0)
{
var filter = Builders<WorkItemMongoDB>.Filter.Eq(p => p.Id, id.ToString());
var updates = Builders<WorkItemMongoDB>.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;
}
}
}

View File

@ -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; }
}

View File

@ -7,7 +7,7 @@
public string? Description { get; set; }
public double PlannedWork { get; set; }
public double CompletedWork { get; set; }
public List<FloorMongoDB>? Floors { get; set; }
public List<FloorMongoDB> Floors { get; set; } = new List<FloorMongoDB>();
}
public class BuildingMongoDBVM
{

View File

@ -6,7 +6,7 @@
public string? FloorName { get; set; }
public double PlannedWork { get; set; }
public double CompletedWork { get; set; }
public List<WorkAreaMongoDB>? WorkAreas { get; set; }
public List<WorkAreaMongoDB> WorkAreas { get; set; } = new List<WorkAreaMongoDB>();
}
public class FloorMongoDBVM

View File

@ -7,7 +7,7 @@
public string? ShortName { get; set; }
public string? ProjectAddress { get; set; }
public string? ContactPerson { get; set; }
public List<BuildingMongoDB>? Buildings { get; set; }
public List<BuildingMongoDB> Buildings { get; set; } = new List<BuildingMongoDB>();
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public StatusMasterMongoDB? ProjectStatus { get; set; }

View File

@ -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;
}

View File

@ -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;

View File

@ -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<object>.SuccessResponse(workItems, $"{workItems.Count} records of tasks fetched successfully", 200));
return Ok(ApiResponse<object>.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<Guid> projectIds = new List<Guid>();
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();

View File

@ -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<WorkItem> workItems)
{
try
{
await _projectCache.ManageWorkItemDetailsToCache(workItems);
}
catch (Exception ex)
{
_logger.LogWarning("Error occured while saving workItems form Cache: {Error}", ex.Message);
}
}
public async Task<List<WorkItemMongoDB>?> 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<WorkItemMongoDB?> 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 ---------------------------------------

View File

@ -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"
}
}