Added the API to get list organization hierarchy for certain employee
This commit is contained in:
parent
7928c6ca36
commit
7c80e49809
7628
Marco.Pms.DataAccess/Migrations/20251111065550_Added_OrganiazationHierarchy_Related_Table.Designer.cs
generated
Normal file
7628
Marco.Pms.DataAccess/Migrations/20251111065550_Added_OrganiazationHierarchy_Related_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Marco.Pms.DataAccess.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Added_OrganiazationHierarchy_Related_Table : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrganizationHierarchies",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
EmployeeId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
ReportToId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
IsPrimary = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
AssignedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
AssignedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrganizationHierarchies", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrganizationHierarchies_Employees_AssignedById",
|
||||
column: x => x.AssignedById,
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrganizationHierarchies_Employees_EmployeeId",
|
||||
column: x => x.EmployeeId,
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrganizationHierarchies_Employees_ReportToId",
|
||||
column: x => x.ReportToId,
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrganizationHierarchies_Tenants_TenantId",
|
||||
column: x => x.TenantId,
|
||||
principalTable: "Tenants",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrgHierarchyLogs",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
OrganizationHierarchyId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
ReAssignedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
ReAssignedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrgHierarchyLogs", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrgHierarchyLogs_Employees_ReAssignedById",
|
||||
column: x => x.ReAssignedById,
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrgHierarchyLogs_OrganizationHierarchies_OrganizationHierarc~",
|
||||
column: x => x.OrganizationHierarchyId,
|
||||
principalTable: "OrganizationHierarchies",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrgHierarchyLogs_Tenants_TenantId",
|
||||
column: x => x.TenantId,
|
||||
principalTable: "Tenants",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrganizationHierarchies_AssignedById",
|
||||
table: "OrganizationHierarchies",
|
||||
column: "AssignedById");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrganizationHierarchies_EmployeeId",
|
||||
table: "OrganizationHierarchies",
|
||||
column: "EmployeeId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrganizationHierarchies_ReportToId",
|
||||
table: "OrganizationHierarchies",
|
||||
column: "ReportToId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrganizationHierarchies_TenantId",
|
||||
table: "OrganizationHierarchies",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrgHierarchyLogs_OrganizationHierarchyId",
|
||||
table: "OrgHierarchyLogs",
|
||||
column: "OrganizationHierarchyId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrgHierarchyLogs_ReAssignedById",
|
||||
table: "OrgHierarchyLogs",
|
||||
column: "ReAssignedById");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrgHierarchyLogs_TenantId",
|
||||
table: "OrgHierarchyLogs",
|
||||
column: "TenantId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrgHierarchyLogs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrganizationHierarchies");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4387,6 +4387,35 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgHierarchyLog", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("OrganizationHierarchyId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<DateTime>("ReAssignedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<Guid>("ReAssignedById")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrganizationHierarchyId");
|
||||
|
||||
b.HasIndex("ReAssignedById");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("OrgHierarchyLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgServiceMapping", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -4501,6 +4530,46 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrganizationHierarchy", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<DateTime>("AssignedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<Guid>("AssignedById")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("EmployeeId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsPrimary")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<Guid>("ReportToId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignedById");
|
||||
|
||||
b.HasIndex("EmployeeId");
|
||||
|
||||
b.HasIndex("ReportToId");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("OrganizationHierarchies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.ProjectOrgMapping", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -6999,6 +7068,33 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.Navigation("Tenant");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgHierarchyLog", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.OrganizationModel.OrganizationHierarchy", "OrganizationHierarchy")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrganizationHierarchyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "ReAssignedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReAssignedById")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||
.WithMany()
|
||||
.HasForeignKey("TenantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("OrganizationHierarchy");
|
||||
|
||||
b.Navigation("ReAssignedBy");
|
||||
|
||||
b.Navigation("Tenant");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgServiceMapping", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.OrganizationModel.Organization", "Organization")
|
||||
@ -7018,6 +7114,41 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.Navigation("Service");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrganizationHierarchy", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "AssignedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("AssignedById")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee")
|
||||
.WithMany()
|
||||
.HasForeignKey("EmployeeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportTo")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportToId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||
.WithMany()
|
||||
.HasForeignKey("TenantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AssignedBy");
|
||||
|
||||
b.Navigation("Employee");
|
||||
|
||||
b.Navigation("ReportTo");
|
||||
|
||||
b.Navigation("Tenant");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.ProjectOrgMapping", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "AssignedBy")
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
namespace Marco.Pms.Model.Dtos.Organization
|
||||
{
|
||||
public class OrganizationHierarchyDto
|
||||
{
|
||||
public Guid ReportToId { get; set; }
|
||||
public bool IsPrimary { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
}
|
||||
@ -13,14 +13,8 @@ namespace Marco.Pms.Model.OrganizationModel
|
||||
[ValidateNever]
|
||||
[ForeignKey("OrganizationHierarchyId")]
|
||||
public OrganizationHierarchy? OrganizationHierarchy { get; set; }
|
||||
public DateTime AssignedAt { get; set; }
|
||||
public Guid AssignedById { get; set; }
|
||||
|
||||
[ValidateNever]
|
||||
[ForeignKey("AssignedById")]
|
||||
public Employee? AssignedBy { get; set; }
|
||||
public DateTime? ReAssignedAt { get; set; }
|
||||
public Guid? ReAssignedById { get; set; }
|
||||
public DateTime ReAssignedAt { get; set; }
|
||||
public Guid ReAssignedById { get; set; }
|
||||
|
||||
[ValidateNever]
|
||||
[ForeignKey("ReAssignedById")]
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
using Marco.Pms.Model.ViewModels.Activities;
|
||||
|
||||
namespace Marco.Pms.Model.ViewModels.Organization
|
||||
{
|
||||
public class OrganizationHierarchyVM
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public BasicEmployeeVM? Employee { get; set; }
|
||||
public BasicEmployeeVM? ReportTo { get; set; }
|
||||
public bool IsPrimary { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public DateTime AssignedAt { get; set; }
|
||||
public BasicEmployeeVM? AssignedBy { get; set; }
|
||||
}
|
||||
}
|
||||
@ -104,6 +104,8 @@ namespace Marco.Pms.Services.Controllers
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Put Functions ===================================================================
|
||||
|
||||
@ -59,7 +59,8 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
dest => dest.Id,
|
||||
// Explicitly and safely convert string Id to Guid Id
|
||||
opt => opt.MapFrom(src => new Guid(src.Id))
|
||||
);
|
||||
);
|
||||
CreateMap<OrganizationHierarchy, OrganizationHierarchyVM>();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -268,11 +268,58 @@ namespace Marco.Pms.Services.Service
|
||||
return ApiResponse<object>.ErrorResponse("Internal error", "An internal exception occurred", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the active organization hierarchy list for a specified employee within a given tenant.
|
||||
/// </summary>
|
||||
/// <param name="employeeId">ID of the employee whose hierarchy is requested.</param>
|
||||
/// <param name="loggedInEmployee">Logged-in employee making the request (for audit/logging).</param>
|
||||
/// <param name="tenantId">Tenant ID for multi-tenant filtering.</param>
|
||||
/// <param name="loggedOrganizationId">Organization ID of the logged-in employee (for access validation).</param>
|
||||
/// <returns>ApiResponse containing the list of organization hierarchy view models or error details.</returns>
|
||||
public async Task<ApiResponse<object>> GetOrganizationHierarchyListAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId)
|
||||
{
|
||||
return ApiResponse<object>.SuccessResponse(new { });
|
||||
// Validate input IDs
|
||||
if (tenantId == Guid.Empty || loggedOrganizationId == Guid.Empty)
|
||||
{
|
||||
_logger.LogWarning("Access denied: Invalid tenantId or loggedOrganizationId. TenantId: {TenantId}, OrganizationId: {OrganizationId}", tenantId, loggedOrganizationId);
|
||||
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant or organization identifier.", 403);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Query to get active organization hierarchies, including related navigation properties for richer data
|
||||
var organizationHierarchies = await _context.OrganizationHierarchies
|
||||
.Include(oh => oh.Employee).ThenInclude(e => e!.JobRole)
|
||||
.Include(oh => oh.AssignedBy).ThenInclude(e => e!.JobRole)
|
||||
.Include(oh => oh.ReportTo).ThenInclude(e => e!.JobRole)
|
||||
.AsNoTracking()
|
||||
.Where(oh => oh.EmployeeId == employeeId && oh.IsActive && oh.TenantId == tenantId)
|
||||
.OrderByDescending(oh => oh.AssignedAt)
|
||||
.ToListAsync();
|
||||
|
||||
// Check if any records found
|
||||
if (!organizationHierarchies.Any())
|
||||
{
|
||||
_logger.LogWarning("No active organization hierarchy found for EmployeeId: {EmployeeId} in TenantId: {TenantId}.", employeeId, tenantId);
|
||||
return ApiResponse<object>.SuccessResponse(new List<OrganizationHierarchyVM>(), "No active superiors found.", 200);
|
||||
}
|
||||
|
||||
// Map entities to view models
|
||||
var response = _mapper.Map<List<OrganizationHierarchyVM>>(organizationHierarchies);
|
||||
|
||||
_logger.LogInfo("Fetched {Count} active superiors for EmployeeId: {EmployeeId} in TenantId: {TenantId}.", response.Count, employeeId, tenantId);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} superior(s) fetched successfully.", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred while fetching organization hierarchy list for EmployeeId: {EmployeeId} in TenantId: {TenantId}.", employeeId, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An error occurred while processing your request.", 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Post Functions ===================================================================
|
||||
@ -734,6 +781,7 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Put Functions ===================================================================
|
||||
|
||||
@ -16,6 +16,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
Task<ApiResponse<object>> CreateOrganizationAsync(CreateOrganizationDto model, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
|
||||
Task<ApiResponse<object>> AssignOrganizationToProjectAsync(AssignOrganizationDto model, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
|
||||
Task<ApiResponse<object>> AssignOrganizationToTenantAsync(Guid organizationId, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Put Functions ===================================================================
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"Title": "Dev"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1"
|
||||
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMSOrg"
|
||||
},
|
||||
"SmtpSettings": {
|
||||
"SmtpServer": "smtp.gmail.com",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user