diff --git a/Marco.Pms.Services/Controllers/DashboardController.cs b/Marco.Pms.Services/Controllers/DashboardController.cs index 891fcbe..cf7927e 100644 --- a/Marco.Pms.Services/Controllers/DashboardController.cs +++ b/Marco.Pms.Services/Controllers/DashboardController.cs @@ -228,7 +228,7 @@ namespace Marco.Pms.Services.Controllers // --- Step 1: Get the list of projects the user can access --- // This query is more efficient as it only selects the IDs needed. - var projects = await _projectServices.GetMyProjectIdsAsync(tenantId, loggedInEmployee); + var projects = await _projectServices.GetMyProjectIdsAsync(loggedInEmployee, tenantId); var accessibleActiveProjectIds = await _context.Projects .Where(p => p.ProjectStatusId == ActiveId && projects.Contains(p.Id)) @@ -354,7 +354,7 @@ namespace Marco.Pms.Services.Controllers // --- Logic for ALL Accessible Projects --- // 2c. Get a list of all projects the user is allowed to see. - var accessibleProjectIds = await _projectServices.GetMyProjectIdsAsync(tenantId, loggedInEmployee); + var accessibleProjectIds = await _projectServices.GetMyProjectIdsAsync(loggedInEmployee, tenantId); if (!accessibleProjectIds.Any()) { diff --git a/Marco.Pms.Services/Controllers/EmployeeController.cs b/Marco.Pms.Services/Controllers/EmployeeController.cs index aa58e95..15da5d4 100644 --- a/Marco.Pms.Services/Controllers/EmployeeController.cs +++ b/Marco.Pms.Services/Controllers/EmployeeController.cs @@ -270,7 +270,7 @@ namespace MarcoBMS.Services.Controllers else if (hasViewTeamMembersPermission && !showInactive && !projectId.HasValue) { // Only active team members with limited permission - var projectIds = await _projectServices.GetMyProjectIdsAsync(tenantId, loggedInEmployee); + var projectIds = await _projectServices.GetMyProjectIdsAsync(loggedInEmployee, tenantId); employees = await _context.ProjectAllocations .AsNoTracking() diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 4b76165..52e0589 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -40,12 +40,21 @@ namespace MarcoBMS.Services.Controllers #region =================================================================== Project Get APIs =================================================================== + [HttpGet("list/basic/all")] + public async Task GetBothProjectBasicList([FromQuery] string? searchString) + { + // Get the current user + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _projectServices.GetBothProjectBasicListAsync(searchString, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + [HttpGet("list/basic")] public async Task GetAllProjectsBasic([FromQuery] bool provideAll = false) { // Get the current user var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAllProjectsBasicAsync(provideAll, tenantId, loggedInEmployee); + var response = await _projectServices.GetAllProjectsBasicAsync(provideAll, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -70,7 +79,7 @@ namespace MarcoBMS.Services.Controllers return BadRequest(ApiResponse.ErrorResponse("Invalid request data provided.", errors, 400)); } var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAllProjectsAsync(pageNumber, pageSize, tenantId, loggedInEmployee); + var response = await _projectServices.GetAllProjectsAsync(pageNumber, pageSize, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -93,11 +102,10 @@ namespace MarcoBMS.Services.Controllers } var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectAsync(id, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } - [HttpGet("details/{id}")] public async Task GetProjectDetails([FromRoute] Guid id) { @@ -116,7 +124,7 @@ namespace MarcoBMS.Services.Controllers // Step 2: Get logged-in employee var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectDetailsAsync(id, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectDetailsAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -137,7 +145,7 @@ namespace MarcoBMS.Services.Controllers var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectDetailsOldAsync(id, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectDetailsOldAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -158,7 +166,7 @@ namespace MarcoBMS.Services.Controllers // 2. Prepare data without I/O Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.CreateProjectAsync(projectDto, tenantId, loggedInEmployee); + var response = await _projectServices.CreateProjectAsync(projectDto, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Create_Project", Response = response.Data }; @@ -188,7 +196,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.UpdateProjectAsync(id, updateProjectDto, tenantId, loggedInEmployee); + var response = await _projectServices.UpdateProjectAsync(id, updateProjectDto, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Update_Project", Response = response.Data }; @@ -214,7 +222,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetEmployeeByProjectIdAsync(projectId, organizationId, includeInactive, tenantId, loggedInEmployee); + var response = await _projectServices.GetEmployeeByProjectIdAsync(projectId, organizationId, includeInactive, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -231,7 +239,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectAllocationAsync(projectId, organizationId, serviceId, includeInactive, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectAllocationAsync(projectId, organizationId, serviceId, includeInactive, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -248,7 +256,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.ManageAllocationAsync(projectAllocationDot, tenantId, loggedInEmployee); + var response = await _projectServices.ManageAllocationAsync(projectAllocationDot, loggedInEmployee, tenantId); if (response.Success) { List employeeIds = response.Data.Select(pa => pa.EmployeeId).ToList(); @@ -274,7 +282,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectsByEmployeeAsync(employeeId, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectsByEmployeeAsync(employeeId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -291,7 +299,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectByEmployeeBasicAsync(employeeId, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectByEmployeeBasicAsync(employeeId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -308,7 +316,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.AssigneProjectsToEmployeeAsync(projectAllocationDtos, employeeId, tenantId, loggedInEmployee); + var response = await _projectServices.AssigneProjectsToEmployeeAsync(projectAllocationDtos, employeeId, loggedInEmployee, tenantId); if (response.Success) { List projectIds = response.Data.Select(pa => pa.ProjectId).ToList(); @@ -323,7 +331,7 @@ namespace MarcoBMS.Services.Controllers public async Task GetProjectTeamByServiceAndOrganization(Guid projectId, [FromQuery] Guid? serviceId, [FromQuery] Guid? organizationId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectTeamByServiceAndOrganizationAsync(projectId, serviceId, organizationId, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectTeamByServiceAndOrganizationAsync(projectId, serviceId, organizationId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -344,7 +352,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetInfraDetailsAsync(projectId, serviceId, tenantId, loggedInEmployee); + var response = await _projectServices.GetInfraDetailsAsync(projectId, serviceId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -362,7 +370,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetWorkItemsAsync(workAreaId, serviceId, tenantId, loggedInEmployee); + var response = await _projectServices.GetWorkItemsAsync(workAreaId, serviceId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -382,7 +390,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetTasksByEmployeeAsync(employeeId, fromDate.Value, toDate.Value, tenantId, loggedInEmployee); + var response = await _projectServices.GetTasksByEmployeeAsync(employeeId, fromDate.Value, toDate.Value, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -403,7 +411,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var serviceResponse = await _projectServices.ManageProjectInfraAsync(infraDtos, tenantId, loggedInEmployee); + var serviceResponse = await _projectServices.ManageProjectInfraAsync(infraDtos, loggedInEmployee, tenantId); var response = serviceResponse.Response; var notification = serviceResponse.Notification; if (notification != null) @@ -427,7 +435,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.CreateProjectTaskAsync(workItemDtos, tenantId, loggedInEmployee); + var response = await _projectServices.CreateProjectTaskAsync(workItemDtos, loggedInEmployee, tenantId); if (response.Success) { List workAreaIds = response.Data.Select(pa => pa.WorkItem?.WorkAreaId ?? Guid.Empty).ToList(); @@ -453,7 +461,7 @@ namespace MarcoBMS.Services.Controllers // --- Step 2: Prepare data without I/O --- Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var serviceResponse = await _projectServices.DeleteProjectTaskAsync(id, tenantId, loggedInEmployee); + var serviceResponse = await _projectServices.DeleteProjectTaskAsync(id, loggedInEmployee, tenantId); var response = serviceResponse.Response; var notification = serviceResponse.Notification; if (notification != null) @@ -471,7 +479,7 @@ namespace MarcoBMS.Services.Controllers public async Task ManageProjectLevelPermission([FromBody] ProjctLevelPermissionDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.ManageProjectLevelPermissionAsync(model, tenantId, loggedInEmployee); + var response = await _projectServices.ManageProjectLevelPermissionAsync(model, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -479,7 +487,7 @@ namespace MarcoBMS.Services.Controllers public async Task GetAssignedProjectLevelPermission(Guid employeeId, Guid projectId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAssignedProjectLevelPermissionAsync(employeeId, projectId, tenantId, loggedInEmployee); + var response = await _projectServices.GetAssignedProjectLevelPermissionAsync(employeeId, projectId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -495,7 +503,7 @@ namespace MarcoBMS.Services.Controllers public async Task AssignProjectLevelModules() { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.AssignProjectLevelModulesAsync(tenantId, loggedInEmployee); + var response = await _projectServices.AssignProjectLevelModulesAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -503,7 +511,7 @@ namespace MarcoBMS.Services.Controllers public async Task GetEmployeeToWhomProjectLevelAssigned(Guid projectId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetEmployeeToWhomProjectLevelAssignedAsync(projectId, tenantId, loggedInEmployee); + var response = await _projectServices.GetEmployeeToWhomProjectLevelAssignedAsync(projectId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -515,7 +523,7 @@ namespace MarcoBMS.Services.Controllers public async Task AssignServiceToProject(Guid projectId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAssignedServiceToProjectAsync(projectId, tenantId, loggedInEmployee); + var response = await _projectServices.GetAssignedServiceToProjectAsync(projectId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -524,7 +532,7 @@ namespace MarcoBMS.Services.Controllers public async Task AssignServiceToProject([FromBody] AssignServiceDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.AssignServiceToProjectAsync(model, tenantId, loggedInEmployee); + var response = await _projectServices.AssignServiceToProjectAsync(model, loggedInEmployee, tenantId); if (response.Success) { string message = response.Message; @@ -539,7 +547,7 @@ namespace MarcoBMS.Services.Controllers public async Task DeassignServiceToProject([FromBody] DeassignServiceDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.DeassignServiceToProjectAsync(model, tenantId, loggedInEmployee); + var response = await _projectServices.DeassignServiceToProjectAsync(model, loggedInEmployee, tenantId); if (response.Success) { string message = response.Message; @@ -557,14 +565,15 @@ namespace MarcoBMS.Services.Controllers public async Task GetAssignedOrganizationsToProject(Guid projectId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAssignedOrganizationsToProjectAsync(projectId, tenantId, loggedInEmployee); + var response = await _projectServices.GetAssignedOrganizationsToProjectAsync(projectId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpGet("get/assigned/organization/dropdown/{projectId}")] public async Task GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetAssignedOrganizationsToProjectForDropdownAsync(projectId, tenantId, loggedInEmployee); + var response = await _projectServices.GetAssignedOrganizationsToProjectForDropdownAsync(projectId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index fe8b1bc..ed39779 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -58,22 +58,21 @@ namespace Marco.Pms.Services.Service #region =================================================================== Job Status APIs =================================================================== /// - /// Retrieves job status records filtered by optional statusId and projectId within tenant context. - /// If both statusId and projectId are specified, returns next possible statuses based on team role mappings. - /// Otherwise, returns all global statuses ordered by name. + /// Retrieves job statuses based on optional filtering by status ID, project ID, team role, and tenant context. + /// Returns allowed next statuses for a given status in a project or all statuses if no filters provided. /// - /// Optional current job status ID to find next possible statuses. - /// Optional project ID for filtering based on employee's allocation. - /// Employee requesting the statuses. - /// Tenant identifier for multi-tenant scope. - /// ApiResponse containing list of job statuses or error details. + /// Optional current job status ID to retrieve next allowed statuses. + /// Optional project ID to scope the status mappings. + /// Currently authenticated employee. + /// Tenant ID for multi-tenant isolation. + /// ApiResponse containing the list of job statuses or error information. public async Task> GetJobStatusAsync(Guid? statusId, Guid? projectId, Employee loggedInEmployee, Guid tenantId) { - _logger.LogDebug("GetJobStatusAsync called by employee {EmployeeId} in tenant {TenantId}", loggedInEmployee.Id, tenantId); + _logger.LogDebug("GetJobStatusAsync called by EmployeeId {EmployeeId} in TenantId {TenantId}", loggedInEmployee.Id, tenantId); if (tenantId == Guid.Empty) { - _logger.LogWarning("TenantId is missing in GetJobStatusAsync request by employee {EmployeeId}", loggedInEmployee.Id); + _logger.LogWarning("Invalid tenant context (empty TenantId) in GetJobStatusAsync for EmployeeId {EmployeeId}", loggedInEmployee.Id); return ApiResponse.ErrorResponse("Access Denied", "Invalid tenant context.", 403); } @@ -83,11 +82,13 @@ namespace Marco.Pms.Services.Service if (statusId.HasValue && projectId.HasValue) { - var statusMappingQuery = _context.JobStatusMappings + // Base query for status mappings scoped by tenant and status filter, including related statuses + var baseMappingQuery = _context.JobStatusMappings + .Include(jsm => jsm.Status) .Include(jsm => jsm.NextStatus) - .Where(jsm => jsm.StatusId == statusId && jsm.NextStatus != null && jsm.TenantId == tenantId); + .Where(jsm => jsm.StatusId == statusId && jsm.Status != null && jsm.NextStatus != null && jsm.TenantId == tenantId); - // Find employee's latest project allocation to determine team role + // Find employee's most recent active allocation to get team role context var projectAllocation = await _context.ServiceProjectAllocations .Where(spa => spa.ProjectId == projectId && spa.EmployeeId == loggedInEmployee.Id && spa.TenantId == tenantId && spa.IsActive) .OrderByDescending(spa => spa.AssignedAt) @@ -95,35 +96,46 @@ namespace Marco.Pms.Services.Service var teamRoleId = projectAllocation?.TeamRoleId; - // Check if mappings exist for the employee's team role; fallback to null team role mappings - var hasTeamStatusMapping = projectAllocation != null && - await statusMappingQuery.AnyAsync(jsm => jsm.TeamRoleId == teamRoleId); + // Determine if mappings exist for employee's team role, fallback to null team role otherwise + bool hasTeamSpecificMapping = projectAllocation != null && + await baseMappingQuery.AnyAsync(jsm => jsm.TeamRoleId == teamRoleId); - if (hasTeamStatusMapping) + IQueryable filteredMappingQuery = hasTeamSpecificMapping + ? baseMappingQuery.Where(jsm => jsm.TeamRoleId == teamRoleId) + : baseMappingQuery.Where(jsm => jsm.TeamRoleId == null); + + var mappedStatuses = await filteredMappingQuery.ToListAsync(); + + // Aggregate next statuses plus the current status, ordered by Level for meaningful sequence + statuses = mappedStatuses.Select(jsm => jsm.NextStatus!).ToList(); + + var currentStatus = mappedStatuses.Select(jsm => jsm.Status!).FirstOrDefault(); + if (currentStatus != null && !statuses.Any(js => js.Id == currentStatus.Id)) { - statusMappingQuery = statusMappingQuery.Where(jsm => jsm.TeamRoleId == teamRoleId); - } - else - { - statusMappingQuery = statusMappingQuery.Where(jsm => jsm.TeamRoleId == null); + statuses.Add(currentStatus); } - statuses = await statusMappingQuery.Select(jsm => jsm.NextStatus!).OrderBy(js => js.Level).ToListAsync(); + statuses = statuses.OrderBy(js => js.Level).ToList(); } else { - // No specific filters - return all job statuses ordered by name - statuses = await _context.JobStatus.OrderBy(js => js.Level).ToListAsync(); + // No filters: return all job statuses ordered by Level ascending + statuses = await _context.JobStatus + .OrderBy(js => js.Level) + .ToListAsync(); } - _logger.LogInfo("Fetched {Count} job status records for tenant {TenantId}", statuses.Count, tenantId); + _logger.LogInfo("GetJobStatusAsync fetched {Count} status record(s) for TenantId {TenantId}", statuses.Count, tenantId); return ApiResponse.SuccessResponse(statuses, $"{statuses.Count} job status record(s) fetched successfully", 200); } catch (Exception ex) { - _logger.LogError(ex, "Error fetching job status for employee {EmployeeId} in tenant {TenantId}", loggedInEmployee.Id, tenantId); - return ApiResponse.ErrorResponse("Internal Server Error", "An error occurred while fetching job statuses. Please try again later.", 500); + _logger.LogError(ex, "Error retrieving job statuses for EmployeeId {EmployeeId} in TenantId {TenantId}", loggedInEmployee.Id, tenantId); + return ApiResponse.ErrorResponse( + "Internal Server Error", + "An error occurred while fetching job statuses. Please try again later.", + 500); } } diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index f02a456..6321714 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -53,8 +53,82 @@ namespace Marco.Pms.Services.Service } #region =================================================================== Project Get APIs =================================================================== + /// + /// Retrieves a combined list of basic infrastructure and active service projects accessible by the logged-in employee within a tenant. + /// + /// Optional search term to filter projects by name (if implemented). + /// Authenticated employee requesting the data. + /// Tenant identifier to ensure multi-tenant data isolation. + /// Returns an ApiResponse containing the distinct combined list of basic project view models or an error response. + public async Task> GetBothProjectBasicListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId) + { + if (tenantId == Guid.Empty) + { + _logger.LogWarning("GetBothProjectBasicListAsync called with invalid tenant context by EmployeeId {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "Invalid tenant context.", 403); + } - public async Task> GetAllProjectsBasicAsync(bool provideAll, Guid tenantId, Employee loggedInEmployee) + try + { + // Retrieve list of project IDs accessible by the employee for tenant isolation and security + var accessibleProjectIds = await GetMyProjects(loggedInEmployee, tenantId); + + // Fetch infrastructure projects concurrently filtered by accessible IDs and tenant + var infraProjectTask = Task.Run(async () => + { + await using var context = await _dbContextFactory.CreateDbContextAsync(); + var infraProjectsQuery = context.Projects + .Where(p => accessibleProjectIds.Contains(p.Id) && p.TenantId == tenantId); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + var normalized = searchString.Trim().ToLowerInvariant(); + infraProjectsQuery = infraProjectsQuery + .Where(p => p.Name.ToLower().Contains(normalized)); + } + + var infraProjects = await infraProjectsQuery.ToListAsync(); + return infraProjects.Select(p => _mapper.Map(p)).ToList(); + }); + + // Fetch active service projects concurrently with tenant isolation + var serviceProjectTask = Task.Run(async () => + { + await using var context = await _dbContextFactory.CreateDbContextAsync(); + var serviceProjectsQuery = context.ServiceProjects + .Where(sp => sp.TenantId == tenantId && sp.IsActive); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + var normalized = searchString.Trim().ToLowerInvariant(); + serviceProjectsQuery = serviceProjectsQuery + .Where(sp => sp.Name.ToLower().Contains(normalized)); + } + + var serviceProjects = await serviceProjectsQuery.ToListAsync(); + return serviceProjects.Select(sp => _mapper.Map(sp)).ToList(); + }); + + // Wait for both concurrent tasks to complete + await Task.WhenAll(infraProjectTask, serviceProjectTask); + + // Combine, remove duplicates, and prepare response list + var combinedProjects = infraProjectTask.Result.Concat(serviceProjectTask.Result).OrderBy(p => p.Name).Distinct().ToList(); + + _logger.LogInfo("GetBothProjectBasicListAsync returning {Count} projects for tenant {TenantId} by EmployeeId {EmployeeId}", + combinedProjects.Count, tenantId, loggedInEmployee.Id); + + return ApiResponse.SuccessResponse(combinedProjects, "Service and infrastructure projects fetched successfully.", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Unexpected error in GetBothProjectBasicListAsync for tenant {TenantId} by EmployeeId {EmployeeId}", + tenantId, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Server Error", "An error occurred while fetching projects.", 500); + } + } + + public async Task> GetAllProjectsBasicAsync(bool provideAll, Employee loggedInEmployee, Guid tenantId) { try { @@ -74,7 +148,7 @@ namespace Marco.Pms.Services.Service } else { - accessibleProjectIds = await GetMyProjects(tenantId, loggedInEmployee); + accessibleProjectIds = await GetMyProjects(loggedInEmployee, tenantId); } if (accessibleProjectIds == null || !accessibleProjectIds.Any()) @@ -97,14 +171,14 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("An internal server error occurred. Please try again later.", null, 500); } } - public async Task> GetAllProjectsAsync(int pageNumber, int pageSize, Guid tenantId, Employee loggedInEmployee) + public async Task> GetAllProjectsAsync(int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId) { try { _logger.LogInfo("Starting GetAllProjects for TenantId: {TenantId}, User: {UserId}", tenantId, loggedInEmployee.Id); // --- Step 1: Get a list of project IDs the user can access --- - List projectIds = await GetMyProjects(tenantId, loggedInEmployee); + List projectIds = await GetMyProjects(loggedInEmployee, tenantId); if (!projectIds.Any()) { _logger.LogInfo("User has no assigned projects. Returning empty list."); @@ -171,7 +245,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("An internal server error occurred. Please try again later.", null, 500); } } - public async Task> GetProjectAsync(Guid id, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { try { @@ -216,7 +290,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("An internal server error occurred.", null, 500); } } - public async Task> GetProjectDetailsAsync(Guid id, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { try { @@ -280,7 +354,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("An internal server error occurred. Please try again later.", null, 500); } } - public async Task> GetProjectDetailsOldAsync(Guid id, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectDetailsOldAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { var project = await _context.Projects .Where(c => c.TenantId == tenantId && c.Id == id) @@ -375,7 +449,7 @@ namespace Marco.Pms.Services.Service #region =================================================================== Project Manage APIs =================================================================== - public async Task> CreateProjectAsync(CreateProjectDto model, Guid tenantId, Employee loggedInEmployee) + public async Task> CreateProjectAsync(CreateProjectDto model, Employee loggedInEmployee, Guid tenantId) { // Begin a new scope for service resolution. using var scope = _serviceScopeFactory.CreateScope(); @@ -489,7 +563,7 @@ namespace Marco.Pms.Services.Service /// The ID of the project to update. /// The data to update the project with. /// An ApiResponse confirming the update or an appropriate error. - public async Task> UpdateProjectAsync(Guid id, UpdateProjectDto model, Guid tenantId, Employee loggedInEmployee) + public async Task> UpdateProjectAsync(Guid id, UpdateProjectDto model, Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _firebase = scope.ServiceProvider.GetRequiredService(); @@ -624,7 +698,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee (used for permission checks). /// An ApiResponse containing a list of employees or an error. - public async Task> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee) + public async Task> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Employee loggedInEmployee, Guid tenantId) { // --- Step 1: Input Validation --- if (projectId == Guid.Empty) @@ -706,7 +780,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee for permission checks. /// An ApiResponse containing allocation details or an appropriate error. - public async Task> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Employee loggedInEmployee, Guid tenantId) { // --- Step 1: Input Validation --- if (projectId == Guid.Empty) @@ -810,7 +884,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee for permission checks. /// An ApiResponse containing the list of processed allocations. - public async Task>> ManageAllocationAsync(List allocationsDto, Guid tenantId, Employee loggedInEmployee) + public async Task>> ManageAllocationAsync(List allocationsDto, Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _firebase = scope.ServiceProvider.GetRequiredService(); @@ -933,7 +1007,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee for permission checks. /// An ApiResponse containing a list of basic project details or an error. - public async Task> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectsByEmployeeAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId) { // --- Step 1: Input Validation --- if (employeeId == Guid.Empty) @@ -953,7 +1027,7 @@ namespace Marco.Pms.Services.Service // This is a placeholder for your actual, more specific permission logic. // It should also handle the case where a user is requesting their own projects (employeeId == loggedInEmployee.Id). var hasPermission = await _permission.HasPermission(PermissionsMaster.ViewProject, loggedInEmployee.Id); - var projectIds = await GetMyProjects(tenantId, loggedInEmployee); + var projectIds = await GetMyProjects(loggedInEmployee, tenantId); if (!hasPermission) { _logger.LogWarning("Access DENIED for user {UserId} trying to view projects for employee {TargetEmployeeId}.", loggedInEmployee.Id, employeeId); @@ -1011,7 +1085,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee for permission checks. /// An ApiResponse containing the list of processed allocations. - public async Task>> AssigneProjectsToEmployeeAsync(List allocationsDto, Guid employeeId, Guid tenantId, Employee loggedInEmployee) + public async Task>> AssigneProjectsToEmployeeAsync(List allocationsDto, Guid employeeId, Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _firebase = scope.ServiceProvider.GetRequiredService(); @@ -1140,8 +1214,7 @@ namespace Marco.Pms.Services.Service }); return ApiResponse>.SuccessResponse(resultVm, "Assignments managed successfully.", 200); } - - public async Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId) { // Log the start of the method execution with key input parameters _logger.LogInfo("Fetching projects for EmployeeId: {EmployeeId}, TenantId: {TenantId} by User: {UserId}", @@ -1206,7 +1279,7 @@ namespace Marco.Pms.Services.Service 500); } } - public async Task> GetProjectTeamByServiceAndOrganization(Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetProjectTeamByServiceAndOrganization(Guid projectId, Guid? serviceId, Guid? organizationId, Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _permission = scope.ServiceProvider.GetRequiredService(); @@ -1281,9 +1354,8 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(result, "Employee list fetched successfully", 200); } - public async Task> GetProjectTeamByServiceAndOrganizationAsync( - Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee) + Guid projectId, Guid? serviceId, Guid? organizationId, Employee loggedInEmployee, Guid tenantId) { _logger.LogDebug("Started fetching project team. ProjectId: {ProjectId}, ServiceId: {ServiceId}, OrganizationId: {OrganizationId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", projectId, serviceId ?? Guid.Empty, organizationId ?? Guid.Empty, tenantId, loggedInEmployee.Id); @@ -1391,7 +1463,6 @@ namespace Marco.Pms.Services.Service } } - #endregion #region =================================================================== Project InfraStructure Get APIs =================================================================== @@ -1400,7 +1471,7 @@ namespace Marco.Pms.Services.Service /// Retrieves the full infrastructure hierarchy (Buildings, Floors, Work Areas) for a project, /// including aggregated work summaries. /// - public async Task> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Employee loggedInEmployee, Guid tenantId) { _logger.LogInfo("GetInfraDetails called for ProjectId: {ProjectId}", projectId); @@ -1530,7 +1601,7 @@ namespace Marco.Pms.Services.Service /// The ID of the current tenant. /// The current authenticated employee for permission checks. /// An ApiResponse containing a list of work items or an error. - public async Task> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Employee loggedInEmployee, Guid tenantId) { _logger.LogInfo("GetWorkItems called for WorkAreaId: {WorkAreaId} by User: {UserId}", workAreaId, loggedInEmployee.Id); @@ -1659,7 +1730,7 @@ namespace Marco.Pms.Services.Service /// The tenant ID to filter tasks. /// The employee requesting the data (for authorization/logging). /// An ApiResponse containing the task details. - public async Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee) + public async Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Employee loggedInEmployee, Guid tenantId) { _logger.LogInfo("Fetching tasks for EmployeeId: {EmployeeId} from {FromDate} to {ToDate} for TenantId: {TenantId}", employeeId, fromDate, toDate, tenantId); @@ -1730,7 +1801,7 @@ namespace Marco.Pms.Services.Service #region =================================================================== Project Infrastructre Manage APIs =================================================================== - public async Task ManageProjectInfraAsync(List infraDtos, Guid tenantId, Employee loggedInEmployee) + public async Task ManageProjectInfraAsync(List infraDtos, Employee loggedInEmployee, Guid tenantId) { // 1. Guard Clause: Handle null or empty input gracefully. if (infraDtos == null || !infraDtos.Any()) @@ -1821,7 +1892,7 @@ namespace Marco.Pms.Services.Service /// Creates or updates a batch of work items. /// This method is optimized to perform all database operations in a single, atomic transaction. /// - public async Task>> CreateProjectTaskAsync(List workItemDtos, Guid tenantId, Employee loggedInEmployee) + public async Task>> CreateProjectTaskAsync(List workItemDtos, Employee loggedInEmployee, Guid tenantId) { _logger.LogInfo("CreateProjectTask called with {Count} items by user {UserId}", workItemDtos?.Count ?? 0, loggedInEmployee.Id); @@ -1967,7 +2038,7 @@ namespace Marco.Pms.Services.Service return ApiResponse>.SuccessResponse(responseList, message, 200); } - public async Task DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee) + public async Task DeleteProjectTaskAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _firebase = scope.ServiceProvider.GetRequiredService(); @@ -2074,7 +2145,7 @@ namespace Marco.Pms.Services.Service /// Tenant Guid. /// Currently logged in employee. /// API response indicating the result. - public async Task> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Guid tenantId, Employee loggedInEmployee) + public async Task> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Employee loggedInEmployee, Guid tenantId) { // Log: Method entry and received parameters _logger.LogInfo("ManageProjectLevelPermissionAsync started for EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, TenantId: {TenantId}", @@ -2213,7 +2284,7 @@ namespace Marco.Pms.Services.Service /// Unique identifier of the tenant. /// The authenticated employee making this request. /// ApiResponse containing the permission mappings or error details. - public async Task> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Employee loggedInEmployee, Guid tenantId) { // Log the attempt to fetch project-level permissions _logger.LogInfo( @@ -2291,7 +2362,7 @@ namespace Marco.Pms.Services.Service /// Tenant ID associated with assignment. /// Logged-in employee context. /// API response containing feature details associated with specified modules. - public async Task> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee) + public async Task> AssignProjectLevelModulesAsync(Employee loggedInEmployee, Guid tenantId) { // Log entry at the start of the method. _logger.LogInfo("AssignProjectLevelModulesAsync called for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id); @@ -2342,7 +2413,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Failed to assign project-level modules.", ex.Message); } } - public async Task> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId) { // Log method entry and parameters for traceability _logger.LogInfo("Fetching employees with project-level permissions. ProjectId: {ProjectId}, TenantId: {TenantId}, RequestedBy: {EmployeeId}", @@ -2396,7 +2467,7 @@ namespace Marco.Pms.Services.Service /// The tenant identifier for multi-tenant data isolation. /// The employee making the request, whose permissions are checked. /// An ApiResponse containing the list of assigned services or an error response. - public async Task> GetAssignedServiceToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetAssignedServiceToProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId) { try { @@ -2483,7 +2554,7 @@ namespace Marco.Pms.Services.Service /// Tenant identifier for proper multi-tenant separation. /// The employee requesting the service assignment, used for permission checks. /// ApiResponse with assigned services info or error details. - public async Task> AssignServiceToProjectAsync(AssignServiceDto model, Guid tenantId, Employee loggedInEmployee) + public async Task> AssignServiceToProjectAsync(AssignServiceDto model, Employee loggedInEmployee, Guid tenantId) { // Begin a transaction to ensure atomicity of assignments await using var transaction = await _context.Database.BeginTransactionAsync(); @@ -2586,7 +2657,7 @@ namespace Marco.Pms.Services.Service /// Tenant context for multi-tenant data isolation. /// Employee executing the operation, used for permission checks. /// ApiResponse indicating success or failure. - public async Task> DeassignServiceToProjectAsync(DeassignServiceDto model, Guid tenantId, Employee loggedInEmployee) + public async Task> DeassignServiceToProjectAsync(DeassignServiceDto model, Employee loggedInEmployee, Guid tenantId) { await using var transaction = await _context.Database.BeginTransactionAsync(); @@ -2660,7 +2731,7 @@ namespace Marco.Pms.Services.Service #region =================================================================== Assign Organization APIs =================================================================== - public async Task> GetAssignedOrganizationsToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetAssignedOrganizationsToProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId) { _logger.LogDebug("Started fetching assigned organizations for ProjectId: {ProjectId} and TenantId: {TenantId} by user {UserId}", projectId, tenantId, loggedInEmployee.Id); @@ -2829,7 +2900,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal error", "An internal exception occurred", 500); } } - public async Task> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee) + public async Task> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId) { _logger.LogDebug("Started fetching assigned organizations for ProjectId: {ProjectId} and TenantId: {TenantId} by user {UserId}", projectId, tenantId, loggedInEmployee.Id); @@ -2951,7 +3022,6 @@ namespace Marco.Pms.Services.Service } } - #endregion #region =================================================================== Helper Functions =================================================================== @@ -2988,16 +3058,16 @@ namespace Marco.Pms.Services.Service var projectAllocation = await projectAllocationQuery.ToListAsync(); return projectAllocation; } - public async Task> GetMyProjects(Guid tenantId, Employee LoggedInEmployee) + public async Task> GetMyProjects(Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _permission = scope.ServiceProvider.GetRequiredService(); - var projectIds = await _cache.GetProjects(LoggedInEmployee.Id, tenantId); + var projectIds = await _cache.GetProjects(loggedInEmployee.Id, tenantId); if (projectIds == null) { - var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageProject, LoggedInEmployee.Id); + var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageProject, loggedInEmployee.Id); if (hasPermission) { var projects = await _context.Projects.Where(c => c.TenantId == tenantId).ToListAsync(); @@ -3005,18 +3075,18 @@ namespace Marco.Pms.Services.Service } else { - var allocation = await GetProjectByEmployeeID(LoggedInEmployee.Id); + var allocation = await GetProjectByEmployeeID(loggedInEmployee.Id); if (!allocation.Any()) { return new List(); } projectIds = allocation.Select(c => c.ProjectId).Distinct().ToList(); } - await _cache.AddProjects(LoggedInEmployee.Id, projectIds, tenantId); + await _cache.AddProjects(loggedInEmployee.Id, projectIds, tenantId); } return projectIds; } - public async Task> GetMyProjectIdsAsync(Guid tenantId, Employee loggedInEmployee) + public async Task> GetMyProjectIdsAsync(Employee loggedInEmployee, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _permission = scope.ServiceProvider.GetRequiredService(); diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs index 078c66e..dac1921 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs @@ -10,46 +10,47 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces { public interface IProjectServices { - Task> GetAllProjectsBasicAsync(bool provideAll, Guid tenantId, Employee loggedInEmployee); - Task> GetAllProjectsAsync(int pageNumber, int pageSize, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectAsync(Guid id, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectDetailsAsync(Guid id, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectDetailsOldAsync(Guid id, Guid tenantId, Employee loggedInEmployee); - Task> CreateProjectAsync(CreateProjectDto projectDto, Guid tenantId, Employee loggedInEmployee); - Task> UpdateProjectAsync(Guid id, UpdateProjectDto updateProjectDto, Guid tenantId, Employee loggedInEmployee); - Task> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Guid tenantId, Employee loggedInEmployee); - Task>> ManageAllocationAsync(List projectAllocationDots, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); - Task>> AssigneProjectsToEmployeeAsync(List projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); - Task> GetProjectTeamByServiceAndOrganizationAsync(Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee); + Task> GetBothProjectBasicListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId); + Task> GetAllProjectsBasicAsync(bool provideAll, Employee loggedInEmployee, Guid tenantId); + Task> GetAllProjectsAsync(int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectAsync(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectDetailsOldAsync(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> CreateProjectAsync(CreateProjectDto projectDto, Employee loggedInEmployee, Guid tenantId); + Task> UpdateProjectAsync(Guid id, UpdateProjectDto updateProjectDto, Employee loggedInEmployee, Guid tenantId); + Task> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Employee loggedInEmployee, Guid tenantId); + Task>> ManageAllocationAsync(List projectAllocationDots, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectsByEmployeeAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId); + Task>> AssigneProjectsToEmployeeAsync(List projectAllocationDtos, Guid employeeId, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId); + Task> GetProjectTeamByServiceAndOrganizationAsync(Guid projectId, Guid? serviceId, Guid? organizationId, Employee loggedInEmployee, Guid tenantId); - Task> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee); - Task> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee); - Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee); - Task ManageProjectInfraAsync(List infraDtos, Guid tenantId, Employee loggedInEmployee); - Task>> CreateProjectTaskAsync(List workItemDtos, Guid tenantId, Employee loggedInEmployee); - Task DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee); + Task> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Employee loggedInEmployee, Guid tenantId); + Task> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Employee loggedInEmployee, Guid tenantId); + Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Employee loggedInEmployee, Guid tenantId); + Task ManageProjectInfraAsync(List infraDtos, Employee loggedInEmployee, Guid tenantId); + Task>> CreateProjectTaskAsync(List workItemDtos, Employee loggedInEmployee, Guid tenantId); + Task DeleteProjectTaskAsync(Guid id, Employee loggedInEmployee, Guid tenantId); Task> GetAllProjectByTanentID(Guid tanentId); Task> GetProjectByEmployeeID(Guid employeeId); Task> GetTeamByProject(Guid TenantId, Guid ProjectId, Guid? OrganizationId, bool IncludeInactive); - Task> GetMyProjectIdsAsync(Guid tenantId, Employee LoggedInEmployee); + Task> GetMyProjectIdsAsync(Employee loggedInEmployee, Guid tenantId); - Task> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Guid tenantId, Employee loggedInEmployee); - Task> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Guid tenantId, Employee loggedInEmployee); - Task> AssignProjectLevelModulesAsync(Guid tenantId, Employee loggedInEmployee); - Task> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); + Task> ManageProjectLevelPermissionAsync(ProjctLevelPermissionDto model, Employee loggedInEmployee, Guid tenantId); + Task> GetAssignedProjectLevelPermissionAsync(Guid employeeId, Guid projectId, Employee loggedInEmployee, Guid tenantId); + Task> AssignProjectLevelModulesAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetEmployeeToWhomProjectLevelAssignedAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId); Task> GetAllPermissionFroProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId); - Task> GetAssignedServiceToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); - Task> AssignServiceToProjectAsync(AssignServiceDto model, Guid tenantId, Employee loggedInEmployee); - Task> DeassignServiceToProjectAsync(DeassignServiceDto model, Guid tenantId, Employee loggedInEmployee); + Task> GetAssignedServiceToProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId); + Task> AssignServiceToProjectAsync(AssignServiceDto model, Employee loggedInEmployee, Guid tenantId); + Task> DeassignServiceToProjectAsync(DeassignServiceDto model, Employee loggedInEmployee, Guid tenantId); - Task> GetAssignedOrganizationsToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); - Task> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); + Task> GetAssignedOrganizationsToProjectAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId); + Task> GetAssignedOrganizationsToProjectForDropdownAsync(Guid projectId, Employee loggedInEmployee, Guid tenantId); } }