Merge pull request 'Add new API to get organization details' (#141) from Ashutosh_Task_#1362 into Organization_Management
Reviewed-on: #141
This commit is contained in:
commit
33cd7113a7
@ -8,6 +8,6 @@
|
|||||||
public required string Address { get; set; }
|
public required string Address { get; set; }
|
||||||
public required string ContactNumber { get; set; }
|
public required string ContactNumber { get; set; }
|
||||||
public string? logoImage { get; set; }
|
public string? logoImage { get; set; }
|
||||||
public required List<Guid> ServiceIds { get; set; }
|
public List<Guid>? ServiceIds { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
public required string ContactPerson { get; set; }
|
public required string ContactPerson { get; set; }
|
||||||
public required string Address { get; set; }
|
public required string Address { get; set; }
|
||||||
public required string ContactNumber { get; set; }
|
public required string ContactNumber { get; set; }
|
||||||
public required List<Guid> ServiceIds { get; set; }
|
public List<Guid>? ServiceIds { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,6 @@
|
|||||||
public required string OrganizationSize { get; set; }
|
public required string OrganizationSize { get; set; }
|
||||||
public required Guid IndustryId { get; set; }
|
public required Guid IndustryId { get; set; }
|
||||||
public required string Reference { get; set; }
|
public required string Reference { get; set; }
|
||||||
public required List<Guid> ServiceIds { get; set; }
|
public List<Guid>? ServiceIds { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Organization
|
||||||
|
{
|
||||||
|
public class OrganizationDetailsVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
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; }
|
||||||
|
public int ActiveEmployeeCount { get; set; }
|
||||||
|
public int ActiveApplicationUserCount { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public BasicEmployeeVM? UpdatedBy { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
public List<ProjectServiceMappingVM>? Projects { get; set; }
|
||||||
|
public string? logoImage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Organization
|
||||||
|
{
|
||||||
|
public class ProjectServiceMappingVM
|
||||||
|
{
|
||||||
|
public BasicProjectVM? Project { get; set; }
|
||||||
|
public ServiceMasterVM? Service { get; set; }
|
||||||
|
public DateTime PlannedStartDate { get; set; }
|
||||||
|
public DateTime PlannedEndDate { get; set; }
|
||||||
|
public DateTime ActualStartDate { get; set; }
|
||||||
|
public DateTime? ActualEndDate { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -55,66 +55,200 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
public async Task<IActionResult> GetOrganizarionListAsync([FromQuery] string? searchString, [FromQuery] double? sprid, [FromQuery] bool active = true,
|
public async Task<IActionResult> GetOrganizarionListAsync([FromQuery] string? searchString, [FromQuery] double? sprid, [FromQuery] bool active = true,
|
||||||
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
|
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Fetching organization list. SearchString: {SearchString}, SPRID: {SPRID}, Active: {Active}, Page: {PageNumber}, Size: {PageSize}",
|
||||||
|
searchString ?? "", sprid ?? 0, active, pageNumber, pageSize);
|
||||||
|
|
||||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
using var scope = _serviceScope.CreateScope();
|
|
||||||
|
|
||||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
var organizationQuery = _context.Organizations
|
// Base query filtering by active status
|
||||||
.Where(o => o.IsActive == active);
|
IQueryable<Organization> organizationQuery = _context.Organizations.Where(o => o.IsActive == active);
|
||||||
|
|
||||||
if (sprid.HasValue)
|
if (sprid.HasValue)
|
||||||
{
|
{
|
||||||
|
// Filter by SPRID if provided
|
||||||
organizationQuery = organizationQuery.Where(o => o.SPRID == sprid.Value);
|
organizationQuery = organizationQuery.Where(o => o.SPRID == sprid.Value);
|
||||||
|
_logger.LogDebug("Filtering organizations by SPRID: {SPRID}", sprid.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var organizationIds = await _context.TenantOrgMappings.Where(to => to.TenantId == tenantId && to.IsActive).Select(to => to.OrganizationId).ToListAsync();
|
// Get organization IDs mapped to current tenant that are active
|
||||||
|
var organizationIds = await _context.TenantOrgMappings
|
||||||
|
.Where(to => to.TenantId == tenantId && to.IsActive)
|
||||||
|
.Select(to => to.OrganizationId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
organizationQuery = organizationQuery.Where(o => organizationIds.Contains(o.Id));
|
organizationQuery = organizationQuery.Where(o => organizationIds.Contains(o.Id));
|
||||||
|
_logger.LogDebug("Filtering organizations by tenant's mapped IDs count: {Count}", organizationIds.Count);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(searchString))
|
if (!string.IsNullOrWhiteSpace(searchString))
|
||||||
{
|
{
|
||||||
organizationQuery = organizationQuery.Where(sp =>
|
// Filter by search string on organization name -- extend here if needed
|
||||||
sp.Name.Contains(searchString)
|
organizationQuery = organizationQuery.Where(o => o.Name.Contains(searchString));
|
||||||
//|| sp.ContactPerson.Contains(searchString)
|
_logger.LogDebug("Filtering organizations by search string: {SearchString}", searchString);
|
||||||
//|| sp.Address.Contains(searchString)
|
|
||||||
//|| sp.Email.Contains(searchString)
|
|
||||||
//|| sp.ContactNumber.Contains(searchString)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get total count for pagination
|
||||||
var totalCount = await organizationQuery.CountAsync();
|
var totalCount = await organizationQuery.CountAsync();
|
||||||
var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
|
var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
|
||||||
|
|
||||||
|
// Fetch page of organizations sorted by name
|
||||||
var organizations = await organizationQuery
|
var organizations = await organizationQuery
|
||||||
.OrderBy(e => e.Name)
|
.OrderBy(o => o.Name)
|
||||||
.Skip((pageNumber - 1) * pageSize)
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var createdByIds = organizations.Where(o => o.CreatedById != null).Select(o => o.CreatedById).ToList();
|
// Collect creator and updater employee IDs
|
||||||
var updatedByIds = organizations.Where(o => o.UpdatedById != null).Select(o => o.UpdatedById).ToList();
|
var createdByIds = organizations.Where(o => o.CreatedById != null).Select(o => o.CreatedById!.Value).Distinct().ToList();
|
||||||
|
var updatedByIds = organizations.Where(o => o.UpdatedById != null).Select(o => o.UpdatedById!.Value).Distinct().ToList();
|
||||||
|
|
||||||
var employees = await _context.Employees.Where(e => createdByIds.Contains(e.Id) || updatedByIds.Contains(e.Id)).ToListAsync();
|
// Fetch corresponding employee details in one query
|
||||||
|
var employeeIds = createdByIds.Union(updatedByIds).ToList();
|
||||||
|
var employees = await _context.Employees.Where(e => employeeIds.Contains(e.Id)).ToListAsync();
|
||||||
|
|
||||||
|
// Map data to view models including created and updated by employees
|
||||||
var vm = organizations.Select(o =>
|
var vm = organizations.Select(o =>
|
||||||
{
|
{
|
||||||
var result = _mapper.Map<OrganizationVM>(o);
|
var orgVm = _mapper.Map<OrganizationVM>(o);
|
||||||
result.CreatedBy = employees.Where(e => e.Id == o.CreatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
|
orgVm.CreatedBy = employees.Where(e => e.Id == o.CreatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
|
||||||
result.UpdatedBy = employees.Where(e => e.Id == o.UpdatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
|
orgVm.UpdatedBy = employees.Where(e => e.Id == o.UpdatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
|
||||||
return result;
|
return orgVm;
|
||||||
});
|
}).ToList();
|
||||||
|
|
||||||
var response = new
|
var response = new
|
||||||
{
|
{
|
||||||
CurrentPage = pageNumber,
|
CurrentPage = pageNumber,
|
||||||
TotalPages = totalPages,
|
TotalPages = totalPages,
|
||||||
TotalEntites = totalCount,
|
TotalEntities = totalCount,
|
||||||
Data = vm,
|
Data = vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully fetched the Service Provider list", 200));
|
_logger.LogInfo("Fetched {Count} organizations (Page {PageNumber} of {TotalPages})", vm.Count, pageNumber, totalPages);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully fetched the organization list", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("details/{id}")]
|
||||||
|
public async Task<IActionResult> GetOrganizationDetailsAsync(Guid id)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Started fetching details for OrganizationId: {OrganizationId}", id);
|
||||||
|
|
||||||
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the logged-in employee (for filter/permission checks)
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
|
// Fetch the organization entity by Id
|
||||||
|
var organization = await _context.Organizations.FirstOrDefaultAsync(o => o.Id == id);
|
||||||
|
if (organization == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Organization not found for OrganizationId: {OrganizationId}", id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch CreatedBy employee (with JobRole)
|
||||||
|
var createdByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Employees
|
||||||
|
.Include(e => e.JobRole)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == organization.CreatedById);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch UpdatedBy employee (with JobRole)
|
||||||
|
var updatedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
if (organization.UpdatedById.HasValue)
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Employees
|
||||||
|
.Include(e => e.JobRole)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == organization.UpdatedById);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch the organization's service mappings and corresponding services
|
||||||
|
var orgServiceMappingTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.OrgServiceMappings
|
||||||
|
.Include(os => os.Service)
|
||||||
|
.Where(os => os.OrganizationId == id).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch active employees in the organization
|
||||||
|
var employeeListTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Employees
|
||||||
|
.Where(e => e.OrganizationId == id && e.IsActive).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(createdByTask, updatedByTask, orgServiceMappingTask, employeeListTask);
|
||||||
|
|
||||||
|
var createdByEmployee = createdByTask.Result;
|
||||||
|
var updatedByEmployee = updatedByTask.Result;
|
||||||
|
var orgServiceMappings = orgServiceMappingTask.Result;
|
||||||
|
var employeeList = employeeListTask.Result;
|
||||||
|
|
||||||
|
var activeEmployeeCount = employeeList.Count;
|
||||||
|
var activeApplicationUserCount = employeeList.Count(e => e.HasApplicationAccess);
|
||||||
|
|
||||||
|
// Start query for projects mapped to this organization (including project and service info)
|
||||||
|
var baseProjectOrgMappingQuery = _context.ProjectOrgMappings
|
||||||
|
.Include(po => po.ProjectService)
|
||||||
|
.ThenInclude(ps => ps!.Service)
|
||||||
|
.Include(po => po.ProjectService)
|
||||||
|
.ThenInclude(ps => ps!.Project)
|
||||||
|
.Where(po => po.OrganizationId == id && po.ProjectService != null);
|
||||||
|
|
||||||
|
// If logged-in employee is not from the requested organization, restrict projects to those also mapped to their org
|
||||||
|
List<ProjectOrgMapping> projectOrgMappings;
|
||||||
|
if (loggedInEmployee.OrganizationId != id)
|
||||||
|
{
|
||||||
|
var projectIds = await _context.ProjectOrgMappings
|
||||||
|
.Include(po => po.ProjectService)
|
||||||
|
.Where(po => po.OrganizationId == loggedInEmployee.OrganizationId && po.ProjectService != null)
|
||||||
|
.Select(po => po.ProjectService!.ProjectId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
projectOrgMappings = await baseProjectOrgMappingQuery
|
||||||
|
.Where(po => projectIds.Contains(po.ProjectService!.ProjectId))
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
projectOrgMappings = await baseProjectOrgMappingQuery.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map results to output view model
|
||||||
|
var response = _mapper.Map<OrganizationDetailsVM>(organization);
|
||||||
|
response.ActiveApplicationUserCount = activeApplicationUserCount;
|
||||||
|
response.ActiveEmployeeCount = activeEmployeeCount;
|
||||||
|
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(createdByEmployee);
|
||||||
|
response.UpdatedBy = _mapper.Map<BasicEmployeeVM>(updatedByEmployee);
|
||||||
|
response.Projects = _mapper.Map<List<ProjectServiceMappingVM>>(projectOrgMappings.Select(po => po.ProjectService).ToList());
|
||||||
|
|
||||||
|
_logger.LogInfo("Fetched organization details for OrganizationId: {OrganizationId}, Employee count: {EmployeeCount}, App user count: {AppUserCount}, Project count: {ProjectCount}",
|
||||||
|
id, activeEmployeeCount, activeApplicationUserCount, response.Projects.Count);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully fetched the organization details", 200));
|
||||||
|
}
|
||||||
|
catch (DbUpdateException dbEx)
|
||||||
|
{
|
||||||
|
_logger.LogError(dbEx, "Database exception while fetching details for OrganizationId: {OrganizationId}", id);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Unhandled exception while fetching details for OrganizationId: {OrganizationId}", id);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -207,7 +341,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
?? await _context.JobRoles.FirstOrDefaultAsync(jr => jr.TenantId == tenantId);
|
?? await _context.JobRoles.FirstOrDefaultAsync(jr => jr.TenantId == tenantId);
|
||||||
|
|
||||||
// Parse full name safely (consider improving split logic for multi-part names)
|
// Parse full name safely (consider improving split logic for multi-part names)
|
||||||
var fullName = model.ContactPerson?.Split(' ', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
var fullName = model.ContactPerson.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
Employee newEmployee = new Employee
|
Employee newEmployee = new Employee
|
||||||
{
|
{
|
||||||
@ -223,19 +357,22 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
IsSystem = false,
|
IsSystem = false,
|
||||||
IsPrimary = true,
|
IsPrimary = true,
|
||||||
OrganizationId = organization.Id,
|
OrganizationId = organization.Id,
|
||||||
HasApplicationAccess = user.Id != null
|
HasApplicationAccess = true
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.Employees.Add(newEmployee);
|
_context.Employees.Add(newEmployee);
|
||||||
|
|
||||||
// Map organization services
|
// Map organization services
|
||||||
var serviceOrgMappings = model.ServiceIds.Select(s => new OrgServiceMapping
|
if (model.ServiceIds?.Any() ?? false)
|
||||||
{
|
{
|
||||||
ServiceId = s,
|
var serviceOrgMappings = model.ServiceIds.Select(s => new OrgServiceMapping
|
||||||
OrganizationId = organization.Id
|
{
|
||||||
}).ToList();
|
ServiceId = s,
|
||||||
|
OrganizationId = organization.Id
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
_context.OrgServiceMappings.AddRange(serviceOrgMappings);
|
_context.OrgServiceMappings.AddRange(serviceOrgMappings);
|
||||||
|
}
|
||||||
|
|
||||||
// Persist all changes
|
// Persist all changes
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
@ -593,66 +730,115 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
#region =================================================================== Put Functions ===================================================================
|
#region =================================================================== Put Functions ===================================================================
|
||||||
|
|
||||||
//[HttpPut("edit/{id}")]
|
[HttpPut("edit/{id}")]
|
||||||
//public async Task<IActionResult> UpdateServiceProviderAsync(Guid id, [FromBody] UpdateOrganizationDto model)
|
public async Task<IActionResult> UpdateOrganiationAsync(Guid id, [FromBody] UpdateOrganizationDto model)
|
||||||
//{
|
{
|
||||||
// await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
// using var scope = _serviceScope.CreateScope();
|
|
||||||
|
|
||||||
// var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
try
|
||||||
|
{
|
||||||
|
// Get the current logged-in employee
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
// var clientTask = Task.Run(async () =>
|
_logger.LogDebug("Started updating service provider OrganizationId: {OrganizationId} by EmployeeId: {EmployeeId}",
|
||||||
// {
|
id, loggedInEmployee.Id);
|
||||||
// await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
// return await context.Clients.FirstOrDefaultAsync(c => c.PrimaryEmployeeId == loggedInEmployee.Id && c.TenantId == tenantId);
|
|
||||||
// });
|
|
||||||
// var employeeTask = Task.Run(async () =>
|
|
||||||
// {
|
|
||||||
// await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
// return await context.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.OrganizationId == id && e.IsPrimary);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// await Task.WhenAll(clientTask, employeeTask);
|
// Check if the user is a tenant-level employee and restrict editing to their own org
|
||||||
|
var isTenantEmployee = await _context.Tenants.AnyAsync(t => t.Id == tenantId && t.OrganizationId == loggedInEmployee.OrganizationId);
|
||||||
|
if (!isTenantEmployee && loggedInEmployee.OrganizationId != id)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied. Tenant-level employee {EmployeeId} attempted to update another organization (OrganizationId: {OrganizationId})",
|
||||||
|
loggedInEmployee.Id, id);
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission to update the organization", 403));
|
||||||
|
}
|
||||||
|
|
||||||
// var client = clientTask.Result;
|
// Fetch the active organization entity
|
||||||
// var employee = employeeTask.Result;
|
var organization = await _context.Organizations.FirstOrDefaultAsync(o => o.Id == id && o.IsActive);
|
||||||
|
if (organization == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Organization with Id {OrganizationId} not found or inactive.", id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found", 404));
|
||||||
|
}
|
||||||
|
|
||||||
// if (employee == null)
|
// Update basic organization fields
|
||||||
// {
|
organization.Name = model.Name;
|
||||||
// return NotFound(ApiResponse<object>.ErrorResponse("Primary employee for service provider not found", "Primary employee for service provider not found in database", 400));
|
organization.ContactPerson = model.ContactPerson;
|
||||||
// }
|
organization.Address = model.Address;
|
||||||
|
organization.ContactNumber = model.ContactNumber;
|
||||||
|
organization.UpdatedById = loggedInEmployee.Id;
|
||||||
|
organization.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
// if (!(loggedInEmployee.ApplicationUser?.IsRootUser ?? false) && !loggedInEmployee.IsPrimary && client == null && employee.Id == loggedInEmployee.Id)
|
// Fetch the primary active employee of the organization
|
||||||
// {
|
var employee = await _context.Employees.FirstOrDefaultAsync(e => e.OrganizationId == id && e.IsPrimary && e.IsActive);
|
||||||
// return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create new service provider.", 403));
|
if (employee == null)
|
||||||
// }
|
{
|
||||||
// if (model.Id == id)
|
_logger.LogWarning("Primary employee not found for OrganizationId: {OrganizationId}", id);
|
||||||
// {
|
return NotFound(ApiResponse<object>.ErrorResponse("Primary employee not found", "Primary employee not found", 404));
|
||||||
// return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Input", "Id from path parameters do not matches with id from model", 400));
|
}
|
||||||
// }
|
|
||||||
// var serviceProvider = await _context.ServiceProviders.FirstOrDefaultAsync(sp => sp.Id == model.Id);
|
|
||||||
// if (serviceProvider == null)
|
|
||||||
// {
|
|
||||||
// return NotFound(ApiResponse<object>.ErrorResponse("Service Provider not found", "Service Provider not found in database", 404));
|
|
||||||
// }
|
|
||||||
// _mapper.Map(model, serviceProvider);
|
|
||||||
|
|
||||||
// _context.ServiceProviders.Update(serviceProvider);
|
// Split contact person's name into first and last names
|
||||||
|
var fullName = (model.ContactPerson ?? string.Empty).Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
employee.FirstName = fullName.Length > 0 ? fullName[0] : string.Empty;
|
||||||
|
employee.LastName = fullName.Length > 1 ? fullName[^1] : string.Empty;
|
||||||
|
employee.CurrentAddress = model.Address;
|
||||||
|
employee.PermanentAddress = model.Address;
|
||||||
|
employee.PhoneNumber = model.ContactNumber;
|
||||||
|
|
||||||
// var fullName = model.ContactPerson.Split(" ");
|
// Update organization's service mappings if service IDs are provided
|
||||||
|
if (model.ServiceIds?.Any() ?? false)
|
||||||
|
{
|
||||||
|
// Fetch existing service mappings (as no tracking for diff logic)
|
||||||
|
var orgServiceMappings = await _context.OrgServiceMappings
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(os => os.OrganizationId == id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
// employee.FirstName = fullName[0];
|
var existedServiceIds = orgServiceMappings.Select(os => os.ServiceId).ToList();
|
||||||
// employee.LastName = fullName[fullName.Length - 1];
|
|
||||||
// employee.CurrentAddress = model.Address;
|
|
||||||
// employee.PermanentAddress = model.Address;
|
|
||||||
// employee.PhoneNumber = model.PhoneNumber;
|
|
||||||
|
|
||||||
// _context.Employees.Update(employee);
|
// Determine new service mappings to add
|
||||||
// await _context.SaveChangesAsync();
|
var newServiceIds = model.ServiceIds.Except(existedServiceIds).ToList();
|
||||||
|
var orgServicesToDelete = orgServiceMappings
|
||||||
|
.Where(s => !model.ServiceIds.Contains(s.ServiceId))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
// var response = _mapper.Map<OrganizationVM>(serviceProvider);
|
// Add new service mappings
|
||||||
// return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully updated the service provider", 200));
|
if (newServiceIds.Any())
|
||||||
//}
|
{
|
||||||
|
var newMappings = newServiceIds.Select(sid => new OrgServiceMapping
|
||||||
|
{
|
||||||
|
OrganizationId = id,
|
||||||
|
ServiceId = sid
|
||||||
|
});
|
||||||
|
await _context.OrgServiceMappings.AddRangeAsync(newMappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove deleted service mappings
|
||||||
|
if (orgServicesToDelete.Any())
|
||||||
|
{
|
||||||
|
_context.OrgServiceMappings.RemoveRange(orgServicesToDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var response = _mapper.Map<OrganizationVM>(organization);
|
||||||
|
|
||||||
|
_logger.LogInfo("Successfully updated service provider OrganizationId: {OrganizationId} by EmployeeId: {EmployeeId}",
|
||||||
|
id, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully updated the service provider", 200));
|
||||||
|
}
|
||||||
|
catch (DbUpdateException dbEx)
|
||||||
|
{
|
||||||
|
_logger.LogError(dbEx, "Database exception occurred while updating OrganizationId: {OrganizationId}", id);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "A database exception occurred", 500));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Unhandled exception occurred while updating OrganizationId: {OrganizationId}", id);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -549,7 +549,11 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
ApplicationUserId = applicationUser.Id,
|
ApplicationUserId = applicationUser.Id,
|
||||||
JobRole = adminJobRole, // Link to the newly created role
|
JobRole = adminJobRole, // Link to the newly created role
|
||||||
CurrentAddress = model.BillingAddress,
|
CurrentAddress = model.BillingAddress,
|
||||||
OrganizationId = organization.Id
|
IsActive = true,
|
||||||
|
IsSystem = false,
|
||||||
|
IsPrimary = true,
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
HasApplicationAccess = true
|
||||||
};
|
};
|
||||||
_context.Employees.Add(employeeUser);
|
_context.Employees.Add(employeeUser);
|
||||||
|
|
||||||
@ -636,13 +640,16 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_context.ProjectAllocations.Add(projectAllocation);
|
_context.ProjectAllocations.Add(projectAllocation);
|
||||||
|
|
||||||
// Map organization services
|
// Map organization services
|
||||||
var serviceOrgMappings = model.ServiceIds.Select(s => new OrgServiceMapping
|
if (model.ServiceIds?.Any() ?? false)
|
||||||
{
|
{
|
||||||
ServiceId = s,
|
var serviceOrgMappings = model.ServiceIds.Select(s => new OrgServiceMapping
|
||||||
OrganizationId = organization.Id
|
{
|
||||||
}).ToList();
|
ServiceId = s,
|
||||||
|
OrganizationId = organization.Id
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
_context.OrgServiceMappings.AddRange(serviceOrgMappings);
|
_context.OrgServiceMappings.AddRange(serviceOrgMappings);
|
||||||
|
}
|
||||||
|
|
||||||
// All entities are now added to the context. Save them all in a single database operation.
|
// All entities are now added to the context. Save them all in a single database operation.
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
|
@ -47,6 +47,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
CreateMap<CreateOrganizationDto, Organization>();
|
CreateMap<CreateOrganizationDto, Organization>();
|
||||||
CreateMap<Organization, OrganizationVM>();
|
CreateMap<Organization, OrganizationVM>();
|
||||||
CreateMap<Organization, BasicOrganizationVm>();
|
CreateMap<Organization, BasicOrganizationVm>();
|
||||||
|
CreateMap<Organization, OrganizationDetailsVM>();
|
||||||
CreateMap<OrganizationMongoDB, BasicOrganizationVm>()
|
CreateMap<OrganizationMongoDB, BasicOrganizationVm>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
@ -127,6 +128,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
CreateMap<Project, ProjectListVM>();
|
CreateMap<Project, ProjectListVM>();
|
||||||
CreateMap<Project, ProjectDto>();
|
CreateMap<Project, ProjectDto>();
|
||||||
CreateMap<ProjectMongoDB, ProjectListVM>();
|
CreateMap<ProjectMongoDB, ProjectListVM>();
|
||||||
|
CreateMap<ProjectServiceMapping, ProjectServiceMappingVM>();
|
||||||
CreateMap<ProjectMongoDB, ProjectVM>()
|
CreateMap<ProjectMongoDB, ProjectVM>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user