Added the serviceId in project allocation
This commit is contained in:
parent
9b59a4d6b6
commit
7d85cb5f4c
6133
Marco.Pms.DataAccess/Migrations/20250920105816_Added_Service_FK_In_ProjectAllocation.Designer.cs
generated
Normal file
6133
Marco.Pms.DataAccess/Migrations/20250920105816_Added_Service_FK_In_ProjectAllocation.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_Service_FK_In_ProjectAllocation : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ServiceId",
|
||||||
|
table: "ProjectAllocations",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: true,
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logoImage",
|
||||||
|
table: "Organizations",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Organizations",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("4e3a6d31-c640-40f7-8d67-6c109fcdb9ea"),
|
||||||
|
column: "logoImage",
|
||||||
|
value: null);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProjectAllocations_ServiceId",
|
||||||
|
table: "ProjectAllocations",
|
||||||
|
column: "ServiceId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ProjectAllocations_ServiceMasters_ServiceId",
|
||||||
|
table: "ProjectAllocations",
|
||||||
|
column: "ServiceId",
|
||||||
|
principalTable: "ServiceMasters",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ProjectAllocations_ServiceMasters_ServiceId",
|
||||||
|
table: "ProjectAllocations");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ProjectAllocations_ServiceId",
|
||||||
|
table: "ProjectAllocations");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ServiceId",
|
||||||
|
table: "ProjectAllocations");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logoImage",
|
||||||
|
table: "Organizations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3643,6 +3643,9 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<Guid?>("UpdatedById")
|
b.Property<Guid?>("UpdatedById")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("logoImage")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Organizations");
|
b.ToTable("Organizations");
|
||||||
@ -3918,6 +3921,9 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<DateTime?>("ReAllocationDate")
|
b.Property<DateTime?>("ReAllocationDate")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ServiceId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<Guid>("TenantId")
|
b.Property<Guid>("TenantId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
@ -3927,6 +3933,8 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
b.ToTable("ProjectAllocations");
|
b.ToTable("ProjectAllocations");
|
||||||
@ -5858,6 +5866,10 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.Master.ServiceMaster", "Service")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("TenantId")
|
.HasForeignKey("TenantId")
|
||||||
@ -5868,6 +5880,8 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("Project");
|
b.Navigation("Project");
|
||||||
|
|
||||||
|
b.Navigation("Service");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
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 string? logoImage { get; set; }
|
||||||
public required List<Guid> ServiceIds { get; set; }
|
public required List<Guid> ServiceIds { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
public class ProjectAllocationDot
|
public class ProjectAllocationDot
|
||||||
{
|
{
|
||||||
public Guid EmpID { get; set; }
|
public Guid EmployeeId { get; set; }
|
||||||
public Guid JobRoleId { get; set; }
|
public Guid JobRoleId { get; set; }
|
||||||
public Guid ProjectId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
|
public Guid ServiceId { get; set; }
|
||||||
public bool Status { get; set; }
|
public bool Status { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,6 +14,7 @@
|
|||||||
{
|
{
|
||||||
public Guid ProjectId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
public Guid JobRoleId { get; set; }
|
public Guid JobRoleId { get; set; }
|
||||||
|
public Guid ServiceId { get; set; }
|
||||||
public bool Status { get; set; }
|
public bool Status { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
return new ProjectAllocation
|
return new ProjectAllocation
|
||||||
{
|
{
|
||||||
AllocationDate = DateTime.Now,
|
AllocationDate = DateTime.Now,
|
||||||
EmployeeId = model.EmpID,
|
EmployeeId = model.EmployeeId,
|
||||||
JobRoleId = model.JobRoleId,
|
JobRoleId = model.JobRoleId,
|
||||||
TenantId = TenantId,
|
TenantId = TenantId,
|
||||||
ProjectId = model.ProjectId
|
ProjectId = model.ProjectId
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
public string Address { get; set; } = string.Empty;
|
public string Address { get; set; } = string.Empty;
|
||||||
public string ContactNumber { get; set; } = string.Empty;
|
public string ContactNumber { get; set; } = string.Empty;
|
||||||
public double SPRID { get; set; }
|
public double SPRID { get; set; }
|
||||||
|
public string? logoImage { get; set; }
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public Guid? CreatedById { get; set; }
|
public Guid? CreatedById { get; set; }
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Projects
|
namespace Marco.Pms.Model.Projects
|
||||||
{
|
{
|
||||||
@ -21,9 +22,15 @@ namespace Marco.Pms.Model.Projects
|
|||||||
public bool IsActive { get; set; } = true;
|
public bool IsActive { get; set; } = true;
|
||||||
|
|
||||||
public Guid ProjectId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
|
|
||||||
[ForeignKey("ProjectId")]
|
[ForeignKey("ProjectId")]
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
public Project? Project { get; set; }
|
public Project? Project { get; set; }
|
||||||
|
public Guid? ServiceId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("ServiceId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public ServiceMaster? Service { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public DateTime AllocationDate { get; set; }
|
public DateTime AllocationDate { get; set; }
|
||||||
|
@ -11,6 +11,7 @@ namespace Marco.Pms.Model.ViewModels.Organization
|
|||||||
public string? Address { get; set; }
|
public string? Address { get; set; }
|
||||||
public string? ContactNumber { get; set; }
|
public string? ContactNumber { get; set; }
|
||||||
public double SPRID { get; set; }
|
public double SPRID { get; set; }
|
||||||
|
public string? logoImage { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
public BasicEmployeeVM? UpdatedBy { get; set; }
|
public BasicEmployeeVM? UpdatedBy { get; set; }
|
||||||
|
@ -219,7 +219,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("allocation/{projectId}")]
|
[HttpGet("allocation/{projectId}")]
|
||||||
public async Task<IActionResult> GetProjectAllocation(Guid projectId, [FromQuery] Guid? organizationId, [FromQuery] bool includeInactive = false)
|
public async Task<IActionResult> GetProjectAllocation(Guid projectId, [FromQuery] Guid? organizationId, [FromQuery] Guid? serviceId, [FromQuery] bool includeInactive = false)
|
||||||
{
|
{
|
||||||
// --- Step 1: Input Validation ---
|
// --- Step 1: Input Validation ---
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
@ -231,7 +231,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
// --- Step 2: Prepare data without I/O ---
|
// --- Step 2: Prepare data without I/O ---
|
||||||
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
var response = await _projectServices.GetProjectAllocationAsync(projectId, organizationId, includeInactive, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetProjectAllocationAsync(projectId, organizationId, serviceId, includeInactive, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +161,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
CreateMap<ProjectAllocationDot, ProjectAllocation>()
|
CreateMap<ProjectAllocationDot, ProjectAllocation>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.EmployeeId,
|
dest => dest.EmployeeId,
|
||||||
// Explicitly and safely convert string ProjectStatusId to Guid ProjectStatusId
|
opt => opt.MapFrom(src => src.EmployeeId));
|
||||||
opt => opt.MapFrom(src => src.EmpID));
|
|
||||||
CreateMap<ProjectsAllocationDto, ProjectAllocation>();
|
CreateMap<ProjectsAllocationDto, ProjectAllocation>();
|
||||||
CreateMap<ProjectAllocation, ProjectAllocationVM>();
|
CreateMap<ProjectAllocation, ProjectAllocationVM>();
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
/// <param name="tenantId">The ID of the current tenant.</param>
|
/// <param name="tenantId">The ID of the current tenant.</param>
|
||||||
/// <param name="loggedInEmployee">The current authenticated employee for permission checks.</param>
|
/// <param name="loggedInEmployee">The current authenticated employee for permission checks.</param>
|
||||||
/// <returns>An ApiResponse containing allocation details or an appropriate error.</returns>
|
/// <returns>An ApiResponse containing allocation details or an appropriate error.</returns>
|
||||||
public async Task<ApiResponse<object>> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
// --- Step 1: Input Validation ---
|
// --- Step 1: Input Validation ---
|
||||||
if (projectId == Guid.Empty)
|
if (projectId == Guid.Empty)
|
||||||
@ -595,7 +595,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
.ThenInclude(e => e!.JobRole)
|
.ThenInclude(e => e!.JobRole)
|
||||||
.Include(pa => pa.Employee)
|
.Include(pa => pa.Employee)
|
||||||
.ThenInclude(e => e!.Organization)
|
.ThenInclude(e => e!.Organization)
|
||||||
.Where(pa => pa.ProjectId == projectId && pa.TenantId == tenantId);
|
.Include(pa => pa.Service)
|
||||||
|
.Where(pa => pa.ProjectId == projectId && pa.TenantId == tenantId && pa.Service != null);
|
||||||
|
|
||||||
// Conditionally apply the filter for active allocations.
|
// Conditionally apply the filter for active allocations.
|
||||||
if (!includeInactive)
|
if (!includeInactive)
|
||||||
@ -628,6 +629,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
OrganizationName = pa.Employee.Organization!.Name,
|
OrganizationName = pa.Employee.Organization!.Name,
|
||||||
|
|
||||||
|
ServiceName = pa.Service!.Name,
|
||||||
|
|
||||||
// Simplified JobRoleId logic: Use the allocation's role if it exists, otherwise fall back to the employee's default role.
|
// Simplified JobRoleId logic: Use the allocation's role if it exists, otherwise fall back to the employee's default role.
|
||||||
JobRoleId = pa.JobRoleId ?? pa.Employee.JobRoleId
|
JobRoleId = pa.JobRoleId ?? pa.Employee.JobRoleId
|
||||||
})
|
})
|
||||||
@ -679,8 +682,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Step 2: Fetch all relevant existing data in ONE database call ---
|
// --- Step 2: Fetch all relevant existing data in ONE database call ---
|
||||||
var employeeProjectPairs = allocationsDto.Select(a => new { a.EmpID, a.ProjectId }).ToList();
|
var employeeProjectPairs = allocationsDto.Select(a => new { a.EmployeeId, a.ProjectId }).ToList();
|
||||||
List<Guid> employeeIds = allocationsDto.Select(a => a.EmpID).Distinct().ToList();
|
List<Guid> employeeIds = allocationsDto.Select(a => a.EmployeeId).Distinct().ToList();
|
||||||
|
|
||||||
// Fetch all currently active allocations for the employees and projects in this batch.
|
// Fetch all currently active allocations for the employees and projects in this batch.
|
||||||
// We use a dictionary for fast O(1) lookups inside the loop.
|
// We use a dictionary for fast O(1) lookups inside the loop.
|
||||||
@ -695,7 +698,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
// --- Step 3: Process logic IN MEMORY ---
|
// --- Step 3: Process logic IN MEMORY ---
|
||||||
foreach (var dto in allocationsDto)
|
foreach (var dto in allocationsDto)
|
||||||
{
|
{
|
||||||
var key = (dto.EmpID, dto.ProjectId);
|
var key = (dto.EmployeeId, dto.ProjectId);
|
||||||
existingAllocations.TryGetValue(key, out var existingAllocation);
|
existingAllocations.TryGetValue(key, out var existingAllocation);
|
||||||
|
|
||||||
if (dto.Status == false) // User wants to DEACTIVATE the allocation
|
if (dto.Status == false) // User wants to DEACTIVATE the allocation
|
||||||
@ -726,8 +729,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _cache.ClearAllProjectIds(dto.EmpID);
|
await _cache.ClearAllProjectIds(dto.EmployeeId);
|
||||||
_logger.LogInfo("Successfully completed cache invalidation for employee {EmployeeId}.", dto.EmpID);
|
_logger.LogInfo("Successfully completed cache invalidation for employee {EmployeeId}.", dto.EmployeeId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<object>> CreateProjectAsync(CreateProjectDto projectDto, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> CreateProjectAsync(CreateProjectDto projectDto, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> UpdateProjectAsync(Guid id, UpdateProjectDto updateProjectDto, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> UpdateProjectAsync(Guid id, UpdateProjectDto updateProjectDto, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetEmployeeByProjectIdAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, bool includeInactive, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetProjectAllocationAsync(Guid projectId, Guid? organizationId, Guid? serviceId, bool includeInactive, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<List<ProjectAllocationVM>>> ManageAllocationAsync(List<ProjectAllocationDot> projectAllocationDots, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<List<ProjectAllocationVM>>> ManageAllocationAsync(List<ProjectAllocationDot> projectAllocationDots, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user