Merge branch 'ProjectDetails_Split_API' of https://git.marcoaiot.com/admin/marco.pms.api into ProjectDetails_Split_API
This commit is contained in:
commit
60517f3f60
@ -106,6 +106,7 @@ namespace Marco.Pms.CacheHelper
|
|||||||
workAreaMongoList.Add(new WorkAreaMongoDB
|
workAreaMongoList.Add(new WorkAreaMongoDB
|
||||||
{
|
{
|
||||||
Id = wa.Id.ToString(),
|
Id = wa.Id.ToString(),
|
||||||
|
FloorId = wa.FloorId.ToString(),
|
||||||
AreaName = wa.AreaName,
|
AreaName = wa.AreaName,
|
||||||
PlannedWork = waPlanned,
|
PlannedWork = waPlanned,
|
||||||
CompletedWork = waCompleted
|
CompletedWork = waCompleted
|
||||||
@ -118,6 +119,7 @@ namespace Marco.Pms.CacheHelper
|
|||||||
floorMongoList.Add(new FloorMongoDB
|
floorMongoList.Add(new FloorMongoDB
|
||||||
{
|
{
|
||||||
Id = floor.Id.ToString(),
|
Id = floor.Id.ToString(),
|
||||||
|
BuildingId = floor.BuildingId.ToString(),
|
||||||
FloorName = floor.FloorName,
|
FloorName = floor.FloorName,
|
||||||
PlannedWork = floorPlanned,
|
PlannedWork = floorPlanned,
|
||||||
CompletedWork = floorCompleted,
|
CompletedWork = floorCompleted,
|
||||||
@ -131,6 +133,7 @@ namespace Marco.Pms.CacheHelper
|
|||||||
buildingMongoList.Add(new BuildingMongoDB
|
buildingMongoList.Add(new BuildingMongoDB
|
||||||
{
|
{
|
||||||
Id = building.Id.ToString(),
|
Id = building.Id.ToString(),
|
||||||
|
ProjectId = building.ProjectId.ToString(),
|
||||||
BuildingName = building.Name,
|
BuildingName = building.Name,
|
||||||
Description = building.Description,
|
Description = building.Description,
|
||||||
PlannedWork = buildingPlanned,
|
PlannedWork = buildingPlanned,
|
||||||
@ -477,7 +480,59 @@ namespace Marco.Pms.CacheHelper
|
|||||||
var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions);
|
var result = await _projetCollection.UpdateOneAsync(filter, update, updateOptions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public async Task<WorkAreaInfoMongoDB?> GetBuildingAndFloorByWorkAreaIdFromCache(Guid workAreaId)
|
||||||
|
{
|
||||||
|
var pipeline = new[]
|
||||||
|
{
|
||||||
|
new BsonDocument("$unwind", "$Buildings"),
|
||||||
|
new BsonDocument("$unwind", "$Buildings.Floors"),
|
||||||
|
new BsonDocument("$unwind", "$Buildings.Floors.WorkAreas"),
|
||||||
|
new BsonDocument("$match", new BsonDocument("Buildings.Floors.WorkAreas._id", workAreaId.ToString())),
|
||||||
|
new BsonDocument("$project", new BsonDocument
|
||||||
|
{
|
||||||
|
{ "_id", 0 },
|
||||||
|
{ "ProjectId", "$_id" },
|
||||||
|
{ "ProjectName", "$Name" },
|
||||||
|
{ "PlannedWork", "$PlannedWork" },
|
||||||
|
{ "CompletedWork", "$CompletedWork" },
|
||||||
|
{
|
||||||
|
"Building", new BsonDocument
|
||||||
|
{
|
||||||
|
{ "_id", "$Buildings._id" },
|
||||||
|
{ "BuildingName", "$Buildings.BuildingName" },
|
||||||
|
{ "Description", "$Buildings.Description" },
|
||||||
|
{ "PlannedWork", "$Buildings.PlannedWork" },
|
||||||
|
{ "CompletedWork", "$Buildings.CompletedWork" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Floor", new BsonDocument
|
||||||
|
{
|
||||||
|
{ "_id", "$Buildings.Floors._id" },
|
||||||
|
{ "FloorName", "$Buildings.Floors.FloorName" },
|
||||||
|
{ "PlannedWork", "$Buildings.Floors.PlannedWork" },
|
||||||
|
{ "CompletedWork", "$Buildings.Floors.CompletedWork" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "WorkArea", "$Buildings.Floors.WorkAreas" }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var result = await _projetCollection.Aggregate<WorkAreaInfoMongoDB>(pipeline).FirstOrDefaultAsync();
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public async Task<List<WorkItemMongoDB>> GetWorkItemsByWorkAreaIdsFromCache(List<Guid> workAreaIds)
|
||||||
|
{
|
||||||
|
var stringWorkAreaIds = workAreaIds.Select(wa => wa.ToString()).ToList();
|
||||||
|
var filter = Builders<WorkItemMongoDB>.Filter.In(w => w.WorkAreaId, stringWorkAreaIds);
|
||||||
|
|
||||||
|
var workItems = await _taskCollection // replace with your actual collection name
|
||||||
|
.Find(filter)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return workItems;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------- WorkItem -------------------------------------------------------
|
// ------------------------------------------------------- WorkItem -------------------------------------------------------
|
||||||
|
|
||||||
@ -485,12 +540,14 @@ namespace Marco.Pms.CacheHelper
|
|||||||
{
|
{
|
||||||
var activityIds = workItems.Select(wi => wi.ActivityId).ToList();
|
var activityIds = workItems.Select(wi => wi.ActivityId).ToList();
|
||||||
var workCategoryIds = workItems.Select(wi => wi.WorkCategoryId).ToList();
|
var workCategoryIds = workItems.Select(wi => wi.WorkCategoryId).ToList();
|
||||||
|
var workItemIds = workItems.Select(wi => wi.Id).ToList();
|
||||||
// fetching Activity master
|
// fetching Activity master
|
||||||
var activities = await _context.ActivityMasters.Where(a => activityIds.Contains(a.Id)).ToListAsync() ?? new List<ActivityMaster>();
|
var activities = await _context.ActivityMasters.Where(a => activityIds.Contains(a.Id)).ToListAsync() ?? new List<ActivityMaster>();
|
||||||
|
|
||||||
// Fetching Work Category
|
// Fetching Work Category
|
||||||
var workCategories = await _context.WorkCategoryMasters.Where(wc => workCategoryIds.Contains(wc.Id)).ToListAsync() ?? new List<WorkCategoryMaster>();
|
var workCategories = await _context.WorkCategoryMasters.Where(wc => workCategoryIds.Contains(wc.Id)).ToListAsync() ?? new List<WorkCategoryMaster>();
|
||||||
|
var task = await _context.TaskAllocations.Where(t => workItemIds.Contains(t.WorkItemId) && t.AssignmentDate == DateTime.UtcNow).ToListAsync();
|
||||||
|
var todaysAssign = task.Sum(t => t.PlannedTask);
|
||||||
foreach (WorkItem workItem in workItems)
|
foreach (WorkItem workItem in workItems)
|
||||||
{
|
{
|
||||||
var activity = activities.FirstOrDefault(a => a.Id == workItem.ActivityId) ?? new ActivityMaster();
|
var activity = activities.FirstOrDefault(a => a.Id == workItem.ActivityId) ?? new ActivityMaster();
|
||||||
@ -501,10 +558,11 @@ namespace Marco.Pms.CacheHelper
|
|||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.WorkAreaId, workItem.WorkAreaId.ToString()),
|
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.ParentTaskId, (workItem.ParentTaskId != null ? workItem.ParentTaskId.ToString() : null)),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.PlannedWork, workItem.PlannedWork),
|
Builders<WorkItemMongoDB>.Update.Set(r => r.PlannedWork, workItem.PlannedWork),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.TodaysAssigned, 0),
|
Builders<WorkItemMongoDB>.Update.Set(r => r.TodaysAssigned, todaysAssign),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.CompletedWork, workItem.CompletedWork),
|
Builders<WorkItemMongoDB>.Update.Set(r => r.CompletedWork, workItem.CompletedWork),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.Description, workItem.Description),
|
Builders<WorkItemMongoDB>.Update.Set(r => r.Description, workItem.Description),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.TaskDate, workItem.TaskDate),
|
Builders<WorkItemMongoDB>.Update.Set(r => r.TaskDate, workItem.TaskDate),
|
||||||
|
Builders<WorkItemMongoDB>.Update.Set(r => r.ExpireAt, DateTime.UtcNow.Date.AddDays(1)),
|
||||||
Builders<WorkItemMongoDB>.Update.Set(r => r.ActivityMaster, new ActivityMasterMongoDB
|
Builders<WorkItemMongoDB>.Update.Set(r => r.ActivityMaster, new ActivityMasterMongoDB
|
||||||
{
|
{
|
||||||
Id = activity.Id.ToString(),
|
Id = activity.Id.ToString(),
|
||||||
@ -520,6 +578,16 @@ namespace Marco.Pms.CacheHelper
|
|||||||
);
|
);
|
||||||
var options = new UpdateOptions { IsUpsert = true };
|
var options = new UpdateOptions { IsUpsert = true };
|
||||||
var result = await _taskCollection.UpdateOneAsync(filter, updates, options);
|
var result = await _taskCollection.UpdateOneAsync(filter, updates, options);
|
||||||
|
if (result.UpsertedId != null)
|
||||||
|
{
|
||||||
|
var indexKeys = Builders<WorkItemMongoDB>.IndexKeys.Ascending(x => x.ExpireAt);
|
||||||
|
var indexOptions = new CreateIndexOptions
|
||||||
|
{
|
||||||
|
ExpireAfter = TimeSpan.Zero // required for fixed expiration time
|
||||||
|
};
|
||||||
|
var indexModel = new CreateIndexModel<WorkItemMongoDB>(indexKeys, indexOptions);
|
||||||
|
await _taskCollection.Indexes.CreateOneAsync(indexModel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task<List<WorkItemMongoDB>> GetWorkItemDetailsByWorkAreaFromCache(Guid workAreaId)
|
public async Task<List<WorkItemMongoDB>> GetWorkItemDetailsByWorkAreaFromCache(Guid workAreaId)
|
||||||
|
@ -7,12 +7,16 @@
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public double PlannedWork { get; set; }
|
public double PlannedWork { get; set; }
|
||||||
public double CompletedWork { get; set; }
|
public double CompletedWork { get; set; }
|
||||||
|
public string ProjectId { get; set; } = string.Empty;
|
||||||
public List<FloorMongoDB> Floors { get; set; } = new List<FloorMongoDB>();
|
public List<FloorMongoDB> Floors { get; set; } = new List<FloorMongoDB>();
|
||||||
}
|
}
|
||||||
public class BuildingMongoDBVM
|
public class BuildingMongoDBVM
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
public string? Name { get; set; }
|
public string? BuildingName { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
public double PlannedWork { get; set; }
|
||||||
|
public double CompletedWork { get; set; }
|
||||||
|
public string ProjectId { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
public class FloorMongoDB
|
public class FloorMongoDB
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string BuildingId { get; set; } = string.Empty;
|
||||||
public string? FloorName { get; set; }
|
public string? FloorName { get; set; }
|
||||||
public double PlannedWork { get; set; }
|
public double PlannedWork { get; set; }
|
||||||
public double CompletedWork { get; set; }
|
public double CompletedWork { get; set; }
|
||||||
@ -12,6 +13,9 @@
|
|||||||
public class FloorMongoDBVM
|
public class FloorMongoDBVM
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string BuildingId { get; set; } = string.Empty;
|
||||||
public string? FloorName { get; set; }
|
public string? FloorName { get; set; }
|
||||||
|
public double PlannedWork { get; set; }
|
||||||
|
public double CompletedWork { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
Marco.Pms.Model/MongoDBModels/WorkAreaInfoMongoDB.cs
Normal file
13
Marco.Pms.Model/MongoDBModels/WorkAreaInfoMongoDB.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.MongoDBModels
|
||||||
|
{
|
||||||
|
public class WorkAreaInfoMongoDB
|
||||||
|
{
|
||||||
|
public string ProjectId { get; set; } = string.Empty;
|
||||||
|
public string? ProjectName { get; set; }
|
||||||
|
public BuildingMongoDBVM? Building { get; set; }
|
||||||
|
public FloorMongoDBVM? Floor { get; set; }
|
||||||
|
public WorkAreaMongoDB? WorkArea { get; set; }
|
||||||
|
public double CompletedWork { get; set; }
|
||||||
|
public double PlannedWork { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
public class WorkAreaMongoDB
|
public class WorkAreaMongoDB
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string FloorId { get; set; } = string.Empty;
|
||||||
public string? AreaName { get; set; }
|
public string? AreaName { get; set; }
|
||||||
public double PlannedWork { get; set; }
|
public double PlannedWork { get; set; }
|
||||||
public double CompletedWork { get; set; }
|
public double CompletedWork { get; set; }
|
||||||
|
@ -12,5 +12,6 @@
|
|||||||
public double CompletedWork { get; set; } = 0;
|
public double CompletedWork { get; set; } = 0;
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public DateTime TaskDate { get; set; }
|
public DateTime TaskDate { get; set; }
|
||||||
|
public DateTime ExpireAt { get; set; } = DateTime.UtcNow.Date.AddDays(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +237,10 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
.Include(c => c.ProjectStatus)
|
.Include(c => c.ProjectStatus)
|
||||||
.FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Id == id);
|
.FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Id == id);
|
||||||
projectVM = GetProjectViewModel(project);
|
projectVM = GetProjectViewModel(project);
|
||||||
|
if (project != null)
|
||||||
|
{
|
||||||
|
await _cache.AddProjectDetails(project);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -927,7 +931,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var responseList = new List<WorkItemVM>();
|
var responseList = new List<WorkItemVM>();
|
||||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
string message = "";
|
string message = "";
|
||||||
List<Guid> projectIds = new List<Guid>();
|
List<Guid> workAreaIds = new List<Guid>();
|
||||||
var workItemIds = workItemDtos.Where(wi => wi.Id != null && wi.Id != Guid.Empty).Select(wi => wi.Id).ToList();
|
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();
|
var workItems = await _context.WorkItems.AsNoTracking().Where(wi => workItemIds.Contains(wi.Id)).ToListAsync();
|
||||||
|
|
||||||
@ -980,7 +984,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
WorkItemId = workItem.Id,
|
WorkItemId = workItem.Id,
|
||||||
WorkItem = workItem
|
WorkItem = workItem
|
||||||
});
|
});
|
||||||
projectIds.Add(building.ProjectId);
|
workAreaIds.Add(workItem.WorkAreaId);
|
||||||
|
|
||||||
}
|
}
|
||||||
string responseMessage = "";
|
string responseMessage = "";
|
||||||
@ -1007,7 +1011,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "Infra", ProjectIds = projectIds, Message = message };
|
var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "WorkItem", WorkAreaIds = workAreaIds, Message = message };
|
||||||
|
|
||||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||||
|
|
||||||
@ -1019,7 +1023,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
{
|
{
|
||||||
Guid tenantId = _userHelper.GetTenantId();
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
List<Guid> projectIds = new List<Guid>();
|
List<Guid> workAreaIds = new List<Guid>();
|
||||||
WorkItem? task = await _context.WorkItems.AsNoTracking().Include(t => t.WorkArea).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId);
|
WorkItem? task = await _context.WorkItems.AsNoTracking().Include(t => t.WorkArea).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId);
|
||||||
if (task != null)
|
if (task != null)
|
||||||
{
|
{
|
||||||
@ -1036,9 +1040,9 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var floor = await _context.Floor.Include(f => f.Building).FirstOrDefaultAsync(f => f.Id == floorId);
|
var floor = await _context.Floor.Include(f => f.Building).FirstOrDefaultAsync(f => f.Id == floorId);
|
||||||
|
|
||||||
|
|
||||||
projectIds.Add(floor?.Building?.ProjectId ?? Guid.Empty);
|
workAreaIds.Add(task.WorkAreaId);
|
||||||
|
|
||||||
var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "Infra", ProjectIds = projectIds, Message = $"Task Deleted in Building: {floor?.Building?.Name}, on Floor: {floor?.FloorName}, in Area: {task.WorkArea?.AreaName} by {LoggedInEmployee.FirstName} {LoggedInEmployee.LastName}" };
|
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.Clients.All.SendAsync("NotificationEventHandler", notification);
|
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Globalization;
|
|
||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Dtos.Attendance;
|
|
||||||
using Marco.Pms.Model.Dtos.Mail;
|
using Marco.Pms.Model.Dtos.Mail;
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Mail;
|
using Marco.Pms.Model.Mail;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Report;
|
using Marco.Pms.Services.Helpers;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -26,13 +24,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
private readonly IWebHostEnvironment _env;
|
private readonly IWebHostEnvironment _env;
|
||||||
public ReportController(ApplicationDbContext context, IEmailSender emailSender, ILoggingService logger, UserHelper userHelper, IWebHostEnvironment env)
|
private readonly ReportHelper _reportHelper;
|
||||||
|
public ReportController(ApplicationDbContext context, IEmailSender emailSender, ILoggingService logger, UserHelper userHelper, IWebHostEnvironment env, ReportHelper reportHelper)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
_env = env;
|
_env = env;
|
||||||
|
_reportHelper = reportHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("set-mail")]
|
[HttpPost("set-mail")]
|
||||||
@ -151,7 +151,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
/// <returns>An ApiResponse indicating the success or failure of retrieving statistics and sending the email.</returns>
|
/// <returns>An ApiResponse indicating the success or failure of retrieving statistics and sending the email.</returns>
|
||||||
private async Task<ApiResponse<object>> GetProjectStatistics(Guid projectId, List<string> recipientEmails, string body, string subject, Guid tenantId)
|
private async Task<ApiResponse<object>> GetProjectStatistics(Guid projectId, List<string> recipientEmails, string body, string subject, Guid tenantId)
|
||||||
{
|
{
|
||||||
DateTime reportDate = DateTime.UtcNow.AddDays(-1).Date;
|
|
||||||
|
|
||||||
if (projectId == Guid.Empty)
|
if (projectId == Guid.Empty)
|
||||||
{
|
{
|
||||||
@ -159,161 +158,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return ApiResponse<object>.ErrorResponse("Provided empty Project ID.", "Provided empty Project ID.", 400);
|
return ApiResponse<object>.ErrorResponse("Provided empty Project ID.", "Provided empty Project ID.", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
var project = await _context.Projects
|
|
||||||
.AsNoTracking()
|
|
||||||
.FirstOrDefaultAsync(p => p.Id == projectId);
|
|
||||||
|
|
||||||
if (project == null)
|
var statisticReport = await _reportHelper.GetDailyProjectReport(projectId, tenantId);
|
||||||
|
|
||||||
|
if (statisticReport == null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("User attempted to fetch project progress for project ID {ProjectId} but not found.", projectId);
|
_logger.LogWarning("User attempted to fetch project progress for project ID {ProjectId} but not found.", projectId);
|
||||||
return ApiResponse<object>.ErrorResponse("Project not found.", "Project not found.", 404);
|
return ApiResponse<object>.ErrorResponse("Project not found.", "Project not found.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
var statisticReport = new ProjectStatisticReport
|
|
||||||
{
|
|
||||||
Date = reportDate,
|
|
||||||
ProjectName = project.Name ?? "",
|
|
||||||
TimeStamp = DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Preload relevant data
|
|
||||||
var projectAllocations = await _context.ProjectAllocations
|
|
||||||
.Include(p => p.Employee)
|
|
||||||
.Where(p => p.ProjectId == project.Id && p.IsActive)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var assignedEmployeeIds = projectAllocations.Select(p => p.EmployeeId).ToHashSet();
|
|
||||||
|
|
||||||
var attendances = await _context.Attendes
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(a => a.ProjectID == project.Id && a.InTime != null && a.InTime.Value.Date == reportDate)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var checkedInEmployeeIds = attendances.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
|
||||||
var checkoutPendingIds = attendances.Where(a => a.OutTime == null).Select(a => a.EmployeeID).Distinct().ToHashSet();
|
|
||||||
var regularizationIds = attendances
|
|
||||||
.Where(a => a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
|
|
||||||
.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
|
||||||
|
|
||||||
// Preload buildings, floors, areas
|
|
||||||
var buildings = await _context.Buildings.Where(b => b.ProjectId == project.Id).ToListAsync();
|
|
||||||
var buildingIds = buildings.Select(b => b.Id).ToList();
|
|
||||||
|
|
||||||
var floors = await _context.Floor.Where(f => buildingIds.Contains(f.BuildingId)).ToListAsync();
|
|
||||||
var floorIds = floors.Select(f => f.Id).ToList();
|
|
||||||
|
|
||||||
var areas = await _context.WorkAreas.Where(a => floorIds.Contains(a.FloorId)).ToListAsync();
|
|
||||||
var areaIds = areas.Select(a => a.Id).ToList();
|
|
||||||
|
|
||||||
var workItems = await _context.WorkItems
|
|
||||||
.Include(w => w.ActivityMaster)
|
|
||||||
.Where(w => areaIds.Contains(w.WorkAreaId))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var itemIds = workItems.Select(i => i.Id).ToList();
|
|
||||||
|
|
||||||
var tasks = await _context.TaskAllocations
|
|
||||||
.Where(t => itemIds.Contains(t.WorkItemId))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var taskIds = tasks.Select(t => t.Id).ToList();
|
|
||||||
|
|
||||||
var taskMembers = await _context.TaskMembers
|
|
||||||
.Include(m => m.Employee)
|
|
||||||
.Where(m => taskIds.Contains(m.TaskAllocationId))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// Aggregate data
|
|
||||||
double totalPlannedWork = workItems.Sum(w => w.PlannedWork);
|
|
||||||
double totalCompletedWork = workItems.Sum(w => w.CompletedWork);
|
|
||||||
|
|
||||||
var todayAssignedTasks = tasks.Where(t => t.AssignmentDate.Date == reportDate).ToList();
|
|
||||||
var reportPending = tasks.Where(t => t.ReportedDate == null).ToList();
|
|
||||||
|
|
||||||
double totalPlannedTask = todayAssignedTasks.Sum(t => t.PlannedTask);
|
|
||||||
double totalCompletedTask = todayAssignedTasks.Sum(t => t.CompletedTask);
|
|
||||||
var jobRoleIds = projectAllocations.Select(pa => pa.JobRoleId).ToList();
|
|
||||||
var jobRoles = await _context.JobRoles
|
|
||||||
.Where(j => j.TenantId == project.TenantId && jobRoleIds.Contains(j.Id))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// Team on site
|
|
||||||
var teamOnSite = jobRoles
|
|
||||||
.Select(role =>
|
|
||||||
{
|
|
||||||
var count = projectAllocations.Count(p => p.JobRoleId == role.Id && checkedInEmployeeIds.Contains(p.EmployeeId));
|
|
||||||
return new TeamOnSite { RoleName = role.Name, NumberofEmployees = count };
|
|
||||||
})
|
|
||||||
.OrderByDescending(t => t.NumberofEmployees)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// Task details
|
|
||||||
var performedTasks = todayAssignedTasks.Select(task =>
|
|
||||||
{
|
|
||||||
var workItem = workItems.FirstOrDefault(w => w.Id == task.WorkItemId);
|
|
||||||
var area = areas.FirstOrDefault(a => a.Id == workItem?.WorkAreaId);
|
|
||||||
var floor = floors.FirstOrDefault(f => f.Id == area?.FloorId);
|
|
||||||
var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId);
|
|
||||||
|
|
||||||
string activityName = workItem?.ActivityMaster?.ActivityName ?? "";
|
|
||||||
string location = $"{building?.Name} > {floor?.FloorName}</span><br/><span style=\"color: gray; font-size: small; padding-left: 10px;\"> {floor?.FloorName}-{area?.AreaName}";
|
|
||||||
double pending = (workItem?.PlannedWork ?? 0) - (workItem?.CompletedWork ?? 0);
|
|
||||||
|
|
||||||
var taskTeam = taskMembers
|
|
||||||
.Where(m => m.TaskAllocationId == task.Id)
|
|
||||||
.Select(m =>
|
|
||||||
{
|
|
||||||
string name = $"{m.Employee?.FirstName ?? ""} {m.Employee?.LastName ?? ""}";
|
|
||||||
var role = jobRoles.FirstOrDefault(r => r.Id == m.Employee?.JobRoleId);
|
|
||||||
return new TaskTeam { Name = name, RoleName = role?.Name ?? "" };
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return new PerformedTask
|
|
||||||
{
|
|
||||||
Activity = activityName,
|
|
||||||
Location = location,
|
|
||||||
AssignedToday = task.PlannedTask,
|
|
||||||
CompletedToday = task.CompletedTask,
|
|
||||||
Pending = pending,
|
|
||||||
Comment = task.Description,
|
|
||||||
Team = taskTeam
|
|
||||||
};
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
// Attendance details
|
|
||||||
var performedAttendance = attendances.Select(att =>
|
|
||||||
{
|
|
||||||
var alloc = projectAllocations.FirstOrDefault(p => p.EmployeeId == att.EmployeeID);
|
|
||||||
var role = jobRoles.FirstOrDefault(r => r.Id == alloc?.JobRoleId);
|
|
||||||
string name = $"{alloc?.Employee?.FirstName ?? ""} {alloc?.Employee?.LastName ?? ""}";
|
|
||||||
|
|
||||||
return new PerformedAttendance
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
RoleName = role?.Name ?? "",
|
|
||||||
InTime = att.InTime ?? DateTime.UtcNow,
|
|
||||||
OutTime = att.OutTime,
|
|
||||||
Comment = att.Comment
|
|
||||||
};
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
// Fill report
|
|
||||||
statisticReport.TodaysAttendances = checkedInEmployeeIds.Count;
|
|
||||||
statisticReport.TotalEmployees = assignedEmployeeIds.Count;
|
|
||||||
statisticReport.RegularizationPending = regularizationIds.Count;
|
|
||||||
statisticReport.CheckoutPending = checkoutPendingIds.Count;
|
|
||||||
statisticReport.TotalPlannedWork = totalPlannedWork;
|
|
||||||
statisticReport.TotalCompletedWork = totalCompletedWork;
|
|
||||||
statisticReport.TotalPlannedTask = totalPlannedTask;
|
|
||||||
statisticReport.TotalCompletedTask = totalCompletedTask;
|
|
||||||
statisticReport.CompletionStatus = totalPlannedWork > 0 ? totalCompletedWork / totalPlannedWork : 0;
|
|
||||||
statisticReport.TodaysAssignTasks = todayAssignedTasks.Count;
|
|
||||||
statisticReport.ReportPending = reportPending.Count;
|
|
||||||
statisticReport.TeamOnSite = teamOnSite;
|
|
||||||
statisticReport.PerformedTasks = performedTasks;
|
|
||||||
statisticReport.PerformedAttendance = performedAttendance;
|
|
||||||
|
|
||||||
// Send Email
|
// Send Email
|
||||||
var emailBody = await _emailSender.SendProjectStatisticsEmail(recipientEmails, body, subject, statisticReport);
|
var emailBody = await _emailSender.SendProjectStatisticsEmail(recipientEmails, body, subject, statisticReport);
|
||||||
var employee = await _context.Employees.FirstOrDefaultAsync(e => e.Email != null && recipientEmails.Contains(e.Email)) ?? new Employee();
|
var employee = await _context.Employees.FirstOrDefaultAsync(e => e.Email != null && recipientEmails.Contains(e.Email)) ?? new Employee();
|
||||||
|
@ -19,7 +19,7 @@ COPY ["Marco.Pms.Services/Marco.Pms.Services.csproj", "Marco.Pms.Services/"]
|
|||||||
COPY ["Marco.Pms.DataAccess/Marco.Pms.DataAccess.csproj", "Marco.Pms.DataAccess/"]
|
COPY ["Marco.Pms.DataAccess/Marco.Pms.DataAccess.csproj", "Marco.Pms.DataAccess/"]
|
||||||
COPY ["Marco.Pms.Model/Marco.Pms.Model.csproj", "Marco.Pms.Model/"]
|
COPY ["Marco.Pms.Model/Marco.Pms.Model.csproj", "Marco.Pms.Model/"]
|
||||||
COPY ["Marco.Pms.Utility/Marco.Pms.Utility.csproj", "Marco.Pms.Utility/"]
|
COPY ["Marco.Pms.Utility/Marco.Pms.Utility.csproj", "Marco.Pms.Utility/"]
|
||||||
COPY ["Marco.Pms.Utility/Marco.Pms.CacheHelper.csproj", "Marco.Pms.CacheHelper/"]
|
COPY ["Marco.Pms.CacheHelper/Marco.Pms.CacheHelper.csproj", "Marco.Pms.CacheHelper/"]
|
||||||
RUN dotnet restore "./Marco.Pms.Services/Marco.Pms.Services.csproj"
|
RUN dotnet restore "./Marco.Pms.Services/Marco.Pms.Services.csproj"
|
||||||
COPY . .
|
COPY . .
|
||||||
WORKDIR "/src/Marco.Pms.Services"
|
WORKDIR "/src/Marco.Pms.Services"
|
||||||
|
@ -120,6 +120,36 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
_logger.LogWarning("Error occured while updating planned work and completed work in building infra form Cache: {Error}", ex.Message);
|
_logger.LogWarning("Error occured while updating planned work and completed work in building infra form Cache: {Error}", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task<WorkAreaInfoMongoDB?> GetBuildingAndFloorByWorkAreaId(Guid workAreaId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _projectCache.GetBuildingAndFloorByWorkAreaIdFromCache(workAreaId);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Error occured while fetching workArea Details using its ID form Cache: {Error}", ex.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<List<WorkItemMongoDB>?> GetWorkItemsByWorkAreaIds(List<Guid> workAreaIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _projectCache.GetWorkItemsByWorkAreaIdsFromCache(workAreaIds);
|
||||||
|
if (response.Count > 0)
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Error occured while fetching workItems list using workArea IDs list form Cache: {Error}", ex.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------- WorkItem -------------------------------------------------------
|
// ------------------------------------------------------- WorkItem -------------------------------------------------------
|
||||||
|
|
||||||
|
274
Marco.Pms.Services/Helpers/ReportHelper.cs
Normal file
274
Marco.Pms.Services/Helpers/ReportHelper.cs
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using Marco.Pms.DataAccess.Data;
|
||||||
|
using Marco.Pms.Model.Dtos.Attendance;
|
||||||
|
using Marco.Pms.Model.MongoDBModels;
|
||||||
|
using Marco.Pms.Model.ViewModels.Report;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Helpers
|
||||||
|
{
|
||||||
|
public class ReportHelper
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext _context;
|
||||||
|
private readonly CacheUpdateHelper _cache;
|
||||||
|
public ReportHelper(CacheUpdateHelper cache, ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
_cache = cache;
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
public async Task<ProjectStatisticReport?> GetDailyProjectReport(Guid projectId, Guid tenantId)
|
||||||
|
{
|
||||||
|
// await _cache.GetBuildingAndFloorByWorkAreaId();
|
||||||
|
DateTime reportDate = DateTime.UtcNow.AddDays(-1).Date;
|
||||||
|
var project = await _cache.GetProjectDetails(projectId);
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
var projectSQL = await _context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||||
|
if (projectSQL != null)
|
||||||
|
{
|
||||||
|
project = new ProjectMongoDB
|
||||||
|
{
|
||||||
|
Id = projectSQL.Id.ToString(),
|
||||||
|
Name = projectSQL.Name,
|
||||||
|
ShortName = projectSQL.ShortName,
|
||||||
|
ProjectAddress = projectSQL.ProjectAddress,
|
||||||
|
ContactPerson = projectSQL.ContactPerson
|
||||||
|
};
|
||||||
|
await _cache.AddProjectDetails(projectSQL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (project != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var statisticReport = new ProjectStatisticReport
|
||||||
|
{
|
||||||
|
Date = reportDate,
|
||||||
|
ProjectName = project.Name ?? "",
|
||||||
|
TimeStamp = DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preload relevant data
|
||||||
|
var projectAllocations = await _context.ProjectAllocations
|
||||||
|
.Include(p => p.Employee)
|
||||||
|
.Where(p => p.ProjectId == projectId && p.IsActive)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var assignedEmployeeIds = projectAllocations.Select(p => p.EmployeeId).ToHashSet();
|
||||||
|
|
||||||
|
var attendances = await _context.Attendes
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(a => a.ProjectID == projectId && a.InTime != null && a.InTime.Value.Date == reportDate)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var checkedInEmployeeIds = attendances.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
var checkoutPendingIds = attendances.Where(a => a.OutTime == null).Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
var regularizationIds = attendances
|
||||||
|
.Where(a => a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
|
||||||
|
.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
|
||||||
|
// Preload buildings, floors, areas
|
||||||
|
List<BuildingMongoDBVM>? buildings = null;
|
||||||
|
List<FloorMongoDBVM>? floors = null;
|
||||||
|
List<WorkAreaMongoDB>? areas = null;
|
||||||
|
List<WorkItemMongoDB>? workItems = null;
|
||||||
|
|
||||||
|
// Fetch Buildings
|
||||||
|
buildings = project.Buildings
|
||||||
|
.Select(b => new BuildingMongoDBVM
|
||||||
|
{
|
||||||
|
Id = b.Id,
|
||||||
|
ProjectId = b.ProjectId,
|
||||||
|
BuildingName = b.BuildingName,
|
||||||
|
Description = b.Description
|
||||||
|
}).ToList();
|
||||||
|
if (buildings == null)
|
||||||
|
{
|
||||||
|
buildings = await _context.Buildings
|
||||||
|
.Where(b => b.ProjectId == projectId)
|
||||||
|
.Select(b => new BuildingMongoDBVM
|
||||||
|
{
|
||||||
|
Id = b.Id.ToString(),
|
||||||
|
ProjectId = b.ProjectId.ToString(),
|
||||||
|
BuildingName = b.Name,
|
||||||
|
Description = b.Description
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch Floors
|
||||||
|
floors = project.Buildings
|
||||||
|
.SelectMany(b => b.Floors.Select(f => new FloorMongoDBVM
|
||||||
|
{
|
||||||
|
Id = f.Id.ToString(),
|
||||||
|
BuildingId = f.BuildingId,
|
||||||
|
FloorName = f.FloorName
|
||||||
|
})).ToList();
|
||||||
|
if (floors == null)
|
||||||
|
{
|
||||||
|
var buildingIds = buildings.Select(b => Guid.Parse(b.Id)).ToList();
|
||||||
|
floors = await _context.Floor
|
||||||
|
.Where(f => buildingIds.Contains(f.BuildingId))
|
||||||
|
.Select(f => new FloorMongoDBVM
|
||||||
|
{
|
||||||
|
Id = f.Id.ToString(),
|
||||||
|
BuildingId = f.BuildingId.ToString(),
|
||||||
|
FloorName = f.FloorName
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch Work Areas
|
||||||
|
areas = project.Buildings
|
||||||
|
.SelectMany(b => b.Floors)
|
||||||
|
.SelectMany(f => f.WorkAreas).ToList();
|
||||||
|
if (areas == null)
|
||||||
|
{
|
||||||
|
var floorIds = floors.Select(f => Guid.Parse(f.Id)).ToList();
|
||||||
|
areas = await _context.WorkAreas
|
||||||
|
.Where(a => floorIds.Contains(a.FloorId))
|
||||||
|
.Select(wa => new WorkAreaMongoDB
|
||||||
|
{
|
||||||
|
Id = wa.Id.ToString(),
|
||||||
|
FloorId = wa.FloorId.ToString(),
|
||||||
|
AreaName = wa.AreaName,
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var areaIds = areas.Select(a => Guid.Parse(a.Id)).ToList();
|
||||||
|
|
||||||
|
// fetch Work Items
|
||||||
|
workItems = await _cache.GetWorkItemsByWorkAreaIds(areaIds);
|
||||||
|
if (workItems == null)
|
||||||
|
{
|
||||||
|
workItems = await _context.WorkItems
|
||||||
|
.Include(w => w.ActivityMaster)
|
||||||
|
.Where(w => areaIds.Contains(w.WorkAreaId))
|
||||||
|
.Select(wi => new WorkItemMongoDB
|
||||||
|
{
|
||||||
|
Id = wi.Id.ToString(),
|
||||||
|
WorkAreaId = wi.WorkAreaId.ToString(),
|
||||||
|
PlannedWork = wi.PlannedWork,
|
||||||
|
CompletedWork = wi.CompletedWork,
|
||||||
|
Description = wi.Description,
|
||||||
|
TaskDate = wi.TaskDate,
|
||||||
|
ActivityMaster = new ActivityMasterMongoDB
|
||||||
|
{
|
||||||
|
ActivityName = wi.ActivityMaster != null ? wi.ActivityMaster.ActivityName : null,
|
||||||
|
UnitOfMeasurement = wi.ActivityMaster != null ? wi.ActivityMaster.UnitOfMeasurement : null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemIds = workItems.Select(i => Guid.Parse(i.Id)).ToList();
|
||||||
|
|
||||||
|
var tasks = await _context.TaskAllocations
|
||||||
|
.Where(t => itemIds.Contains(t.WorkItemId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var taskIds = tasks.Select(t => t.Id).ToList();
|
||||||
|
|
||||||
|
var taskMembers = await _context.TaskMembers
|
||||||
|
.Include(m => m.Employee)
|
||||||
|
.Where(m => taskIds.Contains(m.TaskAllocationId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Aggregate data
|
||||||
|
double totalPlannedWork = workItems.Sum(w => w.PlannedWork);
|
||||||
|
double totalCompletedWork = workItems.Sum(w => w.CompletedWork);
|
||||||
|
|
||||||
|
var todayAssignedTasks = tasks.Where(t => t.AssignmentDate.Date == reportDate).ToList();
|
||||||
|
var reportPending = tasks.Where(t => t.ReportedDate == null).ToList();
|
||||||
|
|
||||||
|
double totalPlannedTask = todayAssignedTasks.Sum(t => t.PlannedTask);
|
||||||
|
double totalCompletedTask = todayAssignedTasks.Sum(t => t.CompletedTask);
|
||||||
|
var jobRoleIds = projectAllocations.Select(pa => pa.JobRoleId).ToList();
|
||||||
|
var jobRoles = await _context.JobRoles
|
||||||
|
.Where(j => j.TenantId == tenantId && jobRoleIds.Contains(j.Id))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Team on site
|
||||||
|
var teamOnSite = jobRoles
|
||||||
|
.Select(role =>
|
||||||
|
{
|
||||||
|
var count = projectAllocations.Count(p => p.JobRoleId == role.Id && checkedInEmployeeIds.Contains(p.EmployeeId));
|
||||||
|
return new TeamOnSite { RoleName = role.Name, NumberofEmployees = count };
|
||||||
|
})
|
||||||
|
.OrderByDescending(t => t.NumberofEmployees)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Task details
|
||||||
|
var performedTasks = todayAssignedTasks.Select(task =>
|
||||||
|
{
|
||||||
|
var workItem = workItems.FirstOrDefault(w => w.Id == task.WorkItemId.ToString());
|
||||||
|
var area = areas.FirstOrDefault(a => a.Id == workItem?.WorkAreaId);
|
||||||
|
var floor = floors.FirstOrDefault(f => f.Id == area?.FloorId);
|
||||||
|
var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId);
|
||||||
|
|
||||||
|
string activityName = workItem?.ActivityMaster?.ActivityName ?? "";
|
||||||
|
string location = $"{building?.BuildingName} > {floor?.FloorName}</span><br/><span style=\"color: gray; font-size: small; padding-left: 10px;\"> {floor?.FloorName}-{area?.AreaName}";
|
||||||
|
double pending = (workItem?.PlannedWork ?? 0) - (workItem?.CompletedWork ?? 0);
|
||||||
|
|
||||||
|
var taskTeam = taskMembers
|
||||||
|
.Where(m => m.TaskAllocationId == task.Id)
|
||||||
|
.Select(m =>
|
||||||
|
{
|
||||||
|
string name = $"{m.Employee?.FirstName ?? ""} {m.Employee?.LastName ?? ""}";
|
||||||
|
var role = jobRoles.FirstOrDefault(r => r.Id == m.Employee?.JobRoleId);
|
||||||
|
return new TaskTeam { Name = name, RoleName = role?.Name ?? "" };
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new PerformedTask
|
||||||
|
{
|
||||||
|
Activity = activityName,
|
||||||
|
Location = location,
|
||||||
|
AssignedToday = task.PlannedTask,
|
||||||
|
CompletedToday = task.CompletedTask,
|
||||||
|
Pending = pending,
|
||||||
|
Comment = task.Description,
|
||||||
|
Team = taskTeam
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Attendance details
|
||||||
|
var performedAttendance = attendances.Select(att =>
|
||||||
|
{
|
||||||
|
var alloc = projectAllocations.FirstOrDefault(p => p.EmployeeId == att.EmployeeID);
|
||||||
|
var role = jobRoles.FirstOrDefault(r => r.Id == alloc?.JobRoleId);
|
||||||
|
string name = $"{alloc?.Employee?.FirstName ?? ""} {alloc?.Employee?.LastName ?? ""}";
|
||||||
|
|
||||||
|
return new PerformedAttendance
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
RoleName = role?.Name ?? "",
|
||||||
|
InTime = att.InTime ?? DateTime.UtcNow,
|
||||||
|
OutTime = att.OutTime,
|
||||||
|
Comment = att.Comment
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Fill report
|
||||||
|
statisticReport.TodaysAttendances = checkedInEmployeeIds.Count;
|
||||||
|
statisticReport.TotalEmployees = assignedEmployeeIds.Count;
|
||||||
|
statisticReport.RegularizationPending = regularizationIds.Count;
|
||||||
|
statisticReport.CheckoutPending = checkoutPendingIds.Count;
|
||||||
|
statisticReport.TotalPlannedWork = totalPlannedWork;
|
||||||
|
statisticReport.TotalCompletedWork = totalCompletedWork;
|
||||||
|
statisticReport.TotalPlannedTask = totalPlannedTask;
|
||||||
|
statisticReport.TotalCompletedTask = totalCompletedTask;
|
||||||
|
statisticReport.CompletionStatus = totalPlannedWork > 0 ? totalCompletedWork / totalPlannedWork : 0;
|
||||||
|
statisticReport.TodaysAssignTasks = todayAssignedTasks.Count;
|
||||||
|
statisticReport.ReportPending = reportPending.Count;
|
||||||
|
statisticReport.TeamOnSite = teamOnSite;
|
||||||
|
statisticReport.PerformedTasks = performedTasks;
|
||||||
|
statisticReport.PerformedAttendance = performedAttendance;
|
||||||
|
return statisticReport;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ namespace MarcoBMS.Services.Middleware
|
|||||||
var response = context.Response;
|
var response = context.Response;
|
||||||
var request = context.Request;
|
var request = context.Request;
|
||||||
var tenantId = context.User.FindFirst("TenantId")?.Value;
|
var tenantId = context.User.FindFirst("TenantId")?.Value;
|
||||||
|
string origin = request.Headers["Origin"].FirstOrDefault() ?? "";
|
||||||
|
|
||||||
using (LogContext.PushProperty("TenantId", tenantId))
|
using (LogContext.PushProperty("TenantId", tenantId))
|
||||||
using (LogContext.PushProperty("TraceId", context.TraceIdentifier))
|
using (LogContext.PushProperty("TraceId", context.TraceIdentifier))
|
||||||
@ -33,6 +33,8 @@ namespace MarcoBMS.Services.Middleware
|
|||||||
using (LogContext.PushProperty("Timestamp", DateTime.UtcNow))
|
using (LogContext.PushProperty("Timestamp", DateTime.UtcNow))
|
||||||
using (LogContext.PushProperty("IpAddress", context.Connection.RemoteIpAddress?.ToString()))
|
using (LogContext.PushProperty("IpAddress", context.Connection.RemoteIpAddress?.ToString()))
|
||||||
using (LogContext.PushProperty("RequestPath", request.Path))
|
using (LogContext.PushProperty("RequestPath", request.Path))
|
||||||
|
using (LogContext.PushProperty("Origin", origin))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -137,6 +137,7 @@ builder.Services.AddScoped<EmployeeHelper>();
|
|||||||
builder.Services.AddScoped<ProjectsHelper>();
|
builder.Services.AddScoped<ProjectsHelper>();
|
||||||
builder.Services.AddScoped<DirectoryHelper>();
|
builder.Services.AddScoped<DirectoryHelper>();
|
||||||
builder.Services.AddScoped<MasterHelper>();
|
builder.Services.AddScoped<MasterHelper>();
|
||||||
|
builder.Services.AddScoped<ReportHelper>();
|
||||||
builder.Services.AddScoped<CacheUpdateHelper>();
|
builder.Services.AddScoped<CacheUpdateHelper>();
|
||||||
builder.Services.AddScoped<ProjectCache>();
|
builder.Services.AddScoped<ProjectCache>();
|
||||||
builder.Services.AddScoped<EmployeeCache>();
|
builder.Services.AddScoped<EmployeeCache>();
|
||||||
|
@ -218,7 +218,7 @@ namespace MarcoBMS.Services.Service
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Token is invalid
|
// Token is invalid
|
||||||
Console.WriteLine($"Token validation failed: {ex.Message}");
|
_logger.LogError($"Token validation failed: {ex.Message}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user