Compare commits
No commits in common. "0c6f5e0df0b179eeca2edc5e3a7f87722c74b207" and "ef84ba34da9354602d1291e0571572c5837a8e84" have entirely different histories.
0c6f5e0df0
...
ef84ba34da
@ -1,10 +0,0 @@
|
|||||||
namespace Marco.Pms.Model.Filters
|
|
||||||
{
|
|
||||||
public class TaskFilter
|
|
||||||
{
|
|
||||||
public List<Guid>? BuildingIds { get; set; }
|
|
||||||
public List<Guid>? FloorIds { get; set; }
|
|
||||||
public List<Guid>? ActivityIds { get; set; }
|
|
||||||
public List<Guid>? ServiceIds { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,7 +2,6 @@
|
|||||||
using Marco.Pms.Model.Activities;
|
using Marco.Pms.Model.Activities;
|
||||||
using Marco.Pms.Model.Dtos.Activities;
|
using Marco.Pms.Model.Dtos.Activities;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Model.Filters;
|
|
||||||
using Marco.Pms.Model.Mapper;
|
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;
|
||||||
@ -18,7 +17,6 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Text.Json;
|
|
||||||
using Document = Marco.Pms.Model.DocumentManager.Document;
|
using Document = Marco.Pms.Model.DocumentManager.Document;
|
||||||
|
|
||||||
namespace MarcoBMS.Services.Controllers
|
namespace MarcoBMS.Services.Controllers
|
||||||
@ -430,8 +428,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("list")]
|
[HttpGet("list")]
|
||||||
public async Task<IActionResult> GetTasksList([FromQuery] Guid projectId, [FromQuery] string? filter, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20,
|
public async Task<IActionResult> GetTasksList([FromQuery] Guid projectId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
|
||||||
[FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
|
|
||||||
{
|
{
|
||||||
_logger.LogInfo("GetTasksList called for projectId: {ProjectId}, dateFrom: {DateFrom}, dateTo: {DateTo}", projectId, dateFrom ?? "", dateTo ?? "");
|
_logger.LogInfo("GetTasksList called for projectId: {ProjectId}, dateFrom: {DateFrom}, dateTo: {DateTo}", projectId, dateFrom ?? "", dateTo ?? "");
|
||||||
|
|
||||||
@ -439,103 +436,76 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
DateTime fromDate = new DateTime();
|
DateTime fromDate = new DateTime();
|
||||||
DateTime toDate = new DateTime();
|
DateTime toDate = new DateTime();
|
||||||
|
|
||||||
// 1. Parse and validate dateFrom
|
// Parse and validate dateFrom
|
||||||
if (dateFrom != null && !DateTime.TryParse(dateFrom, out fromDate))
|
if (dateFrom != null && !DateTime.TryParse(dateFrom, out fromDate))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Invalid starting date provided: {DateFrom}", dateFrom);
|
_logger.LogWarning("Invalid starting date provided: {DateFrom}", dateFrom);
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid starting date.", "Invalid starting date.", 400));
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid starting date.", "Invalid starting date.", 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Parse and validate dateTo
|
// Parse and validate dateTo
|
||||||
if (dateTo != null && !DateTime.TryParse(dateTo, out toDate))
|
if (dateTo != null && !DateTime.TryParse(dateTo, out toDate))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Invalid ending date provided: {DateTo}", dateTo);
|
_logger.LogWarning("Invalid ending date provided: {DateTo}", dateTo);
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid ending date.", "Invalid ending date.", 400));
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid ending date.", "Invalid ending date.", 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Set default date range if not provided
|
// Set default date range if not provided
|
||||||
fromDate = dateFrom == null ? DateTime.UtcNow.Date : fromDate;
|
fromDate = dateFrom == null ? DateTime.UtcNow.Date : fromDate;
|
||||||
toDate = dateTo == null ? fromDate.AddDays(1) : toDate;
|
toDate = dateTo == null ? fromDate.AddDays(1) : toDate;
|
||||||
|
|
||||||
|
// 1. Get all buildings under this project
|
||||||
|
_logger.LogInfo("Fetching buildings for projectId: {ProjectId}", projectId);
|
||||||
|
var buildings = await _context.Buildings
|
||||||
|
.Where(b => b.ProjectId == projectId && b.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var buildingIds = buildings.Select(b => b.Id).ToList();
|
||||||
|
|
||||||
|
// 2. Get floors under the buildings
|
||||||
|
var floors = await _context.Floor
|
||||||
|
.Where(f => buildingIds.Contains(f.BuildingId) && f.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
var floorIds = floors.Select(f => f.Id).ToList();
|
||||||
|
|
||||||
|
// 3. Get work areas under the floors
|
||||||
|
var workAreas = await _context.WorkAreas
|
||||||
|
.Where(a => floorIds.Contains(a.FloorId) && a.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
var workAreaIds = workAreas.Select(a => a.Id).ToList();
|
||||||
|
|
||||||
|
// 4. Get work items under the work areas
|
||||||
|
var workItems = await _context.WorkItems
|
||||||
|
.Where(i => workAreaIds.Contains(i.WorkAreaId) && i.TenantId == tenantId)
|
||||||
|
.Include(i => i.ActivityMaster)
|
||||||
|
.ToListAsync();
|
||||||
|
var workItemIds = workItems.Select(i => i.Id).ToList();
|
||||||
|
|
||||||
_logger.LogInfo("Fetching task allocations between {FromDate} and {ToDate}", fromDate, toDate);
|
_logger.LogInfo("Fetching task allocations between {FromDate} and {ToDate}", fromDate, toDate);
|
||||||
|
|
||||||
// 4. Get task allocations in the specified date range
|
// 5. Get task allocations in the specified date range
|
||||||
var taskAllocationQuery = _context.TaskAllocations
|
var taskAllocations = await _context.TaskAllocations
|
||||||
.Include(t => t.Employee)
|
.Include(t => t.Employee)
|
||||||
.Include(t => t.ReportedBy)
|
.Include(t => t.ReportedBy)
|
||||||
.Include(t => t.ApprovedBy)
|
.Include(t => t.ApprovedBy)
|
||||||
.Include(t => t.WorkStatus)
|
.Include(t => t.WorkStatus)
|
||||||
.Include(t => t.WorkItem)
|
.Include(t => t.WorkItem)
|
||||||
.ThenInclude(wi => wi!.ActivityMaster)
|
.Where(t => workItemIds.Contains(t.WorkItemId) &&
|
||||||
.ThenInclude(a => a!.ActivityGroup)
|
|
||||||
.ThenInclude(ag => ag!.Service)
|
|
||||||
.Include(t => t.WorkItem)
|
|
||||||
.ThenInclude(wi => wi!.WorkCategoryMaster)
|
|
||||||
.Include(t => t.WorkItem)
|
|
||||||
.ThenInclude(wi => wi!.WorkArea)
|
|
||||||
.ThenInclude(wa => wa!.Floor)
|
|
||||||
.ThenInclude(f => f!.Building)
|
|
||||||
.Where(t => t.WorkItem != null &&
|
|
||||||
t.WorkItem.WorkArea != null &&
|
|
||||||
t.WorkItem.WorkArea.Floor != null &&
|
|
||||||
t.WorkItem.WorkArea.Floor.Building != null &&
|
|
||||||
t.WorkItem.WorkArea.Floor.Building.ProjectId != projectId &&
|
|
||||||
t.AssignmentDate.Date >= fromDate.Date &&
|
t.AssignmentDate.Date >= fromDate.Date &&
|
||||||
t.AssignmentDate.Date <= toDate.Date &&
|
t.AssignmentDate.Date <= toDate.Date &&
|
||||||
t.TenantId == tenantId);
|
t.TenantId == tenantId)
|
||||||
|
|
||||||
var taskFilter = TryDeserializeFilter(filter);
|
|
||||||
|
|
||||||
if (taskFilter != null)
|
|
||||||
{
|
|
||||||
if (taskFilter.BuildingIds?.Any() ?? false)
|
|
||||||
{
|
|
||||||
taskAllocationQuery = taskAllocationQuery.Where(t => t.WorkItem != null &&
|
|
||||||
t.WorkItem.WorkArea != null &&
|
|
||||||
t.WorkItem.WorkArea.Floor != null &&
|
|
||||||
taskFilter.BuildingIds.Contains(t.WorkItem.WorkArea.Floor.BuildingId));
|
|
||||||
}
|
|
||||||
if (taskFilter.FloorIds?.Any() ?? false)
|
|
||||||
{
|
|
||||||
taskAllocationQuery = taskAllocationQuery.Where(t => t.WorkItem != null &&
|
|
||||||
t.WorkItem.WorkArea != null &&
|
|
||||||
taskFilter.FloorIds.Contains(t.WorkItem.WorkArea.FloorId));
|
|
||||||
}
|
|
||||||
if (taskFilter.ActivityIds?.Any() ?? false)
|
|
||||||
{
|
|
||||||
taskAllocationQuery = taskAllocationQuery.Where(t => t.WorkItem != null &&
|
|
||||||
taskFilter.ActivityIds.Contains(t.WorkItem.ActivityId));
|
|
||||||
}
|
|
||||||
if (taskFilter.ServiceIds?.Any() ?? false)
|
|
||||||
{
|
|
||||||
taskAllocationQuery = taskAllocationQuery.Where(t => t.WorkItem != null &&
|
|
||||||
t.WorkItem.ActivityMaster != null &&
|
|
||||||
t.WorkItem.ActivityMaster.ActivityGroup != null &&
|
|
||||||
taskFilter.ServiceIds.Contains(t.WorkItem.ActivityMaster.ActivityGroup.ServiceId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int totalRecords = await taskAllocationQuery.CountAsync();
|
|
||||||
int totalPages = (int)Math.Ceiling((double)totalRecords / pageSize);
|
|
||||||
|
|
||||||
var taskAllocations = await taskAllocationQuery
|
|
||||||
.OrderByDescending(t => t.AssignmentDate)
|
|
||||||
.Skip((pageNumber - 1) * pageSize)
|
|
||||||
.Take(pageSize)
|
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var taskIds = taskAllocations.Select(t => t.Id).ToList();
|
var taskIds = taskAllocations.Select(t => t.Id).ToList();
|
||||||
|
|
||||||
// 5. Load team members
|
// 6. Load team members
|
||||||
_logger.LogInfo("Loading task members and related employee data.");
|
_logger.LogInfo("Loading task members and related employee data.");
|
||||||
var teamMembers = await _context.TaskMembers
|
var teamMembers = await _context.TaskMembers
|
||||||
.Include(t => t.Employee)
|
.Include(t => t.Employee)
|
||||||
.Where(t => taskIds.Contains(t.TaskAllocationId))
|
.Where(t => taskIds.Contains(t.TaskAllocationId))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
// 6. Load task comments
|
// 7. Load task comments
|
||||||
_logger.LogInfo("Fetching comments and attachments.");
|
_logger.LogInfo("Fetching comments and attachments.");
|
||||||
var allComments = await _context.TaskComments
|
var allComments = await _context.TaskComments
|
||||||
.Include(c => c.Employee)
|
.Include(c => c.Employee)
|
||||||
@ -543,14 +513,14 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
var commentIds = allComments.Select(c => c.Id).ToList();
|
var commentIds = allComments.Select(c => c.Id).ToList();
|
||||||
|
|
||||||
// 7. Load all attachments (task and comment)
|
// 8. Load all attachments (task and comment)
|
||||||
var attachments = await _context.TaskAttachments
|
var attachments = await _context.TaskAttachments
|
||||||
.Where(t => taskIds.Contains(t.ReferenceId) || commentIds.Contains(t.ReferenceId))
|
.Where(t => taskIds.Contains(t.ReferenceId) || commentIds.Contains(t.ReferenceId))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var documentIds = attachments.Select(t => t.DocumentId).ToList();
|
var documentIds = attachments.Select(t => t.DocumentId).ToList();
|
||||||
|
|
||||||
// 8. Load actual documents from attachment references
|
// 9. Load actual documents from attachment references
|
||||||
var documents = await _context.Documents
|
var documents = await _context.Documents
|
||||||
.Where(d => documentIds.Contains(d.Id))
|
.Where(d => documentIds.Contains(d.Id))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@ -636,18 +606,9 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
tasks.Add(response);
|
tasks.Add(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
var VM = new
|
|
||||||
{
|
|
||||||
TotalCount = totalRecords,
|
|
||||||
TotalPages = totalPages,
|
|
||||||
CurrentPage = pageNumber,
|
|
||||||
PageSize = pageSize,
|
|
||||||
Data = tasks
|
|
||||||
};
|
|
||||||
|
|
||||||
_logger.LogInfo("Task list constructed successfully. Returning {Count} tasks.", tasks.Count);
|
_logger.LogInfo("Task list constructed successfully. Returning {Count} tasks.", tasks.Count);
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(VM, "Success", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(tasks, "Success", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("get/{taskId}")]
|
[HttpGet("get/{taskId}")]
|
||||||
@ -908,44 +869,5 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse("Task has been approved", "Task has been approved", 200));
|
return Ok(ApiResponse<object>.SuccessResponse("Task has been approved", "Task has been approved", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskFilter? TryDeserializeFilter(string? filter)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(filter))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
||||||
TaskFilter? expenseFilter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// First, try to deserialize directly. This is the expected case (e.g., from a web client).
|
|
||||||
expenseFilter = JsonSerializer.Deserialize<TaskFilter>(filter, options);
|
|
||||||
}
|
|
||||||
catch (JsonException ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "[{MethodName}] Failed to directly deserialize filter. Attempting to unescape and re-parse. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
|
||||||
|
|
||||||
// If direct deserialization fails, it might be an escaped string (common with tools like Postman or some mobile clients).
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Unescape the string first, then deserialize the result.
|
|
||||||
string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
|
|
||||||
if (!string.IsNullOrWhiteSpace(unescapedJsonString))
|
|
||||||
{
|
|
||||||
expenseFilter = JsonSerializer.Deserialize<TaskFilter>(unescapedJsonString, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (JsonException ex1)
|
|
||||||
{
|
|
||||||
// If both attempts fail, log the final error and return null.
|
|
||||||
_logger.LogError(ex1, "[{MethodName}] All attempts to deserialize the filter failed. Filter will be ignored. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return expenseFilter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user