Added the promotor and PMC in project VM
This commit is contained in:
parent
4c6070fee5
commit
18d590ccbe
@ -74,14 +74,20 @@ namespace Marco.Pms.Helpers
|
||||
Id = promotor.Id.ToString(),
|
||||
Name = promotor.Name,
|
||||
ContactPerson = promotor.ContactPerson,
|
||||
Email = promotor.Email
|
||||
Email = promotor.Email,
|
||||
Address = promotor.Address,
|
||||
ContactNumber = promotor.ContactNumber,
|
||||
SPRID = promotor.SPRID
|
||||
}),
|
||||
Builders<ProjectMongoDB>.Update.Set(r => r.PMC, new OrganizationMongoDB
|
||||
{
|
||||
Id = pmc.Id.ToString(),
|
||||
Name = pmc.Name,
|
||||
ContactPerson = pmc.ContactPerson,
|
||||
Email = pmc.Email
|
||||
Email = pmc.Email,
|
||||
Address = promotor.Address,
|
||||
ContactNumber = promotor.ContactNumber,
|
||||
SPRID = promotor.SPRID
|
||||
}),
|
||||
Builders<ProjectMongoDB>.Update.Set(r => r.StartDate, project.StartDate),
|
||||
Builders<ProjectMongoDB>.Update.Set(r => r.EndDate, project.EndDate),
|
||||
|
@ -3,8 +3,11 @@
|
||||
public class OrganizationMongoDB
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string ContactPerson { get; set; } = string.Empty;
|
||||
public string? Name { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? ContactPerson { get; set; }
|
||||
public string? Address { get; set; }
|
||||
public string? ContactNumber { get; set; }
|
||||
public double SPRID { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -511,6 +511,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
[HttpPost("assign/service")]
|
||||
public async Task<IActionResult> AssignServiceToProject([FromBody] AssignServiceDto model)
|
||||
{
|
||||
|
@ -84,7 +84,10 @@ namespace Marco.Pms.Services.Helpers
|
||||
Id = o.Id.ToString(),
|
||||
Name = o.Name,
|
||||
ContactPerson = o.ContactPerson,
|
||||
Email = o.Email
|
||||
Email = o.Email,
|
||||
Address = o.Address,
|
||||
ContactNumber = o.ContactNumber,
|
||||
SPRID = o.SPRID
|
||||
}) // Projection
|
||||
.FirstOrDefaultAsync();
|
||||
});
|
||||
@ -100,7 +103,10 @@ namespace Marco.Pms.Services.Helpers
|
||||
Id = o.Id.ToString(),
|
||||
Name = o.Name,
|
||||
ContactPerson = o.ContactPerson,
|
||||
Email = o.Email
|
||||
Email = o.Email,
|
||||
Address = o.Address,
|
||||
ContactNumber = o.ContactNumber,
|
||||
SPRID = o.SPRID
|
||||
}) // Projection
|
||||
.FirstOrDefaultAsync();
|
||||
});
|
||||
@ -300,7 +306,10 @@ namespace Marco.Pms.Services.Helpers
|
||||
Id = o.Id.ToString(),
|
||||
Name = o.Name,
|
||||
ContactPerson = o.ContactPerson,
|
||||
Email = o.Email
|
||||
Email = o.Email,
|
||||
Address = o.Address,
|
||||
ContactNumber = o.ContactNumber,
|
||||
SPRID = o.SPRID
|
||||
}) // Projection
|
||||
.ToListAsync();
|
||||
});
|
||||
|
@ -47,6 +47,12 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
CreateMap<CreateOrganizationDto, Organization>();
|
||||
CreateMap<Organization, OrganizationVM>();
|
||||
CreateMap<Organization, BasicOrganizationVm>();
|
||||
CreateMap<OrganizationMongoDB, BasicOrganizationVm>()
|
||||
.ForMember(
|
||||
dest => dest.Id,
|
||||
// Explicitly and safely convert string Id to Guid Id
|
||||
opt => opt.MapFrom(src => new Guid(src.Id))
|
||||
);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -2165,281 +2165,350 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
#region =================================================================== Assign Service APIs ===================================================================
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of services assigned to a specific project based on the logged-in employee's organization and permissions.
|
||||
/// </summary>
|
||||
/// <param name="projectId">The unique identifier of the project.</param>
|
||||
/// <param name="tenantId">The tenant identifier for multi-tenant data isolation.</param>
|
||||
/// <param name="loggedInEmployee">The employee making the request, whose permissions are checked.</param>
|
||||
/// <returns>An ApiResponse containing the list of assigned services or an error response.</returns>
|
||||
public async Task<ApiResponse<object>> GetAssignedServiceToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
|
||||
// Fetch the project to ensure it exists in the given tenant scope
|
||||
var project = await _context.Projects
|
||||
.AsNoTracking() // No changes are made, so use NoTracking for performance
|
||||
.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||
|
||||
var project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||
if (project == null)
|
||||
{
|
||||
_logger.LogWarning("Project not found. ProjectId: {ProjectId}, TenantId: {TenantId}", projectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
||||
}
|
||||
|
||||
var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
|
||||
// Verify logged-in employee has permission on the project
|
||||
var hasPermission = await permissionService.HasProjectPermission(loggedInEmployee, projectId);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to update project {ProjectId}.", loggedInEmployee.Id, projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to modify this project.", 403);
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to access project {ProjectId}.", loggedInEmployee.Id, projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to access this project.", 403);
|
||||
}
|
||||
|
||||
List<ServiceMaster> services = new List<ServiceMaster>();
|
||||
List<ServiceMaster> assignedServices;
|
||||
|
||||
// Check if the logged-in employee's organization matches both Promoter and PMC of the project
|
||||
if (project.PromoterId == loggedInEmployee.OrganizationId && project.PMCId == loggedInEmployee.OrganizationId)
|
||||
{
|
||||
var projectServices = await _context.ProjectServiceMappings
|
||||
// Get all active services assigned directly to the project within the tenant
|
||||
assignedServices = await _context.ProjectServiceMappings
|
||||
.AsNoTracking()
|
||||
.Include(ps => ps.Service)
|
||||
.Where(ps => ps.ProjectId == projectId && ps.Service != null && ps.TenantId == tenantId && ps.IsActive)
|
||||
.Where(ps => ps.ProjectId == projectId && ps.IsActive && ps.TenantId == tenantId && ps.Service != null)
|
||||
.Select(ps => ps.Service!)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
services = projectServices.Select(ps => ps.Service!).Distinct().ToList();
|
||||
|
||||
_logger.LogInfo("User {UserId} requested all services for project {ProjectId} as Promoter and PMC.", loggedInEmployee.Id, projectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var orgProjectMapping = await _context.ProjectOrgMappings
|
||||
// Get the active project services mapped to the employee's organization for this project
|
||||
assignedServices = await _context.ProjectOrgMappings
|
||||
.AsNoTracking()
|
||||
.Include(po => po.ProjectService)
|
||||
.ThenInclude(ps => ps!.Service)
|
||||
.Where(po => po.OrganizationId == loggedInEmployee.OrganizationId && po.ProjectService != null
|
||||
&& po.ProjectService.IsActive && po.ProjectService.ProjectId == projectId && po.ProjectService.Service != null)
|
||||
.Where(po =>
|
||||
po.OrganizationId == loggedInEmployee.OrganizationId &&
|
||||
po.ProjectService != null &&
|
||||
po.ProjectService.IsActive &&
|
||||
po.ProjectService.ProjectId == projectId &&
|
||||
po.ProjectService.Service != null)
|
||||
.Select(po => po.ProjectService!.Service!)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
services = orgProjectMapping.Select(po => po.ProjectService!.Service!).Distinct().ToList();
|
||||
_logger.LogInfo("User {UserId} requested services for project {ProjectId} via organization mapping.", loggedInEmployee.Id, projectId);
|
||||
}
|
||||
var response = _mapper.Map<List<ServiceMasterVM>>(services);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the services for this project", 200);
|
||||
// Map entities to view models
|
||||
var serviceViewModels = _mapper.Map<List<ServiceMasterVM>>(assignedServices);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(serviceViewModels, "Successfully fetched the services for this project", 200);
|
||||
}
|
||||
catch (DbUpdateException dbEx)
|
||||
{
|
||||
//await transaction.RollbackAsync();
|
||||
|
||||
_logger.LogError(dbEx, "Database Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500);
|
||||
_logger.LogError(dbEx, "Database exception occurred while fetching assigned services to project {ProjectId} for tenant {TenantId}.", projectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500);
|
||||
_logger.LogError(ex, "Unexpected exception occurred while fetching assigned services to project {ProjectId} for tenant {TenantId}.", projectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An unexpected internal exception occurred", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns one or multiple services to a project with specified planned and actual dates.
|
||||
/// Checks for project existence and employee permissions before assignment.
|
||||
/// </summary>
|
||||
/// <param name="model">Data transfer object containing project ID, list of service IDs, and planned dates.</param>
|
||||
/// <param name="tenantId">Tenant identifier for proper multi-tenant separation.</param>
|
||||
/// <param name="loggedInEmployee">The employee requesting the service assignment, used for permission checks.</param>
|
||||
/// <returns>ApiResponse with assigned services info or error details.</returns>
|
||||
public async Task<ApiResponse<object>> AssignServiceToProjectAsync(AssignServiceDto model, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
// Begin a transaction to ensure atomicity of assignments
|
||||
await using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
|
||||
// Validate project exists within the tenant
|
||||
var project = await _context.Projects
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
|
||||
|
||||
var project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
|
||||
if (project == null)
|
||||
{
|
||||
_logger.LogWarning("Project not found. ProjectId: {ProjectId}, TenantId: {TenantId}", model.ProjectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
||||
}
|
||||
|
||||
var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, model.ProjectId);
|
||||
// Validate permission for logged-in employee to assign services to project
|
||||
var hasPermission = await permissionService.HasProjectPermission(loggedInEmployee, model.ProjectId);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to update project {ProjectId}.", loggedInEmployee.Id, model.ProjectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to modify this project.", 403);
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to assign services to project {ProjectId}.", loggedInEmployee.Id, model.ProjectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to modify this project.", 403);
|
||||
}
|
||||
|
||||
var todaysDate = DateTime.UtcNow.Date;
|
||||
// Fetch existing active project service mappings for the requested service IDs, within the same tenant
|
||||
var existingProjectServices = await _context.ProjectServiceMappings
|
||||
.Where(sp => model.ServiceIds.Contains(sp.ServiceId) && sp.ProjectId == model.ProjectId && sp.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
var projectServicesTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ProjectServiceMappings
|
||||
.Where(sp => model.ServiceIds.Contains(sp.ServiceId) && sp.ProjectId == model.ProjectId && sp.IsActive).ToListAsync();
|
||||
});
|
||||
// Fetch service details for the provided service IDs within the tenant scope
|
||||
var services = await _context.ServiceMasters
|
||||
.Where(s => model.ServiceIds.Contains(s.Id) && s.TenantId == tenantId)
|
||||
.ToListAsync();
|
||||
|
||||
var serviceTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceMasters.Where(s => model.ServiceIds.Contains(s.Id) && s.TenantId == tenantId).ToListAsync();
|
||||
});
|
||||
|
||||
await Task.WhenAll(projectServicesTask, serviceTask);
|
||||
|
||||
var projectServices = projectServicesTask.Result;
|
||||
var services = serviceTask.Result;
|
||||
// Current UTC timestamp for actual start date
|
||||
var currentUtc = DateTime.UtcNow;
|
||||
|
||||
// Add new project service mappings if not already present
|
||||
foreach (var serviceId in model.ServiceIds)
|
||||
{
|
||||
|
||||
var projectService = projectServices.FirstOrDefault(ps => ps.ServiceId == serviceId);
|
||||
if (projectService == null)
|
||||
if (!existingProjectServices.Any(ps => ps.ServiceId == serviceId))
|
||||
{
|
||||
projectService = new ProjectServiceMapping
|
||||
var newMapping = new ProjectServiceMapping
|
||||
{
|
||||
ProjectId = project.Id,
|
||||
ServiceId = serviceId,
|
||||
TenantId = project.TenantId,
|
||||
TenantId = tenantId,
|
||||
PlannedStartDate = model.PlannedStartDate,
|
||||
PlannedEndDate = model.PlannedEndDate,
|
||||
ActualStartDate = DateTime.UtcNow,
|
||||
ActualStartDate = currentUtc,
|
||||
IsActive = true
|
||||
};
|
||||
_context.ProjectServiceMappings.Add(projectService);
|
||||
_context.ProjectServiceMappings.Add(newMapping);
|
||||
_logger.LogInfo("Assigned service {ServiceId} to project {ProjectId} by user {UserId}.", serviceId, model.ProjectId, loggedInEmployee.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInfo("Service {ServiceId} is already assigned and active for project {ProjectId}.", serviceId, model.ProjectId);
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
|
||||
// Prepare response combining project and service data mapped to view models
|
||||
var response = services.Select(s => new ProjectServiceVM
|
||||
{
|
||||
Project = _mapper.Map<BasicProjectVM>(project),
|
||||
Service = _mapper.Map<ServiceMasterVM>(s),
|
||||
PlannedStartDate = model.PlannedStartDate,
|
||||
PlannedEndDate = model.PlannedEndDate,
|
||||
ActualStartDate = DateTime.UtcNow
|
||||
});
|
||||
return ApiResponse<object>.SuccessResponse(response, "Services has been assigned to the project", 200);
|
||||
ActualStartDate = currentUtc
|
||||
}).ToList();
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Services have been assigned to the project successfully", 200);
|
||||
}
|
||||
catch (DbUpdateException dbEx)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
|
||||
_logger.LogError(dbEx, "Database Exception has been occured, While assigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500);
|
||||
_logger.LogError(dbEx, "Database exception while assigning services to project {ProjectId} for tenant {TenantId} by user {UserId}.", model.ProjectId, tenantId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "A database exception has occurred", 500);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception has been occured, While assigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500);
|
||||
await transaction.RollbackAsync();
|
||||
_logger.LogError(ex, "Unexpected exception while assigning services to project {ProjectId} for tenant {TenantId} by user {UserId}.", model.ProjectId, tenantId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An unexpected internal exception has occurred", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deassigns specified services from a project by marking them inactive and setting actual end date.
|
||||
/// Validates project existence and employee permission before making updates.
|
||||
/// </summary>
|
||||
/// <param name="model">Contains ProjectId and list of ServiceIds to deassign.</param>
|
||||
/// <param name="tenantId">Tenant context for multi-tenant data isolation.</param>
|
||||
/// <param name="loggedInEmployee">Employee executing the operation, used for permission checks.</param>
|
||||
/// <returns>ApiResponse indicating success or failure.</returns>
|
||||
public async Task<ApiResponse<object>> DeassignServiceToProjectAsync(DeassignServiceDto model, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
await using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
|
||||
// Validate that project exists for given tenant
|
||||
var project = await _context.Projects
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
|
||||
|
||||
var project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
|
||||
if (project == null)
|
||||
{
|
||||
_logger.LogWarning("Project not found. ProjectId: {ProjectId}, TenantId: {TenantId}", model.ProjectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
||||
}
|
||||
|
||||
var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, model.ProjectId);
|
||||
// Verify permission to update project
|
||||
var hasPermission = await permissionService.HasProjectPermission(loggedInEmployee, model.ProjectId);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to update project {ProjectId}.", loggedInEmployee.Id, model.ProjectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to modify this project.", 403);
|
||||
_logger.LogWarning("Access DENIED for user {UserId} trying to deassign services from project {ProjectId}.", loggedInEmployee.Id, model.ProjectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to modify this project.", 403);
|
||||
}
|
||||
var todaysDate = DateTime.UtcNow.Date;
|
||||
|
||||
var projectServicesTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ProjectServiceMappings
|
||||
.AsNoTracking()
|
||||
.Where(sp => model.ServiceIds.Contains(sp.ServiceId) && sp.ProjectId == model.ProjectId && sp.IsActive).ToListAsync();
|
||||
});
|
||||
|
||||
var serviceTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceMasters.Where(s => model.ServiceIds.Contains(s.Id) && s.TenantId == tenantId).ToListAsync();
|
||||
});
|
||||
|
||||
await Task.WhenAll(projectServicesTask, serviceTask);
|
||||
|
||||
var projectServices = projectServicesTask.Result;
|
||||
var services = serviceTask.Result;
|
||||
// Fetch active project service mappings matching provided service IDs
|
||||
var projectServices = await _context.ProjectServiceMappings
|
||||
.Where(ps => model.ServiceIds.Contains(ps.ServiceId) && ps.ProjectId == model.ProjectId && ps.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
if (!projectServices.Any())
|
||||
{
|
||||
return ApiResponse<object>.ErrorResponse("Project Service mapping not found", "Project Service mapping not found in database", 404);
|
||||
_logger.LogWarning("No matching active project service mappings found for deassignment. ProjectId: {ProjectId}, ServiceIds: {ServiceIds}",
|
||||
model.ProjectId, string.Join(",", model.ServiceIds));
|
||||
return ApiResponse<object>.ErrorResponse("Project Service mapping not found", "No active service mappings found in database", 404);
|
||||
}
|
||||
|
||||
projectServices = projectServices.Select(ps =>
|
||||
var currentUtc = DateTime.UtcNow;
|
||||
|
||||
// Mark mappings as inactive and set actual end date to now
|
||||
foreach (var ps in projectServices)
|
||||
{
|
||||
ps.IsActive = false;
|
||||
return ps;
|
||||
}).ToList();
|
||||
ps.ActualEndDate = currentUtc;
|
||||
}
|
||||
|
||||
_context.ProjectServiceMappings.UpdateRange(projectServices);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(new { }, "Services has been deassigned to the project", 200);
|
||||
_logger.LogInfo("User {UserId} deassigned {Count} services from project {ProjectId}.", loggedInEmployee.Id, projectServices.Count, model.ProjectId);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(new { }, "Services have been deassigned from the project successfully", 200);
|
||||
}
|
||||
catch (DbUpdateException dbEx)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
|
||||
_logger.LogError(dbEx, "Database Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500);
|
||||
_logger.LogError(dbEx, "Database exception occurred while deassigning services from project {ProjectId} by user {UserId}.", model.ProjectId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "A database exception has occurred", 500);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500);
|
||||
await transaction.RollbackAsync();
|
||||
_logger.LogError(ex, "Unexpected exception occurred while deassigning services from project {ProjectId} by user {UserId}.", model.ProjectId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An unexpected internal exception has occurred", 500);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Assign Organization APIs ===================================================================
|
||||
|
||||
public async Task<ApiResponse<object>> GetAssignedOrganizationsToProjectAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
_logger.LogDebug("Started fetching assigned organizations for ProjectId: {ProjectId} and TenantId: {TenantId} by user {UserId}",
|
||||
projectId, tenantId, loggedInEmployee.Id);
|
||||
|
||||
try
|
||||
{
|
||||
// Create a scoped PermissionServices instance for permission checks
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||
|
||||
// Retrieve the project by projectId and tenantId
|
||||
var project = await _context.Projects
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||
|
||||
var project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||
if (project == null)
|
||||
{
|
||||
_logger.LogWarning("Project not found. ProjectId: {ProjectId}, TenantId: {TenantId}", projectId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404);
|
||||
}
|
||||
|
||||
var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
|
||||
// Check if the logged in employee has permission to access the project
|
||||
var hasPermission = await permissionService.HasProjectPermission(loggedInEmployee, projectId);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access DENIED for user {UserId} attempting to update project {ProjectId}.", loggedInEmployee.Id, projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to modify this project.", 403);
|
||||
_logger.LogWarning("Access denied for user {UserId} on project {ProjectId}", loggedInEmployee.Id, projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to access this project.", 403);
|
||||
}
|
||||
|
||||
var projectOrgMapping = await _context.ProjectOrgMappings
|
||||
// Fetch all project-organization mappings with related service and organization data
|
||||
var projectOrgMappings = await _context.ProjectOrgMappings
|
||||
.AsNoTracking()
|
||||
.Include(po => po.ProjectService)
|
||||
.ThenInclude(ps => ps!.Service)
|
||||
.Include(po => po.Organization)
|
||||
.Where(po => po.ProjectService != null && po.ProjectService.ProjectId == projectId && po.TenantId == tenantId)
|
||||
.Where(po => po.ProjectService != null
|
||||
&& po.ProjectService.ProjectId == projectId
|
||||
&& po.TenantId == tenantId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
var response = projectOrgMapping.Where(po => po.Organization != null).Select(po => new ProjectOrganizationVM
|
||||
{
|
||||
Id = po.Organization!.Id,
|
||||
Name = po.Organization.Name,
|
||||
Email = po.Organization.Email,
|
||||
ContactPerson = po.Organization.ContactPerson,
|
||||
SPRID = po.Organization.SPRID,
|
||||
logoImage = po.Organization.logoImage,
|
||||
AssignedBy = _mapper.Map<BasicEmployeeVM>(po.AssignedBy),
|
||||
Service = _mapper.Map<ServiceMasterVM>(po.ProjectService!.Service),
|
||||
AssignedDate = po.AssignedDate,
|
||||
CompletionDate = po.CompletionDate
|
||||
}).ToList();
|
||||
// Filter and map the data to the desired view model
|
||||
var response = projectOrgMappings
|
||||
.Where(po => po.Organization != null)
|
||||
.Select(po => new ProjectOrganizationVM
|
||||
{
|
||||
Id = po.Organization!.Id,
|
||||
Name = po.Organization.Name,
|
||||
Email = po.Organization.Email,
|
||||
ContactPerson = po.Organization.ContactPerson,
|
||||
SPRID = po.Organization.SPRID,
|
||||
logoImage = po.Organization.logoImage,
|
||||
AssignedBy = _mapper.Map<BasicEmployeeVM>(po.AssignedBy),
|
||||
Service = _mapper.Map<ServiceMasterVM>(po.ProjectService!.Service),
|
||||
AssignedDate = po.AssignedDate,
|
||||
CompletionDate = po.CompletionDate
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the list of organization assigned to the project", 200);
|
||||
_logger.LogInfo("Fetched {Count} assigned organizations for ProjectId: {ProjectId}", response.Count, projectId);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the list of organizations assigned to the project", 200);
|
||||
}
|
||||
catch (DbUpdateException dbEx)
|
||||
{
|
||||
//await transaction.RollbackAsync();
|
||||
|
||||
_logger.LogError(dbEx, "Database Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500);
|
||||
_logger.LogError(dbEx, "Database exception while fetching assigned organizations for ProjectId: {ProjectId}", projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception has been occured, While deassigning the sevice to the project");
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500);
|
||||
_logger.LogError(ex, "Unhandled exception while fetching assigned organizations for ProjectId: {ProjectId}", projectId);
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user