Solving the rebase confilt
This commit is contained in:
commit
194764c9d6
File diff suppressed because one or more lines are too long
3547
Marco.Pms.DataAccess/Migrations/20250731100859_Added_New_Parameters_In_Tenant_Table.Designer.cs
generated
Normal file
3547
Marco.Pms.DataAccess/Migrations/20250731100859_Added_New_Parameters_In_Tenant_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3550
Marco.Pms.DataAccess/Migrations/20250801101253_Added_New_Parameter_In_Tenant_Table.Designer.cs
generated
Normal file
3550
Marco.Pms.DataAccess/Migrations/20250801101253_Added_New_Parameter_In_Tenant_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_New_Parameter_In_Tenant_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "OfficeNumber",
|
||||||
|
table: "Tenants",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Tenants",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"),
|
||||||
|
column: "OfficeNumber",
|
||||||
|
value: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "OfficeNumber",
|
||||||
|
table: "Tenants");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3550
Marco.Pms.DataAccess/Migrations/20250801111158_Fixed_Spelling_Mistake_In_Tenant_Table.Designer.cs
generated
Normal file
3550
Marco.Pms.DataAccess/Migrations/20250801111158_Fixed_Spelling_Mistake_In_Tenant_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Fixed_Spelling_Mistake_In_Tenant_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "OragnizationSize",
|
||||||
|
table: "Tenants",
|
||||||
|
newName: "OrganizationSize");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "OrganizationSize",
|
||||||
|
table: "Tenants",
|
||||||
|
newName: "OragnizationSize");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3872
Marco.Pms.DataAccess/Migrations/20250804061007_Added_Subscription_Related_Tables.Designer.cs
generated
Normal file
3872
Marco.Pms.DataAccess/Migrations/20250804061007_Added_Subscription_Related_Tables.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,207 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_Subscription_Related_Tables : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SubscriptionStatus",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SubscriptionStatus", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SubscriptionPlans",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
PlanName = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Description = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
PriceQuarterly = table.Column<double>(type: "double", nullable: false),
|
||||||
|
PriceMonthly = table.Column<double>(type: "double", nullable: false),
|
||||||
|
PriceHalfMonthly = table.Column<double>(type: "double", nullable: false),
|
||||||
|
PriceYearly = table.Column<double>(type: "double", nullable: false),
|
||||||
|
TrialDays = table.Column<int>(type: "int", nullable: false),
|
||||||
|
MaxUser = table.Column<double>(type: "double", nullable: false),
|
||||||
|
MaxStorage = table.Column<double>(type: "double", nullable: false),
|
||||||
|
FeaturesId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CreateAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
UpdateAt = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||||
|
CurrencyId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CreatedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
|
||||||
|
IsActive = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SubscriptionPlans", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_CurrencyMaster_CurrencyId",
|
||||||
|
column: x => x.CurrencyId,
|
||||||
|
principalTable: "CurrencyMaster",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id");
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TenantSubscriptions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
PlanId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
StartDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
EndDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
IsTrial = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
StatusId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CurrencyId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
NextBillingDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
CancellationDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||||
|
AutoRemew = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
UpdateAt = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||||
|
CreatedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
|
||||||
|
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TenantSubscriptions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_CurrencyMaster_CurrencyId",
|
||||||
|
column: x => x.CurrencyId,
|
||||||
|
principalTable: "CurrencyMaster",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_Employees_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_Employees_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionPlans_PlanId",
|
||||||
|
column: x => x.PlanId,
|
||||||
|
principalTable: "SubscriptionPlans",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionStatus_StatusId",
|
||||||
|
column: x => x.StatusId,
|
||||||
|
principalTable: "SubscriptionStatus",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_Tenants_TenantId",
|
||||||
|
column: x => x.TenantId,
|
||||||
|
principalTable: "Tenants",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "SubscriptionStatus",
|
||||||
|
columns: new[] { "Id", "Name" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ new Guid("1c0e422e-01b6-412f-b72a-1db004cc8a7f"), "Suspended" },
|
||||||
|
{ new Guid("4ed487b1-af22-4e25-aecd-b63fd850cf2d"), "InActive" },
|
||||||
|
{ new Guid("cd3a68ea-41fd-42f0-bd0c-c871c7337727"), "Active" }
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CreatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CurrencyId",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CurrencyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_UpdatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_CreatedById",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_CurrencyId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "CurrencyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_PlanId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "PlanId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_StatusId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "StatusId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_TenantId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "TenantId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TenantSubscriptions_UpdatedById",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "UpdatedById");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TenantSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SubscriptionStatus");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3872
Marco.Pms.DataAccess/Migrations/20250804063600_Corrected_Typo_In_Subscription_Table.Designer.cs
generated
Normal file
3872
Marco.Pms.DataAccess/Migrations/20250804063600_Corrected_Typo_In_Subscription_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Corrected_Typo_In_Subscription_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "AutoRemew",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
newName: "AutoRenew");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "AutoRenew",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
newName: "AutoRemew");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3872
Marco.Pms.DataAccess/Migrations/20250804064532_Corrected_Typo_In_SubscriptionPlan_Table.Designer.cs
generated
Normal file
3872
Marco.Pms.DataAccess/Migrations/20250804064532_Corrected_Typo_In_SubscriptionPlan_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Corrected_Typo_In_SubscriptionPlan_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "PriceHalfMonthly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
newName: "PriceHalfYearly");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "PriceHalfYearly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
newName: "PriceHalfMonthly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,411 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Seprated_SubscriptionPlan_And_SubscriptionPlanDetails : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_StatusMasters_Tenants_TenantId",
|
||||||
|
table: "StatusMasters");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_CurrencyMaster_CurrencyId",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_CreatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_UpdatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionPlans_PlanId",
|
||||||
|
table: "TenantSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CreatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CurrencyId",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_SubscriptionPlans_UpdatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_StatusMasters_TenantId",
|
||||||
|
table: "StatusMasters");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CreateAt",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CreatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CurrencyId",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "FeaturesId",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MaxStorage",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MaxUser",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PriceHalfYearly",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PriceMonthly",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PriceQuarterly",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PriceYearly",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "TrialDays",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UpdateAt",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UpdatedById",
|
||||||
|
table: "SubscriptionPlans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "TenantId",
|
||||||
|
table: "StatusMasters");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsCancelled",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "MaxUsers",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SubscriptionPlanDetails",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
Price = table.Column<double>(type: "double", nullable: false),
|
||||||
|
Frequency = table.Column<int>(type: "int", nullable: false),
|
||||||
|
TrialDays = table.Column<int>(type: "int", nullable: false),
|
||||||
|
MaxUser = table.Column<double>(type: "double", nullable: false),
|
||||||
|
MaxStorage = table.Column<double>(type: "double", nullable: false),
|
||||||
|
FeaturesId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CreateAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
UpdateAt = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||||
|
PlanId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CurrencyId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
CreatedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
UpdatedById = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
|
||||||
|
IsActive = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SubscriptionPlanDetails", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlanDetails_CurrencyMaster_CurrencyId",
|
||||||
|
column: x => x.CurrencyId,
|
||||||
|
principalTable: "CurrencyMaster",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlanDetails_Employees_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlanDetails_Employees_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SubscriptionPlanDetails_SubscriptionPlans_PlanId",
|
||||||
|
column: x => x.PlanId,
|
||||||
|
principalTable: "SubscriptionPlans",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlanDetails_CreatedById",
|
||||||
|
table: "SubscriptionPlanDetails",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlanDetails_CurrencyId",
|
||||||
|
table: "SubscriptionPlanDetails",
|
||||||
|
column: "CurrencyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlanDetails_PlanId",
|
||||||
|
table: "SubscriptionPlanDetails",
|
||||||
|
column: "PlanId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlanDetails_UpdatedById",
|
||||||
|
table: "SubscriptionPlanDetails",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionPlanDetails_PlanId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "PlanId",
|
||||||
|
principalTable: "SubscriptionPlanDetails",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionPlanDetails_PlanId",
|
||||||
|
table: "TenantSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SubscriptionPlanDetails");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsCancelled",
|
||||||
|
table: "TenantSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MaxUsers",
|
||||||
|
table: "TenantSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "CreateAt",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "CreatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "CurrencyId",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "FeaturesId",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "MaxStorage",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "MaxUser",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "PriceHalfYearly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "PriceMonthly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "PriceQuarterly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "PriceYearly",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "TrialDays",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "UpdateAt",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "UpdatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: true,
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "TenantId",
|
||||||
|
table: "StatusMasters",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "StatusMasters",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"),
|
||||||
|
column: "TenantId",
|
||||||
|
value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"));
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "StatusMasters",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"),
|
||||||
|
column: "TenantId",
|
||||||
|
value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"));
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "StatusMasters",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"),
|
||||||
|
column: "TenantId",
|
||||||
|
value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"));
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "StatusMasters",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"),
|
||||||
|
column: "TenantId",
|
||||||
|
value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"));
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "StatusMasters",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"),
|
||||||
|
column: "TenantId",
|
||||||
|
value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26"));
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CreatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_CurrencyId",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CurrencyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SubscriptionPlans_UpdatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "UpdatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_StatusMasters_TenantId",
|
||||||
|
table: "StatusMasters",
|
||||||
|
column: "TenantId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_StatusMasters_Tenants_TenantId",
|
||||||
|
table: "StatusMasters",
|
||||||
|
column: "TenantId",
|
||||||
|
principalTable: "Tenants",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_CurrencyMaster_CurrencyId",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CurrencyId",
|
||||||
|
principalTable: "CurrencyMaster",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_CreatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "CreatedById",
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SubscriptionPlans_Employees_UpdatedById",
|
||||||
|
table: "SubscriptionPlans",
|
||||||
|
column: "UpdatedById",
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_TenantSubscriptions_SubscriptionPlans_PlanId",
|
||||||
|
table: "TenantSubscriptions",
|
||||||
|
column: "PlanId",
|
||||||
|
principalTable: "SubscriptionPlans",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
using Marco.Pms.Model.MongoDBModels.Employees;
|
using Marco.Pms.Model.MongoDBModels.Employees;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
|
||||||
namespace Marco.Pms.Helpers.CacheHelper
|
namespace Marco.Pms.Helpers.CacheHelper
|
||||||
@ -8,8 +9,11 @@ namespace Marco.Pms.Helpers.CacheHelper
|
|||||||
public class EmployeeCache
|
public class EmployeeCache
|
||||||
{
|
{
|
||||||
private readonly IMongoCollection<EmployeePermissionMongoDB> _collection;
|
private readonly IMongoCollection<EmployeePermissionMongoDB> _collection;
|
||||||
public EmployeeCache(IConfiguration configuration)
|
private readonly ILogger<EmployeeCache> _logger;
|
||||||
|
|
||||||
|
public EmployeeCache(IConfiguration configuration, ILogger<EmployeeCache> logger)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
var connectionString = configuration["MongoDB:ConnectionString"];
|
var connectionString = configuration["MongoDB:ConnectionString"];
|
||||||
var mongoUrl = new MongoUrl(connectionString);
|
var mongoUrl = new MongoUrl(connectionString);
|
||||||
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
|
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
|
||||||
@ -185,6 +189,25 @@ namespace Marco.Pms.Helpers.CacheHelper
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public async Task<bool> ClearAllEmployeesFromCacheByEmployeeIds(List<string> employeeIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filter = Builders<EmployeePermissionMongoDB>.Filter.In(x => x.Id, employeeIds);
|
||||||
|
|
||||||
|
var result = await _collection.DeleteManyAsync(filter);
|
||||||
|
|
||||||
|
if (result.DeletedCount == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error occured while deleting employee profile");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A private method to handle the one-time setup of the collection's indexes.
|
// A private method to handle the one-time setup of the collection's indexes.
|
||||||
private async Task InitializeCollectionAsync()
|
private async Task InitializeCollectionAsync()
|
||||||
|
53
Marco.Pms.Helpers/Utility/FeatureDetailsHelper.cs
Normal file
53
Marco.Pms.Helpers/Utility/FeatureDetailsHelper.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using Marco.Pms.Model.TenantModels.MongoDBModel;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Helpers.Utility
|
||||||
|
{
|
||||||
|
public class FeatureDetailsHelper
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<FeatureDetails> _collection;
|
||||||
|
private readonly ILogger<FeatureDetailsHelper> _logger;
|
||||||
|
public FeatureDetailsHelper(IConfiguration configuration, ILogger<FeatureDetailsHelper> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
var connectionString = configuration["MongoDB:ModificationConnectionString"];
|
||||||
|
var mongoUrl = new MongoUrl(connectionString);
|
||||||
|
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
|
||||||
|
var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
|
||||||
|
_collection = mongoDB.GetCollection<FeatureDetails>("FeatureDetails");
|
||||||
|
}
|
||||||
|
public async Task<FeatureDetails?> GetFeatureDetails(Guid Id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filter = Builders<FeatureDetails>.Filter.Eq(e => e.Id, Id);
|
||||||
|
|
||||||
|
var result = await _collection
|
||||||
|
.Find(filter)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Exception occured while fetchig features for subscription plan");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> AddFeatureDetails(FeatureDetails featureDetails)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _collection.InsertOneAsync(featureDetails);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Exception occured while fetchig features for subscription plan");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
224
Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs
Normal file
224
Marco.Pms.Helpers/Utility/SidebarMenuHelper.cs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
using Marco.Pms.Model.AppMenu;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace Marco.Pms.CacheHelper
|
||||||
|
{
|
||||||
|
public class SidebarMenuHelper
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<MenuSection> _collection;
|
||||||
|
private readonly ILogger<SidebarMenuHelper> _logger;
|
||||||
|
|
||||||
|
public SidebarMenuHelper(IConfiguration configuration, ILogger<SidebarMenuHelper> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
var connectionString = configuration["MongoDB:ModificationConnectionString"];
|
||||||
|
var mongoUrl = new MongoUrl(connectionString);
|
||||||
|
var client = new MongoClient(mongoUrl);
|
||||||
|
var database = client.GetDatabase(mongoUrl.DatabaseName);
|
||||||
|
_collection = database.GetCollection<MenuSection>("Menus");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MenuSection?> CreateMenuSectionAsync(MenuSection section)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _collection.InsertOneAsync(section);
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error occurred while adding MenuSection.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MenuSection?> UpdateMenuSectionAsync(Guid sectionId, MenuSection updatedSection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);
|
||||||
|
|
||||||
|
var update = Builders<MenuSection>.Update
|
||||||
|
.Set(s => s.Header, updatedSection.Header)
|
||||||
|
.Set(s => s.Title, updatedSection.Title)
|
||||||
|
.Set(s => s.Items, updatedSection.Items);
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update);
|
||||||
|
|
||||||
|
if (result.ModifiedCount > 0)
|
||||||
|
{
|
||||||
|
return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error updating MenuSection.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MenuSection?> AddMenuItemAsync(Guid sectionId, MenuItem newItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newItem.Id = Guid.NewGuid();
|
||||||
|
|
||||||
|
var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);
|
||||||
|
|
||||||
|
var update = Builders<MenuSection>.Update.Push(s => s.Items, newItem);
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update);
|
||||||
|
|
||||||
|
if (result.ModifiedCount > 0)
|
||||||
|
{
|
||||||
|
return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error adding menu item.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MenuItem?> UpdateMenuItemAsync(Guid sectionId, Guid itemId, MenuItem updatedItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filter = Builders<MenuSection>.Filter.And(
|
||||||
|
Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId),
|
||||||
|
Builders<MenuSection>.Filter.ElemMatch(s => s.Items, i => i.Id == itemId)
|
||||||
|
);
|
||||||
|
|
||||||
|
var update = Builders<MenuSection>.Update
|
||||||
|
.Set("Items.$.Text", updatedItem.Text)
|
||||||
|
.Set("Items.$.Icon", updatedItem.Icon)
|
||||||
|
.Set("Items.$.Available", updatedItem.Available)
|
||||||
|
.Set("Items.$.Link", updatedItem.Link)
|
||||||
|
.Set("Items.$.PermissionIds", updatedItem.PermissionIds);
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update);
|
||||||
|
|
||||||
|
if (result.ModifiedCount > 0)
|
||||||
|
{
|
||||||
|
// Re-fetch section and return the updated item
|
||||||
|
var section = await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
|
||||||
|
return section?.Items.FirstOrDefault(i => i.Id == itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error updating MenuItem.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MenuSection?> AddSubMenuItemAsync(Guid sectionId, Guid itemId, SubMenuItem newSubItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newSubItem.Id = Guid.NewGuid();
|
||||||
|
|
||||||
|
// Match the MenuSection and the specific MenuItem inside it
|
||||||
|
var filter = Builders<MenuSection>.Filter.And(
|
||||||
|
Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId),
|
||||||
|
Builders<MenuSection>.Filter.ElemMatch(s => s.Items, i => i.Id == itemId)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use positional operator `$` to target matched MenuItem and push into its Submenu
|
||||||
|
var update = Builders<MenuSection>.Update.Push("Items.$.Submenu", newSubItem);
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update);
|
||||||
|
|
||||||
|
if (result.ModifiedCount > 0)
|
||||||
|
{
|
||||||
|
return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error adding submenu item.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SubMenuItem?> UpdateSubmenuItemAsync(Guid sectionId, Guid itemId, Guid subItemId, SubMenuItem updatedSub)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);
|
||||||
|
|
||||||
|
var arrayFilters = new List<ArrayFilterDefinition>
|
||||||
|
{
|
||||||
|
new BsonDocumentArrayFilterDefinition<BsonDocument>(
|
||||||
|
new BsonDocument("item._id", itemId.ToString())),
|
||||||
|
new BsonDocumentArrayFilterDefinition<BsonDocument>(
|
||||||
|
new BsonDocument("sub._id", subItemId.ToString()))
|
||||||
|
};
|
||||||
|
|
||||||
|
var update = Builders<MenuSection>.Update
|
||||||
|
.Set("Items.$[item].Submenu.$[sub].Text", updatedSub.Text)
|
||||||
|
.Set("Items.$[item].Submenu.$[sub].Available", updatedSub.Available)
|
||||||
|
.Set("Items.$[item].Submenu.$[sub].Link", updatedSub.Link)
|
||||||
|
.Set("Items.$[item].Submenu.$[sub].PermissionKeys", updatedSub.PermissionIds);
|
||||||
|
|
||||||
|
var options = new UpdateOptions { ArrayFilters = arrayFilters };
|
||||||
|
|
||||||
|
var result = await _collection.UpdateOneAsync(filter, update, options);
|
||||||
|
|
||||||
|
if (result.ModifiedCount == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var updatedSection = await _collection.Find(x => x.Id == sectionId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
var subItem = updatedSection?.Items
|
||||||
|
.FirstOrDefault(i => i.Id == itemId)?
|
||||||
|
.Submenu
|
||||||
|
.FirstOrDefault(s => s.Id == subItemId);
|
||||||
|
|
||||||
|
return subItem;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error updating SubMenuItem.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<List<MenuSection>> GetAllMenuSectionsAsync(Guid tenantId)
|
||||||
|
{
|
||||||
|
var filter = Builders<MenuSection>.Filter.Eq(e => e.TenantId, tenantId);
|
||||||
|
|
||||||
|
var result = await _collection
|
||||||
|
.Find(filter)
|
||||||
|
.ToListAsync();
|
||||||
|
if (result.Any())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
tenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26");
|
||||||
|
filter = Builders<MenuSection>.Filter.Eq(e => e.TenantId, tenantId);
|
||||||
|
|
||||||
|
result = await _collection
|
||||||
|
.Find(filter)
|
||||||
|
.ToListAsync();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
23
Marco.Pms.Model/AppMenu/MenuItem.cs
Normal file
23
Marco.Pms.Model/AppMenu/MenuItem.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.AppMenu
|
||||||
|
{
|
||||||
|
public class MenuItem
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public string? Text { get; set; }
|
||||||
|
public string? Icon { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public string? Link { get; set; }
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
public List<SubMenuItem> Submenu { get; set; } = new List<SubMenuItem>();
|
||||||
|
}
|
||||||
|
}
|
21
Marco.Pms.Model/AppMenu/MenuSection.cs
Normal file
21
Marco.Pms.Model/AppMenu/MenuSection.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.AppMenu
|
||||||
|
{
|
||||||
|
public class MenuSection
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public string? Header { get; set; }
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public List<MenuItem> Items { get; set; } = new List<MenuItem>();
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
20
Marco.Pms.Model/AppMenu/SubMenuItem.cs
Normal file
20
Marco.Pms.Model/AppMenu/SubMenuItem.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.AppMenu
|
||||||
|
{
|
||||||
|
public class SubMenuItem
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public string? Text { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public string Link { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
16
Marco.Pms.Model/Dtos/AppMenu/CreateMenuItemDto.cs
Normal file
16
Marco.Pms.Model/Dtos/AppMenu/CreateMenuItemDto.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class CreateMenuItemDto
|
||||||
|
{
|
||||||
|
public required string Text { get; set; }
|
||||||
|
public required string Icon { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public required string Link { get; set; }
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
public List<CreateSubMenuItemDto> Submenu { get; set; } = new List<CreateSubMenuItemDto>();
|
||||||
|
}
|
||||||
|
}
|
9
Marco.Pms.Model/Dtos/AppMenu/CreateMenuSectionDto.cs
Normal file
9
Marco.Pms.Model/Dtos/AppMenu/CreateMenuSectionDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class CreateMenuSectionDto
|
||||||
|
{
|
||||||
|
public required string Header { get; set; }
|
||||||
|
public required string Title { get; set; }
|
||||||
|
public List<CreateMenuItemDto> Items { get; set; } = new List<CreateMenuItemDto>();
|
||||||
|
}
|
||||||
|
}
|
13
Marco.Pms.Model/Dtos/AppMenu/CreateSubMenuItemDto.cs
Normal file
13
Marco.Pms.Model/Dtos/AppMenu/CreateSubMenuItemDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class CreateSubMenuItemDto
|
||||||
|
{
|
||||||
|
public required string Text { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public required string Link { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
16
Marco.Pms.Model/Dtos/AppMenu/UpdateMenuItemDto.cs
Normal file
16
Marco.Pms.Model/Dtos/AppMenu/UpdateMenuItemDto.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class UpdateMenuItemDto
|
||||||
|
{
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
|
||||||
|
public required string Text { get; set; }
|
||||||
|
public required string Icon { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public required string Link { get; set; }
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
9
Marco.Pms.Model/Dtos/AppMenu/UpdateMenuSectionDto.cs
Normal file
9
Marco.Pms.Model/Dtos/AppMenu/UpdateMenuSectionDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class UpdateMenuSectionDto
|
||||||
|
{
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
public required string Header { get; set; }
|
||||||
|
public required string Title { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
Marco.Pms.Model/Dtos/AppMenu/UpdateSubMenuItemDto.cs
Normal file
15
Marco.Pms.Model/Dtos/AppMenu/UpdateSubMenuItemDto.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.AppMenu
|
||||||
|
{
|
||||||
|
public class UpdateSubMenuItemDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string? Text { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
|
||||||
|
public string Link { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Changed from string → List<string>
|
||||||
|
public List<string> PermissionIds { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
12
Marco.Pms.Model/Dtos/Tenant/AddSubscriptionDto.cs
Normal file
12
Marco.Pms.Model/Dtos/Tenant/AddSubscriptionDto.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class AddSubscriptionDto
|
||||||
|
{
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
public Guid PlanId { get; set; }
|
||||||
|
public Guid CurrencyId { get; set; }
|
||||||
|
public double MaxUsers { get; set; }
|
||||||
|
public bool IsTrial { get; set; } = false;
|
||||||
|
public bool AutoRenew { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
12
Marco.Pms.Model/Dtos/Tenant/AttendanceDetailsDto.cs
Normal file
12
Marco.Pms.Model/Dtos/Tenant/AttendanceDetailsDto.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class AttendanceDetailsDto
|
||||||
|
{
|
||||||
|
public List<Guid>? FeatureId { get; set; }
|
||||||
|
public string Name { get; set; } = "Attendance Management";
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public bool ManualEntry { get; set; } = true;
|
||||||
|
public bool LocationTracking { get; set; } = true;
|
||||||
|
public bool ShiftManagement { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
21
Marco.Pms.Model/Dtos/Tenant/CreateTenantDto.cs
Normal file
21
Marco.Pms.Model/Dtos/Tenant/CreateTenantDto.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class CreateTenantDto
|
||||||
|
{
|
||||||
|
public required string FirstName { get; set; }
|
||||||
|
public required string LastName { get; set; }
|
||||||
|
public required string Email { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public required string BillingAddress { get; set; }
|
||||||
|
public string? TaxId { get; set; }
|
||||||
|
public string? logoImage { get; set; }
|
||||||
|
public required string OrganizationName { get; set; }
|
||||||
|
public string? OfficeNumber { get; set; }
|
||||||
|
public required string ContactNumber { get; set; }
|
||||||
|
public required DateTime OnBoardingDate { get; set; }
|
||||||
|
public required string OrganizationSize { get; set; }
|
||||||
|
public required Guid IndustryId { get; set; }
|
||||||
|
public required string Reference { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
Marco.Pms.Model/Dtos/Tenant/DirectoryDetailsDto.cs
Normal file
11
Marco.Pms.Model/Dtos/Tenant/DirectoryDetailsDto.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class DirectoryDetailsDto
|
||||||
|
{
|
||||||
|
public List<Guid>? FeatureId { get; set; }
|
||||||
|
public string Name { get; set; } = "Directory Management";
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public int BucketLimit { get; set; } = 25;
|
||||||
|
public bool OrganizationChart { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
9
Marco.Pms.Model/Dtos/Tenant/ExpenseModuleDetailsDto.cs
Normal file
9
Marco.Pms.Model/Dtos/Tenant/ExpenseModuleDetailsDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class ExpenseModuleDetailsDto
|
||||||
|
{
|
||||||
|
public List<Guid>? FeatureId { get; set; }
|
||||||
|
public string Name { get; set; } = "Expense Management";
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
10
Marco.Pms.Model/Dtos/Tenant/FeatureDetailsDto.cs
Normal file
10
Marco.Pms.Model/Dtos/Tenant/FeatureDetailsDto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class FeatureDetailsDto
|
||||||
|
{
|
||||||
|
public ModulesDetailsDto? Modules { get; set; }
|
||||||
|
public ReportDetailsDto? Reports { get; set; }
|
||||||
|
public SupportDetailsDto? Supports { get; set; }
|
||||||
|
public List<SubscriptionCheckListDto> SubscriptionCheckList { get; set; } = new List<SubscriptionCheckListDto>();
|
||||||
|
}
|
||||||
|
}
|
10
Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs
Normal file
10
Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class ModulesDetailsDto
|
||||||
|
{
|
||||||
|
public ProjectManagementDetailsDto? ProjectManagement { get; set; }
|
||||||
|
public AttendanceDetailsDto? Attendance { get; set; }
|
||||||
|
public DirectoryDetailsDto? Directory { get; set; }
|
||||||
|
public ExpenseModuleDetailsDto? Expense { get; set; }
|
||||||
|
}
|
||||||
|
}
|
13
Marco.Pms.Model/Dtos/Tenant/ProjectManagementDetailsDto.cs
Normal file
13
Marco.Pms.Model/Dtos/Tenant/ProjectManagementDetailsDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class ProjectManagementDetailsDto
|
||||||
|
{
|
||||||
|
public List<Guid>? FeatureId { get; set; }
|
||||||
|
public string Name { get; set; } = "Project Management";
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public int MaxProject { get; set; } = 10;
|
||||||
|
public double MaxTaskPerProject { get; set; } = 100000;
|
||||||
|
public bool GanttChart { get; set; } = false;
|
||||||
|
public bool ResourceAllocation { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
9
Marco.Pms.Model/Dtos/Tenant/ReportDetailsDto.cs
Normal file
9
Marco.Pms.Model/Dtos/Tenant/ReportDetailsDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class ReportDetailsDto
|
||||||
|
{
|
||||||
|
public bool BasicReports { get; set; } = true;
|
||||||
|
public bool CustomReports { get; set; } = false;
|
||||||
|
public List<string> ExportData { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
8
Marco.Pms.Model/Dtos/Tenant/SubscriptionCheckListDto.cs
Normal file
8
Marco.Pms.Model/Dtos/Tenant/SubscriptionCheckListDto.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class SubscriptionCheckListDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
13
Marco.Pms.Model/Dtos/Tenant/SubscriptionPlanDetailsDto.cs
Normal file
13
Marco.Pms.Model/Dtos/Tenant/SubscriptionPlanDetailsDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class SubscriptionPlanDetailsDto
|
||||||
|
{
|
||||||
|
public Guid? Id { get; set; }
|
||||||
|
public double Price { get; set; }
|
||||||
|
public required int TrialDays { get; set; }
|
||||||
|
public required double MaxUser { get; set; }
|
||||||
|
public double MaxStorage { get; set; }
|
||||||
|
public required FeatureDetailsDto Features { get; set; }
|
||||||
|
public Guid CurrencyId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
13
Marco.Pms.Model/Dtos/Tenant/SubscriptionPlanDto.cs
Normal file
13
Marco.Pms.Model/Dtos/Tenant/SubscriptionPlanDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class SubscriptionPlanDto
|
||||||
|
{
|
||||||
|
public Guid? Id { get; set; }
|
||||||
|
public required string PlanName { get; set; }
|
||||||
|
public required string Description { get; set; }
|
||||||
|
public SubscriptionPlanDetailsDto? MonthlyPlan { get; set; }
|
||||||
|
public SubscriptionPlanDetailsDto? QuarterlyPlan { get; set; }
|
||||||
|
public SubscriptionPlanDetailsDto? HalfYearlyPlan { get; set; }
|
||||||
|
public SubscriptionPlanDetailsDto? YearlyPlan { get; set; }
|
||||||
|
}
|
||||||
|
}
|
9
Marco.Pms.Model/Dtos/Tenant/SupportDetailsDto.cs
Normal file
9
Marco.Pms.Model/Dtos/Tenant/SupportDetailsDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class SupportDetailsDto
|
||||||
|
{
|
||||||
|
public bool EmailSupport { get; set; } = true;
|
||||||
|
public bool PhoneSupport { get; set; } = false;
|
||||||
|
public bool PrioritySupport { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
10
Marco.Pms.Model/Dtos/Tenant/UpdateSubscriptionDto.cs
Normal file
10
Marco.Pms.Model/Dtos/Tenant/UpdateSubscriptionDto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class UpdateSubscriptionDto
|
||||||
|
{
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
public Guid PlanId { get; set; }
|
||||||
|
public Guid CurrencyId { get; set; }
|
||||||
|
public double? MaxUsers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
19
Marco.Pms.Model/Dtos/Tenant/UpdateTenantDto.cs
Normal file
19
Marco.Pms.Model/Dtos/Tenant/UpdateTenantDto.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Tenant
|
||||||
|
{
|
||||||
|
public class UpdateTenantDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public required string FirstName { get; set; }
|
||||||
|
public required string LastName { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public required string BillingAddress { get; set; }
|
||||||
|
public string? TaxId { get; set; }
|
||||||
|
public string? logoImage { get; set; }
|
||||||
|
public string? OfficeNumber { get; set; }
|
||||||
|
public required string ContactNumber { get; set; }
|
||||||
|
public required string OrganizationSize { get; set; }
|
||||||
|
public required Guid IndustryId { get; set; }
|
||||||
|
public required string Reference { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using Marco.Pms.Model.Master;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Entitlements
|
|
||||||
{
|
|
||||||
public class Tenant
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public string? Name { get; set; }
|
|
||||||
public string? Description { get; set; }
|
|
||||||
public string? DomainName { get; set; }
|
|
||||||
public string? ContactName { get; set; }
|
|
||||||
public string? ContactNumber { get; set; }
|
|
||||||
public DateTime OnBoardingDate { get; set; }
|
|
||||||
public string? OragnizationSize { get; set; }
|
|
||||||
public Guid? IndustryId { get; set; }
|
|
||||||
|
|
||||||
[ForeignKey("IndustryId")]
|
|
||||||
[ValidateNever]
|
|
||||||
public Industry? Industry { get; set; }
|
|
||||||
|
|
||||||
public bool IsActive { get; set; } = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,9 +2,14 @@
|
|||||||
{
|
{
|
||||||
public static class PermissionsMaster
|
public static class PermissionsMaster
|
||||||
{
|
{
|
||||||
|
public static readonly Guid ManageTenants = Guid.Parse("d032cb1a-3f30-462c-bef0-7ace73a71c0b");
|
||||||
|
public static readonly Guid ModifyTenant = Guid.Parse("00e20637-ce8d-4417-bec4-9b31b5e65092");
|
||||||
|
public static readonly Guid ViewTenant = Guid.Parse("647145c6-2108-4c98-aab4-178602236e55");
|
||||||
|
|
||||||
public static readonly Guid DirectoryAdmin = Guid.Parse("4286a13b-bb40-4879-8c6d-18e9e393beda");
|
public static readonly Guid DirectoryAdmin = Guid.Parse("4286a13b-bb40-4879-8c6d-18e9e393beda");
|
||||||
public static readonly Guid DirectoryManager = Guid.Parse("62668630-13ce-4f52-a0f0-db38af2230c5");
|
public static readonly Guid DirectoryManager = Guid.Parse("62668630-13ce-4f52-a0f0-db38af2230c5");
|
||||||
public static readonly Guid DirectoryUser = Guid.Parse("0f919170-92d4-4337-abd3-49b66fc871bb");
|
public static readonly Guid DirectoryUser = Guid.Parse("0f919170-92d4-4337-abd3-49b66fc871bb");
|
||||||
|
|
||||||
public static readonly Guid ViewProject = Guid.Parse("6ea44136-987e-44ba-9e5d-1cf8f5837ebc");
|
public static readonly Guid ViewProject = Guid.Parse("6ea44136-987e-44ba-9e5d-1cf8f5837ebc");
|
||||||
public static readonly Guid ManageProject = Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614");
|
public static readonly Guid ManageProject = Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614");
|
||||||
public static readonly Guid ManageTeam = Guid.Parse("b94802ce-0689-4643-9e1d-11c86950c35b");
|
public static readonly Guid ManageTeam = Guid.Parse("b94802ce-0689-4643-9e1d-11c86950c35b");
|
||||||
@ -14,15 +19,19 @@
|
|||||||
public static readonly Guid AddAndEditTask = Guid.Parse("08752f33-3b29-4816-b76b-ea8a968ed3c5");
|
public static readonly Guid AddAndEditTask = Guid.Parse("08752f33-3b29-4816-b76b-ea8a968ed3c5");
|
||||||
public static readonly Guid AssignAndReportProgress = Guid.Parse("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2");
|
public static readonly Guid AssignAndReportProgress = Guid.Parse("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2");
|
||||||
public static readonly Guid ApproveTask = Guid.Parse("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c");
|
public static readonly Guid ApproveTask = Guid.Parse("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c");
|
||||||
|
|
||||||
public static readonly Guid ViewAllEmployees = Guid.Parse("60611762-7f8a-4fb5-b53f-b1139918796b");
|
public static readonly Guid ViewAllEmployees = Guid.Parse("60611762-7f8a-4fb5-b53f-b1139918796b");
|
||||||
public static readonly Guid ViewTeamMembers = Guid.Parse("b82d2b7e-0d52-45f3-997b-c008ea460e7f");
|
public static readonly Guid ViewTeamMembers = Guid.Parse("b82d2b7e-0d52-45f3-997b-c008ea460e7f");
|
||||||
public static readonly Guid AddAndEditEmployee = Guid.Parse("a97d366a-c2bb-448d-be93-402bd2324566");
|
public static readonly Guid AddAndEditEmployee = Guid.Parse("a97d366a-c2bb-448d-be93-402bd2324566");
|
||||||
public static readonly Guid AssignRoles = Guid.Parse("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3");
|
public static readonly Guid AssignRoles = Guid.Parse("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3");
|
||||||
|
|
||||||
public static readonly Guid TeamAttendance = Guid.Parse("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e");
|
public static readonly Guid TeamAttendance = Guid.Parse("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e");
|
||||||
public static readonly Guid RegularizeAttendance = Guid.Parse("57802c4a-00aa-4a1f-a048-fd2f70dd44b6");
|
public static readonly Guid RegularizeAttendance = Guid.Parse("57802c4a-00aa-4a1f-a048-fd2f70dd44b6");
|
||||||
public static readonly Guid SelfAttendance = Guid.Parse("ccb0589f-712b-43de-92ed-5b6088e7dc4e");
|
public static readonly Guid SelfAttendance = Guid.Parse("ccb0589f-712b-43de-92ed-5b6088e7dc4e");
|
||||||
|
|
||||||
public static readonly Guid ViewMasters = Guid.Parse("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d");
|
public static readonly Guid ViewMasters = Guid.Parse("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d");
|
||||||
public static readonly Guid ManageMasters = Guid.Parse("588a8824-f924-4955-82d8-fc51956cf323");
|
public static readonly Guid ManageMasters = Guid.Parse("588a8824-f924-4955-82d8-fc51956cf323");
|
||||||
|
|
||||||
public static readonly Guid ExpenseViewSelf = Guid.Parse("385be49f-8fde-440e-bdbc-3dffeb8dd116");
|
public static readonly Guid ExpenseViewSelf = Guid.Parse("385be49f-8fde-440e-bdbc-3dffeb8dd116");
|
||||||
public static readonly Guid ExpenseViewAll = Guid.Parse("01e06444-9ca7-4df4-b900-8c3fa051b92f");
|
public static readonly Guid ExpenseViewAll = Guid.Parse("01e06444-9ca7-4df4-b900-8c3fa051b92f");
|
||||||
public static readonly Guid ExpenseUpload = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7");
|
public static readonly Guid ExpenseUpload = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7");
|
||||||
|
@ -35,8 +35,10 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
PhoneNumber = model.PhoneNumber,
|
PhoneNumber = model.PhoneNumber,
|
||||||
Photo = base64String,
|
Photo = base64String,
|
||||||
IsActive = model.IsActive,
|
IsActive = model.IsActive,
|
||||||
|
IsRootUser = model.ApplicationUser?.IsRootUser ?? false,
|
||||||
IsSystem = model.IsSystem,
|
IsSystem = model.IsSystem,
|
||||||
JoiningDate = model.JoiningDate
|
JoiningDate = model.JoiningDate,
|
||||||
|
TenantId = model.TenantId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static BasicEmployeeVM ToBasicEmployeeVMFromEmployee(this Employee employee)
|
public static BasicEmployeeVM ToBasicEmployeeVMFromEmployee(this Employee employee)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
using Marco.Pms.Model.Utilities;
|
namespace Marco.Pms.Model.Master
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Master
|
|
||||||
{
|
{
|
||||||
public class StatusMaster : TenantRelation
|
public class StatusMaster
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string? Status { get; set; }
|
public string? Status { get; set; }
|
||||||
|
8
Marco.Pms.Model/Master/SubscriptionStatus.cs
Normal file
8
Marco.Pms.Model/Master/SubscriptionStatus.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Master
|
||||||
|
{
|
||||||
|
public class SubscriptionStatus
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
8
Marco.Pms.Model/Master/TenantStatus.cs
Normal file
8
Marco.Pms.Model/Master/TenantStatus.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Master
|
||||||
|
{
|
||||||
|
public class TenantStatus
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class AttendanceDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public List<Guid> FeatureId { get; set; } = new List<Guid>();
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public bool ManualEntry { get; set; } = true;
|
||||||
|
public bool LocationTracking { get; set; } = true;
|
||||||
|
public bool ShiftManagement { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class DirectoryDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public List<Guid> FeatureId { get; set; } = new List<Guid>();
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public int BucketLimit { get; set; } = 25;
|
||||||
|
public bool OrganizationChart { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class ExpenseModuleDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public List<Guid> FeatureId { get; set; } = new List<Guid>();
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
18
Marco.Pms.Model/TenantModels/MongoDBModel/FeatureDetails.cs
Normal file
18
Marco.Pms.Model/TenantModels/MongoDBModel/FeatureDetails.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class FeatureDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public ModulesDetails? Modules { get; set; }
|
||||||
|
public ReportDetails? Reports { get; set; }
|
||||||
|
public SupportDetails? Supports { get; set; }
|
||||||
|
public List<SubscriptionCheckList> SubscriptionCheckList { get; set; } = new List<SubscriptionCheckList>();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
16
Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs
Normal file
16
Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class ModulesDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public ProjectManagementDetails? ProjectManagement { get; set; }
|
||||||
|
public AttendanceDetails? Attendance { get; set; }
|
||||||
|
public DirectoryDetails? Directory { get; set; }
|
||||||
|
public ExpenseModuleDetails? Expense { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class ProjectManagementDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public List<Guid> FeatureId { get; set; } = new List<Guid>();
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
public int MaxProject { get; set; } = 10;
|
||||||
|
public double MaxTaskPerProject { get; set; } = 100000000;
|
||||||
|
public bool GanttChart { get; set; } = false;
|
||||||
|
public bool ResourceAllocation { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
15
Marco.Pms.Model/TenantModels/MongoDBModel/ReportDetails.cs
Normal file
15
Marco.Pms.Model/TenantModels/MongoDBModel/ReportDetails.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class ReportDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public bool BasicReports { get; set; } = true;
|
||||||
|
public bool CustomReports { get; set; } = false;
|
||||||
|
public List<string> ExportData { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class SubscriptionCheckList
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
15
Marco.Pms.Model/TenantModels/MongoDBModel/SupportDetails.cs
Normal file
15
Marco.Pms.Model/TenantModels/MongoDBModel/SupportDetails.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels.MongoDBModel
|
||||||
|
{
|
||||||
|
public class SupportDetails
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public bool EmailSupport { get; set; } = true;
|
||||||
|
public bool PhoneSupport { get; set; } = false;
|
||||||
|
public bool PrioritySupport { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
15
Marco.Pms.Model/TenantModels/SubscriptionPlan.cs
Normal file
15
Marco.Pms.Model/TenantModels/SubscriptionPlan.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace Marco.Pms.Model.TenantModels
|
||||||
|
{
|
||||||
|
public class SubscriptionPlan
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string PlanName { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PLAN_FREQUENCY
|
||||||
|
{
|
||||||
|
MONTHLY = 0, QUARTERLY = 1, HALF_YEARLY = 2, YEARLY = 3
|
||||||
|
}
|
||||||
|
}
|
41
Marco.Pms.Model/TenantModels/SubscriptionPlanDetails.cs
Normal file
41
Marco.Pms.Model/TenantModels/SubscriptionPlanDetails.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels
|
||||||
|
{
|
||||||
|
public class SubscriptionPlanDetails
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public double Price { get; set; }
|
||||||
|
public PLAN_FREQUENCY Frequency { get; set; }
|
||||||
|
public int TrialDays { get; set; } = 30;
|
||||||
|
public double MaxUser { get; set; } = 10;
|
||||||
|
public double MaxStorage { get; set; }
|
||||||
|
public Guid FeaturesId { get; set; }
|
||||||
|
public DateTime CreateAt { get; set; }
|
||||||
|
public DateTime? UpdateAt { get; set; }
|
||||||
|
public Guid PlanId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("PlanId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public SubscriptionPlan? Plan { get; set; }
|
||||||
|
public Guid CurrencyId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CurrencyId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public CurrencyMaster? Currency { get; set; }
|
||||||
|
public Guid CreatedById { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CreatedById")]
|
||||||
|
[ValidateNever]
|
||||||
|
public Employee? CreatedBy { get; set; }
|
||||||
|
public Guid? UpdatedById { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("UpdatedById")]
|
||||||
|
[ValidateNever]
|
||||||
|
public Employee? UpdatedBy { get; set; }
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
38
Marco.Pms.Model/TenantModels/Tenant.cs
Normal file
38
Marco.Pms.Model/TenantModels/Tenant.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels
|
||||||
|
{
|
||||||
|
public class Tenant
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public string ContactName { get; set; } = string.Empty;
|
||||||
|
public string ContactNumber { get; set; } = string.Empty;
|
||||||
|
public string? OfficeNumber { get; set; }
|
||||||
|
public string BillingAddress { get; set; } = string.Empty;
|
||||||
|
public string? TaxId { get; set; }
|
||||||
|
public string? logoImage { get; set; } // Base64
|
||||||
|
public DateTime OnBoardingDate { get; set; }
|
||||||
|
public string? OrganizationSize { get; set; }
|
||||||
|
public Guid? IndustryId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("IndustryId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public Industry? Industry { get; set; }
|
||||||
|
public Guid? CreatedById { get; set; } // EmployeeId
|
||||||
|
public Guid TenantStatusId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("TenantStatusId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public TenantStatus? TenantStatus { get; set; }
|
||||||
|
public string Reference { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsSuperTenant { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
48
Marco.Pms.Model/TenantModels/TenantSubscriptions.cs
Normal file
48
Marco.Pms.Model/TenantModels/TenantSubscriptions.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.TenantModels
|
||||||
|
{
|
||||||
|
public class TenantSubscriptions : TenantRelation
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid PlanId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("PlanId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public SubscriptionPlanDetails? Plan { get; set; }
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
public DateTime EndDate { get; set; }
|
||||||
|
public bool IsTrial { get; set; }
|
||||||
|
public double MaxUsers { get; set; }
|
||||||
|
public Guid StatusId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("StatusId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public SubscriptionStatus? Status { get; set; }
|
||||||
|
public Guid CurrencyId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CurrencyId")]
|
||||||
|
[ValidateNever]
|
||||||
|
public CurrencyMaster? Currency { get; set; }
|
||||||
|
public DateTime NextBillingDate { get; set; }
|
||||||
|
public DateTime? CancellationDate { get; set; }
|
||||||
|
public bool AutoRenew { get; set; } = true;
|
||||||
|
public bool IsCancelled { get; set; } = false;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public DateTime? UpdateAt { get; set; }
|
||||||
|
public Guid CreatedById { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CreatedById")]
|
||||||
|
[ValidateNever]
|
||||||
|
public Employee? CreatedBy { get; set; }
|
||||||
|
public Guid? UpdatedById { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("UpdatedById")]
|
||||||
|
[ValidateNever]
|
||||||
|
public Employee? UpdatedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
12
Marco.Pms.Model/Utilities/TenantFilter.cs
Normal file
12
Marco.Pms.Model/Utilities/TenantFilter.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.Utilities
|
||||||
|
{
|
||||||
|
public class TenantFilter
|
||||||
|
{
|
||||||
|
public List<Guid>? IndustryIds { get; set; }
|
||||||
|
public List<Guid>? CreatedByIds { get; set; }
|
||||||
|
public List<Guid>? TenantStatusIds { get; set; }
|
||||||
|
public List<string>? References { get; set; }
|
||||||
|
public DateTime? StartDate { get; set; }
|
||||||
|
public DateTime? EndDate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Marco.Pms.Model.Entitlements;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Utilities
|
namespace Marco.Pms.Model.Utilities
|
||||||
{
|
{
|
||||||
|
28
Marco.Pms.Model/ViewModels/AppMenu/AppMenuVM.cs
Normal file
28
Marco.Pms.Model/ViewModels/AppMenu/AppMenuVM.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.AppMenu
|
||||||
|
{
|
||||||
|
public class MenuSectionVm
|
||||||
|
{
|
||||||
|
public string? Header { get; set; }
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public List<MenuItemVm> Items { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MenuItemVm
|
||||||
|
{
|
||||||
|
public string? Text { get; set; }
|
||||||
|
public string? Icon { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
public string? Link { get; set; }
|
||||||
|
public List<SubMenuItemVm> Submenu { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubMenuItemVm
|
||||||
|
{
|
||||||
|
public string? Text { get; set; }
|
||||||
|
public bool Available { get; set; } = true;
|
||||||
|
public string Link { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
8
Marco.Pms.Model/ViewModels/AppMenu/MasterMenuVM.cs
Normal file
8
Marco.Pms.Model/ViewModels/AppMenu/MasterMenuVM.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.AppMenu
|
||||||
|
{
|
||||||
|
public class MasterMenuVM
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
13
Marco.Pms.Model/ViewModels/DocumentManager/MenuItemVM.cs
Normal file
13
Marco.Pms.Model/ViewModels/DocumentManager/MenuItemVM.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.DocumentManager
|
||||||
|
{
|
||||||
|
public class MenuItemVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Icon { get; set; }
|
||||||
|
public bool Available { get; set; }
|
||||||
|
public string? Link { get; set; }
|
||||||
|
public List<SubMenuItemVM> Submenu { get; set; } = new List<SubMenuItemVM>();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.DocumentManager
|
||||||
|
{
|
||||||
|
public class MenuSectionApplicationVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public bool Available { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
Marco.Pms.Model/ViewModels/DocumentManager/MenuSectionVM.cs
Normal file
11
Marco.Pms.Model/ViewModels/DocumentManager/MenuSectionVM.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.DocumentManager
|
||||||
|
{
|
||||||
|
public class MenuSectionVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string? Header { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public List<MenuItemVM> Items { get; set; } = new List<MenuItemVM>();
|
||||||
|
}
|
||||||
|
}
|
12
Marco.Pms.Model/ViewModels/DocumentManager/SubMenuItemVM.cs
Normal file
12
Marco.Pms.Model/ViewModels/DocumentManager/SubMenuItemVM.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.DocumentManager
|
||||||
|
{
|
||||||
|
public class SubMenuItemVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public bool Available { get; set; }
|
||||||
|
|
||||||
|
public string? Link { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@
|
|||||||
public string? AadharNumber { get; set; }
|
public string? AadharNumber { get; set; }
|
||||||
|
|
||||||
public bool IsActive { get; set; } = true;
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsRootUser { get; set; }
|
||||||
public string? PanNumber { get; set; }
|
public string? PanNumber { get; set; }
|
||||||
|
|
||||||
public string? Photo { get; set; } // To store the captured photo
|
public string? Photo { get; set; } // To store the captured photo
|
||||||
@ -28,6 +29,7 @@
|
|||||||
public string? ApplicationUserId { get; set; }
|
public string? ApplicationUserId { get; set; }
|
||||||
|
|
||||||
public Guid? JobRoleId { get; set; }
|
public Guid? JobRoleId { get; set; }
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
public bool IsSystem { get; set; }
|
public bool IsSystem { get; set; }
|
||||||
public string? JobRole { get; set; }
|
public string? JobRole { get; set; }
|
||||||
|
|
||||||
|
11
Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs
Normal file
11
Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Projects
|
||||||
|
{
|
||||||
|
public class ProjectHisteryVM
|
||||||
|
{
|
||||||
|
public string? ProjectName { get; set; }
|
||||||
|
public string? ProjectShortName { get; set; }
|
||||||
|
public DateTime AssignedDate { get; set; }
|
||||||
|
public DateTime? RemovedDate { get; set; }
|
||||||
|
public string? Designation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Tenant
|
||||||
|
{
|
||||||
|
public class SubscriptionPlanDetailsVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? PlanName { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public double Price { get; set; }
|
||||||
|
public double MaxUsers { get; set; }
|
||||||
|
public PLAN_FREQUENCY Frequency { get; set; }
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
public DateTime EndDate { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public BasicEmployeeVM? updatedBy { get; set; }
|
||||||
|
public CurrencyMaster? Currency { get; set; }
|
||||||
|
}
|
||||||
|
}
|
20
Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs
Normal file
20
Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
|
using Marco.Pms.Model.TenantModels.MongoDBModel;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Tenant
|
||||||
|
{
|
||||||
|
public class SubscriptionPlanVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? PlanName { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public double? Price { get; set; }
|
||||||
|
public PLAN_FREQUENCY? Frequency { get; set; }
|
||||||
|
public int TrialDays { get; set; }
|
||||||
|
public double MaxUser { get; set; }
|
||||||
|
public double MaxStorage { get; set; }
|
||||||
|
public FeatureDetails? Features { get; set; }
|
||||||
|
public CurrencyMaster? Currency { get; set; }
|
||||||
|
}
|
||||||
|
}
|
43
Marco.Pms.Model/ViewModels/Tenant/TenantDetailsVM.cs
Normal file
43
Marco.Pms.Model/ViewModels/Tenant/TenantDetailsVM.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.TenantModels.MongoDBModel;
|
||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Tenant
|
||||||
|
{
|
||||||
|
public class TenantDetailsVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public string ContactName { get; set; } = string.Empty;
|
||||||
|
public string ContactNumber { get; set; } = string.Empty;
|
||||||
|
public string? OfficeNumber { get; set; }
|
||||||
|
public string BillingAddress { get; set; } = string.Empty;
|
||||||
|
public string? TaxId { get; set; }
|
||||||
|
public string? logoImage { get; set; } // Base64
|
||||||
|
public DateTime OnBoardingDate { get; set; }
|
||||||
|
public string? OrganizationSize { get; set; }
|
||||||
|
public Industry? Industry { get; set; }
|
||||||
|
public TenantStatus? TenantStatus { get; set; }
|
||||||
|
public string Reference { get; set; } = string.Empty;
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsSuperTenant { get; set; } = false;
|
||||||
|
public int SeatsAvailable { get; set; }
|
||||||
|
public int ActiveEmployees { get; set; }
|
||||||
|
public int InActiveEmployees { get; set; }
|
||||||
|
public int? ActiveProjects { get; set; }
|
||||||
|
public int? InProgressProjects { get; set; }
|
||||||
|
public int? OnHoldProjects { get; set; }
|
||||||
|
public int? InActiveProjects { get; set; }
|
||||||
|
public int? CompletedProjects { get; set; }
|
||||||
|
public DateTime? ExpiryDate { get; set; }
|
||||||
|
public DateTime? NextBillingDate { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public List<SubscriptionPlanDetailsVM>? SubscriptionHistery { get; set; }
|
||||||
|
public SubscriptionPlanDetailsVM? CurrentPlan { get; set; }
|
||||||
|
public FeatureDetails? CurrentPlanFeatures { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
18
Marco.Pms.Model/ViewModels/Tenant/TenantListVM.cs
Normal file
18
Marco.Pms.Model/ViewModels/Tenant/TenantListVM.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Tenant
|
||||||
|
{
|
||||||
|
public class TenantListVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public string ContactName { get; set; } = string.Empty;
|
||||||
|
public string ContactNumber { get; set; } = string.Empty;
|
||||||
|
public string? logoImage { get; set; } // Base64
|
||||||
|
public string? OrganizationSize { get; set; }
|
||||||
|
public Industry? Industry { get; set; }
|
||||||
|
public TenantStatus? TenantStatus { get; set; }
|
||||||
|
}
|
||||||
|
}
|
28
Marco.Pms.Model/ViewModels/Tenant/TenantVM.cs
Normal file
28
Marco.Pms.Model/ViewModels/Tenant/TenantVM.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Tenant
|
||||||
|
{
|
||||||
|
public class TenantVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? DomainName { get; set; }
|
||||||
|
public string ContactName { get; set; } = string.Empty;
|
||||||
|
public string ContactNumber { get; set; } = string.Empty;
|
||||||
|
public string BillingAddress { get; set; } = string.Empty;
|
||||||
|
public string? TaxId { get; set; }
|
||||||
|
public string? logoImage { get; set; } // Base64
|
||||||
|
public DateTime OnBoardingDate { get; set; }
|
||||||
|
public string? OrganizationSize { get; set; }
|
||||||
|
public Industry? Industry { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; } // EmployeeId
|
||||||
|
public TenantStatus? TenantStatus { get; set; }
|
||||||
|
public string Reference { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsSuperTenant { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
736
Marco.Pms.Services/Controllers/AppMenuController.cs
Normal file
736
Marco.Pms.Services/Controllers/AppMenuController.cs
Normal file
@ -0,0 +1,736 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Marco.Pms.CacheHelper;
|
||||||
|
using Marco.Pms.Model.AppMenu;
|
||||||
|
using Marco.Pms.Model.Dtos.AppMenu;
|
||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Marco.Pms.Model.ViewModels.AppMenu;
|
||||||
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
||||||
|
using Marco.Pms.Services.Helpers;
|
||||||
|
using Marco.Pms.Services.Service;
|
||||||
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class AppMenuController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly UserHelper _userHelper;
|
||||||
|
private readonly SidebarMenuHelper _sideBarMenuHelper;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
|
|
||||||
|
private readonly Guid tenantId;
|
||||||
|
private static readonly Guid superTenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26");
|
||||||
|
private static readonly Guid ProjectManagement = Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def");
|
||||||
|
private static readonly Guid ExpenseManagement = Guid.Parse("a4e25142-449b-4334-a6e5-22f70e4732d7");
|
||||||
|
private static readonly Guid TaskManagement = Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f");
|
||||||
|
private static readonly Guid EmployeeManagement = Guid.Parse("81ab8a87-8ccd-4015-a917-0627cee6a100");
|
||||||
|
private static readonly Guid AttendanceManagement = Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94");
|
||||||
|
private static readonly Guid MastersMangent = Guid.Parse("be3b3afc-6ccf-4566-b9b6-aafcb65546be");
|
||||||
|
private static readonly Guid DirectoryManagement = Guid.Parse("39e66f81-efc6-446c-95bd-46bff6cfb606");
|
||||||
|
private static readonly Guid TenantManagement = Guid.Parse("2f3509b7-160d-410a-b9b6-daadd96c986d");
|
||||||
|
|
||||||
|
public AppMenuController(UserHelper userHelper,
|
||||||
|
SidebarMenuHelper sideBarMenuHelper,
|
||||||
|
IMapper mapper,
|
||||||
|
ILoggingService logger,
|
||||||
|
IServiceScopeFactory serviceScopeFactory)
|
||||||
|
{
|
||||||
|
|
||||||
|
_userHelper = userHelper;
|
||||||
|
_sideBarMenuHelper = sideBarMenuHelper;
|
||||||
|
_mapper = mapper;
|
||||||
|
_logger = logger;
|
||||||
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
|
tenantId = userHelper.GetTenantId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new sidebar menu section for the tenant.
|
||||||
|
/// Only accessible by root users or for the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="menuSectionDto">The data for the new menu section.</param>
|
||||||
|
/// <returns>HTTP response with result of the operation.</returns>
|
||||||
|
|
||||||
|
[HttpPost("add/sidebar/menu-section")]
|
||||||
|
public async Task<IActionResult> CreateAppSideBarMenu([FromBody] CreateMenuSectionDto menuSectionDto)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser || tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: Employee {EmployeeId} attempted to create sidebar menu in Tenant {TenantId}", loggedInEmployee.Id, tenantId);
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Map DTO to entity
|
||||||
|
var sideMenuSection = _mapper.Map<MenuSection>(menuSectionDto);
|
||||||
|
sideMenuSection.TenantId = tenantId;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 4: Save entity using helper
|
||||||
|
sideMenuSection = await _sideBarMenuHelper.CreateMenuSectionAsync(sideMenuSection);
|
||||||
|
|
||||||
|
if (sideMenuSection == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Failed to create sidebar menu section. Tenant: {TenantId}, Request: {@MenuSectionDto}", tenantId, menuSectionDto);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid MenuSection", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Log success
|
||||||
|
_logger.LogInfo("Sidebar menu created successfully. SectionId: {SectionId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
||||||
|
sideMenuSection.Id, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(sideMenuSection, "Sidebar menu created successfully.", 201));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 6: Handle and log unexpected server errors
|
||||||
|
_logger.LogError(ex, "Unexpected error occurred while creating sidebar menu. Tenant: {TenantId}, EmployeeId: {EmployeeId}, Request: {@MenuSectionDto}",
|
||||||
|
tenantId, loggedInEmployee.Id, menuSectionDto);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates an existing sidebar menu section for the tenant.
|
||||||
|
/// Only accessible by root users or for the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sectionId">The unique identifier of the section to update.</param>
|
||||||
|
/// <param name="updatedSection">The updated data for the sidebar menu section.</param>
|
||||||
|
/// <returns>HTTP response with the result of the operation.</returns>
|
||||||
|
|
||||||
|
[HttpPut("edit/sidebar/menu-section/{sectionId}")]
|
||||||
|
public async Task<IActionResult> UpdateMenuSection(Guid sectionId, [FromBody] UpdateMenuSectionDto updatedSection)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser && tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: User {UserId} attempted to update sidebar menu section {SectionId} in Tenant {TenantId}",
|
||||||
|
loggedInEmployee.Id, sectionId, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Validate request
|
||||||
|
if (sectionId == Guid.Empty || sectionId != updatedSection.Id)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid update request. Tenant: {TenantId}, SectionId: {SectionId}, PayloadId: {PayloadId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, updatedSection.Id, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID or mismatched payload.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Map DTO to entity
|
||||||
|
var menuSectionEntity = _mapper.Map<MenuSection>(updatedSection);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 5: Perform update operation
|
||||||
|
var result = await _sideBarMenuHelper.UpdateMenuSectionAsync(sectionId, menuSectionEntity);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Menu section not found for update. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
||||||
|
sectionId, tenantId, loggedInEmployee.Id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu section not found", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Successful update
|
||||||
|
_logger.LogInfo("Menu section updated successfully. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
||||||
|
sectionId, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Menu section updated successfully"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 7: Unexpected server error
|
||||||
|
_logger.LogError(ex, "Failed to update menu section. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}, Payload: {@UpdatedSection}",
|
||||||
|
sectionId, tenantId, loggedInEmployee.Id, updatedSection);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server error", "An unexpected error occurred while updating the menu section.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new menu item to an existing sidebar menu section.
|
||||||
|
/// Only accessible by root users or for the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sectionId">The unique identifier of the section the item will be added to.</param>
|
||||||
|
/// <param name="newItemDto">The details of the new menu item.</param>
|
||||||
|
/// <returns>HTTP response with the result of the operation.</returns>
|
||||||
|
|
||||||
|
[HttpPost("add/sidebar/menus/{sectionId}/items")]
|
||||||
|
public async Task<IActionResult> AddMenuItem(Guid sectionId, [FromBody] CreateMenuItemDto newItemDto)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser && tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: User {UserId} attempted to add menu item to section {SectionId} in Tenant {TenantId}",
|
||||||
|
loggedInEmployee.Id, sectionId, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Input validation
|
||||||
|
if (sectionId == Guid.Empty || newItemDto == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid AddMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID or menu item payload.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 4: Map DTO to entity
|
||||||
|
var menuItemEntity = _mapper.Map<MenuItem>(newItemDto);
|
||||||
|
|
||||||
|
// Step 5: Perform Add operation
|
||||||
|
var result = await _sideBarMenuHelper.AddMenuItemAsync(sectionId, menuItemEntity);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Menu section not found. Unable to add menu item. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}",
|
||||||
|
sectionId, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu section not found", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Successful addition
|
||||||
|
_logger.LogInfo("Menu item added successfully. SectionId: {SectionId}, MenuItemId: {MenuItemId}, TenantId: {TenantId}, UserId: {UserId}",
|
||||||
|
sectionId, result.Id, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Menu item added successfully"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 7: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error occurred while adding menu item. SectionId: {SectionId}, TenantId: {TenantId}, UserId: {UserId}, Payload: {@NewItemDto}",
|
||||||
|
sectionId, tenantId, loggedInEmployee.Id, newItemDto);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server error", "An unexpected error occurred while adding the menu item.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates an existing menu item inside a sidebar menu section.
|
||||||
|
/// Only accessible by root users or within the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sectionId">The ID of the sidebar menu section.</param>
|
||||||
|
/// <param name="itemId">The ID of the menu item to update.</param>
|
||||||
|
/// <param name="updatedMenuItem">The updated menu item details.</param>
|
||||||
|
/// <returns>HTTP response with the result of the update operation.</returns>
|
||||||
|
|
||||||
|
[HttpPut("edit/sidebar/{sectionId}/items/{itemId}")]
|
||||||
|
public async Task<IActionResult> UpdateMenuItem(Guid sectionId, Guid itemId, [FromBody] UpdateMenuItemDto updatedMenuItem)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser && tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: User {UserId} attempted to update menu item {ItemId} in Section {SectionId}, Tenant {TenantId}",
|
||||||
|
loggedInEmployee.Id, itemId, sectionId, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Input validation
|
||||||
|
if (sectionId == Guid.Empty || itemId == Guid.Empty || updatedMenuItem == null || updatedMenuItem.Id != itemId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid UpdateMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID, item ID, or menu item payload.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Map DTO to entity
|
||||||
|
var menuItemEntity = _mapper.Map<MenuItem>(updatedMenuItem);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 5: Perform update operation
|
||||||
|
var result = await _sideBarMenuHelper.UpdateMenuItemAsync(sectionId, itemId, menuItemEntity);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Menu item not found or update failed. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Menu item not found or update failed.", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Success log
|
||||||
|
_logger.LogInfo("Menu item updated successfully. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Sidebar menu item updated successfully."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// ✅ Step 7: Handle server errors
|
||||||
|
_logger.LogError(ex, "Error occurred while updating menu item. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}, Payload: {@UpdatedMenuItem}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id, updatedMenuItem);
|
||||||
|
|
||||||
|
return StatusCode(
|
||||||
|
500,
|
||||||
|
ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while updating the menu item.", 500)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new sub-menu item to an existing menu item inside a sidebar menu section.
|
||||||
|
/// Only accessible by root users or within the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sectionId">The ID of the sidebar menu section.</param>
|
||||||
|
/// <param name="itemId">The ID of the parent menu item.</param>
|
||||||
|
/// <param name="newSubItem">The details of the new sub-menu item.</param>
|
||||||
|
/// <returns>HTTP response with the result of the add operation.</returns>
|
||||||
|
|
||||||
|
[HttpPost("add/sidebar/menus/{sectionId}/items/{itemId}/subitems")]
|
||||||
|
public async Task<IActionResult> AddSubMenuItem(Guid sectionId, Guid itemId, [FromBody] CreateSubMenuItemDto newSubItem)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser && tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: User {UserId} attempted to add sub-menu item in Section {SectionId}, MenuItem {ItemId}, Tenant {TenantId}",
|
||||||
|
loggedInEmployee.Id, sectionId, itemId, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Validate input
|
||||||
|
if (sectionId == Guid.Empty || itemId == Guid.Empty || newSubItem == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid AddSubMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID, item ID, or sub-menu item payload.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 4: Map DTO to entity
|
||||||
|
var subMenuItemEntity = _mapper.Map<SubMenuItem>(newSubItem);
|
||||||
|
|
||||||
|
// Step 5: Perform add operation
|
||||||
|
var result = await _sideBarMenuHelper.AddSubMenuItemAsync(sectionId, itemId, subMenuItemEntity);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Parent menu item not found. Failed to add sub-menu item. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Parent menu item not found.", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Success logging
|
||||||
|
_logger.LogInfo("Sub-menu item added successfully. Tenant: {TenantId}, SectionId: {SectionId}, ParentItemId: {ItemId}, SubItemId: {SubItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, result.Id, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Sub-menu item added successfully."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 7: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error occurred while adding sub-menu item. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, UserId: {UserId}, Payload: {@NewSubItem}",
|
||||||
|
tenantId, sectionId, itemId, loggedInEmployee.Id, newSubItem);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while adding the sub-menu item.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates an existing sub-menu item inside a sidebar menu section.
|
||||||
|
/// Only accessible by root users or within the super tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sectionId">The ID of the sidebar menu section.</param>
|
||||||
|
/// <param name="itemId">The ID of the parent menu item.</param>
|
||||||
|
/// <param name="subItemId">The ID of the sub-menu item to update.</param>
|
||||||
|
/// <param name="updatedSubMenuItem">The updated sub-menu item details.</param>
|
||||||
|
/// <returns>HTTP response with the result of the update operation.</returns>
|
||||||
|
|
||||||
|
[HttpPut("edit/sidebar/{sectionId}/items/{itemId}/subitems/{subItemId}")]
|
||||||
|
public async Task<IActionResult> UpdateSubmenuItem(Guid sectionId, Guid itemId, Guid subItemId, [FromBody] UpdateSubMenuItemDto updatedSubMenuItem)
|
||||||
|
{
|
||||||
|
// Step 1: Fetch logged-in user
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var isRootUser = loggedInEmployee.ApplicationUser?.IsRootUser ?? false;
|
||||||
|
|
||||||
|
// Step 2: Authorization check
|
||||||
|
if (!isRootUser && tenantId != superTenantId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied: User {UserId} attempted to update sub-menu {SubItemId} under MenuItem {ItemId} in Section {SectionId}, Tenant {TenantId}",
|
||||||
|
loggedInEmployee.Id, subItemId, itemId, sectionId, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "User does not have permission.", 403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Input validation
|
||||||
|
if (sectionId == Guid.Empty || itemId == Guid.Empty || subItemId == Guid.Empty || updatedSubMenuItem == null || updatedSubMenuItem.Id != subItemId)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid UpdateSubMenuItem request. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, SubItemId: {SubItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, subItemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid section ID, menu item ID, sub-item ID, or payload mismatch.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 4: Map DTO to entity
|
||||||
|
var subMenuEntity = _mapper.Map<SubMenuItem>(updatedSubMenuItem);
|
||||||
|
|
||||||
|
// Step 5: Perform update operation
|
||||||
|
var result = await _sideBarMenuHelper.UpdateSubmenuItemAsync(sectionId, itemId, subItemId, subMenuEntity);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Sub-menu item not found or update failed. Tenant: {TenantId}, SectionId: {SectionId}, ItemId: {ItemId}, SubItemId: {SubItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, subItemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Sub-menu item not found.", 404));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Log success
|
||||||
|
_logger.LogInfo("Sub-menu item updated successfully. Tenant: {TenantId}, SectionId: {SectionId}, MenuItemId: {ItemId}, SubItemId: {SubItemId}, UserId: {UserId}",
|
||||||
|
tenantId, sectionId, itemId, subItemId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Sub-menu item updated successfully."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 7: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error occurred while updating sub-menu item. Tenant: {TenantId}, SectionId: {SectionId}, MenuItemId: {ItemId}, SubItemId: {SubItemId}, UserId: {UserId}, Payload: {@UpdatedSubMenuItem}",
|
||||||
|
tenantId, sectionId, itemId, subItemId, loggedInEmployee.Id, updatedSubMenuItem);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while updating the sub-menu item.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches the sidebar menu for the current tenant and filters items based on employee permissions.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The sidebar menu with only the items/sub-items the employee has access to.</returns>
|
||||||
|
|
||||||
|
[HttpGet("get/menu")]
|
||||||
|
public async Task<IActionResult> GetAppSideBarMenu()
|
||||||
|
{
|
||||||
|
// Step 1: Get logged-in employee
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var employeeId = loggedInEmployee.Id;
|
||||||
|
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permissions = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 2: Fetch all menu sections for the tenant
|
||||||
|
var menus = await _sideBarMenuHelper.GetAllMenuSectionsAsync(tenantId);
|
||||||
|
|
||||||
|
foreach (var menu in menus)
|
||||||
|
{
|
||||||
|
var allowedItems = new List<MenuItem>();
|
||||||
|
|
||||||
|
foreach (var item in menu.Items)
|
||||||
|
{
|
||||||
|
// --- Item permission check ---
|
||||||
|
if (!item.PermissionIds.Any())
|
||||||
|
{
|
||||||
|
allowedItems.Add(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert permission string IDs to GUIDs
|
||||||
|
var menuPermissionIds = item.PermissionIds
|
||||||
|
.Select(Guid.Parse)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
bool isAllowed = await _permissions.HasPermissionAny(menuPermissionIds, employeeId);
|
||||||
|
|
||||||
|
// If allowed, filter its submenus as well
|
||||||
|
if (isAllowed)
|
||||||
|
{
|
||||||
|
if (item.Submenu?.Any() == true)
|
||||||
|
{
|
||||||
|
var allowedSubmenus = new List<SubMenuItem>();
|
||||||
|
|
||||||
|
foreach (var subItem in item.Submenu)
|
||||||
|
{
|
||||||
|
if (!subItem.PermissionIds.Any())
|
||||||
|
{
|
||||||
|
allowedSubmenus.Add(subItem);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subMenuPermissionIds = subItem.PermissionIds
|
||||||
|
.Select(Guid.Parse)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
bool isSubItemAllowed = await _permissions.HasPermissionAny(subMenuPermissionIds, employeeId);
|
||||||
|
|
||||||
|
if (isSubItemAllowed)
|
||||||
|
{
|
||||||
|
allowedSubmenus.Add(subItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace with filtered submenus
|
||||||
|
item.Submenu = allowedSubmenus;
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedItems.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace with filtered items
|
||||||
|
menu.Items = allowedItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Log success
|
||||||
|
_logger.LogInfo("Fetched sidebar menu successfully. Tenant: {TenantId}, EmployeeId: {EmployeeId}, SectionsReturned: {Count}",
|
||||||
|
tenantId, employeeId, menus.Count);
|
||||||
|
|
||||||
|
var response = _mapper.Map<List<MenuSectionVM>>(menus);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Sidebar menu fetched successfully"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 4: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error occurred while fetching sidebar menu. Tenant: {TenantId}, EmployeeId: {EmployeeId}",
|
||||||
|
tenantId, employeeId);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while fetching the sidebar menu.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the master menu list based on enabled features for the current tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of master menu items available for the tenant</returns>
|
||||||
|
|
||||||
|
[HttpGet("get/master-list")]
|
||||||
|
public async Task<IActionResult> GetMasterList()
|
||||||
|
{
|
||||||
|
// Start logging scope for observability
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get currently logged-in employee
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
_logger.LogInfo("Fetching master list for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
|
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var generalHelper = scope.ServiceProvider.GetRequiredService<GeneralHelper>();
|
||||||
|
|
||||||
|
// Define static master menus for each feature section
|
||||||
|
var featureMenus = new Dictionary<Guid, List<MasterMenuVM>>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
EmployeeManagement, new List<MasterMenuVM>
|
||||||
|
{
|
||||||
|
new MasterMenuVM { Id = 1, Name = "Application Role" },
|
||||||
|
new MasterMenuVM { Id = 2, Name = "Job Role" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ProjectManagement, new List<MasterMenuVM>
|
||||||
|
{
|
||||||
|
new MasterMenuVM { Id = 3, Name = "Activity" },
|
||||||
|
new MasterMenuVM { Id = 4, Name = "Work Category" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DirectoryManagement, new List<MasterMenuVM>
|
||||||
|
{
|
||||||
|
new MasterMenuVM { Id = 5, Name = "Contact Category" },
|
||||||
|
new MasterMenuVM { Id = 6, Name = "Contact Tag" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExpenseManagement, new List<MasterMenuVM>
|
||||||
|
{
|
||||||
|
new MasterMenuVM { Id = 7, Name = "Expense Type" },
|
||||||
|
new MasterMenuVM { Id = 8, Name = "Payment Mode" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tenantId == superTenantId)
|
||||||
|
{
|
||||||
|
var superResponse = featureMenus.Values.SelectMany(list => list).OrderBy(r => r.Name).ToList();
|
||||||
|
|
||||||
|
_logger.LogInfo("MasterMenu count for TenantId {TenantId}: {Count}", tenantId, superResponse.Count);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(superResponse, "Successfully fetched the master table list", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch features enabled for tenant
|
||||||
|
var featureIds = await generalHelper.GetFeatureIdsByTenentIdAsync(tenantId);
|
||||||
|
_logger.LogInfo("Enabled features for TenantId: {TenantId} -> {FeatureIds}", tenantId, string.Join(",", featureIds));
|
||||||
|
|
||||||
|
// Aggregate menus based on enabled features
|
||||||
|
var response = featureIds
|
||||||
|
.Where(id => featureMenus.ContainsKey(id))
|
||||||
|
.SelectMany(id => featureMenus[id])
|
||||||
|
.OrderBy(r => r.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
_logger.LogInfo("MasterMenu count for TenantId {TenantId}: {Count}", tenantId, response.Count);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully fetched the master table list", 200));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Critical error tracking
|
||||||
|
_logger.LogError(ex, "Error occurred while fetching master menu list for TenantId: {TenantId}", tenantId);
|
||||||
|
return StatusCode(500, ApiResponse<string>.ErrorResponse("An unexpected error occurred while fetching master menu list."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("get/menu-mobile")]
|
||||||
|
public async Task<IActionResult> GetAppSideBarMenuForobile()
|
||||||
|
{
|
||||||
|
// Step 1: Get logged-in employee
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var employeeId = loggedInEmployee.Id;
|
||||||
|
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var _permissions = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Step 2: Fetch all menu sections for the tenant
|
||||||
|
var menus = await _sideBarMenuHelper.GetAllMenuSectionsAsync(tenantId);
|
||||||
|
List<MenuSectionApplicationVM> response = new List<MenuSectionApplicationVM>();
|
||||||
|
|
||||||
|
foreach (var menu in menus)
|
||||||
|
{
|
||||||
|
var allowedItems = new List<MenuItem>();
|
||||||
|
|
||||||
|
foreach (var item in menu.Items)
|
||||||
|
{
|
||||||
|
// --- Item permission check ---
|
||||||
|
if (!item.PermissionIds.Any())
|
||||||
|
{
|
||||||
|
MenuSectionApplicationVM menuVM = new MenuSectionApplicationVM
|
||||||
|
{
|
||||||
|
Id = item.Id,
|
||||||
|
Name = item.Text,
|
||||||
|
Available = true
|
||||||
|
};
|
||||||
|
response.Add(menuVM);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert permission string IDs to GUIDs
|
||||||
|
var menuPermissionIds = item.PermissionIds
|
||||||
|
.Select(Guid.Parse)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
bool isAllowed = await _permissions.HasPermissionAny(menuPermissionIds, employeeId);
|
||||||
|
|
||||||
|
// If allowed, filter its submenus as well
|
||||||
|
if (isAllowed)
|
||||||
|
{
|
||||||
|
if (item.Submenu?.Any() == true)
|
||||||
|
{
|
||||||
|
var allowedSubmenus = new List<SubMenuItem>();
|
||||||
|
|
||||||
|
foreach (var subItem in item.Submenu)
|
||||||
|
{
|
||||||
|
if (!subItem.PermissionIds.Any())
|
||||||
|
{
|
||||||
|
MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM
|
||||||
|
{
|
||||||
|
Id = subItem.Id,
|
||||||
|
Name = subItem.Text,
|
||||||
|
Available = true
|
||||||
|
};
|
||||||
|
response.Add(subMenuVM);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subMenuPermissionIds = subItem.PermissionIds
|
||||||
|
.Select(Guid.Parse)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
bool isSubItemAllowed = await _permissions.HasPermissionAny(subMenuPermissionIds, employeeId);
|
||||||
|
|
||||||
|
if (isSubItemAllowed)
|
||||||
|
{
|
||||||
|
MenuSectionApplicationVM subMenuVM = new MenuSectionApplicationVM
|
||||||
|
{
|
||||||
|
Id = subItem.Id,
|
||||||
|
Name = subItem.Text,
|
||||||
|
Available = true
|
||||||
|
};
|
||||||
|
response.Add(subMenuVM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace with filtered submenus
|
||||||
|
item.Submenu = allowedSubmenus;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSectionApplicationVM menuVM = new MenuSectionApplicationVM
|
||||||
|
{
|
||||||
|
Id = item.Id,
|
||||||
|
Name = item.Text,
|
||||||
|
Available = true
|
||||||
|
};
|
||||||
|
response.Add(menuVM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace with filtered items
|
||||||
|
menu.Items = allowedItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Log success
|
||||||
|
_logger.LogInfo("Fetched sidebar menu successfully. Tenant: {TenantId}, EmployeeId: {EmployeeId}, SectionsReturned: {Count}",
|
||||||
|
tenantId, employeeId, menus.Count);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(response, "Sidebar menu fetched successfully", 200));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 4: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error occurred while fetching sidebar menu. Tenant: {TenantId}, EmployeeId: {EmployeeId}",
|
||||||
|
tenantId, employeeId);
|
||||||
|
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Server Error", "An unexpected error occurred while fetching the sidebar menu.", 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ using Marco.Pms.Model.Projects;
|
|||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Activities;
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
using Marco.Pms.Model.ViewModels.Employee;
|
using Marco.Pms.Model.ViewModels.Employee;
|
||||||
|
using Marco.Pms.Services.Helpers;
|
||||||
using Marco.Pms.Services.Hubs;
|
using Marco.Pms.Services.Hubs;
|
||||||
using Marco.Pms.Services.Service;
|
using Marco.Pms.Services.Service;
|
||||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
@ -36,6 +37,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
private readonly IEmailSender _emailSender;
|
private readonly IEmailSender _emailSender;
|
||||||
private readonly EmployeeHelper _employeeHelper;
|
private readonly EmployeeHelper _employeeHelper;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
|
private readonly GeneralHelper _generalHelper;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
private readonly IHubContext<MarcoHub> _signalR;
|
private readonly IHubContext<MarcoHub> _signalR;
|
||||||
@ -47,13 +49,14 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
public EmployeeController(UserManager<ApplicationUser> userManager, IEmailSender emailSender,
|
public EmployeeController(UserManager<ApplicationUser> userManager, IEmailSender emailSender,
|
||||||
ApplicationDbContext context, EmployeeHelper employeeHelper, UserHelper userHelper, IConfiguration configuration, ILoggingService logger,
|
ApplicationDbContext context, EmployeeHelper employeeHelper, UserHelper userHelper, IConfiguration configuration, ILoggingService logger,
|
||||||
IHubContext<MarcoHub> signalR, PermissionServices permission, IProjectServices projectServices, IMapper mapper)
|
IHubContext<MarcoHub> signalR, PermissionServices permission, IProjectServices projectServices, IMapper mapper, GeneralHelper generalHelper)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
_employeeHelper = employeeHelper;
|
_employeeHelper = employeeHelper;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
|
_generalHelper = generalHelper;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_signalR = signalR;
|
_signalR = signalR;
|
||||||
@ -191,24 +194,88 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var response = await employeeQuery.Take(10).Select(e => _mapper.Map<BasicEmployeeVM>(e)).ToListAsync();
|
var response = await employeeQuery.Take(10).Select(e => _mapper.Map<BasicEmployeeVM>(e)).ToListAsync();
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200));
|
||||||
}
|
}
|
||||||
[HttpGet]
|
|
||||||
[Route("search/{name}/{projectid?}")]
|
/// <summary>
|
||||||
public async Task<IActionResult> SearchEmployee(string name, Guid? projectid)
|
/// Retrieves a paginated list of employees assigned to a specified project (if provided),
|
||||||
|
/// with optional search functionality.
|
||||||
|
/// Ensures that the logged-in user has necessary permissions before accessing project employees.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="projectId">Optional project identifier to filter employees by project.</param>
|
||||||
|
/// <param name="searchString">Optional search string to filter employees by name.</param>
|
||||||
|
/// <param name="pageNumber">Page number for pagination (default = 1).</param>
|
||||||
|
/// <returns>Paginated list of employees in BasicEmployeeVM format wrapped in ApiResponse.</returns>
|
||||||
|
|
||||||
|
[HttpGet("search")]
|
||||||
|
public async Task<IActionResult> GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString,
|
||||||
|
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
// Log API entry with context
|
||||||
|
_logger.LogInfo("Fetching employees. ProjectId: {ProjectId}, SearchString: {SearchString}, PageNumber: {PageNumber}",
|
||||||
|
projectId ?? Guid.Empty, searchString ?? "", pageNumber);
|
||||||
|
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
_logger.LogDebug("Logged-in EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
|
|
||||||
|
// Initialize query scoped by tenant
|
||||||
|
var employeeQuery = _context.Employees.Where(e => e.TenantId == tenantId);
|
||||||
|
|
||||||
|
// Filter by project if projectId is supplied
|
||||||
|
if (projectId.HasValue && projectId.Value != Guid.Empty)
|
||||||
{
|
{
|
||||||
var errors = ModelState.Values
|
_logger.LogDebug("Project filter applied. Checking permission for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}",
|
||||||
.SelectMany(v => v.Errors)
|
loggedInEmployee.Id, projectId);
|
||||||
.Select(e => e.ErrorMessage)
|
|
||||||
.ToList();
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
|
||||||
|
|
||||||
|
// Validate project access permission
|
||||||
|
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value);
|
||||||
|
if (!hasProjectPermission)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have permission for ProjectId: {ProjectId}",
|
||||||
|
loggedInEmployee.Id, projectId);
|
||||||
|
|
||||||
|
return StatusCode(403, ApiResponse<object>.ErrorResponse(
|
||||||
|
"Access denied",
|
||||||
|
"User does not have access to view employees for this project",
|
||||||
|
403));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Employees allocated to the project
|
||||||
|
var employeeIds = await _context.ProjectAllocations
|
||||||
|
.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.TenantId == tenantId)
|
||||||
|
.Select(pa => pa.EmployeeId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
_logger.LogDebug("Project employees retrieved. Total linked employees found: {Count}", employeeIds.Count);
|
||||||
|
|
||||||
|
// Apply project allocation filter
|
||||||
|
employeeQuery = employeeQuery.Where(e => employeeIds.Contains(e.Id));
|
||||||
}
|
}
|
||||||
var result = await _employeeHelper.SearchEmployeeByProjectId(GetTenantId(), name.ToLower(), projectid);
|
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200));
|
// Apply search filter if provided
|
||||||
|
if (!string.IsNullOrWhiteSpace(searchString))
|
||||||
|
{
|
||||||
|
var searchStringLower = searchString.ToLower();
|
||||||
|
_logger.LogDebug("Search filter applied. Search term: {SearchTerm}", searchStringLower);
|
||||||
|
|
||||||
|
employeeQuery = employeeQuery.Where(e =>
|
||||||
|
(e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pagination and Projection (executed in DB)
|
||||||
|
var employees = await employeeQuery
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.Select(e => _mapper.Map<BasicEmployeeVM>(e))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
_logger.LogInfo("Employees fetched successfully. Records returned: {Count}", employees.Count);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(
|
||||||
|
employees,
|
||||||
|
$"{employees.Count} employee records fetched successfully",
|
||||||
|
200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("profile/get/{employeeId}")]
|
[Route("profile/get/{employeeId}")]
|
||||||
public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId)
|
public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId)
|
||||||
@ -233,11 +300,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
return _userHelper.GetTenantId();
|
return _userHelper.GetTenantId();
|
||||||
}
|
}
|
||||||
|
|
||||||
//[HttpPost("manage/quick")]
|
|
||||||
//public async Task<IActionResult> CreateQuickUser([FromBody] CreateQuickUserDto model)
|
|
||||||
//{
|
|
||||||
// return Ok("Pending implementation");
|
|
||||||
//}
|
|
||||||
|
|
||||||
[HttpPost("manage")]
|
[HttpPost("manage")]
|
||||||
public async Task<IActionResult> CreateUser([FromBody] CreateUserDto model)
|
public async Task<IActionResult> CreateUser([FromBody] CreateUserDto model)
|
||||||
@ -294,7 +356,12 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
TenantId = tenantId
|
TenantId = tenantId
|
||||||
|
|
||||||
};
|
};
|
||||||
|
var isSeatsAvaiable = await _generalHelper.CheckSeatsRemainingAsync(tenantId);
|
||||||
|
if (!isSeatsAvaiable)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Maximum number of users reached for Tenant {TenantId}", tenantId);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Maximum number of users reached. Cannot add new user", "Maximum number of users reached. Cannot add new user", 400));
|
||||||
|
}
|
||||||
// Create Identity User
|
// Create Identity User
|
||||||
var result = await _userManager.CreateAsync(user, "User@123");
|
var result = await _userManager.CreateAsync(user, "User@123");
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
@ -447,86 +514,104 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> SuspendEmployee(Guid id)
|
public async Task<IActionResult> SuspendEmployee(Guid id, [FromQuery] bool active = false)
|
||||||
{
|
{
|
||||||
Guid tenantId = _userHelper.GetTenantId();
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.IsActive && e.TenantId == tenantId);
|
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId);
|
||||||
if (employee != null)
|
if (employee == null)
|
||||||
{
|
{
|
||||||
if (employee.IsSystem)
|
_logger.LogWarning("Employee with ID {EmploueeId} not found in database", id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Employee Not found successfully", "Employee Not found successfully", 404));
|
||||||
|
}
|
||||||
|
if (employee.IsSystem)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to suspend system-defined employee with ID {EmployeeId}", LoggedEmployee.Id, employee.Id);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employees cannot be suspended.", "System-defined employees cannot be suspended.", 400));
|
||||||
|
}
|
||||||
|
var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync();
|
||||||
|
if (assignedToTasks.Count != 0)
|
||||||
|
{
|
||||||
|
List<Guid> taskIds = assignedToTasks.Select(t => t.TaskAllocationId).ToList();
|
||||||
|
var tasks = await _context.TaskAllocations.Where(t => taskIds.Contains(t.Id)).ToListAsync();
|
||||||
|
|
||||||
|
foreach (var assignedToTask in assignedToTasks)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to suspend system-defined employee with ID {EmployeeId}", LoggedEmployee.Id, employee.Id);
|
var task = tasks.Find(t => t.Id == assignedToTask.TaskAllocationId);
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employees cannot be suspended.", "System-defined employees cannot be suspended.", 400));
|
if (task != null && task.CompletedTask == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Employee with ID {EmployeeId} is currently assigned to any incomplete task", employee.Id);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Employee is currently assigned to any incomplete task", "Employee is currently assigned to any incomplete task", 400));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
var attendance = await _context.Attendes.Where(a => a.EmployeeID == employee.Id && (a.OutTime == null || a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)).ToListAsync();
|
||||||
|
if (attendance.Count != 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Employee with ID {EmployeeId} have any pending check-out or regularization requests", employee.Id);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Employee have any pending check-out or regularization requests", "Employee have any pending check-out or regularization requests", 400));
|
||||||
|
}
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
employee.IsActive = true;
|
||||||
|
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync();
|
user.IsActive = true;
|
||||||
if (assignedToTasks.Count != 0)
|
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been actived.", employee.Id);
|
||||||
{
|
|
||||||
List<Guid> taskIds = assignedToTasks.Select(t => t.TaskAllocationId).ToList();
|
|
||||||
var tasks = await _context.TaskAllocations.Where(t => taskIds.Contains(t.Id)).ToListAsync();
|
|
||||||
|
|
||||||
foreach (var assignedToTask in assignedToTasks)
|
|
||||||
{
|
|
||||||
var task = tasks.Find(t => t.Id == assignedToTask.TaskAllocationId);
|
|
||||||
if (task != null && task.CompletedTask == 0)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Employee with ID {EmployeeId} is currently assigned to any incomplete task", employee.Id);
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Employee is currently assigned to any incomplete task", "Employee is currently assigned to any incomplete task", 400));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var attendance = await _context.Attendes.Where(a => a.EmployeeID == employee.Id && (a.OutTime == null || a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)).ToListAsync();
|
|
||||||
if (attendance.Count != 0)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Employee with ID {EmployeeId} have any pending check-out or regularization requests", employee.Id);
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Employee have any pending check-out or regularization requests", "Employee have any pending check-out or regularization requests", 400));
|
|
||||||
}
|
|
||||||
employee.IsActive = false;
|
|
||||||
var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
|
|
||||||
if (projectAllocations.Count != 0)
|
|
||||||
{
|
|
||||||
List<ProjectAllocation> allocations = new List<ProjectAllocation>();
|
|
||||||
foreach (var projectAllocation in projectAllocations)
|
|
||||||
{
|
|
||||||
projectAllocation.ReAllocationDate = DateTime.UtcNow;
|
|
||||||
projectAllocation.IsActive = false;
|
|
||||||
allocations.Add(projectAllocation);
|
|
||||||
}
|
|
||||||
_logger.LogInfo("Employee with ID {EmployeeId} has been removed from all assigned projects.", employee.Id);
|
|
||||||
}
|
|
||||||
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
user.IsActive = false;
|
|
||||||
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been suspended.", employee.Id);
|
|
||||||
|
|
||||||
var refreshTokens = await _context.RefreshTokens.AsNoTracking().Where(t => t.UserId == user.Id).ToListAsync();
|
|
||||||
if (refreshTokens.Count != 0)
|
|
||||||
{
|
|
||||||
_context.RefreshTokens.RemoveRange(refreshTokens);
|
|
||||||
_logger.LogInfo("Refresh tokens associated with employee ID {EmployeeId} has been removed.", employee.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
var roleMapping = await _context.EmployeeRoleMappings.AsNoTracking().Where(r => r.EmployeeId == employee.Id).ToListAsync();
|
|
||||||
if (roleMapping.Count != 0)
|
|
||||||
{
|
|
||||||
_context.EmployeeRoleMappings.RemoveRange(roleMapping);
|
|
||||||
_logger.LogInfo("Application role mapping associated with employee ID {EmployeeId} has been removed.", employee.Id);
|
|
||||||
}
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
_logger.LogInfo("Employee with ID {EmployeId} Deleted successfully", employee.Id);
|
|
||||||
var notification = new { LoggedInUserId = LoggedEmployee.Id, Keyword = "Employee", EmployeeId = employee.Id };
|
|
||||||
|
|
||||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
|
||||||
}
|
}
|
||||||
|
_logger.LogInfo("Employee with ID {EmployeId} Actived successfully", employee.Id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Employee with ID {EmploueeId} not found in database", id);
|
employee.IsActive = false;
|
||||||
|
var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
|
||||||
|
if (projectAllocations.Count != 0)
|
||||||
|
{
|
||||||
|
List<ProjectAllocation> allocations = new List<ProjectAllocation>();
|
||||||
|
foreach (var projectAllocation in projectAllocations)
|
||||||
|
{
|
||||||
|
projectAllocation.ReAllocationDate = DateTime.UtcNow;
|
||||||
|
projectAllocation.IsActive = false;
|
||||||
|
allocations.Add(projectAllocation);
|
||||||
|
}
|
||||||
|
_logger.LogInfo("Employee with ID {EmployeeId} has been removed from all assigned projects.", employee.Id);
|
||||||
|
}
|
||||||
|
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
user.IsActive = false;
|
||||||
|
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been suspended.", employee.Id);
|
||||||
|
|
||||||
|
var refreshTokens = await _context.RefreshTokens.AsNoTracking().Where(t => t.UserId == user.Id).ToListAsync();
|
||||||
|
if (refreshTokens.Count != 0)
|
||||||
|
{
|
||||||
|
_context.RefreshTokens.RemoveRange(refreshTokens);
|
||||||
|
_logger.LogInfo("Refresh tokens associated with employee ID {EmployeeId} has been removed.", employee.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
var roleMapping = await _context.EmployeeRoleMappings.AsNoTracking().Where(r => r.EmployeeId == employee.Id).ToListAsync();
|
||||||
|
if (roleMapping.Count != 0)
|
||||||
|
{
|
||||||
|
_context.EmployeeRoleMappings.RemoveRange(roleMapping);
|
||||||
|
_logger.LogInfo("Application role mapping associated with employee ID {EmployeeId} has been removed.", employee.Id);
|
||||||
|
}
|
||||||
|
_logger.LogInfo("Employee with ID {EmployeId} Deleted successfully", employee.Id);
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Exception Occured While activting/deactivting employee {EmployeeId}", employee.Id);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal Error Occured", "Error occured while saving the entity", 500));
|
||||||
|
}
|
||||||
|
var notification = new { LoggedInUserId = LoggedEmployee.Id, Keyword = "Employee", EmployeeId = employee.Id };
|
||||||
|
|
||||||
|
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
|
||||||
}
|
}
|
||||||
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
|
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using AutoMapper;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Mapper;
|
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Master;
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
|
using Marco.Pms.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
@ -15,43 +17,102 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
public class FeatureController : ControllerBase
|
public class FeatureController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
|
private readonly GeneralHelper _generalHelper;
|
||||||
|
//private readonly UserHelper _userHelper;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
|
private readonly Guid tenantId;
|
||||||
|
|
||||||
|
public FeatureController(ApplicationDbContext context, GeneralHelper generalHelper, UserHelper userHelper, IMapper mapper, ILoggingService logger)
|
||||||
public FeatureController(ApplicationDbContext context)
|
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_generalHelper = generalHelper;
|
||||||
|
//_userHelper = userHelper;
|
||||||
|
_mapper = mapper;
|
||||||
|
_logger = logger;
|
||||||
|
tenantId = userHelper.GetTenantId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts FeaturePermissions from Feature entity into FeaturePermissionVM collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">Feature entity from DB</param>
|
||||||
|
/// <returns>Collection of FeaturePermissionVM, ordered by Name</returns>
|
||||||
private ICollection<FeaturePermissionVM> GetFeaturePermissionVMs(Feature model)
|
private ICollection<FeaturePermissionVM> GetFeaturePermissionVMs(Feature model)
|
||||||
{
|
{
|
||||||
ICollection<FeaturePermissionVM> features = [];
|
if (model.FeaturePermissions == null || !model.FeaturePermissions.Any())
|
||||||
if (model.FeaturePermissions != null)
|
|
||||||
{
|
{
|
||||||
foreach (FeaturePermission permission in model.FeaturePermissions)
|
_logger.LogInfo("No feature permissions found for Feature: {FeatureId}", model.Id);
|
||||||
{
|
return new List<FeaturePermissionVM>();
|
||||||
FeaturePermissionVM item = permission.ToFeaturePermissionVMFromFeaturePermission();
|
|
||||||
features.Add(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return features.OrderBy(f => f.Name).ToList();
|
|
||||||
|
// Project and order feature permissions
|
||||||
|
var features = model.FeaturePermissions
|
||||||
|
.Select(p => _mapper.Map<FeaturePermissionVM>(p))
|
||||||
|
.OrderBy(f => f.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
_logger.LogDebug("Mapped {Count} feature permissions for Feature: {FeatureId}", features.Count, model.Id);
|
||||||
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API endpoint to fetch all features and their permissions for the given tenant.
|
||||||
|
/// </summary>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetAllFeatures()
|
public async Task<IActionResult> GetAllFeaturesAsync()
|
||||||
{
|
{
|
||||||
var roles = await _context.Features.Include("FeaturePermissions").Include("Module").ToListAsync();
|
try
|
||||||
|
|
||||||
var rolesVM = roles.Select(c => new FeatureVM()
|
|
||||||
{
|
{
|
||||||
Id = c.Id,
|
_logger.LogInfo("Fetching all features for tenant: {TenantId}", tenantId);
|
||||||
Name = c.Name,
|
|
||||||
Description = c.Description,
|
var featureQuery = _context.Features
|
||||||
FeaturePermissions = GetFeaturePermissionVMs(c),
|
.AsNoTracking(); // Optimization: Read-only query
|
||||||
ModuleId = c.ModuleId,
|
if (tenantId != Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"))
|
||||||
ModuleName = c.Module != null ? c.Module.Name : string.Empty,
|
{
|
||||||
IsActive = c.IsActive
|
|
||||||
}).OrderBy(f => f.Name).ToList();
|
// Step 1: Get tenant-specific FeatureIds
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(rolesVM, "Success.", 200));
|
List<Guid> featureIds = await _generalHelper.GetFeatureIdsByTenentIdAsync(tenantId);
|
||||||
|
if (featureIds == null || !featureIds.Any())
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No features found for tenant: {TenantId}", tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(new List<FeatureVM>(), "No features found.", 200));
|
||||||
|
}
|
||||||
|
_logger.LogDebug("Retrieved {Count} feature IDs for tenant: {TenantId}", featureIds.Count, tenantId);
|
||||||
|
|
||||||
|
// Step 2: Query Features with related FeaturePermissions & Module
|
||||||
|
featureQuery = featureQuery.Where(f => featureIds.Contains(f.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
var features = await featureQuery
|
||||||
|
.Include(f => f.FeaturePermissions)
|
||||||
|
.Include(f => f.Module).ToListAsync();
|
||||||
|
_logger.LogDebug("Fetched {Count} features from DB for tenant: {TenantId}", features.Count, tenantId);
|
||||||
|
|
||||||
|
// Step 3: Map features to ViewModels
|
||||||
|
var featureVMs = features
|
||||||
|
.Select(c => new FeatureVM
|
||||||
|
{
|
||||||
|
Id = c.Id,
|
||||||
|
Name = c.Name,
|
||||||
|
Description = c.Description,
|
||||||
|
FeaturePermissions = GetFeaturePermissionVMs(c),
|
||||||
|
ModuleId = c.ModuleId,
|
||||||
|
ModuleName = c.Module?.Name ?? string.Empty,
|
||||||
|
IsActive = c.IsActive
|
||||||
|
})
|
||||||
|
.OrderBy(f => f.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
_logger.LogInfo("Returning {Count} features for tenant: {TenantId}", featureVMs.Count, tenantId);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(featureVMs, "Success.", 200));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error while fetching features for tenant: {TenantId}", tenantId);
|
||||||
|
return StatusCode(500, ApiResponse<object>.ErrorResponse("An unexpected error occurred.", 500));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("inquiry")]
|
[HttpPost("enquire")]
|
||||||
public async Task<IActionResult> RequestDemo([FromBody] InquiryDto inquiryDto)
|
public async Task<IActionResult> RequestDemo([FromBody] InquiryDto inquiryDto)
|
||||||
{
|
{
|
||||||
Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto();
|
Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto();
|
||||||
|
@ -276,6 +276,23 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("allocation-histery/{employeeId}")]
|
||||||
|
public async Task<IActionResult> GetProjectByEmployeeBasic([FromRoute] Guid employeeId)
|
||||||
|
{
|
||||||
|
// --- Step 1: Input Validation ---
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList();
|
||||||
|
_logger.LogWarning("Get project list by employee Id called with invalid model state \n Errors: {Errors}", string.Join(", ", errors));
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid request data provided.", errors, 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Step 2: Prepare data without I/O ---
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _projectServices.GetProjectByEmployeeBasicAsync(employeeId, tenantId, loggedInEmployee);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("assign-projects/{employeeId}")]
|
[HttpPost("assign-projects/{employeeId}")]
|
||||||
public async Task<IActionResult> AssigneProjectsToEmployee([FromBody] List<ProjectsAllocationDto> projectAllocationDtos, [FromRoute] Guid employeeId)
|
public async Task<IActionResult> AssigneProjectsToEmployee([FromBody] List<ProjectsAllocationDto> projectAllocationDtos, [FromRoute] Guid employeeId)
|
||||||
{
|
{
|
||||||
@ -338,6 +355,25 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var response = await _projectServices.GetWorkItemsAsync(workAreaId, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetWorkItemsAsync(workAreaId, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
[HttpGet("tasks-employee/{employeeId}")]
|
||||||
|
public async Task<IActionResult> GetTasksByEmployee(Guid employeeId, [FromQuery] DateTime? fromDate, DateTime? toDate)
|
||||||
|
{
|
||||||
|
// --- Step 1: Input Validation ---
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList();
|
||||||
|
_logger.LogWarning("Get Work Items by employeeId called with invalid model state \n Errors: {Errors}", string.Join(", ", errors));
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid request data provided.", errors, 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toDate.HasValue) toDate = DateTime.UtcNow;
|
||||||
|
if (!fromDate.HasValue) fromDate = toDate.Value.AddDays(-7);
|
||||||
|
|
||||||
|
// --- Step 2: Prepare data without I/O ---
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _projectServices.GetTasksByEmployeeAsync(employeeId, fromDate.Value, toDate.Value, tenantId, loggedInEmployee);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.DataAccess.Data;
|
|
||||||
using Marco.Pms.Model.Dtos.Employees;
|
using Marco.Pms.Model.Dtos.Employees;
|
||||||
using Marco.Pms.Model.Dtos.Roles;
|
using Marco.Pms.Model.Dtos.Roles;
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
@ -11,12 +10,13 @@ using Marco.Pms.Model.ViewModels;
|
|||||||
using Marco.Pms.Model.ViewModels.Master;
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
using Marco.Pms.Model.ViewModels.Roles;
|
using Marco.Pms.Model.ViewModels.Roles;
|
||||||
using Marco.Pms.Services.Helpers;
|
using Marco.Pms.Services.Helpers;
|
||||||
|
using Marco.Pms.Services.Service;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Data;
|
||||||
#nullable disable
|
#nullable disable
|
||||||
namespace MarcoBMS.Services.Controllers
|
namespace MarcoBMS.Services.Controllers
|
||||||
{
|
{
|
||||||
@ -28,15 +28,15 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly RolesHelper _rolesHelper;
|
private readonly RolesHelper _rolesHelper;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly PermissionServices _permissionService;
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
private readonly CacheUpdateHelper _cache;
|
private readonly CacheUpdateHelper _cache;
|
||||||
|
|
||||||
public RolesController(UserManager<ApplicationUser> userManager, ApplicationDbContext context, RolesHelper rolesHelper, UserHelper userHelper, ILoggingService logger,
|
public RolesController(PermissionServices permissionServices, ApplicationDbContext context, RolesHelper rolesHelper, UserHelper userHelper, ILoggingService logger,
|
||||||
CacheUpdateHelper cache)
|
CacheUpdateHelper cache)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_userManager = userManager;
|
_permissionService = permissionServices;
|
||||||
_rolesHelper = rolesHelper;
|
_rolesHelper = rolesHelper;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -213,12 +213,17 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
Guid TenantId = GetTenantId();
|
Guid TenantId = GetTenantId();
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
if (createRoleDto.FeaturesPermission == null || (createRoleDto.FeaturesPermission != null && createRoleDto.FeaturesPermission.Count == 0))
|
if (createRoleDto.FeaturesPermission == null || (createRoleDto.FeaturesPermission != null && createRoleDto.FeaturesPermission.Count == 0))
|
||||||
{
|
{
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Feature Permission is required.", "Feature Permission is required.", 400));
|
return BadRequest(ApiResponse<object>.ErrorResponse("Feature Permission is required.", "Feature Permission is required.", 400));
|
||||||
}
|
}
|
||||||
|
var hasManageMasterPermission = await _permissionService.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
||||||
|
if (!hasManageMasterPermission)
|
||||||
|
{
|
||||||
|
return StatusCode(403, ApiResponse<object>.SuccessResponse("Access Denied", "User do not have permission for this action", 403));
|
||||||
|
}
|
||||||
bool roleExists = _context.ApplicationRoles
|
bool roleExists = _context.ApplicationRoles
|
||||||
.Any(r => r.TenantId == TenantId && r.Role.ToLower() == createRoleDto.Role.ToLower());// assuming role name is unique per tenant
|
.Any(r => r.TenantId == TenantId && r.Role.ToLower() == createRoleDto.Role.ToLower());// assuming role name is unique per tenant
|
||||||
if (roleExists)
|
if (roleExists)
|
||||||
@ -228,14 +233,19 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
ApplicationRole role = createRoleDto.ToApplicationRoleFromCreateDto(TenantId);
|
ApplicationRole role = createRoleDto.ToApplicationRoleFromCreateDto(TenantId);
|
||||||
_context.ApplicationRoles.Add(role);
|
_context.ApplicationRoles.Add(role);
|
||||||
|
|
||||||
|
var hasPermission = await _permissionService.HasPermission(PermissionsMaster.ManageTenants, loggedInEmployee.Id);
|
||||||
foreach (var permission in createRoleDto.FeaturesPermission)
|
foreach (var permission in createRoleDto.FeaturesPermission)
|
||||||
{
|
{
|
||||||
var item = new RolePermissionMappings() { ApplicationRoleId = role.Id, FeaturePermissionId = permission.Id };
|
if (!hasPermission &&
|
||||||
bool assigned = _context.RolePermissionMappings.Any(c => c.ApplicationRoleId == role.Id && c.FeaturePermissionId == permission.Id);
|
permission.Id != PermissionsMaster.ManageTenants)
|
||||||
if (permission.IsEnabled && !assigned)
|
{
|
||||||
_context.RolePermissionMappings.Add(item);
|
var item = new RolePermissionMappings() { ApplicationRoleId = role.Id, FeaturePermissionId = permission.Id };
|
||||||
else
|
bool assigned = _context.RolePermissionMappings.Any(c => c.ApplicationRoleId == role.Id && c.FeaturePermissionId == permission.Id);
|
||||||
_context.RolePermissionMappings.Remove(item);
|
if (permission.IsEnabled && !assigned)
|
||||||
|
_context.RolePermissionMappings.Add(item);
|
||||||
|
else
|
||||||
|
_context.RolePermissionMappings.Remove(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
|
1785
Marco.Pms.Services/Controllers/TenantController.cs
Normal file
1785
Marco.Pms.Services/Controllers/TenantController.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,8 +6,11 @@ using Marco.Pms.Model.Utilities;
|
|||||||
using Marco.Pms.Model.ViewModels.Employee;
|
using Marco.Pms.Model.ViewModels.Employee;
|
||||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Net.Mail;
|
||||||
|
|
||||||
namespace MarcoBMS.Services.Controllers
|
namespace MarcoBMS.Services.Controllers
|
||||||
{
|
{
|
||||||
@ -18,14 +21,17 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
public class UserController : ControllerBase
|
public class UserController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly EmployeeHelper _employeeHelper;
|
private readonly EmployeeHelper _employeeHelper;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
private readonly IProjectServices _projectServices;
|
private readonly IProjectServices _projectServices;
|
||||||
private readonly RolesHelper _rolesHelper;
|
private readonly RolesHelper _rolesHelper;
|
||||||
|
|
||||||
public UserController(EmployeeHelper employeeHelper, IProjectServices projectServices, UserHelper userHelper, RolesHelper rolesHelper)
|
public UserController(EmployeeHelper employeeHelper, UserManager<ApplicationUser> userManager, ILoggingService logger, IProjectServices projectServices, UserHelper userHelper, RolesHelper rolesHelper)
|
||||||
{
|
{
|
||||||
|
_userManager = userManager;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
|
_logger = logger;
|
||||||
_employeeHelper = employeeHelper;
|
_employeeHelper = employeeHelper;
|
||||||
_projectServices = projectServices;
|
_projectServices = projectServices;
|
||||||
_rolesHelper = rolesHelper;
|
_rolesHelper = rolesHelper;
|
||||||
@ -81,5 +87,44 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(profile, "Success", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(profile, "Success", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("email/{email}")]
|
||||||
|
public async Task<IActionResult> GetUserByEmail(string email)
|
||||||
|
{
|
||||||
|
var isvalid = IsValidEmail(email);
|
||||||
|
if (!isvalid)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("User provided invalid email address");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid email", "Invalid email", 400));
|
||||||
|
}
|
||||||
|
var user = await _userManager.FindByEmailAsync(email);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("User with email {Email} not found in ASP.NET users table", email);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(true, "User not exists", 200));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInfo("User with email {Email} founded in ASP.NET users table", email);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(false, "User exists", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidEmail(string email)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(email))
|
||||||
|
return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var addr = new MailAddress(email);
|
||||||
|
return addr.Address == email.Trim();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,6 +853,18 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
_logger.LogWarning("Error occured while deleting Application role {RoleId} from Cache for employee {EmployeeId}: {Error}", roleId, employeeId, ex.Message);
|
_logger.LogWarning("Error occured while deleting Application role {RoleId} from Cache for employee {EmployeeId}: {Error}", roleId, employeeId, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task ClearAllEmployeesFromCacheByEmployeeIds(List<Guid> employeeIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stringEmployeeIds = employeeIds.Select(e => e.ToString()).ToList();
|
||||||
|
var response = await _employeeCache.ClearAllEmployeesFromCacheByEmployeeIds(stringEmployeeIds);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error occured while deleting all employees from Cache");
|
||||||
|
}
|
||||||
|
}
|
||||||
public async Task ClearAllEmployees()
|
public async Task ClearAllEmployees()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -20,7 +20,7 @@ namespace MarcoBMS.Services.Helpers
|
|||||||
public async Task<Employee> GetEmployeeByID(Guid EmployeeID)
|
public async Task<Employee> GetEmployeeByID(Guid EmployeeID)
|
||||||
{
|
{
|
||||||
|
|
||||||
return await _context.Employees.Include(e => e.JobRole).FirstOrDefaultAsync(e => e.Id == EmployeeID && e.IsActive == true) ?? new Employee { };
|
return await _context.Employees.Include(e => e.JobRole).FirstOrDefaultAsync(e => e.Id == EmployeeID) ?? new Employee { };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Employee> GetEmployeeByApplicationUserID(string ApplicationUserID)
|
public async Task<Employee> GetEmployeeByApplicationUserID(string ApplicationUserID)
|
||||||
@ -29,7 +29,7 @@ namespace MarcoBMS.Services.Helpers
|
|||||||
{
|
{
|
||||||
var result = await _context.Employees.Where(c => c.ApplicationUserId == ApplicationUserID && c.IsActive == true).ToListAsync();
|
var result = await _context.Employees.Where(c => c.ApplicationUserId == ApplicationUserID && c.IsActive == true).ToListAsync();
|
||||||
|
|
||||||
return await _context.Employees.Where(c => c.ApplicationUserId == ApplicationUserID && c.IsActive == true).SingleOrDefaultAsync() ?? new Employee { };
|
return await _context.Employees.Include(e => e.ApplicationUser).Where(c => c.ApplicationUserId == ApplicationUserID && c.ApplicationUser != null && c.IsActive == true).SingleOrDefaultAsync() ?? new Employee { };
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
|
using Marco.Pms.Helpers.Utility;
|
||||||
using Marco.Pms.Model.MongoDBModels.Masters;
|
using Marco.Pms.Model.MongoDBModels.Masters;
|
||||||
using Marco.Pms.Model.MongoDBModels.Project;
|
using Marco.Pms.Model.MongoDBModels.Project;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
@ -11,13 +12,16 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||||
private readonly ApplicationDbContext _context; // Keeping this for direct scoped context use where appropriate
|
private readonly ApplicationDbContext _context; // Keeping this for direct scoped context use where appropriate
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
|
private readonly FeatureDetailsHelper _featureDetailsHelper;
|
||||||
public GeneralHelper(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
public GeneralHelper(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||||
ApplicationDbContext context,
|
ApplicationDbContext context,
|
||||||
ILoggingService logger)
|
ILoggingService logger,
|
||||||
|
FeatureDetailsHelper featureDetailsHelper)
|
||||||
{
|
{
|
||||||
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_featureDetailsHelper = featureDetailsHelper ?? throw new ArgumentNullException(nameof(featureDetailsHelper));
|
||||||
}
|
}
|
||||||
public async Task<List<BuildingMongoDB>> GetProjectInfraFromDB(Guid projectId)
|
public async Task<List<BuildingMongoDB>> GetProjectInfraFromDB(Guid projectId)
|
||||||
{
|
{
|
||||||
@ -211,5 +215,161 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
return new List<WorkItemMongoDB>();
|
return new List<WorkItemMongoDB>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves all enabled feature IDs for a given tenant based on their active subscription.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tenantId">The unique identifier of the tenant.</param>
|
||||||
|
/// <returns>A list of feature IDs available for the tenant.</returns>
|
||||||
|
public async Task<List<Guid>> GetFeatureIdsByTenentIdAsync(Guid tenantId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Fetching feature IDs for tenant: {TenantId}", tenantId);
|
||||||
|
|
||||||
|
// Step 1: Get active tenant subscription with plan
|
||||||
|
var tenantSubscription = await _context.TenantSubscriptions
|
||||||
|
.Include(ts => ts.Plan)
|
||||||
|
.AsNoTracking() // Optimization: Read-only query, no need to track
|
||||||
|
.FirstOrDefaultAsync(ts =>
|
||||||
|
ts.TenantId == tenantId &&
|
||||||
|
ts.Plan != null &&
|
||||||
|
!ts.IsCancelled &&
|
||||||
|
ts.EndDate.Date >= DateTime.UtcNow.Date); // FIX: Subscription should not be expired
|
||||||
|
|
||||||
|
if (tenantSubscription == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No active subscription found for tenant: {TenantId}", tenantId);
|
||||||
|
return new List<Guid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("Active subscription found for tenant: {TenantId}, PlanId: {PlanId}",
|
||||||
|
tenantId, tenantSubscription.Plan!.Id);
|
||||||
|
|
||||||
|
var featureIds = new List<Guid> { new Guid("2f3509b7-160d-410a-b9b6-daadd96c986d"), new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be") };
|
||||||
|
|
||||||
|
// Step 2: Get feature details from Plan
|
||||||
|
var featureDetails = await _featureDetailsHelper.GetFeatureDetails(tenantSubscription.Plan!.FeaturesId);
|
||||||
|
|
||||||
|
if (featureDetails == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No feature details found for tenant: {TenantId}, PlanId: {PlanId}",
|
||||||
|
tenantId, tenantSubscription.Plan!.Id);
|
||||||
|
return new List<Guid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Collect all enabled feature IDs from modules
|
||||||
|
|
||||||
|
if (featureDetails.Modules?.Attendance?.Enabled == true)
|
||||||
|
{
|
||||||
|
featureIds.AddRange(featureDetails.Modules.Attendance.FeatureId);
|
||||||
|
_logger.LogDebug("Added Attendance module features for tenant: {TenantId}", tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (featureDetails.Modules?.ProjectManagement?.Enabled == true)
|
||||||
|
{
|
||||||
|
featureIds.AddRange(featureDetails.Modules.ProjectManagement.FeatureId);
|
||||||
|
_logger.LogDebug("Added Project Management module features for tenant: {TenantId}", tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (featureDetails.Modules?.Directory?.Enabled == true)
|
||||||
|
{
|
||||||
|
featureIds.AddRange(featureDetails.Modules.Directory.FeatureId);
|
||||||
|
_logger.LogDebug("Added Directory module features for tenant: {TenantId}", tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (featureDetails.Modules?.Expense?.Enabled == true)
|
||||||
|
{
|
||||||
|
featureIds.AddRange(featureDetails.Modules.Expense.FeatureId);
|
||||||
|
_logger.LogDebug("Added Expense module features for tenant: {TenantId}", tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("Returning {Count} feature IDs for tenant: {TenantId}", featureIds.Count, tenantId);
|
||||||
|
|
||||||
|
return featureIds.Distinct().ToList();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Step 4: Handle unexpected errors
|
||||||
|
_logger.LogError(ex, "Error retrieving feature IDs for tenant: {TenantId}", tenantId);
|
||||||
|
return new List<Guid>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the tenant still has available seats (MaxUsers not exceeded).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tenantId">The ID of the tenant to check.</param>
|
||||||
|
/// <returns>True if seats are available; otherwise false.</returns>
|
||||||
|
public async Task<bool> CheckSeatsRemainingAsync(Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Checking seats remaining for TenantId: {TenantId}", tenantId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Run both queries concurrently
|
||||||
|
var totalSeatsTask = GetMaxSeatsAsync(tenantId);
|
||||||
|
var totalSeatsTakenTask = GetActiveEmployeesCountAsync(tenantId);
|
||||||
|
|
||||||
|
await Task.WhenAll(totalSeatsTask, totalSeatsTakenTask);
|
||||||
|
|
||||||
|
var totalSeats = await totalSeatsTask;
|
||||||
|
var totalSeatsTaken = await totalSeatsTakenTask;
|
||||||
|
|
||||||
|
_logger.LogInfo(
|
||||||
|
"TenantId: {TenantId} | TotalSeats: {TotalSeats} | SeatsTaken: {SeatsTaken}",
|
||||||
|
tenantId, totalSeats, totalSeatsTaken);
|
||||||
|
|
||||||
|
bool seatsAvailable = totalSeats >= totalSeatsTaken;
|
||||||
|
|
||||||
|
_logger.LogDebug("TenantId: {TenantId} | Seats Available: {SeatsAvailable}",
|
||||||
|
tenantId, seatsAvailable);
|
||||||
|
|
||||||
|
return seatsAvailable;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error checking seats for TenantId: {TenantId}", tenantId);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the maximum number of allowed seats (MaxUsers) for a tenant.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<double> GetMaxSeatsAsync(Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Fetching maximum seats for TenantId: {TenantId}", tenantId);
|
||||||
|
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
|
var maxSeats = await dbContext.TenantSubscriptions
|
||||||
|
.Where(ts => ts.TenantId == tenantId && !ts.IsCancelled)
|
||||||
|
.Select(ts => ts.MaxUsers)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
_logger.LogDebug("TenantId: {TenantId} | MaxSeats: {MaxSeats}", tenantId, maxSeats);
|
||||||
|
|
||||||
|
return maxSeats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of active employees for a tenant.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<int> GetActiveEmployeesCountAsync(Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Counting active employees for TenantId: {TenantId}", tenantId);
|
||||||
|
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
|
var activeEmployees = await dbContext.Employees
|
||||||
|
.Where(e => e.TenantId == tenantId && e.IsActive)
|
||||||
|
.CountAsync();
|
||||||
|
|
||||||
|
_logger.LogDebug("TenantId: {TenantId} | ActiveEmployees: {ActiveEmployees}", tenantId, activeEmployees);
|
||||||
|
|
||||||
|
return activeEmployees;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,13 @@ namespace MarcoBMS.Services.Helpers
|
|||||||
|
|
||||||
// --- Step 3: Execute the main query on the main thread using its original context ---
|
// --- Step 3: Execute the main query on the main thread using its original context ---
|
||||||
// This is now safe because the background task is using a different DbContext instance.
|
// This is now safe because the background task is using a different DbContext instance.
|
||||||
var permissions = await (
|
var roleIds = await employeeRoleIdsQuery.ToListAsync();
|
||||||
from rpm in _context.RolePermissionMappings
|
|
||||||
join fp in _context.FeaturePermissions.Include(f => f.Feature)
|
var permissionIds = await _context.RolePermissionMappings
|
||||||
on rpm.FeaturePermissionId equals fp.Id
|
.Where(rp => roleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).ToListAsync();
|
||||||
where employeeRoleIdsQuery.Contains(rpm.ApplicationRoleId) && fp.IsEnabled == true
|
|
||||||
select fp)
|
var permissions = await _context.FeaturePermissions.Include(f => f.Feature)
|
||||||
|
.Where(fp => permissionIds.Contains(fp.Id))
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using System.Security.Claims;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.DataAccess.Data;
|
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace MarcoBMS.Services.Helpers
|
namespace MarcoBMS.Services.Helpers
|
||||||
{
|
{
|
||||||
@ -25,6 +26,15 @@ namespace MarcoBMS.Services.Helpers
|
|||||||
var tenant = _httpContextAccessor.HttpContext?.User.FindFirst("TenantId")?.Value;
|
var tenant = _httpContextAccessor.HttpContext?.User.FindFirst("TenantId")?.Value;
|
||||||
return (tenant != null ? Guid.Parse(tenant) : Guid.Empty);
|
return (tenant != null ? Guid.Parse(tenant) : Guid.Empty);
|
||||||
}
|
}
|
||||||
|
public async Task<Tenant?> GetCurrentTenant()
|
||||||
|
{
|
||||||
|
var tenantId = _httpContextAccessor.HttpContext?.User.FindFirst("TenantId")?.Value;
|
||||||
|
if (tenantId != null)
|
||||||
|
{
|
||||||
|
return await _context.Tenants.FirstOrDefaultAsync(t => t.Id == Guid.Parse(tenantId));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IdentityUser?> GetCurrentUserAsync()
|
public async Task<IdentityUser?> GetCurrentUserAsync()
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Marco.Pms.Model.Directory;
|
using Marco.Pms.Model.Directory;
|
||||||
using Marco.Pms.Model.Dtos.Directory;
|
using Marco.Pms.Model.Dtos.Directory;
|
||||||
|
using Marco.Pms.Model.AppMenu;
|
||||||
|
using Marco.Pms.Model.Dtos.AppMenu;
|
||||||
using Marco.Pms.Model.Dtos.Expenses;
|
using Marco.Pms.Model.Dtos.Expenses;
|
||||||
using Marco.Pms.Model.Dtos.Master;
|
using Marco.Pms.Model.Dtos.Master;
|
||||||
using Marco.Pms.Model.Dtos.Project;
|
using Marco.Pms.Model.Dtos.Project;
|
||||||
|
using Marco.Pms.Model.Dtos.Tenant;
|
||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Model.Expenses;
|
using Marco.Pms.Model.Expenses;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.MongoDBModels;
|
using Marco.Pms.Model.MongoDBModels;
|
||||||
@ -13,6 +17,8 @@ using Marco.Pms.Model.MongoDBModels.Expenses;
|
|||||||
using Marco.Pms.Model.MongoDBModels.Masters;
|
using Marco.Pms.Model.MongoDBModels.Masters;
|
||||||
using Marco.Pms.Model.MongoDBModels.Project;
|
using Marco.Pms.Model.MongoDBModels.Project;
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Projects;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
|
using Marco.Pms.Model.TenantModels.MongoDBModel;
|
||||||
using Marco.Pms.Model.ViewModels.Activities;
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
using Marco.Pms.Model.ViewModels.Directory;
|
using Marco.Pms.Model.ViewModels.Directory;
|
||||||
using Marco.Pms.Model.ViewModels.DocumentManager;
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
||||||
@ -21,6 +27,7 @@ using Marco.Pms.Model.ViewModels.Expanses;
|
|||||||
using Marco.Pms.Model.ViewModels.Expenses;
|
using Marco.Pms.Model.ViewModels.Expenses;
|
||||||
using Marco.Pms.Model.ViewModels.Master;
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
using Marco.Pms.Model.ViewModels.Projects;
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
|
using Marco.Pms.Model.ViewModels.Tenant;
|
||||||
|
|
||||||
namespace Marco.Pms.Services.MappingProfiles
|
namespace Marco.Pms.Services.MappingProfiles
|
||||||
{
|
{
|
||||||
@ -28,6 +35,67 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
{
|
{
|
||||||
public MappingProfile()
|
public MappingProfile()
|
||||||
{
|
{
|
||||||
|
#region ======================================================= Tenant =======================================================
|
||||||
|
CreateMap<Tenant, TenantVM>();
|
||||||
|
CreateMap<Tenant, TenantListVM>();
|
||||||
|
CreateMap<Tenant, TenantDetailsVM>();
|
||||||
|
|
||||||
|
CreateMap<CreateTenantDto, Tenant>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.ContactName,
|
||||||
|
opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}")
|
||||||
|
)
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Name,
|
||||||
|
opt => opt.MapFrom(src => src.OrganizationName)
|
||||||
|
);
|
||||||
|
CreateMap<UpdateTenantDto, Tenant>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.ContactName,
|
||||||
|
opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}")
|
||||||
|
);
|
||||||
|
|
||||||
|
CreateMap<SubscriptionPlanDetails, SubscriptionPlanVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.PlanName,
|
||||||
|
opt => opt.MapFrom(src => src.Plan != null ? src.Plan.PlanName : "")
|
||||||
|
)
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Description,
|
||||||
|
opt => opt.MapFrom(src => src.Plan != null ? src.Plan.Description : "")
|
||||||
|
);
|
||||||
|
CreateMap<TenantSubscriptions, SubscriptionPlanDetailsVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.PlanName,
|
||||||
|
opt => opt.MapFrom(src => src.Plan!.Plan != null ? src.Plan.Plan.PlanName : "")
|
||||||
|
)
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Description,
|
||||||
|
opt => opt.MapFrom(src => src.Plan!.Plan != null ? src.Plan.Plan.Description : "")
|
||||||
|
)
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Price,
|
||||||
|
opt => opt.MapFrom(src => src.Plan != null ? src.Plan.Price : 0)
|
||||||
|
)
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Frequency,
|
||||||
|
opt => opt.MapFrom(src => src.Plan != null ? src.Plan.Frequency : PLAN_FREQUENCY.MONTHLY)
|
||||||
|
);
|
||||||
|
CreateMap<SubscriptionPlanDetailsDto, SubscriptionPlanDetails>();
|
||||||
|
CreateMap<SubscriptionPlanDto, SubscriptionPlan>();
|
||||||
|
|
||||||
|
CreateMap<FeatureDetailsDto, FeatureDetails>();
|
||||||
|
CreateMap<SubscriptionCheckListDto, SubscriptionCheckList>();
|
||||||
|
CreateMap<SupportDetailsDto, SupportDetails>();
|
||||||
|
CreateMap<ReportDetailsDto, ReportDetails>();
|
||||||
|
CreateMap<ModulesDetailsDto, ModulesDetails>();
|
||||||
|
CreateMap<ProjectManagementDetailsDto, ProjectManagementDetails>();
|
||||||
|
CreateMap<AttendanceDetailsDto, AttendanceDetails>();
|
||||||
|
CreateMap<DirectoryDetailsDto, DirectoryDetails>();
|
||||||
|
CreateMap<ExpenseModuleDetailsDto, ExpenseModuleDetails>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region ======================================================= Projects =======================================================
|
#region ======================================================= Projects =======================================================
|
||||||
// Your mappings
|
// Your mappings
|
||||||
CreateMap<Project, ProjectVM>();
|
CreateMap<Project, ProjectVM>();
|
||||||
@ -160,6 +228,8 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
|
|
||||||
#region ======================================================= Master =======================================================
|
#region ======================================================= Master =======================================================
|
||||||
|
|
||||||
|
CreateMap<FeaturePermission, FeaturePermissionVM>();
|
||||||
|
|
||||||
#region ======================================================= Expenses Type Master =======================================================
|
#region ======================================================= Expenses Type Master =======================================================
|
||||||
|
|
||||||
CreateMap<ExpensesTypeMasterDto, ExpensesTypeMaster>()
|
CreateMap<ExpensesTypeMasterDto, ExpensesTypeMaster>()
|
||||||
@ -242,6 +312,29 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region ======================================================= AppMenu =======================================================
|
||||||
|
CreateMap<CreateMenuSectionDto, MenuSection>();
|
||||||
|
CreateMap<UpdateMenuSectionDto, MenuSection>();
|
||||||
|
CreateMap<MenuSection, MenuSectionVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Name,
|
||||||
|
opt => opt.MapFrom(src => src.Title));
|
||||||
|
|
||||||
|
CreateMap<CreateMenuItemDto, MenuItem>();
|
||||||
|
CreateMap<UpdateMenuItemDto, MenuItem>();
|
||||||
|
CreateMap<MenuItem, MenuItemVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Name,
|
||||||
|
opt => opt.MapFrom(src => src.Text));
|
||||||
|
|
||||||
|
CreateMap<CreateSubMenuItemDto, SubMenuItem>();
|
||||||
|
CreateMap<UpdateSubMenuItemDto, SubMenuItem>();
|
||||||
|
CreateMap<SubMenuItem, SubMenuItemVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Name,
|
||||||
|
opt => opt.MapFrom(src => src.Text));
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region ======================================================= Directory =======================================================
|
#region ======================================================= Directory =======================================================
|
||||||
|
|
||||||
CreateMap<Contact, ContactVM>();
|
CreateMap<Contact, ContactVM>();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Marco.Pms.CacheHelper;
|
||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Helpers;
|
using Marco.Pms.Helpers;
|
||||||
using Marco.Pms.Helpers.CacheHelper;
|
using Marco.Pms.Helpers.CacheHelper;
|
||||||
@ -172,6 +173,7 @@ builder.Services.AddTransient<S3UploadService>();
|
|||||||
#region Customs Services
|
#region Customs Services
|
||||||
builder.Services.AddScoped<RefreshTokenService>();
|
builder.Services.AddScoped<RefreshTokenService>();
|
||||||
builder.Services.AddScoped<PermissionServices>();
|
builder.Services.AddScoped<PermissionServices>();
|
||||||
|
builder.Services.AddScoped<MasterDataService>();
|
||||||
builder.Services.AddScoped<ISignalRService, SignalRService>();
|
builder.Services.AddScoped<ISignalRService, SignalRService>();
|
||||||
builder.Services.AddScoped<IProjectServices, ProjectServices>();
|
builder.Services.AddScoped<IProjectServices, ProjectServices>();
|
||||||
builder.Services.AddScoped<IExpensesService, ExpensesService>();
|
builder.Services.AddScoped<IExpensesService, ExpensesService>();
|
||||||
@ -188,6 +190,7 @@ builder.Services.AddScoped<DirectoryHelper>();
|
|||||||
builder.Services.AddScoped<MasterHelper>();
|
builder.Services.AddScoped<MasterHelper>();
|
||||||
builder.Services.AddScoped<ReportHelper>();
|
builder.Services.AddScoped<ReportHelper>();
|
||||||
builder.Services.AddScoped<CacheUpdateHelper>();
|
builder.Services.AddScoped<CacheUpdateHelper>();
|
||||||
|
builder.Services.AddScoped<FeatureDetailsHelper>();
|
||||||
builder.Services.AddScoped<UtilityMongoDBHelper>();
|
builder.Services.AddScoped<UtilityMongoDBHelper>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -196,6 +199,7 @@ builder.Services.AddScoped<ProjectCache>();
|
|||||||
builder.Services.AddScoped<EmployeeCache>();
|
builder.Services.AddScoped<EmployeeCache>();
|
||||||
builder.Services.AddScoped<ReportCache>();
|
builder.Services.AddScoped<ReportCache>();
|
||||||
builder.Services.AddScoped<ExpenseCache>();
|
builder.Services.AddScoped<ExpenseCache>();
|
||||||
|
builder.Services.AddScoped<SidebarMenuHelper>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// Singleton services (one instance for the app's lifetime)
|
// Singleton services (one instance for the app's lifetime)
|
||||||
|
337
Marco.Pms.Services/Service/MasterDataService.cs
Normal file
337
Marco.Pms.Services/Service/MasterDataService.cs
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
using Marco.Pms.Model.Forum;
|
||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Service
|
||||||
|
{
|
||||||
|
public class MasterDataService
|
||||||
|
{
|
||||||
|
public List<TicketStatusMaster> GetTicketStatusesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<TicketStatusMaster>
|
||||||
|
{
|
||||||
|
new TicketStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "New",
|
||||||
|
Description = "This is a newly created issue.",
|
||||||
|
ColorCode = "#FFCC99",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Assigned",
|
||||||
|
Description = "Assigned to employee or team of employees",
|
||||||
|
ColorCode = "#E6FF99",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "In Progress",
|
||||||
|
Description = "These issues are currently in progress",
|
||||||
|
ColorCode = "#99E6FF",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "In Review",
|
||||||
|
Description = "These issues are currently under review",
|
||||||
|
ColorCode = "#8592a3",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Done",
|
||||||
|
Description = "The following issues are resolved and closed",
|
||||||
|
ColorCode = "#B399FF",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<TicketTypeMaster> GetTicketTypesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<TicketTypeMaster>
|
||||||
|
{
|
||||||
|
new TicketTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Quality Issue",
|
||||||
|
Description = "An identified problem that affects the performance, reliability, or standards of a product or service",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Help Desk",
|
||||||
|
Description = "A support service that assists users with technical issues, requests, or inquiries.",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<TicketPriorityMaster> GetTicketPrioritysData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<TicketPriorityMaster>
|
||||||
|
{
|
||||||
|
new TicketPriorityMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Low",
|
||||||
|
ColorCode = "008000",
|
||||||
|
Level = 1,
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketPriorityMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Medium",
|
||||||
|
ColorCode = "FFFF00",
|
||||||
|
Level = 2,
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketPriorityMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "High",
|
||||||
|
ColorCode = "#FFA500",
|
||||||
|
Level = 3,
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketPriorityMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Critical",
|
||||||
|
ColorCode = "#FFA500",
|
||||||
|
Level = 4,
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketPriorityMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Urgent",
|
||||||
|
ColorCode = "#FF0000",
|
||||||
|
Level = 5,
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<TicketTagMaster> GetTicketTagsData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<TicketTagMaster>
|
||||||
|
{
|
||||||
|
new TicketTagMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Quality Issue",
|
||||||
|
ColorCode = "#e59866",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new TicketTagMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Help Desk",
|
||||||
|
ColorCode = "#85c1e9",
|
||||||
|
IsDefault = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<WorkCategoryMaster> GetWorkCategoriesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<WorkCategoryMaster>
|
||||||
|
{
|
||||||
|
new WorkCategoryMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Fresh Work",
|
||||||
|
Description = "Created new task in a professional or creative context",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new WorkCategoryMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Rework",
|
||||||
|
Description = "Revising, modifying, or correcting a task to improve its quality or fix issues",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new WorkCategoryMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Quality Issue",
|
||||||
|
Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<WorkStatusMaster> GetWorkStatusesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<WorkStatusMaster>
|
||||||
|
{
|
||||||
|
new WorkStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Approve",
|
||||||
|
Description = "Confirm the tasks are actually finished as reported",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new WorkStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Partially Approve",
|
||||||
|
Description = "Not all tasks are actually finished as reported",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new WorkStatusMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "NCR",
|
||||||
|
Description = "Tasks are not finished as reported or have any issues in al the tasks",
|
||||||
|
IsSystem = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<ExpensesTypeMaster> GetExpensesTypeesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<ExpensesTypeMaster>
|
||||||
|
{
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Procurement",
|
||||||
|
Description = "Materials, equipment and supplies purchased for site operations.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Transport",
|
||||||
|
Description = "Vehicle fuel, logistics services and delivery of goods or personnel.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Travelling",
|
||||||
|
Description = "Delivery of personnel.",
|
||||||
|
NoOfPersonsRequired = true,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Mobilization",
|
||||||
|
Description = "Site setup costs including equipment deployment and temporary infrastructure.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Employee Welfare",
|
||||||
|
Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.",
|
||||||
|
NoOfPersonsRequired = true,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Maintenance & Utilities",
|
||||||
|
Description = "Machinery servicing, electricity, water, and temporary office needs.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Vendor/Supplier Payments",
|
||||||
|
Description = "Scheduled payments for external services or goods.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new ExpensesTypeMaster
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Compliance & Safety",
|
||||||
|
Description = "Government fees, insurance, inspections and safety-related expenditures.",
|
||||||
|
NoOfPersonsRequired = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<PaymentModeMatser> GetPaymentModesData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<PaymentModeMatser>
|
||||||
|
{
|
||||||
|
new PaymentModeMatser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Cash",
|
||||||
|
Description = "Physical currency; still used for small or informal transactions.",
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new PaymentModeMatser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "Cheque",
|
||||||
|
Description = "Paper-based payment order; less common now due to processing delays and fraud risks.",
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new PaymentModeMatser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "NetBanking",
|
||||||
|
Description = "Online banking portals used to transfer funds directly between accounts",
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
},
|
||||||
|
new PaymentModeMatser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = "UPI",
|
||||||
|
Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.",
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public List<object> GetData(Guid tenantId)
|
||||||
|
{
|
||||||
|
return new List<object>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,18 @@ namespace Marco.Pms.Services.Service
|
|||||||
var hasPermission = featurePermissionIds.Contains(featurePermissionId);
|
var hasPermission = featurePermissionIds.Contains(featurePermissionId);
|
||||||
return hasPermission;
|
return hasPermission;
|
||||||
}
|
}
|
||||||
|
public async Task<bool> HasPermissionAny(List<Guid> featurePermissionIds, Guid employeeId)
|
||||||
|
{
|
||||||
|
var allFeaturePermissionIds = await _cache.GetPermissions(employeeId);
|
||||||
|
if (allFeaturePermissionIds == null)
|
||||||
|
{
|
||||||
|
List<FeaturePermission> featurePermission = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
|
||||||
|
allFeaturePermissionIds = featurePermission.Select(fp => fp.Id).ToList();
|
||||||
|
}
|
||||||
|
var hasPermission = featurePermissionIds.Any(f => allFeaturePermissionIds.Contains(f));
|
||||||
|
|
||||||
|
return hasPermission;
|
||||||
|
}
|
||||||
public async Task<bool> HasProjectPermission(Employee LoggedInEmployee, Guid projectId)
|
public async Task<bool> HasProjectPermission(Employee LoggedInEmployee, Guid projectId)
|
||||||
{
|
{
|
||||||
var employeeId = LoggedInEmployee.Id;
|
var employeeId = LoggedInEmployee.Id;
|
||||||
|
@ -7,6 +7,7 @@ using Marco.Pms.Model.Employees;
|
|||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Model.MongoDBModels.Project;
|
using Marco.Pms.Model.MongoDBModels.Project;
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Projects;
|
||||||
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Employee;
|
using Marco.Pms.Model.ViewModels.Employee;
|
||||||
using Marco.Pms.Model.ViewModels.Projects;
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
@ -227,10 +228,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
projectVM = _mapper.Map<ProjectVM>(projectDetails);
|
projectVM = _mapper.Map<ProjectVM>(projectDetails);
|
||||||
if (projectVM.ProjectStatus != null)
|
|
||||||
{
|
|
||||||
projectVM.ProjectStatus.TenantId = tenantId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectVM == null)
|
if (projectVM == null)
|
||||||
@ -895,6 +892,73 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<List<ProjectAllocationVM>>.SuccessResponse(resultVm, "Assignments managed successfully.", 200);
|
return ApiResponse<List<ProjectAllocationVM>>.SuccessResponse(resultVm, "Assignments managed successfully.", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<object>> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee)
|
||||||
|
{
|
||||||
|
// Log the start of the method execution with key input parameters
|
||||||
|
_logger.LogInfo("Fetching projects for EmployeeId: {EmployeeId}, TenantId: {TenantId} by User: {UserId}",
|
||||||
|
employeeId, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Retrieve project allocations linked to the specified employee and tenant
|
||||||
|
var projectAllocation = await _context.ProjectAllocations
|
||||||
|
.AsNoTracking() // Optimization: no tracking since entities are not updated
|
||||||
|
.Include(pa => pa.Project) // Include related Project data
|
||||||
|
.Include(pa => pa.Employee).ThenInclude(e => e!.JobRole) // Include related Employee and their JobRole
|
||||||
|
.Where(pa => pa.EmployeeId == employeeId
|
||||||
|
&& pa.TenantId == tenantId
|
||||||
|
&& pa.Project != null
|
||||||
|
&& pa.Employee != null)
|
||||||
|
.Select(pa => new
|
||||||
|
{
|
||||||
|
ProjectName = pa.Project!.Name,
|
||||||
|
ProjectShortName = pa.Project.ShortName,
|
||||||
|
AssignedDate = pa.AllocationDate,
|
||||||
|
RemovedDate = pa.ReAllocationDate,
|
||||||
|
Designation = pa.Employee!.JobRole!.Name,
|
||||||
|
DesignationId = pa.JobRoleId
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var designationIds = projectAllocation.Select(pa => pa.DesignationId).ToList();
|
||||||
|
|
||||||
|
var designations = await _context.JobRoles.Where(jr => designationIds.Contains(jr.Id)).ToListAsync();
|
||||||
|
|
||||||
|
var response = projectAllocation.Select(pa =>
|
||||||
|
{
|
||||||
|
var designation = designations.FirstOrDefault(jr => jr.Id == pa.DesignationId);
|
||||||
|
return new ProjectHisteryVM
|
||||||
|
{
|
||||||
|
ProjectName = pa.ProjectName,
|
||||||
|
ProjectShortName = pa.ProjectShortName,
|
||||||
|
AssignedDate = pa.AssignedDate,
|
||||||
|
RemovedDate = pa.RemovedDate,
|
||||||
|
Designation = designation?.Name
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Log successful retrieval including count of records
|
||||||
|
_logger.LogInfo("Successfully fetched {Count} projects for EmployeeId: {EmployeeId}",
|
||||||
|
projectAllocation.Count, employeeId);
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(
|
||||||
|
response,
|
||||||
|
$"{response.Count} project assignments fetched for employee.",
|
||||||
|
200);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log the exception with stack trace for debugging
|
||||||
|
_logger.LogError(ex, "Error occurred while fetching projects for EmployeeId: {EmployeeId}, TenantId: {TenantId}",
|
||||||
|
employeeId, tenantId);
|
||||||
|
|
||||||
|
return ApiResponse<object>.ErrorResponse(
|
||||||
|
"An error occurred while fetching project assignments.",
|
||||||
|
500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Project InfraStructure Get APIs ===================================================================
|
#region =================================================================== Project InfraStructure Get APIs ===================================================================
|
||||||
@ -1025,6 +1089,83 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves tasks assigned to a specific employee within a date range for a tenant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="employeeId">The ID of the employee to filter tasks.</param>
|
||||||
|
/// <param name="fromDate">The start date to filter task assignments.</param>
|
||||||
|
/// <param name="toDate">The end date to filter task assignments.</param>
|
||||||
|
/// <param name="tenantId">The tenant ID to filter tasks.</param>
|
||||||
|
/// <param name="loggedInEmployee">The employee requesting the data (for authorization/logging).</param>
|
||||||
|
/// <returns>An ApiResponse containing the task details.</returns>
|
||||||
|
public async Task<ApiResponse<object>> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Fetching tasks for EmployeeId: {EmployeeId} from {FromDate} to {ToDate} for TenantId: {TenantId}",
|
||||||
|
employeeId, fromDate, toDate, tenantId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Query TaskMembers with related necessary fields in one projection to minimize DB calls and data size
|
||||||
|
var taskData = await _context.TaskMembers
|
||||||
|
.Where(tm => tm.EmployeeId == employeeId &&
|
||||||
|
tm.TenantId == tenantId &&
|
||||||
|
tm.TaskAllocation != null &&
|
||||||
|
tm.TaskAllocation.AssignmentDate.Date >= fromDate.Date &&
|
||||||
|
tm.TaskAllocation.AssignmentDate.Date <= toDate.Date)
|
||||||
|
.Select(tm => new
|
||||||
|
{
|
||||||
|
AssignmentDate = tm.TaskAllocation!.AssignmentDate,
|
||||||
|
PlannedTask = tm.TaskAllocation.PlannedTask,
|
||||||
|
CompletedTask = tm.TaskAllocation.CompletedTask,
|
||||||
|
ProjectId = tm.TaskAllocation.WorkItem!.WorkArea!.Floor!.Building!.ProjectId,
|
||||||
|
BuildingName = tm.TaskAllocation.WorkItem.WorkArea.Floor.Building!.Name,
|
||||||
|
FloorName = tm.TaskAllocation.WorkItem.WorkArea.Floor.FloorName,
|
||||||
|
AreaName = tm.TaskAllocation.WorkItem.WorkArea.AreaName,
|
||||||
|
ActivityName = tm.TaskAllocation.WorkItem.ActivityMaster!.ActivityName,
|
||||||
|
ActivityUnit = tm.TaskAllocation.WorkItem.ActivityMaster.UnitOfMeasurement
|
||||||
|
})
|
||||||
|
.OrderByDescending(t => t.AssignmentDate)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
_logger.LogInfo("Retrieved {TaskCount} tasks for EmployeeId: {EmployeeId}", taskData.Count, employeeId);
|
||||||
|
|
||||||
|
// Extract distinct project IDs to fetch project details efficiently
|
||||||
|
var distinctProjectIds = taskData.Select(t => t.ProjectId).Distinct().ToList();
|
||||||
|
|
||||||
|
var projects = await _context.Projects
|
||||||
|
.Where(p => distinctProjectIds.Contains(p.Id))
|
||||||
|
.Select(p => new { p.Id, p.Name })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Prepare the response
|
||||||
|
var response = taskData.Select(t =>
|
||||||
|
{
|
||||||
|
var project = projects.FirstOrDefault(p => p.Id == t.ProjectId);
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
ProjectName = project?.Name ?? "Unknown Project",
|
||||||
|
t.AssignmentDate,
|
||||||
|
t.PlannedTask,
|
||||||
|
t.CompletedTask,
|
||||||
|
Location = $"{t.BuildingName} > {t.FloorName} > {t.AreaName}",
|
||||||
|
ActivityName = t.ActivityName,
|
||||||
|
ActivityUnit = t.ActivityUnit
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
_logger.LogInfo("Successfully prepared task response for EmployeeId: {EmployeeId}", employeeId);
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(response, "Task fetched successfully", 200);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error while fetching tasks for EmployeeId: {EmployeeId}", employeeId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("An error occurred while fetching the tasks.", 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
#region =================================================================== Project Infrastructre Manage APIs ===================================================================
|
||||||
|
@ -20,8 +20,11 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
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);
|
||||||
|
Task<ApiResponse<object>> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
|
||||||
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
Task<ApiResponse<object>> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<List<WorkItemVM>>> CreateProjectTaskAsync(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<List<WorkItemVM>>> CreateProjectTaskAsync(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
{
|
{
|
||||||
"Cors": {
|
"Cors": {
|
||||||
"AllowedOrigins": "*",
|
"AllowedOrigins": "*",
|
||||||
"AllowedMethods": "*",
|
"AllowedMethods": "*",
|
||||||
"AllowedHeaders": "*"
|
"AllowedHeaders": "*"
|
||||||
},
|
},
|
||||||
"Environment": {
|
"Environment": {
|
||||||
"Name": "Development",
|
"Name": "Development",
|
||||||
"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=MarcoBMS1"
|
||||||
},
|
},
|
||||||
"SmtpSettings": {
|
"SmtpSettings": {
|
||||||
"SmtpServer": "smtp.gmail.com",
|
"SmtpServer": "smtp.gmail.com",
|
||||||
"Port": 587,
|
"Port": 587,
|
||||||
"SenderName": "MarcoAIOT",
|
"SenderName": "MarcoAIOT",
|
||||||
"SenderEmail": "marcoioitsoft@gmail.com",
|
"SenderEmail": "marcoioitsoft@gmail.com",
|
||||||
"Password": "qrtq wfuj hwpp fhqr"
|
"Password": "qrtq wfuj hwpp fhqr"
|
||||||
},
|
},
|
||||||
//"SmtpSettings": {
|
//"SmtpSettings": {
|
||||||
// "SmtpServer": "mail.marcoaiot.com",
|
// "SmtpServer": "mail.marcoaiot.com",
|
||||||
// "Port": 587,
|
// "Port": 587,
|
||||||
// "SenderName": "MarcoAIOT",
|
// "SenderName": "MarcoAIOT",
|
||||||
// "SenderEmail": "ashutosh.nehete@marcoaiot.com",
|
// "SenderEmail": "ashutosh.nehete@marcoaiot.com",
|
||||||
// "Password": "Reset@123"
|
// "Password": "Reset@123"
|
||||||
//},
|
//},
|
||||||
"AppSettings": {
|
"AppSettings": {
|
||||||
"WebFrontendUrl": "http://localhost:5173",
|
"WebFrontendUrl": "http://localhost:5173",
|
||||||
"ImagesBaseUrl": "http://localhost:5173"
|
"ImagesBaseUrl": "http://localhost:5173"
|
||||||
},
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Issuer": "http://localhost:5246",
|
"Issuer": "http://localhost:5246",
|
||||||
"Audience": "http://localhost:5246",
|
"Audience": "http://localhost:5246",
|
||||||
"Key": "sworffishhkjfa9dnfdndfu33infnajfj",
|
"Key": "sworffishhkjfa9dnfdndfu33infnajfj",
|
||||||
"ExpiresInMinutes": 60,
|
"ExpiresInMinutes": 60,
|
||||||
"RefreshTokenExpiresInDays": 7
|
"RefreshTokenExpiresInDays": 7
|
||||||
},
|
},
|
||||||
"MailingList": {
|
"MailingList": {
|
||||||
"RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
"RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
||||||
//"ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
//"ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
||||||
},
|
},
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"AccessKey": "AKIARZDBH3VDMSUUY2FX",
|
"AccessKey": "AKIARZDBH3VDMSUUY2FX",
|
||||||
"SecretKey": "NTS5XXgZINQbU6ctpNuLXtIY/Qk9GCgD9Rr5yNJP",
|
"SecretKey": "NTS5XXgZINQbU6ctpNuLXtIY/Qk9GCgD9Rr5yNJP",
|
||||||
"Region": "us-east-1",
|
"Region": "us-east-1",
|
||||||
"BucketName": "testenv-marco-pms-documents"
|
"BucketName": "testenv-marco-pms-documents"
|
||||||
},
|
},
|
||||||
"MongoDB": {
|
"MongoDB": {
|
||||||
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
|
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
|
||||||
"ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500",
|
"ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500",
|
||||||
"ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500"
|
"ModificationConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSLocalDev?authSource=admin&eplicaSet=rs01&directConnection=true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user