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 Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Marco.Pms.Helpers.CacheHelper
|
||||
@ -8,8 +9,11 @@ namespace Marco.Pms.Helpers.CacheHelper
|
||||
public class EmployeeCache
|
||||
{
|
||||
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 mongoUrl = new MongoUrl(connectionString);
|
||||
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
|
||||
@ -185,6 +189,25 @@ namespace Marco.Pms.Helpers.CacheHelper
|
||||
|
||||
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.
|
||||
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 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 DirectoryManager = Guid.Parse("62668630-13ce-4f52-a0f0-db38af2230c5");
|
||||
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 ManageProject = Guid.Parse("172fc9b6-755b-4f62-ab26-55c34a330614");
|
||||
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 AssignAndReportProgress = Guid.Parse("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2");
|
||||
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 ViewTeamMembers = Guid.Parse("b82d2b7e-0d52-45f3-997b-c008ea460e7f");
|
||||
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 TeamAttendance = Guid.Parse("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e");
|
||||
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 ViewMasters = Guid.Parse("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d");
|
||||
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 ExpenseViewAll = Guid.Parse("01e06444-9ca7-4df4-b900-8c3fa051b92f");
|
||||
public static readonly Guid ExpenseUpload = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7");
|
||||
|
@ -35,8 +35,10 @@ namespace Marco.Pms.Model.Mapper
|
||||
PhoneNumber = model.PhoneNumber,
|
||||
Photo = base64String,
|
||||
IsActive = model.IsActive,
|
||||
IsRootUser = model.ApplicationUser?.IsRootUser ?? false,
|
||||
IsSystem = model.IsSystem,
|
||||
JoiningDate = model.JoiningDate
|
||||
JoiningDate = model.JoiningDate,
|
||||
TenantId = model.TenantId
|
||||
};
|
||||
}
|
||||
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 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.Entitlements;
|
||||
using Marco.Pms.Model.TenantModels;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
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 bool IsActive { get; set; } = true;
|
||||
public bool IsRootUser { get; set; }
|
||||
public string? PanNumber { get; set; }
|
||||
|
||||
public string? Photo { get; set; } // To store the captured photo
|
||||
@ -28,6 +29,7 @@
|
||||
public string? ApplicationUserId { get; set; }
|
||||
|
||||
public Guid? JobRoleId { get; set; }
|
||||
public Guid TenantId { get; set; }
|
||||
public bool IsSystem { 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.ViewModels.Activities;
|
||||
using Marco.Pms.Model.ViewModels.Employee;
|
||||
using Marco.Pms.Services.Helpers;
|
||||
using Marco.Pms.Services.Hubs;
|
||||
using Marco.Pms.Services.Service;
|
||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||
@ -36,6 +37,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly EmployeeHelper _employeeHelper;
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly GeneralHelper _generalHelper;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly IHubContext<MarcoHub> _signalR;
|
||||
@ -47,13 +49,14 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
public EmployeeController(UserManager<ApplicationUser> userManager, IEmailSender emailSender,
|
||||
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;
|
||||
_userManager = userManager;
|
||||
_emailSender = emailSender;
|
||||
_employeeHelper = employeeHelper;
|
||||
_userHelper = userHelper;
|
||||
_generalHelper = generalHelper;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
_signalR = signalR;
|
||||
@ -191,24 +194,88 @@ namespace MarcoBMS.Services.Controllers
|
||||
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));
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("search/{name}/{projectid?}")]
|
||||
public async Task<IActionResult> SearchEmployee(string name, Guid? projectid)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
var errors = ModelState.Values
|
||||
.SelectMany(v => v.Errors)
|
||||
.Select(e => e.ErrorMessage)
|
||||
.ToList();
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||
|
||||
}
|
||||
var result = await _employeeHelper.SearchEmployeeByProjectId(GetTenantId(), name.ToLower(), projectid);
|
||||
/// <summary>
|
||||
/// 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>
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200));
|
||||
[HttpGet("search")]
|
||||
public async Task<IActionResult> GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString,
|
||||
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
_logger.LogDebug("Project filter applied. Checking permission for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}",
|
||||
loggedInEmployee.Id, projectId);
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// 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]
|
||||
[Route("profile/get/{employeeId}")]
|
||||
public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId)
|
||||
@ -233,11 +300,6 @@ namespace MarcoBMS.Services.Controllers
|
||||
return _userHelper.GetTenantId();
|
||||
}
|
||||
|
||||
//[HttpPost("manage/quick")]
|
||||
//public async Task<IActionResult> CreateQuickUser([FromBody] CreateQuickUserDto model)
|
||||
//{
|
||||
// return Ok("Pending implementation");
|
||||
//}
|
||||
|
||||
[HttpPost("manage")]
|
||||
public async Task<IActionResult> CreateUser([FromBody] CreateUserDto model)
|
||||
@ -294,7 +356,12 @@ namespace MarcoBMS.Services.Controllers
|
||||
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
|
||||
var result = await _userManager.CreateAsync(user, "User@123");
|
||||
if (!result.Succeeded)
|
||||
@ -447,20 +514,21 @@ namespace MarcoBMS.Services.Controllers
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> SuspendEmployee(Guid id)
|
||||
public async Task<IActionResult> SuspendEmployee(Guid id, [FromQuery] bool active = false)
|
||||
{
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.IsActive && e.TenantId == tenantId);
|
||||
if (employee != null)
|
||||
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId);
|
||||
if (employee == null)
|
||||
{
|
||||
_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));
|
||||
}
|
||||
else
|
||||
{
|
||||
var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync();
|
||||
if (assignedToTasks.Count != 0)
|
||||
{
|
||||
@ -483,6 +551,20 @@ namespace MarcoBMS.Services.Controllers
|
||||
_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)
|
||||
{
|
||||
user.IsActive = true;
|
||||
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been actived.", employee.Id);
|
||||
|
||||
}
|
||||
_logger.LogInfo("Employee with ID {EmployeId} Actived successfully", employee.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
employee.IsActive = false;
|
||||
var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
|
||||
if (projectAllocations.Count != 0)
|
||||
@ -516,17 +598,20 @@ namespace MarcoBMS.Services.Controllers
|
||||
_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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Employee with ID {EmploueeId} not found in database", id);
|
||||
}
|
||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
|
||||
}
|
||||
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
|
||||
|
@ -1,9 +1,11 @@
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.Mapper;
|
||||
using AutoMapper;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Master;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
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.EntityFrameworkCore;
|
||||
|
||||
@ -15,43 +17,102 @@ namespace MarcoBMS.Services.Controllers
|
||||
public class FeatureController : ControllerBase
|
||||
{
|
||||
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)
|
||||
public FeatureController(ApplicationDbContext context, GeneralHelper generalHelper, UserHelper userHelper, IMapper mapper, ILoggingService logger)
|
||||
{
|
||||
_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)
|
||||
{
|
||||
ICollection<FeaturePermissionVM> features = [];
|
||||
if (model.FeaturePermissions != null)
|
||||
if (model.FeaturePermissions == null || !model.FeaturePermissions.Any())
|
||||
{
|
||||
foreach (FeaturePermission permission in model.FeaturePermissions)
|
||||
{
|
||||
FeaturePermissionVM item = permission.ToFeaturePermissionVMFromFeaturePermission();
|
||||
features.Add(item);
|
||||
}
|
||||
}
|
||||
return features.OrderBy(f => f.Name).ToList();
|
||||
_logger.LogInfo("No feature permissions found for Feature: {FeatureId}", model.Id);
|
||||
return new List<FeaturePermissionVM>();
|
||||
}
|
||||
|
||||
// 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]
|
||||
public async Task<IActionResult> GetAllFeatures()
|
||||
public async Task<IActionResult> GetAllFeaturesAsync()
|
||||
{
|
||||
var roles = await _context.Features.Include("FeaturePermissions").Include("Module").ToListAsync();
|
||||
try
|
||||
{
|
||||
_logger.LogInfo("Fetching all features for tenant: {TenantId}", tenantId);
|
||||
|
||||
var rolesVM = roles.Select(c => new FeatureVM()
|
||||
var featureQuery = _context.Features
|
||||
.AsNoTracking(); // Optimization: Read-only query
|
||||
if (tenantId != Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"))
|
||||
{
|
||||
|
||||
// Step 1: Get tenant-specific FeatureIds
|
||||
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 != null ? c.Module.Name : string.Empty,
|
||||
ModuleName = c.Module?.Name ?? string.Empty,
|
||||
IsActive = c.IsActive
|
||||
}).OrderBy(f => f.Name).ToList();
|
||||
return Ok(ApiResponse<object>.SuccessResponse(rolesVM, "Success.", 200));
|
||||
})
|
||||
.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));
|
||||
}
|
||||
|
||||
[HttpPost("inquiry")]
|
||||
[HttpPost("enquire")]
|
||||
public async Task<IActionResult> RequestDemo([FromBody] InquiryDto inquiryDto)
|
||||
{
|
||||
Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto();
|
||||
|
@ -276,6 +276,23 @@ namespace MarcoBMS.Services.Controllers
|
||||
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}")]
|
||||
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);
|
||||
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
|
||||
|
||||
|
@ -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.Roles;
|
||||
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.Roles;
|
||||
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.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Data;
|
||||
#nullable disable
|
||||
namespace MarcoBMS.Services.Controllers
|
||||
{
|
||||
@ -28,15 +28,15 @@ namespace MarcoBMS.Services.Controllers
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly RolesHelper _rolesHelper;
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly PermissionServices _permissionService;
|
||||
private readonly ILoggingService _logger;
|
||||
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)
|
||||
{
|
||||
_context = context;
|
||||
_userManager = userManager;
|
||||
_permissionService = permissionServices;
|
||||
_rolesHelper = rolesHelper;
|
||||
_userHelper = userHelper;
|
||||
_logger = logger;
|
||||
@ -213,12 +213,17 @@ namespace MarcoBMS.Services.Controllers
|
||||
}
|
||||
|
||||
Guid TenantId = GetTenantId();
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
.Any(r => r.TenantId == TenantId && r.Role.ToLower() == createRoleDto.Role.ToLower());// assuming role name is unique per tenant
|
||||
if (roleExists)
|
||||
@ -228,7 +233,11 @@ namespace MarcoBMS.Services.Controllers
|
||||
ApplicationRole role = createRoleDto.ToApplicationRoleFromCreateDto(TenantId);
|
||||
_context.ApplicationRoles.Add(role);
|
||||
|
||||
var hasPermission = await _permissionService.HasPermission(PermissionsMaster.ManageTenants, loggedInEmployee.Id);
|
||||
foreach (var permission in createRoleDto.FeaturesPermission)
|
||||
{
|
||||
if (!hasPermission &&
|
||||
permission.Id != PermissionsMaster.ManageTenants)
|
||||
{
|
||||
var item = new RolePermissionMappings() { ApplicationRoleId = role.Id, FeaturePermissionId = permission.Id };
|
||||
bool assigned = _context.RolePermissionMappings.Any(c => c.ApplicationRoleId == role.Id && c.FeaturePermissionId == permission.Id);
|
||||
@ -237,6 +246,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
else
|
||||
_context.RolePermissionMappings.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
return Ok(ApiResponse<object>.SuccessResponse(role.ToRoleVMFromApplicationRole(), "Roles created successfully.", 200));
|
||||
|
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.Services.Service.ServiceInterfaces;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace MarcoBMS.Services.Controllers
|
||||
{
|
||||
@ -18,14 +21,17 @@ namespace MarcoBMS.Services.Controllers
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly EmployeeHelper _employeeHelper;
|
||||
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly IProjectServices _projectServices;
|
||||
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;
|
||||
_logger = logger;
|
||||
_employeeHelper = employeeHelper;
|
||||
_projectServices = projectServices;
|
||||
_rolesHelper = rolesHelper;
|
||||
@ -81,5 +87,44 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
try
|
||||
|
@ -20,7 +20,7 @@ namespace MarcoBMS.Services.Helpers
|
||||
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)
|
||||
@ -29,7 +29,7 @@ namespace MarcoBMS.Services.Helpers
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Helpers.Utility;
|
||||
using Marco.Pms.Model.MongoDBModels.Masters;
|
||||
using Marco.Pms.Model.MongoDBModels.Project;
|
||||
using MarcoBMS.Services.Service;
|
||||
@ -11,13 +12,16 @@ namespace Marco.Pms.Services.Helpers
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||
private readonly ApplicationDbContext _context; // Keeping this for direct scoped context use where appropriate
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly FeatureDetailsHelper _featureDetailsHelper;
|
||||
public GeneralHelper(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||
ApplicationDbContext context,
|
||||
ILoggingService logger)
|
||||
ILoggingService logger,
|
||||
FeatureDetailsHelper featureDetailsHelper)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_featureDetailsHelper = featureDetailsHelper ?? throw new ArgumentNullException(nameof(featureDetailsHelper));
|
||||
}
|
||||
public async Task<List<BuildingMongoDB>> GetProjectInfraFromDB(Guid projectId)
|
||||
{
|
||||
@ -211,5 +215,161 @@ namespace Marco.Pms.Services.Helpers
|
||||
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 ---
|
||||
// This is now safe because the background task is using a different DbContext instance.
|
||||
var permissions = await (
|
||||
from rpm in _context.RolePermissionMappings
|
||||
join fp in _context.FeaturePermissions.Include(f => f.Feature)
|
||||
on rpm.FeaturePermissionId equals fp.Id
|
||||
where employeeRoleIdsQuery.Contains(rpm.ApplicationRoleId) && fp.IsEnabled == true
|
||||
select fp)
|
||||
var roleIds = await employeeRoleIdsQuery.ToListAsync();
|
||||
|
||||
var permissionIds = await _context.RolePermissionMappings
|
||||
.Where(rp => roleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).ToListAsync();
|
||||
|
||||
var permissions = await _context.FeaturePermissions.Include(f => f.Feature)
|
||||
.Where(fp => permissionIds.Contains(fp.Id))
|
||||
.Distinct()
|
||||
.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.Entitlements;
|
||||
using Marco.Pms.Model.TenantModels;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace MarcoBMS.Services.Helpers
|
||||
{
|
||||
@ -25,6 +26,15 @@ namespace MarcoBMS.Services.Helpers
|
||||
var tenant = _httpContextAccessor.HttpContext?.User.FindFirst("TenantId")?.Value;
|
||||
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()
|
||||
{
|
||||
|
@ -1,10 +1,14 @@
|
||||
using AutoMapper;
|
||||
using Marco.Pms.Model.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.Master;
|
||||
using Marco.Pms.Model.Dtos.Project;
|
||||
using Marco.Pms.Model.Dtos.Tenant;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.Expenses;
|
||||
using Marco.Pms.Model.Master;
|
||||
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.Project;
|
||||
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.Directory;
|
||||
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.Master;
|
||||
using Marco.Pms.Model.ViewModels.Projects;
|
||||
using Marco.Pms.Model.ViewModels.Tenant;
|
||||
|
||||
namespace Marco.Pms.Services.MappingProfiles
|
||||
{
|
||||
@ -28,6 +35,67 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
{
|
||||
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 =======================================================
|
||||
// Your mappings
|
||||
CreateMap<Project, ProjectVM>();
|
||||
@ -160,6 +228,8 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
|
||||
#region ======================================================= Master =======================================================
|
||||
|
||||
CreateMap<FeaturePermission, FeaturePermissionVM>();
|
||||
|
||||
#region ======================================================= Expenses Type Master =======================================================
|
||||
|
||||
CreateMap<ExpensesTypeMasterDto, ExpensesTypeMaster>()
|
||||
@ -242,6 +312,29 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
|
||||
#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 =======================================================
|
||||
|
||||
CreateMap<Contact, ContactVM>();
|
||||
|
@ -1,3 +1,4 @@
|
||||
using Marco.Pms.CacheHelper;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Helpers;
|
||||
using Marco.Pms.Helpers.CacheHelper;
|
||||
@ -172,6 +173,7 @@ builder.Services.AddTransient<S3UploadService>();
|
||||
#region Customs Services
|
||||
builder.Services.AddScoped<RefreshTokenService>();
|
||||
builder.Services.AddScoped<PermissionServices>();
|
||||
builder.Services.AddScoped<MasterDataService>();
|
||||
builder.Services.AddScoped<ISignalRService, SignalRService>();
|
||||
builder.Services.AddScoped<IProjectServices, ProjectServices>();
|
||||
builder.Services.AddScoped<IExpensesService, ExpensesService>();
|
||||
@ -188,6 +190,7 @@ builder.Services.AddScoped<DirectoryHelper>();
|
||||
builder.Services.AddScoped<MasterHelper>();
|
||||
builder.Services.AddScoped<ReportHelper>();
|
||||
builder.Services.AddScoped<CacheUpdateHelper>();
|
||||
builder.Services.AddScoped<FeatureDetailsHelper>();
|
||||
builder.Services.AddScoped<UtilityMongoDBHelper>();
|
||||
#endregion
|
||||
|
||||
@ -196,6 +199,7 @@ builder.Services.AddScoped<ProjectCache>();
|
||||
builder.Services.AddScoped<EmployeeCache>();
|
||||
builder.Services.AddScoped<ReportCache>();
|
||||
builder.Services.AddScoped<ExpenseCache>();
|
||||
builder.Services.AddScoped<SidebarMenuHelper>();
|
||||
#endregion
|
||||
|
||||
// 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);
|
||||
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)
|
||||
{
|
||||
var employeeId = LoggedInEmployee.Id;
|
||||
|
@ -7,6 +7,7 @@ using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.MongoDBModels.Project;
|
||||
using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.TenantModels;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Model.ViewModels.Employee;
|
||||
using Marco.Pms.Model.ViewModels.Projects;
|
||||
@ -227,10 +228,6 @@ namespace Marco.Pms.Services.Service
|
||||
else
|
||||
{
|
||||
projectVM = _mapper.Map<ProjectVM>(projectDetails);
|
||||
if (projectVM.ProjectStatus != null)
|
||||
{
|
||||
projectVM.ProjectStatus.TenantId = tenantId;
|
||||
}
|
||||
}
|
||||
|
||||
if (projectVM == null)
|
||||
@ -895,6 +892,73 @@ namespace Marco.Pms.Services.Service
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
#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<object>> GetProjectsByEmployeeAsync(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>> 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<ApiResponse<List<WorkItemVM>>> CreateProjectTaskAsync(List<WorkItemDto> workItemDtos, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ServiceResponse> DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
||||
|
@ -49,6 +49,6 @@
|
||||
"MongoDB": {
|
||||
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
|
||||
"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