Merge pull request 'Organization_Hierarchy' (#153) from Organization_Hierarchy into Service_Project_Management

Reviewed-on: #153
This commit is contained in:
ashutosh.nehete 2025-11-13 04:29:48 +00:00
commit 6e945cf6c1
14 changed files with 9279 additions and 909 deletions

View File

@ -204,6 +204,8 @@ namespace Marco.Pms.DataAccess.Data
public DbSet<TenantOrgMapping> TenantOrgMappings { get; set; } public DbSet<TenantOrgMapping> TenantOrgMappings { get; set; }
public DbSet<OrgServiceMapping> OrgServiceMappings { get; set; } public DbSet<OrgServiceMapping> OrgServiceMappings { get; set; }
public DbSet<ProjectOrgMapping> ProjectOrgMappings { get; set; } public DbSet<ProjectOrgMapping> ProjectOrgMappings { get; set; }
public DbSet<OrganizationHierarchy> OrganizationHierarchies { get; set; }
public DbSet<OrgHierarchyLog> OrgHierarchyLogs { get; set; }
#endregion #endregion
#region ======================================================= Service Project ======================================================= #region ======================================================= Service Project =======================================================

File diff suppressed because one or more lines are too long

View File

@ -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");
}
}
}

View File

@ -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 => modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgServiceMapping", b =>
{ {
b.Property<Guid>("Id") 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 => modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.ProjectOrgMapping", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -7561,6 +7630,33 @@ namespace Marco.Pms.DataAccess.Migrations
b.Navigation("Tenant"); 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 => modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.OrgServiceMapping", b =>
{ {
b.HasOne("Marco.Pms.Model.OrganizationModel.Organization", "Organization") b.HasOne("Marco.Pms.Model.OrganizationModel.Organization", "Organization")
@ -7580,6 +7676,41 @@ namespace Marco.Pms.DataAccess.Migrations
b.Navigation("Service"); 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 => modelBuilder.Entity("Marco.Pms.Model.OrganizationModel.ProjectOrgMapping", b =>
{ {
b.HasOne("Marco.Pms.Model.Employees.Employee", "AssignedBy") b.HasOne("Marco.Pms.Model.Employees.Employee", "AssignedBy")

View File

@ -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; }
}
}

View File

@ -0,0 +1,23 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.OrganizationModel
{
public class OrgHierarchyLog : TenantRelation
{
public Guid Id { get; set; }
public Guid OrganizationHierarchyId { get; set; }
[ValidateNever]
[ForeignKey("OrganizationHierarchyId")]
public OrganizationHierarchy? OrganizationHierarchy { get; set; }
public DateTime ReAssignedAt { get; set; }
public Guid ReAssignedById { get; set; }
[ValidateNever]
[ForeignKey("ReAssignedById")]
public Employee? ReAssignedBy { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.OrganizationModel
{
public class OrganizationHierarchy : TenantRelation
{
public Guid Id { get; set; }
public Guid EmployeeId { get; set; }
[ValidateNever]
[ForeignKey("EmployeeId")]
public Employee? Employee { get; set; }
public Guid ReportToId { get; set; }
[ValidateNever]
[ForeignKey("ReportToId")]
public Employee? ReportTo { get; set; }
public bool IsPrimary { get; set; }
public bool IsActive { get; set; }
public DateTime AssignedAt { get; set; }
public Guid AssignedById { get; set; }
[ValidateNever]
[ForeignKey("AssignedById")]
public Employee? AssignedBy { get; set; }
}
}

View File

@ -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; }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,7 @@ namespace Marco.Pms.Services.MappingProfiles
// Explicitly and safely convert string Id to Guid Id // Explicitly and safely convert string Id to Guid Id
opt => opt.MapFrom(src => new Guid(src.Id)) opt => opt.MapFrom(src => new Guid(src.Id))
); );
CreateMap<OrganizationHierarchy, OrganizationHierarchyVM>();
#endregion #endregion

View File

@ -185,6 +185,7 @@ builder.Services.AddScoped<IDirectoryService, DirectoryService>();
builder.Services.AddScoped<IFirebaseService, FirebaseService>(); builder.Services.AddScoped<IFirebaseService, FirebaseService>();
builder.Services.AddScoped<IRazorpayService, RazorpayService>(); builder.Services.AddScoped<IRazorpayService, RazorpayService>();
builder.Services.AddScoped<IAesEncryption, AesEncryption>(); builder.Services.AddScoped<IAesEncryption, AesEncryption>();
builder.Services.AddScoped<IOrganizationService, OrganizationService>();
builder.Services.AddScoped<ITenantService, TenantService>(); builder.Services.AddScoped<ITenantService, TenantService>();
builder.Services.AddScoped<IServiceProject, ServiceProjectService>(); builder.Services.AddScoped<IServiceProject, ServiceProjectService>();
#endregion #endregion

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
using Marco.Pms.Model.Dtos.Organization;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Utilities;
namespace Marco.Pms.Services.Service.ServiceInterfaces
{
public interface IOrganizationService
{
#region =================================================================== Get Functions ===================================================================
Task<ApiResponse<object>> GetOrganizarionListAsync(string? searchString, double? sprid, bool active, int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
Task<ApiResponse<object>> GetOrganizationDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
Task<ApiResponse<object>> GetOrganizationHierarchyListAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
#endregion
#region =================================================================== Post Functions ===================================================================
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);
Task<ApiResponse<object>> ManageOrganizationHierarchyAsync(Guid employeeId, List<OrganizationHierarchyDto> model, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
#endregion
#region =================================================================== Put Functions ===================================================================
Task<ApiResponse<object>> UpdateOrganiationAsync(Guid id, UpdateOrganizationDto model, Employee loggedInEmployee, Guid tenantId, Guid loggedOrganizationId);
#endregion
#region =================================================================== Delete Functions ===================================================================
#endregion
}
}

View File

@ -9,7 +9,7 @@
"Title": "Dev" "Title": "Dev"
}, },
"ConnectionStrings": { "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": { "SmtpSettings": {
"SmtpServer": "smtp.gmail.com", "SmtpServer": "smtp.gmail.com",