Compare commits
19 Commits
Service_Pr
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a3ffe1d3d6 | |||
| 55c2ca73de | |||
| bcba454b6e | |||
| e73413c849 | |||
| 457e3b411e | |||
| 8f5a49deed | |||
| f1f5fc263f | |||
| 64aab7d712 | |||
| c7a73e78fb | |||
| 1b94592026 | |||
| 9c95b12a8f | |||
| df0e9f7b46 | |||
| 24e45037da | |||
| a31266ee4a | |||
| bd2f9d953f | |||
| d5a7ad0716 | |||
| 4108915b92 | |||
| dad135571d | |||
| 5a402925b1 |
@ -213,9 +213,15 @@ namespace Marco.Pms.DataAccess.Data
|
|||||||
public DbSet<ServiceProjectServiceMapping> ServiceProjectServiceMapping { get; set; }
|
public DbSet<ServiceProjectServiceMapping> ServiceProjectServiceMapping { get; set; }
|
||||||
public DbSet<TeamRoleMaster> TeamRoleMasters { get; set; }
|
public DbSet<TeamRoleMaster> TeamRoleMasters { get; set; }
|
||||||
public DbSet<ServiceProjectTag> ServiceProjectTags { get; set; }
|
public DbSet<ServiceProjectTag> ServiceProjectTags { get; set; }
|
||||||
|
//public DbSet<TalkingPoint> TalkingPoints { get; set; }
|
||||||
|
//public DbSet<TalkingPointAttachment> TalkingPointAttachments { get; set; }
|
||||||
public DbSet<ServiceProjectTagMapping> ServiceProjectTagMappings { get; set; }
|
public DbSet<ServiceProjectTagMapping> ServiceProjectTagMappings { get; set; }
|
||||||
public DbSet<ServiceProjectAllocation> ServiceProjectAllocations { get; set; }
|
public DbSet<ServiceProjectAllocation> ServiceProjectAllocations { get; set; }
|
||||||
|
|
||||||
|
#region ======================================================= Project Branch =======================================================
|
||||||
|
public DbSet<ProjectBranch> ProjectBranches { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region ======================================================= Job =======================================================
|
#region ======================================================= Job =======================================================
|
||||||
public DbSet<JobTicket> JobTickets { get; set; }
|
public DbSet<JobTicket> JobTickets { get; set; }
|
||||||
public DbSet<JobStatus> JobStatus { get; set; }
|
public DbSet<JobStatus> JobStatus { get; set; }
|
||||||
@ -1280,8 +1286,8 @@ namespace Marco.Pms.DataAccess.Data
|
|||||||
new JobStatus { Id = Guid.Parse("32d76a02-8f44-4aa0-9b66-c3716c45a918"), Name = "New", DisplayName = "New", Level = 1 },
|
new JobStatus { Id = Guid.Parse("32d76a02-8f44-4aa0-9b66-c3716c45a918"), Name = "New", DisplayName = "New", Level = 1 },
|
||||||
new JobStatus { Id = Guid.Parse("cfa1886d-055f-4ded-84c6-42a2a8a14a66"), Name = "Assigned", DisplayName = "Assigned", Level = 2 },
|
new JobStatus { Id = Guid.Parse("cfa1886d-055f-4ded-84c6-42a2a8a14a66"), Name = "Assigned", DisplayName = "Assigned", Level = 2 },
|
||||||
new JobStatus { Id = Guid.Parse("5a6873a5-fed7-4745-a52f-8f61bf3bd72d"), Name = "In Progress", DisplayName = "In Progress", Level = 3 },
|
new JobStatus { Id = Guid.Parse("5a6873a5-fed7-4745-a52f-8f61bf3bd72d"), Name = "In Progress", DisplayName = "In Progress", Level = 3 },
|
||||||
new JobStatus { Id = Guid.Parse("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"), Name = "Review", DisplayName = "Review", Level = 4 },
|
new JobStatus { Id = Guid.Parse("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"), Name = "Work Done", DisplayName = "Work Done", Level = 4 },
|
||||||
new JobStatus { Id = Guid.Parse("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"), Name = "Done", DisplayName = "Done", Level = 5 },
|
new JobStatus { Id = Guid.Parse("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"), Name = "Review Done", DisplayName = "Review Done", Level = 5 },
|
||||||
new JobStatus { Id = Guid.Parse("3ddeefb5-ae3c-4e10-a922-35e0a452bb69"), Name = "Closed", DisplayName = "Closed", Level = 6 },
|
new JobStatus { Id = Guid.Parse("3ddeefb5-ae3c-4e10-a922-35e0a452bb69"), Name = "Closed", DisplayName = "Closed", Level = 6 },
|
||||||
new JobStatus { Id = Guid.Parse("75a0c8b8-9c6a-41af-80bf-b35bab722eb2"), Name = "On Hold", DisplayName = "On Hold", Level = 7 }
|
new JobStatus { Id = Guid.Parse("75a0c8b8-9c6a-41af-80bf-b35bab722eb2"), Name = "On Hold", DisplayName = "On Hold", Level = 7 }
|
||||||
);
|
);
|
||||||
|
|||||||
8895
Marco.Pms.DataAccess/Migrations/20251119065548_Added_ProjectBranches_Table.Designer.cs
generated
Normal file
8895
Marco.Pms.DataAccess/Migrations/20251119065548_Added_ProjectBranches_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,122 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_ProjectBranches_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Projects",
|
||||||
|
keyColumn: "ContactPerson",
|
||||||
|
keyValue: null,
|
||||||
|
column: "ContactPerson",
|
||||||
|
value: "");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "ContactPerson",
|
||||||
|
table: "Projects",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext",
|
||||||
|
oldNullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProjectBranches",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
BranchName = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
ProjectId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
ContactInformation = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Address = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
BranchType = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
GoogleMapUrl = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
IsActive = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
CreatedById = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||||
|
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_ProjectBranches", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProjectBranches_Employees_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProjectBranches_Employees_UpdatedById",
|
||||||
|
column: x => x.UpdatedById,
|
||||||
|
principalTable: "Employees",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProjectBranches_ServiceProjects_ProjectId",
|
||||||
|
column: x => x.ProjectId,
|
||||||
|
principalTable: "ServiceProjects",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProjectBranches_Tenants_TenantId",
|
||||||
|
column: x => x.TenantId,
|
||||||
|
principalTable: "Tenants",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProjectBranches_CreatedById",
|
||||||
|
table: "ProjectBranches",
|
||||||
|
column: "CreatedById");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProjectBranches_ProjectId",
|
||||||
|
table: "ProjectBranches",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProjectBranches_TenantId",
|
||||||
|
table: "ProjectBranches",
|
||||||
|
column: "TenantId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProjectBranches_UpdatedById",
|
||||||
|
table: "ProjectBranches",
|
||||||
|
column: "UpdatedById");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProjectBranches");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "ContactPerson",
|
||||||
|
table: "Projects",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext")
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_ProjectBranch_As_ForignKey_In_JobTickets_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ProjectBranchId",
|
||||||
|
table: "JobTickets",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: true,
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "JobStatus",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
|
||||||
|
columns: new[] { "DisplayName", "Name" },
|
||||||
|
values: new object[] { "Work Done", "Work Done" });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "JobStatus",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
|
||||||
|
columns: new[] { "DisplayName", "Name" },
|
||||||
|
values: new object[] { "Review Done", "Review Done" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_JobTickets_ProjectBranchId",
|
||||||
|
table: "JobTickets",
|
||||||
|
column: "ProjectBranchId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_JobTickets_ProjectBranches_ProjectBranchId",
|
||||||
|
table: "JobTickets",
|
||||||
|
column: "ProjectBranchId",
|
||||||
|
principalTable: "ProjectBranches",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_JobTickets_ProjectBranches_ProjectBranchId",
|
||||||
|
table: "JobTickets");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_JobTickets_ProjectBranchId",
|
||||||
|
table: "JobTickets");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ProjectBranchId",
|
||||||
|
table: "JobTickets");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "JobStatus",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
|
||||||
|
columns: new[] { "DisplayName", "Name" },
|
||||||
|
values: new object[] { "Review", "Review" });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "JobStatus",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
|
||||||
|
columns: new[] { "DisplayName", "Name" },
|
||||||
|
values: new object[] { "Done", "Done" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8909
Marco.Pms.DataAccess/Migrations/20251120051203_Added_IsArchive_In_JobTicket_Table.Designer.cs
generated
Normal file
8909
Marco.Pms.DataAccess/Migrations/20251120051203_Added_IsArchive_In_JobTicket_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_IsArchive_In_JobTicket_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsArchive",
|
||||||
|
table: "JobTickets",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsArchive",
|
||||||
|
table: "JobTickets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8899
Marco.Pms.DataAccess/Migrations/20251120111120_Removed_Project_ForignKey_From_Expenses_Table.Designer.cs
generated
Normal file
8899
Marco.Pms.DataAccess/Migrations/20251120111120_Removed_Project_ForignKey_From_Expenses_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Removed_Project_ForignKey_From_Expenses_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Expenses_Projects_ProjectId",
|
||||||
|
table: "Expenses");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Expenses_ProjectId",
|
||||||
|
table: "Expenses");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Expenses_ProjectId",
|
||||||
|
table: "Expenses",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Expenses_Projects_ProjectId",
|
||||||
|
table: "Expenses",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Removed_Project_ForignKey_From_PaymentRequest_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_PaymentRequests_Projects_ProjectId",
|
||||||
|
table: "PaymentRequests");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_PaymentRequests_ProjectId",
|
||||||
|
table: "PaymentRequests");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PaymentRequests_ProjectId",
|
||||||
|
table: "PaymentRequests",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_PaymentRequests_Projects_ProjectId",
|
||||||
|
table: "PaymentRequests",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Removed_Project_ForignKey_From_RecurringPayment_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_RecurringPayments_Projects_ProjectId",
|
||||||
|
table: "RecurringPayments");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_RecurringPayments_ProjectId",
|
||||||
|
table: "RecurringPayments");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_RecurringPayments_ProjectId",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_RecurringPayments_Projects_ProjectId",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Removed_Project_ForignKey_From_ProjectContactMapping_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ContactProjectMappings_Projects_ProjectId",
|
||||||
|
table: "ContactProjectMappings");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ContactProjectMappings_ProjectId",
|
||||||
|
table: "ContactProjectMappings");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ContactProjectMappings_ProjectId",
|
||||||
|
table: "ContactProjectMappings",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ContactProjectMappings_Projects_ProjectId",
|
||||||
|
table: "ContactProjectMappings",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8873
Marco.Pms.DataAccess/Migrations/20251125072208_Corrected_JobTicketId_Spelling_In_JobAttendance.Designer.cs
generated
Normal file
8873
Marco.Pms.DataAccess/Migrations/20251125072208_Corrected_JobTicketId_Spelling_In_JobAttendance.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,106 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Corrected_JobTicketId_Spelling_In_JobAttendance : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_JobAttendance_JobTickets_JobTcketId",
|
||||||
|
table: "JobAttendance");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_JobAttendanceLogs_JobTickets_JobTcketId",
|
||||||
|
table: "JobAttendanceLogs");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "JobTcketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
newName: "JobTicketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_JobAttendanceLogs_JobTcketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
newName: "IX_JobAttendanceLogs_JobTicketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "JobTcketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
newName: "JobTicketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_JobAttendance_JobTcketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
newName: "IX_JobAttendance_JobTicketId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_JobAttendance_JobTickets_JobTicketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
column: "JobTicketId",
|
||||||
|
principalTable: "JobTickets",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_JobAttendanceLogs_JobTickets_JobTicketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
column: "JobTicketId",
|
||||||
|
principalTable: "JobTickets",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_JobAttendance_JobTickets_JobTicketId",
|
||||||
|
table: "JobAttendance");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_JobAttendanceLogs_JobTickets_JobTicketId",
|
||||||
|
table: "JobAttendanceLogs");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "JobTicketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
newName: "JobTcketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_JobAttendanceLogs_JobTicketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
newName: "IX_JobAttendanceLogs_JobTcketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "JobTicketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
newName: "JobTcketId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_JobAttendance_JobTicketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
newName: "IX_JobAttendance_JobTcketId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_JobAttendance_JobTickets_JobTcketId",
|
||||||
|
table: "JobAttendance",
|
||||||
|
column: "JobTcketId",
|
||||||
|
principalTable: "JobTickets",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_JobAttendanceLogs_JobTickets_JobTcketId",
|
||||||
|
table: "JobAttendanceLogs",
|
||||||
|
column: "JobTcketId",
|
||||||
|
principalTable: "JobTickets",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -898,8 +898,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ContactId");
|
b.HasIndex("ContactId");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
b.ToTable("ContactProjectMappings");
|
b.ToTable("ContactProjectMappings");
|
||||||
@ -2329,8 +2327,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProcessedById");
|
b.HasIndex("ProcessedById");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
|
||||||
|
|
||||||
b.HasIndex("ReviewedById");
|
b.HasIndex("ReviewedById");
|
||||||
|
|
||||||
b.HasIndex("StatusId");
|
b.HasIndex("StatusId");
|
||||||
@ -2798,8 +2794,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("PaidById");
|
b.HasIndex("PaidById");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
|
||||||
|
|
||||||
b.HasIndex("RecurringPaymentId");
|
b.HasIndex("RecurringPaymentId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
@ -2926,8 +2920,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ExpenseCategoryId");
|
b.HasIndex("ExpenseCategoryId");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
|
||||||
|
|
||||||
b.HasIndex("StatusId");
|
b.HasIndex("StatusId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
@ -4799,6 +4791,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<string>("ContactPerson")
|
b.Property<string>("ContactPerson")
|
||||||
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<DateTime?>("EndDate")
|
b.Property<DateTime?>("EndDate")
|
||||||
@ -5061,7 +5054,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<Guid>("EmployeeId")
|
b.Property<Guid>("EmployeeId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<Guid>("JobTcketId")
|
b.Property<Guid>("JobTicketId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<DateTime>("TaggedInAt")
|
b.Property<DateTime>("TaggedInAt")
|
||||||
@ -5083,7 +5076,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("EmployeeId");
|
b.HasIndex("EmployeeId");
|
||||||
|
|
||||||
b.HasIndex("JobTcketId");
|
b.HasIndex("JobTicketId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
@ -5111,7 +5104,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<Guid>("JobAttendanceId")
|
b.Property<Guid>("JobAttendanceId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<Guid>("JobTcketId")
|
b.Property<Guid>("JobTicketId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<string>("Latitude")
|
b.Property<string>("Latitude")
|
||||||
@ -5137,7 +5130,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("JobAttendanceId");
|
b.HasIndex("JobAttendanceId");
|
||||||
|
|
||||||
b.HasIndex("JobTcketId");
|
b.HasIndex("JobTicketId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
@ -5260,16 +5253,16 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
|
Id = new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
|
||||||
DisplayName = "Review",
|
DisplayName = "Work Done",
|
||||||
Level = 4,
|
Level = 4,
|
||||||
Name = "Review"
|
Name = "Work Done"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
|
Id = new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
|
||||||
DisplayName = "Done",
|
DisplayName = "Review Done",
|
||||||
Level = 5,
|
Level = 5,
|
||||||
Name = "Done"
|
Name = "Review Done"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
@ -5493,6 +5486,12 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<bool>("IsActive")
|
b.Property<bool>("IsActive")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsArchive")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ProjectBranchId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<Guid>("ProjectId")
|
b.Property<Guid>("ProjectId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
@ -5526,6 +5525,8 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("CreatedById");
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectBranchId");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.HasIndex("StatusId");
|
b.HasIndex("StatusId");
|
||||||
@ -5537,6 +5538,65 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.ToTable("JobTickets");
|
b.ToTable("JobTickets");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ProjectBranch", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("BranchName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("BranchType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ContactInformation")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<Guid>("CreatedById")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleMapUrl")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<Guid>("TenantId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UpdatedById")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("UpdatedById");
|
||||||
|
|
||||||
|
b.ToTable("ProjectBranches");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ServiceProject", b =>
|
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ServiceProject", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@ -6803,12 +6863,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ProjectId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("TenantId")
|
.HasForeignKey("TenantId")
|
||||||
@ -6817,8 +6871,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("Contact");
|
b.Navigation("Contact");
|
||||||
|
|
||||||
b.Navigation("Project");
|
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -7310,12 +7362,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ProcessedById");
|
.HasForeignKey("ProcessedById");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ProjectId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "ReviewedBy")
|
b.HasOne("Marco.Pms.Model.Employees.Employee", "ReviewedBy")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ReviewedById");
|
.HasForeignKey("ReviewedById");
|
||||||
@ -7348,8 +7394,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("ProcessedBy");
|
b.Navigation("ProcessedBy");
|
||||||
|
|
||||||
b.Navigation("Project");
|
|
||||||
|
|
||||||
b.Navigation("ReviewedBy");
|
b.Navigation("ReviewedBy");
|
||||||
|
|
||||||
b.Navigation("Status");
|
b.Navigation("Status");
|
||||||
@ -7480,10 +7524,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("PaidById");
|
.HasForeignKey("PaidById");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ProjectId");
|
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Expenses.RecurringPayment", "RecurringPayment")
|
b.HasOne("Marco.Pms.Model.Expenses.RecurringPayment", "RecurringPayment")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("RecurringPaymentId");
|
.HasForeignKey("RecurringPaymentId");
|
||||||
@ -7508,8 +7548,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("PaidBy");
|
b.Navigation("PaidBy");
|
||||||
|
|
||||||
b.Navigation("Project");
|
|
||||||
|
|
||||||
b.Navigation("RecurringPayment");
|
b.Navigation("RecurringPayment");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
@ -7562,10 +7600,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ExpenseCategoryId");
|
.HasForeignKey("ExpenseCategoryId");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ProjectId");
|
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Expenses.Masters.RecurringPaymentStatus", "Status")
|
b.HasOne("Marco.Pms.Model.Expenses.Masters.RecurringPaymentStatus", "Status")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("StatusId")
|
.HasForeignKey("StatusId")
|
||||||
@ -7588,8 +7622,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("ExpenseCategory");
|
b.Navigation("ExpenseCategory");
|
||||||
|
|
||||||
b.Navigation("Project");
|
|
||||||
|
|
||||||
b.Navigation("Status");
|
b.Navigation("Status");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
@ -8221,7 +8253,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.ServiceProject.JobTicket", "JobTicket")
|
b.HasOne("Marco.Pms.Model.ServiceProject.JobTicket", "JobTicket")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("JobTcketId")
|
.HasForeignKey("JobTicketId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
@ -8258,7 +8290,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.ServiceProject.JobTicket", "JobTicket")
|
b.HasOne("Marco.Pms.Model.ServiceProject.JobTicket", "JobTicket")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("JobTcketId")
|
.HasForeignKey("JobTicketId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
@ -8418,6 +8450,10 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.ServiceProject.ProjectBranch", "ProjectBranch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectBranchId");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.ServiceProject.ServiceProject", "Project")
|
b.HasOne("Marco.Pms.Model.ServiceProject.ServiceProject", "Project")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ProjectId")
|
.HasForeignKey("ProjectId")
|
||||||
@ -8444,6 +8480,8 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("Project");
|
b.Navigation("Project");
|
||||||
|
|
||||||
|
b.Navigation("ProjectBranch");
|
||||||
|
|
||||||
b.Navigation("Status");
|
b.Navigation("Status");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
@ -8451,6 +8489,39 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Navigation("UpdatedBy");
|
b.Navigation("UpdatedBy");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ProjectBranch", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.ServiceProject.ServiceProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TenantId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UpdatedById");
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
|
||||||
|
b.Navigation("Tenant");
|
||||||
|
|
||||||
|
b.Navigation("UpdatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ServiceProject", b =>
|
modelBuilder.Entity("Marco.Pms.Model.ServiceProject.ServiceProject", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Marco.Pms.Model.OrganizationModel.Organization", "Client")
|
b.HasOne("Marco.Pms.Model.OrganizationModel.Organization", "Client")
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.Projects;
|
|
||||||
using Marco.Pms.Model.Utilities;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Directory
|
namespace Marco.Pms.Model.Directory
|
||||||
{
|
{
|
||||||
@ -9,9 +8,6 @@ namespace Marco.Pms.Model.Directory
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid ProjectId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
[ValidateNever]
|
|
||||||
[ForeignKey("ProjectId")]
|
|
||||||
public Project? Project { get; set; }
|
|
||||||
public Guid ContactId { get; set; }
|
public Guid ContactId { get; set; }
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("ContactId")]
|
[ForeignKey("ContactId")]
|
||||||
|
|||||||
@ -8,6 +8,7 @@ namespace Marco.Pms.Model.Dtos.ServiceProject
|
|||||||
public required string Title { get; set; }
|
public required string Title { get; set; }
|
||||||
public required string Description { get; set; }
|
public required string Description { get; set; }
|
||||||
public required Guid ProjectId { get; set; }
|
public required Guid ProjectId { get; set; }
|
||||||
|
public Guid? ProjectBranchId { get; set; }
|
||||||
public List<BasicEmployeeDto>? Assignees { get; set; }
|
public List<BasicEmployeeDto>? Assignees { get; set; }
|
||||||
public required DateTime StartDate { get; set; }
|
public required DateTime StartDate { get; set; }
|
||||||
public required DateTime DueDate { get; set; }
|
public required DateTime DueDate { get; set; }
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace Marco.Pms.Model.Dtos.ServiceProject
|
|||||||
{
|
{
|
||||||
public class JobAttendanceDto
|
public class JobAttendanceDto
|
||||||
{
|
{
|
||||||
public required Guid JobTcketId { get; set; }
|
public required Guid JobTicketId { get; set; }
|
||||||
public required TAGGING_MARK_TYPE Action { get; set; }
|
public required TAGGING_MARK_TYPE Action { get; set; }
|
||||||
public string? Latitude { get; set; }
|
public string? Latitude { get; set; }
|
||||||
public string? Longitude { get; set; }
|
public string? Longitude { get; set; }
|
||||||
|
|||||||
13
Marco.Pms.Model/Dtos/ServiceProject/ProjectBranchDto.cs
Normal file
13
Marco.Pms.Model/Dtos/ServiceProject/ProjectBranchDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.ServiceProject
|
||||||
|
{
|
||||||
|
public class ProjectBranchDto
|
||||||
|
{
|
||||||
|
public Guid? Id { get; set; }
|
||||||
|
public required string BranchName { get; set; }
|
||||||
|
public required Guid ProjectId { get; set; }
|
||||||
|
public required string ContactInformation { get; set; }
|
||||||
|
public required string Address { get; set; }
|
||||||
|
public required string BranchType { get; set; } // HQ, ATMs, Bank Branches, Overcounter desk
|
||||||
|
public string? GoogleMapUrl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Marco.Pms.Model/Dtos/ServiceProject/TalkingPointDto.cs
Normal file
12
Marco.Pms.Model/Dtos/ServiceProject/TalkingPointDto.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.Dtos.ServiceProject
|
||||||
|
{
|
||||||
|
public class TalkingPointDto
|
||||||
|
{
|
||||||
|
public Guid? Id { get; set; }
|
||||||
|
public required Guid ServiceProjectId { get; set; }
|
||||||
|
public required string Comment { get; set; }
|
||||||
|
public List<FileUploadModel>? Attachments { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,11 +7,11 @@ namespace Marco.Pms.Model.Dtos.ServiceProject
|
|||||||
{
|
{
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public Guid ProjectId { get; set; }
|
|
||||||
public Guid StatusId { get; set; }
|
public Guid StatusId { get; set; }
|
||||||
public List<BasicEmployeeDto>? Assignees { get; set; }
|
public List<BasicEmployeeDto>? Assignees { get; set; }
|
||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public List<TagDto>? Tags { get; set; }
|
public List<TagDto>? Tags { get; set; }
|
||||||
|
public bool IsArchive { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Expenses.Masters;
|
using Marco.Pms.Model.Expenses.Masters;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Projects;
|
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@ -14,10 +13,6 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public string UIDPrefix { get; set; } = default!;
|
public string UIDPrefix { get; set; } = default!;
|
||||||
public int UIDPostfix { get; set; }
|
public int UIDPostfix { get; set; }
|
||||||
public Guid ProjectId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
|
||||||
[ForeignKey("ProjectId")]
|
|
||||||
public Project? Project { get; set; }
|
|
||||||
public Guid ExpensesTypeId { get; set; }
|
public Guid ExpensesTypeId { get; set; }
|
||||||
|
|
||||||
//[ValidateNever]
|
//[ValidateNever]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Expenses.Masters;
|
using Marco.Pms.Model.Expenses.Masters;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Projects;
|
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@ -28,10 +27,6 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public double? TDSPercentage { get; set; }
|
public double? TDSPercentage { get; set; }
|
||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public Guid? ProjectId { get; set; }
|
public Guid? ProjectId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
|
||||||
[ForeignKey("ProjectId")]
|
|
||||||
public Project? Project { get; set; }
|
|
||||||
public Guid? RecurringPaymentId { get; set; }
|
public Guid? RecurringPaymentId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Expenses.Masters;
|
using Marco.Pms.Model.Expenses.Masters;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Projects;
|
|
||||||
using Marco.Pms.Model.TenantModels;
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
@ -29,10 +28,6 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public DateTime? LatestPRGeneratedAt { get; set; }
|
public DateTime? LatestPRGeneratedAt { get; set; }
|
||||||
public DateTime? NextStrikeDate { get; set; }
|
public DateTime? NextStrikeDate { get; set; }
|
||||||
public Guid? ProjectId { get; set; }
|
public Guid? ProjectId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
|
||||||
[ForeignKey("ProjectId")]
|
|
||||||
public Project? Project { get; set; }
|
|
||||||
public int PaymentBufferDays { get; set; }
|
public int PaymentBufferDays { get; set; }
|
||||||
public Guid? ExpenseCategoryId { get; set; }
|
public Guid? ExpenseCategoryId { get; set; }
|
||||||
|
|
||||||
|
|||||||
11
Marco.Pms.Model/Filters/AdvanceFilter.cs
Normal file
11
Marco.Pms.Model/Filters/AdvanceFilter.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.Filters
|
||||||
|
{
|
||||||
|
public class AdvanceFilter
|
||||||
|
{
|
||||||
|
// The dynamic filters from your JSON
|
||||||
|
public List<SortItem>? SortFilters { get; set; }
|
||||||
|
public List<SearchItem>? SearchFilters { get; set; }
|
||||||
|
public List<AdvanceItem>? AdvanceFilters { get; set; }
|
||||||
|
public string GroupByColumn { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Marco.Pms.Model/Filters/AdvanceItem.cs
Normal file
9
Marco.Pms.Model/Filters/AdvanceItem.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Filters
|
||||||
|
{
|
||||||
|
public class AdvanceItem
|
||||||
|
{
|
||||||
|
public string Column { get; set; } = string.Empty;
|
||||||
|
public string Opration { get; set; } = string.Empty; // "greater than", "equal to", etc.
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Marco.Pms.Model/Filters/SearchItem.cs
Normal file
8
Marco.Pms.Model/Filters/SearchItem.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Filters
|
||||||
|
{
|
||||||
|
public class SearchItem
|
||||||
|
{
|
||||||
|
public string Column { get; set; } = string.Empty;
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Marco.Pms.Model/Filters/SortItem.cs
Normal file
8
Marco.Pms.Model/Filters/SortItem.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Marco.Pms.Model.Filters
|
||||||
|
{
|
||||||
|
public class SortItem
|
||||||
|
{
|
||||||
|
public string Column { get; set; } = string.Empty;
|
||||||
|
public bool SortDescending { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ namespace Marco.Pms.Model.Projects
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
[DisplayName("Project Name")]
|
[DisplayName("Project Name")]
|
||||||
public string? Name { get; set; }
|
public string Name { get; set; } = string.Empty;
|
||||||
public string? ShortName { get; set; }
|
public string? ShortName { get; set; }
|
||||||
|
|
||||||
[DisplayName("Project Address")]
|
[DisplayName("Project Address")]
|
||||||
@ -22,7 +22,7 @@ namespace Marco.Pms.Model.Projects
|
|||||||
|
|
||||||
[DisplayName("Contact Person")]
|
[DisplayName("Contact Person")]
|
||||||
|
|
||||||
public string? ContactPerson { get; set; }
|
public string ContactPerson { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
|
|||||||
@ -8,10 +8,10 @@ namespace Marco.Pms.Model.ServiceProject
|
|||||||
public class JobAttendance : TenantRelation
|
public class JobAttendance : TenantRelation
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid JobTcketId { get; set; }
|
public Guid JobTicketId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("JobTcketId")]
|
[ForeignKey("JobTicketId")]
|
||||||
public JobTicket? JobTicket { get; set; }
|
public JobTicket? JobTicket { get; set; }
|
||||||
public TAGGING_MARK_TYPE Action { get; set; }
|
public TAGGING_MARK_TYPE Action { get; set; }
|
||||||
public Guid EmployeeId { get; set; }
|
public Guid EmployeeId { get; set; }
|
||||||
|
|||||||
@ -14,10 +14,10 @@ namespace Marco.Pms.Model.ServiceProject
|
|||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("JobAttendanceId")]
|
[ForeignKey("JobAttendanceId")]
|
||||||
public JobAttendance? JobAttendance { get; set; }
|
public JobAttendance? JobAttendance { get; set; }
|
||||||
public Guid JobTcketId { get; set; }
|
public Guid JobTicketId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("JobTcketId")]
|
[ForeignKey("JobTicketId")]
|
||||||
public JobTicket? JobTicket { get; set; }
|
public JobTicket? JobTicket { get; set; }
|
||||||
public Guid? DocumentId { get; set; }
|
public Guid? DocumentId { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,11 @@ namespace Marco.Pms.Model.ServiceProject
|
|||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("ProjectId")]
|
[ForeignKey("ProjectId")]
|
||||||
public ServiceProject? Project { get; set; }
|
public ServiceProject? Project { get; set; }
|
||||||
|
public Guid? ProjectBranchId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("ProjectBranchId")]
|
||||||
|
public ProjectBranch? ProjectBranch { get; set; }
|
||||||
public Guid StatusId { get; set; }
|
public Guid StatusId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
@ -25,6 +30,7 @@ namespace Marco.Pms.Model.ServiceProject
|
|||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public bool IsActive { get; set; } = true;
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsArchive { get; set; } = false;
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public Guid CreatedById { get; set; }
|
public Guid CreatedById { get; set; }
|
||||||
|
|
||||||
|
|||||||
35
Marco.Pms.Model/ServiceProject/ProjectBranch.cs
Normal file
35
Marco.Pms.Model/ServiceProject/ProjectBranch.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ServiceProject
|
||||||
|
{
|
||||||
|
public class ProjectBranch : TenantRelation
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string BranchName { get; set; } = string.Empty;
|
||||||
|
public Guid ProjectId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("ProjectId")]
|
||||||
|
public ServiceProject? Project { get; set; }
|
||||||
|
public string ContactInformation { get; set; } = string.Empty; // Json string
|
||||||
|
public string Address { get; set; } = string.Empty;
|
||||||
|
public string BranchType { get; set; } = string.Empty; // HQ, ATMs, Bank Branches, Overcounter desk
|
||||||
|
public string? GoogleMapUrl { get; set; }
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public Guid CreatedById { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("CreatedById")]
|
||||||
|
public Employee? CreatedBy { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public Guid? UpdatedById { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("UpdatedById")]
|
||||||
|
public Employee? UpdatedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Marco.Pms.Model/ServiceProject/TalkingPoint.cs
Normal file
31
Marco.Pms.Model/ServiceProject/TalkingPoint.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ServiceProject
|
||||||
|
{
|
||||||
|
public class TalkingPoint : TenantRelation
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid ServiceProjectId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("ServiceProjectId")]
|
||||||
|
public ServiceProject? ServiceProject { get; set; }
|
||||||
|
public string Comment { get; set; } = string.Empty;
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public Guid CreatedById { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("CreatedById")]
|
||||||
|
public Employee? CreatedBy { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public Guid? UpdatedById { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("UpdatedById")]
|
||||||
|
public Employee? UpdatedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
22
Marco.Pms.Model/ServiceProject/TalkingPointAttachment.cs
Normal file
22
Marco.Pms.Model/ServiceProject/TalkingPointAttachment.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Marco.Pms.Model.DocumentManager;
|
||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ServiceProject
|
||||||
|
{
|
||||||
|
public class TalkingPointAttachment : TenantRelation
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid DocumentId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("DocumentId")]
|
||||||
|
public Document? Document { get; set; }
|
||||||
|
public Guid? TalkingPointId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("TalkingPointId")]
|
||||||
|
public TalkingPoint? TalkingPoint { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ namespace Marco.Pms.Model.ViewModels.Expenses
|
|||||||
public class ExpenseDetailsVM
|
public class ExpenseDetailsVM
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public ProjectInfoVM? Project { get; set; }
|
public BasicProjectVM? Project { get; set; }
|
||||||
public ExpenseCategoryMasterVM? ExpenseCategory { get; set; }
|
public ExpenseCategoryMasterVM? ExpenseCategory { get; set; }
|
||||||
public PaymentModeMatserVM? PaymentMode { get; set; }
|
public PaymentModeMatserVM? PaymentMode { get; set; }
|
||||||
public BasicEmployeeVM? PaidBy { get; set; }
|
public BasicEmployeeVM? PaidBy { get; set; }
|
||||||
|
|||||||
@ -9,7 +9,7 @@ namespace Marco.Pms.Model.ViewModels.Expanses
|
|||||||
public class ExpenseList
|
public class ExpenseList
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public ProjectInfoVM? Project { get; set; }
|
public BasicProjectVM? Project { get; set; }
|
||||||
public ExpenseCategoryMasterVM? ExpenseCategory { get; set; }
|
public ExpenseCategoryMasterVM? ExpenseCategory { get; set; }
|
||||||
public PaymentModeMatserVM? PaymentMode { get; set; }
|
public PaymentModeMatserVM? PaymentMode { get; set; }
|
||||||
public BasicEmployeeVM? PaidBy { get; set; }
|
public BasicEmployeeVM? PaidBy { get; set; }
|
||||||
|
|||||||
@ -7,5 +7,6 @@
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public string? JobTicketUId { get; set; }
|
public string? JobTicketUId { get; set; }
|
||||||
public string? StatusName { get; set; }
|
public string? StatusName { get; set; }
|
||||||
|
public bool IsArchive { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.ServiceProject
|
||||||
|
{
|
||||||
|
public class BasicProjectBranchVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? BranchName { get; set; }
|
||||||
|
public string? BranchType { get; set; } // HQ, ATMs, Bank Branches, Overcounter desk
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,8 +6,5 @@
|
|||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public string? ShortName { get; set; }
|
public string? ShortName { get; set; }
|
||||||
public DateTime AssignedDate { get; set; }
|
public DateTime AssignedDate { get; set; }
|
||||||
public string? ContactName { get; set; }
|
|
||||||
public string? ContactPhone { get; set; }
|
|
||||||
public string? ContactEmail { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,13 @@ namespace Marco.Pms.Model.ViewModels.ServiceProject
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public string? JobTicketUId { get; set; }
|
public string? JobTicketUId { get; set; }
|
||||||
public BasicServiceProjectVM? Project { get; set; }
|
public BasicServiceProjectVM? Project { get; set; }
|
||||||
|
public BasicProjectBranchVM? ProjectBranch { get; set; }
|
||||||
public List<BasicEmployeeVM>? Assignees { get; set; }
|
public List<BasicEmployeeVM>? Assignees { get; set; }
|
||||||
public JobStatus? Status { get; set; }
|
public JobStatus? Status { get; set; }
|
||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
public bool IsArchive { get; set; }
|
||||||
public Guid? AttendanceId { get; set; }
|
public Guid? AttendanceId { get; set; }
|
||||||
public TAGGING_MARK_TYPE? TaggingAction { get; set; }
|
public TAGGING_MARK_TYPE? TaggingAction { get; set; }
|
||||||
public TAGGING_MARK_TYPE? NextTaggingAction { get; set; }
|
public TAGGING_MARK_TYPE? NextTaggingAction { get; set; }
|
||||||
|
|||||||
@ -16,6 +16,7 @@ namespace Marco.Pms.Model.ViewModels.ServiceProject
|
|||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
public bool IsArchive { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
public List<TagVM>? Tags { get; set; }
|
public List<TagVM>? Tags { get; set; }
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.ServiceProject
|
||||||
|
{
|
||||||
|
public class ProjectBranchDetailsVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? BranchName { get; set; }
|
||||||
|
public BasicServiceProjectVM? Project { get; set; }
|
||||||
|
public string? ContactInformation { get; set; } // Json string
|
||||||
|
public string? Address { get; set; }
|
||||||
|
public string? BranchType { get; set; } // HQ, ATMs, Bank Branches, Overcounter desk
|
||||||
|
public string? GoogleMapUrl { get; set; }
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? UpdatedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Marco.Pms.Model/ViewModels/ServiceProject/ProjectBranchVM.cs
Normal file
16
Marco.Pms.Model/ViewModels/ServiceProject/ProjectBranchVM.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.ServiceProject
|
||||||
|
{
|
||||||
|
public class ProjectBranchVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? BranchName { get; set; }
|
||||||
|
public BasicServiceProjectVM? Project { get; set; }
|
||||||
|
public string? ContactInformation { get; set; } // Json string
|
||||||
|
public string? Address { get; set; }
|
||||||
|
public string? BranchType { get; set; } // HQ, ATMs, Bank Branches, Overcounter desk
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Marco.Pms.Model/ViewModels/ServiceProject/TalkingPointVM.cs
Normal file
18
Marco.Pms.Model/ViewModels/ServiceProject/TalkingPointVM.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.ServiceProject
|
||||||
|
{
|
||||||
|
public class TalkingPointVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public BasicServiceProjectVM? ServiceProject { get; set; }
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? UpdatedBy { get; set; }
|
||||||
|
public List<DocumentVM>? Attachments { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -474,7 +474,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var _employeeHelper = scope.ServiceProvider.GetRequiredService<EmployeeHelper>();
|
var _employeeHelper = scope.ServiceProvider.GetRequiredService<EmployeeHelper>();
|
||||||
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();
|
||||||
|
|
||||||
var currentEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -517,7 +517,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
{
|
{
|
||||||
attendance.OutTime = finalDateTime;
|
attendance.OutTime = finalDateTime;
|
||||||
attendance.Activity = ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE;
|
attendance.Activity = ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE;
|
||||||
attendance.RequestedById = currentEmployee.Id;
|
attendance.RequestedById = loggedInEmployee.Id;
|
||||||
attendance.RequestedAt = DateTime.UtcNow;
|
attendance.RequestedAt = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -531,7 +531,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
{
|
{
|
||||||
attendance.IsApproved = true;
|
attendance.IsApproved = true;
|
||||||
attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
|
attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
|
||||||
attendance.ApprovedById = currentEmployee.Id;
|
attendance.ApprovedById = loggedInEmployee.Id;
|
||||||
attendance.ApprovedAt = DateTime.UtcNow;
|
attendance.ApprovedAt = DateTime.UtcNow;
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
@ -539,7 +539,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
{
|
{
|
||||||
attendance.IsApproved = false;
|
attendance.IsApproved = false;
|
||||||
attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT;
|
attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT;
|
||||||
attendance.ApprovedById = currentEmployee.Id;
|
attendance.ApprovedById = loggedInEmployee.Id;
|
||||||
attendance.ApprovedAt = DateTime.UtcNow;
|
attendance.ApprovedAt = DateTime.UtcNow;
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
@ -584,7 +584,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
Longitude = recordAttendanceDot.Longitude,
|
Longitude = recordAttendanceDot.Longitude,
|
||||||
|
|
||||||
TenantId = tenantId,
|
TenantId = tenantId,
|
||||||
UpdatedBy = currentEmployee.Id,
|
UpdatedBy = loggedInEmployee.Id,
|
||||||
UpdatedOn = recordAttendanceDot.Date
|
UpdatedOn = recordAttendanceDot.Date
|
||||||
};
|
};
|
||||||
//if (recordAttendanceDot.Image != null && recordAttendanceDot.Image.Count > 0)
|
//if (recordAttendanceDot.Image != null && recordAttendanceDot.Image.Count > 0)
|
||||||
@ -619,7 +619,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
{
|
{
|
||||||
sendActivity = 1;
|
sendActivity = 1;
|
||||||
}
|
}
|
||||||
var notification = new { LoggedInUserId = currentEmployee.Id, Keyword = "Attendance", Activity = sendActivity, ProjectId = attendance.ProjectID, Response = vm };
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Attendance", Activity = sendActivity, ProjectId = attendance.ProjectID, Response = vm };
|
||||||
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
|
||||||
_logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
|
_logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
|
||||||
|
|
||||||
@ -628,10 +628,11 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
// --- Push Notification Section ---
|
// --- Push Notification Section ---
|
||||||
// This section attempts to send a test push notification to the user's device.
|
// This section attempts to send a test push notification to the user's device.
|
||||||
// It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.
|
// It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.
|
||||||
|
var context = HttpContext;
|
||||||
|
string origin = context.Request.Headers["Origin"].FirstOrDefault() ?? "";
|
||||||
var name = $"{vm.FirstName} {vm.LastName}";
|
var name = $"{vm.FirstName} {vm.LastName}";
|
||||||
|
|
||||||
await _firebase.SendAttendanceMessageAsync(attendance.ProjectID, name, recordAttendanceDot.Action, attendance.EmployeeId, tenantId);
|
await _firebase.SendAttendanceMessageAsync(attendance.ProjectID, name, recordAttendanceDot.Action, attendance.EmployeeId, origin, loggedInEmployee.Id, tenantId);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -848,10 +849,12 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
// --- Push Notification Section ---
|
// --- Push Notification Section ---
|
||||||
// This section attempts to send a test push notification to the user's device.
|
// This section attempts to send a test push notification to the user's device.
|
||||||
// It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.
|
// It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.
|
||||||
|
var context = HttpContext;
|
||||||
|
string origin = context.Request.Headers["Origin"].FirstOrDefault() ?? "";
|
||||||
|
|
||||||
var name = $"{vm.FirstName} {vm.LastName}";
|
var name = $"{vm.FirstName} {vm.LastName}";
|
||||||
|
|
||||||
await _firebase.SendAttendanceMessageAsync(attendance.ProjectID, name, recordAttendanceDot.Action, attendance.EmployeeId, tenantId);
|
await _firebase.SendAttendanceMessageAsync(attendance.ProjectID, name, recordAttendanceDot.Action, attendance.EmployeeId, origin, loggedInEmployee.Id, tenantId);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using Marco.Pms.Helpers.Utility;
|
|||||||
using Marco.Pms.Model.Collection;
|
using Marco.Pms.Model.Collection;
|
||||||
using Marco.Pms.Model.Dtos.Collection;
|
using Marco.Pms.Model.Dtos.Collection;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
|
using Marco.Pms.Model.Filters;
|
||||||
using Marco.Pms.Model.MongoDBModels.Utility;
|
using Marco.Pms.Model.MongoDBModels.Utility;
|
||||||
using Marco.Pms.Model.OrganizationModel;
|
using Marco.Pms.Model.OrganizationModel;
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Projects;
|
||||||
@ -13,6 +14,7 @@ using Marco.Pms.Model.ViewModels.Activities;
|
|||||||
using Marco.Pms.Model.ViewModels.Collection;
|
using Marco.Pms.Model.ViewModels.Collection;
|
||||||
using Marco.Pms.Model.ViewModels.Organization;
|
using Marco.Pms.Model.ViewModels.Organization;
|
||||||
using Marco.Pms.Model.ViewModels.Projects;
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
|
using Marco.Pms.Services.Extensions;
|
||||||
using Marco.Pms.Services.Service;
|
using Marco.Pms.Services.Service;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
@ -20,7 +22,9 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
using System.Text.Json;
|
||||||
using Document = Marco.Pms.Model.DocumentManager.Document;
|
using Document = Marco.Pms.Model.DocumentManager.Document;
|
||||||
|
using Invoice = Marco.Pms.Model.Collection.Invoice;
|
||||||
|
|
||||||
namespace Marco.Pms.Services.Controllers
|
namespace Marco.Pms.Services.Controllers
|
||||||
{
|
{
|
||||||
@ -59,8 +63,8 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
[HttpGet("invoice/list")]
|
[HttpGet("invoice/list")]
|
||||||
public async Task<IActionResult> GetInvoiceListAsync([FromQuery] Guid? projectId, [FromQuery] string? searchString, [FromQuery] DateTime? fromDate, [FromQuery] DateTime? toDate,
|
public async Task<IActionResult> GetInvoiceListAsync([FromQuery] Guid? projectId, [FromQuery] string? searchString, [FromQuery] string? filter, [FromQuery] DateTime? fromDate,
|
||||||
[FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1, [FromQuery] bool isActive = true, [FromQuery] bool isPending = false)
|
[FromQuery] DateTime? toDate, [FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1, [FromQuery] bool isActive = true, [FromQuery] bool isPending = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -94,16 +98,52 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
_logger.LogInfo("Permissions validated for EmployeeId {EmployeeId}.", employee.Id);
|
_logger.LogInfo("Permissions validated for EmployeeId {EmployeeId}.", employee.Id);
|
||||||
|
|
||||||
|
var advanceFilter = TryDeserializeFilter(filter);
|
||||||
|
|
||||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
||||||
|
// Fetch related project data asynchronously and in parallel
|
||||||
|
var infraProjectsQuery = _context.Projects
|
||||||
|
.Where(p => p.TenantId == tenantId);
|
||||||
|
|
||||||
|
var serviceProjectsQuery = context.ServiceProjects
|
||||||
|
.Where(sp => sp.TenantId == tenantId);
|
||||||
|
|
||||||
|
if (advanceFilter?.SearchFilters != null && advanceFilter.SearchFilters.Any())
|
||||||
|
{
|
||||||
|
var projectSearchFilter = advanceFilter.SearchFilters
|
||||||
|
.Where(f => f.Column == "ProjectName")
|
||||||
|
.Select(f => new SearchItem { Column = "Name", Value = f.Value })
|
||||||
|
.ToList();
|
||||||
|
if (projectSearchFilter.Any())
|
||||||
|
{
|
||||||
|
infraProjectsQuery = infraProjectsQuery.ApplySearchFilters(projectSearchFilter);
|
||||||
|
serviceProjectsQuery = serviceProjectsQuery.ApplySearchFilters(projectSearchFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var infraProjectsTask = infraProjectsQuery
|
||||||
|
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||||
|
.ToListAsync();
|
||||||
|
var serviceProjectsTask = serviceProjectsQuery
|
||||||
|
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectsTask, serviceProjectsTask);
|
||||||
|
|
||||||
|
var projects = infraProjectsTask.Result;
|
||||||
|
projects.AddRange(serviceProjectsTask.Result);
|
||||||
|
|
||||||
|
var projIds = projects.Select(p => p.Id).Distinct().ToList();
|
||||||
|
|
||||||
// Build invoice query efficiently - always use AsNoTracking for reads
|
// Build invoice query efficiently - always use AsNoTracking for reads
|
||||||
var query = _context.Invoices
|
var query = _context.Invoices
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(i => i.BilledTo)
|
.Include(i => i.BilledTo)
|
||||||
.Include(i => i.CreatedBy).ThenInclude(e => e!.JobRole)
|
.Include(i => i.CreatedBy).ThenInclude(e => e!.JobRole)
|
||||||
.Include(i => i.UpdatedBy).ThenInclude(e => e!.JobRole)
|
.Include(i => i.UpdatedBy).ThenInclude(e => e!.JobRole)
|
||||||
.Where(i => i.IsActive == isActive && i.TenantId == tenantId);
|
.Where(i => projIds.Contains(i.ProjectId) && i.IsActive == isActive && i.TenantId == tenantId);
|
||||||
|
|
||||||
// Filter by date, ensuring date boundaries are correct
|
// Filter by date, ensuring date boundaries are correct
|
||||||
if (fromDate.HasValue && toDate.HasValue)
|
if (fromDate.HasValue && toDate.HasValue)
|
||||||
@ -126,11 +166,22 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
_logger.LogDebug("Project filter applied: {ProjectId}", projectId.Value);
|
_logger.LogDebug("Project filter applied: {ProjectId}", projectId.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query = query.ApplyCustomFilters(advanceFilter, "InvoiceDate");
|
||||||
|
|
||||||
|
if (advanceFilter?.SearchFilters != null)
|
||||||
|
{
|
||||||
|
var invoiceSearchFilter = advanceFilter.SearchFilters.Where(f => f.Column != "ProjectName").ToList();
|
||||||
|
if (invoiceSearchFilter.Any())
|
||||||
|
{
|
||||||
|
query = query.ApplySearchFilters(invoiceSearchFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var totalItems = await query.CountAsync();
|
var totalItems = await query.CountAsync();
|
||||||
|
var totalPages = (int)Math.Ceiling((double)totalItems / pageSize);
|
||||||
_logger.LogInfo("Total invoices found: {TotalItems}", totalItems);
|
_logger.LogInfo("Total invoices found: {TotalItems}", totalItems);
|
||||||
|
|
||||||
var pagedInvoices = await query
|
var pagedInvoices = await query
|
||||||
.OrderByDescending(i => i.InvoiceDate)
|
|
||||||
.Skip((pageNumber - 1) * pageSize)
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@ -155,20 +206,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
_logger.LogDebug("Received payment data for {Count} invoices.", paymentGroups.Count);
|
_logger.LogDebug("Received payment data for {Count} invoices.", paymentGroups.Count);
|
||||||
|
|
||||||
// Fetch related project data asynchronously and in parallel
|
|
||||||
var projIds = pagedInvoices.Select(i => i.ProjectId).Distinct().ToList();
|
|
||||||
var infraProjectsTask = _context.Projects
|
|
||||||
.Where(p => projIds.Contains(p.Id) && p.TenantId == tenantId)
|
|
||||||
.ToListAsync();
|
|
||||||
var serviceProjectsTask = context.ServiceProjects
|
|
||||||
.Where(sp => projIds.Contains(sp.Id) && sp.TenantId == tenantId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
await Task.WhenAll(infraProjectsTask, serviceProjectsTask);
|
|
||||||
|
|
||||||
var infraProjects = infraProjectsTask.Result;
|
|
||||||
var serviceProjects = serviceProjectsTask.Result;
|
|
||||||
|
|
||||||
// Build results and compute balances in memory for tight control
|
// Build results and compute balances in memory for tight control
|
||||||
var results = new List<InvoiceListVM>();
|
var results = new List<InvoiceListVM>();
|
||||||
|
|
||||||
@ -185,16 +222,13 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var vm = _mapper.Map<InvoiceListVM>(invoice);
|
var vm = _mapper.Map<InvoiceListVM>(invoice);
|
||||||
|
|
||||||
// Project mapping logic - minimize nested object allocations
|
// Project mapping logic - minimize nested object allocations
|
||||||
vm.Project = serviceProjects.Where(sp => sp.Id == invoice.ProjectId).Select(p => _mapper.Map<BasicProjectVM>(p)).FirstOrDefault()
|
vm.Project = projects.Where(sp => sp.Id == invoice.ProjectId).FirstOrDefault();
|
||||||
?? infraProjects.Where(ip => ip.Id == invoice.ProjectId).Select(sp => _mapper.Map<BasicProjectVM>(sp)).FirstOrDefault();
|
|
||||||
|
|
||||||
|
|
||||||
vm.BalanceAmount = balance;
|
vm.BalanceAmount = balance;
|
||||||
results.Add(vm);
|
results.Add(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalPages = (int)Math.Ceiling((double)totalItems / pageSize);
|
|
||||||
|
|
||||||
_logger.LogInfo("Returning {Count} invoices (page {PageNumber} of {TotalPages}).", results.Count, pageNumber, totalPages);
|
_logger.LogInfo("Returning {Count} invoices (page {PageNumber} of {TotalPages}).", results.Count, pageNumber, totalPages);
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(
|
return Ok(ApiResponse<object>.SuccessResponse(
|
||||||
@ -1155,6 +1189,45 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
|
|
||||||
|
private AdvanceFilter? TryDeserializeFilter(string? filter)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(filter))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||||
|
AdvanceFilter? advanceFilter = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// First, try to deserialize directly. This is the expected case (e.g., from a web client).
|
||||||
|
advanceFilter = JsonSerializer.Deserialize<AdvanceFilter>(filter, options);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "[{MethodName}] Failed to directly deserialize filter. Attempting to unescape and re-parse. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
||||||
|
|
||||||
|
// If direct deserialization fails, it might be an escaped string (common with tools like Postman or some mobile clients).
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Unescape the string first, then deserialize the result.
|
||||||
|
string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
|
||||||
|
if (!string.IsNullOrWhiteSpace(unescapedJsonString))
|
||||||
|
{
|
||||||
|
advanceFilter = JsonSerializer.Deserialize<AdvanceFilter>(unescapedJsonString, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (JsonException ex1)
|
||||||
|
{
|
||||||
|
// If both attempts fail, log the final error and return null.
|
||||||
|
_logger.LogError(ex1, "[{MethodName}] All attempts to deserialize the filter failed. Filter will be ignored. Filter: {Filter}", nameof(TryDeserializeFilter), filter);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return advanceFilter;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Async permission check helper with scoped DI lifetime
|
/// Async permission check helper with scoped DI lifetime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -206,6 +206,14 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(dashboardVM, "Project counts fetched successfully.", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(dashboardVM, "Project counts fetched successfully.", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("project-completion-status")]
|
||||||
|
public async Task<IActionResult> GetAllProjectsAsync()
|
||||||
|
{
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _projectServices.GetAllProjectsAsync(string.Empty, 0, 0, loggedInEmployee, tenantId);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a dashboard summary of total employees and today's attendance.
|
/// Retrieves a dashboard summary of total employees and today's attendance.
|
||||||
/// If a projectId is provided, it returns totals for that project; otherwise, for all accessible active projects.
|
/// If a projectId is provided, it returns totals for that project; otherwise, for all accessible active projects.
|
||||||
|
|||||||
@ -133,30 +133,13 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("get/project/report/{projectId}")]
|
[HttpGet("get/project/report/{projectId}")]
|
||||||
public async Task<IActionResult> GetProjectReport(Guid projectId)
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var _reportHelper = scope.ServiceProvider.GetRequiredService<ReportHelper>();
|
|
||||||
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
|
|
||||||
|
|
||||||
var resonse = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId);
|
|
||||||
|
|
||||||
if (resonse == null)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Project report not found");
|
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Project report not found", "Project report not found", 404));
|
|
||||||
}
|
|
||||||
_logger.LogInfo("Report for the project fetched successfully");
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(resonse, "Report for the project fetched successfully", 200));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a daily project report by its unique identifier.
|
/// Retrieves a daily project report by its unique identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="projectId">The GUID of the project for which to generate the report.</param>
|
/// <param name="projectId">The GUID of the project for which to generate the report.</param>
|
||||||
/// <returns>An IActionResult containing the project report or an appropriate error response.</returns>
|
/// <returns>An IActionResult containing the project report or an appropriate error response.</returns>
|
||||||
[HttpGet("{projectId}/report")]
|
public async Task<IActionResult> GetProjectReportAsync(Guid projectId, [FromQuery] DateTime? date)
|
||||||
public async Task<IActionResult> GetProjectReportAsync(Guid projectId)
|
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
var _reportHelper = scope.ServiceProvider.GetRequiredService<ReportHelper>();
|
var _reportHelper = scope.ServiceProvider.GetRequiredService<ReportHelper>();
|
||||||
@ -167,8 +150,17 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DateTime reportDate;
|
||||||
|
if (date.HasValue)
|
||||||
|
{
|
||||||
|
reportDate = date.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reportDate = DateTime.UtcNow.AddDays(-1).Date;
|
||||||
|
}
|
||||||
// Call the helper service, which is now available as a class member.
|
// Call the helper service, which is now available as a class member.
|
||||||
var response = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId);
|
var response = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId, reportDate);
|
||||||
|
|
||||||
// Check if the report data was found.
|
// Check if the report data was found.
|
||||||
if (response == null)
|
if (response == null)
|
||||||
|
|||||||
@ -96,6 +96,75 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region =================================================================== Project Branch Functions ===================================================================
|
||||||
|
|
||||||
|
[HttpGet("branch/list/{projectId}")]
|
||||||
|
public async Task<IActionResult> GetProjectBranchListByProject(Guid projectId, [FromQuery] string? searchString, [FromQuery] bool isActive = true,
|
||||||
|
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.GetProjectBranchListByProjectAsync(projectId, isActive, searchString, pageNumber, pageSize, loggedInEmployee, tenantId);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("branch/details/{id}")]
|
||||||
|
public async Task<IActionResult> GetProjectBranchDetails(Guid id)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.GetProjectBranchDetailsAsync(id, loggedInEmployee, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("branch-type/list")]
|
||||||
|
public async Task<IActionResult> GetBranchTypeList([FromQuery] string? searchString)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.GetBranchTypeListAsync(searchString, loggedInEmployee, tenantId);
|
||||||
|
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("branch/create")]
|
||||||
|
public async Task<IActionResult> CreateProjectBranch([FromBody] ProjectBranchDto model)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.CreateProjectBranchAsync(model, loggedInEmployee, tenantId);
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data };
|
||||||
|
await _signalR.SendNotificationAsync(notification);
|
||||||
|
}
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("branch/edit/{id}")]
|
||||||
|
public async Task<IActionResult> UpdateProjectBranch(Guid id, ProjectBranchDto model)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.UpdateProjectBranchAsync(id, model, loggedInEmployee, tenantId);
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data };
|
||||||
|
await _signalR.SendNotificationAsync(notification);
|
||||||
|
}
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("branch/delete/{id}")]
|
||||||
|
public async Task<IActionResult> DeleteProjectBranch(Guid id, [FromQuery] bool isActive = false)
|
||||||
|
{
|
||||||
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _serviceProject.DeleteProjectBranchAsync(id, isActive, loggedInEmployee, tenantId);
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data };
|
||||||
|
await _signalR.SendNotificationAsync(notification);
|
||||||
|
}
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Service Project Allocation Functions ===================================================================
|
#region =================================================================== Service Project Allocation Functions ===================================================================
|
||||||
|
|
||||||
[HttpGet("get/allocation/list")]
|
[HttpGet("get/allocation/list")]
|
||||||
@ -127,10 +196,11 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
#region =================================================================== Job Tickets Functions ===================================================================
|
#region =================================================================== Job Tickets Functions ===================================================================
|
||||||
|
|
||||||
[HttpGet("job/list")]
|
[HttpGet("job/list")]
|
||||||
public async Task<IActionResult> GetJobTicketsList([FromQuery] Guid? projectId, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20, [FromQuery] bool isActive = true)
|
public async Task<IActionResult> GetJobTicketsList([FromQuery] Guid? projectId, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20, [FromQuery] bool isActive = true,
|
||||||
|
[FromQuery] bool isArchive = false)
|
||||||
{
|
{
|
||||||
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
var response = await _serviceProject.GetJobTicketsListAsync(projectId, pageNumber, pageSize, isActive, loggedInEmployee, tenantId);
|
var response = await _serviceProject.GetJobTicketsListAsync(projectId, pageNumber, pageSize, isActive, isArchive, loggedInEmployee, tenantId);
|
||||||
|
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|||||||
96
Marco.Pms.Services/Extensions/QueryableExtensions.cs
Normal file
96
Marco.Pms.Services/Extensions/QueryableExtensions.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using Marco.Pms.Model.Filters;
|
||||||
|
using System.Linq.Dynamic.Core;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Services.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enterprise-grade extension methods for applying dynamic filters and sorting to IQueryable sources.
|
||||||
|
/// </summary>
|
||||||
|
public static class QueryableExtensions
|
||||||
|
{
|
||||||
|
public static IQueryable<T> ApplyCustomFilters<T>(this IQueryable<T> query, AdvanceFilter? filter, string defaultSortColumn)
|
||||||
|
{
|
||||||
|
// 1. Apply Advanced Filters (Arithmetic/Logic)
|
||||||
|
if (filter?.AdvanceFilters != null && filter.AdvanceFilters.Any())
|
||||||
|
{
|
||||||
|
foreach (var advanceFilter in filter.AdvanceFilters)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(advanceFilter.Column)) continue;
|
||||||
|
|
||||||
|
string op = advanceFilter.Opration.ToLower().Trim();
|
||||||
|
string predicate = "";
|
||||||
|
|
||||||
|
// Map your custom strings to Dynamic LINQ operators
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case "greater than": predicate = $"{advanceFilter.Column} > @0"; break;
|
||||||
|
case "less than": predicate = $"{advanceFilter.Column} < @0"; break;
|
||||||
|
case "equal to": predicate = $"{advanceFilter.Column} == @0"; break;
|
||||||
|
case "not equal": predicate = $"{advanceFilter.Column} != @0"; break;
|
||||||
|
case "greater or equal": predicate = $"{advanceFilter.Column} >= @0"; break;
|
||||||
|
case "smaller or equal": predicate = $"{advanceFilter.Column} <= @0"; break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(predicate))
|
||||||
|
{
|
||||||
|
// Dynamic LINQ handles type conversion (string "100" to int 100) automatically
|
||||||
|
query = query.Where(predicate, advanceFilter.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Apply Sorting
|
||||||
|
if (filter?.SortFilters != null && filter.SortFilters.Any())
|
||||||
|
{
|
||||||
|
// Build a comma-separated sort string: "Column1 desc, Column2 asc"
|
||||||
|
var sortExpressions = new List<string>();
|
||||||
|
foreach (var sort in filter.SortFilters)
|
||||||
|
{
|
||||||
|
string direction = sort.SortDescending ? "desc" : "asc";
|
||||||
|
sortExpressions.Add($"{sort.Column} {direction}");
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.OrderBy(string.Join(", ", sortExpressions));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default sorting
|
||||||
|
query = query.OrderBy($"{defaultSortColumn} desc");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 3.Apply GroupBy
|
||||||
|
if (!string.IsNullOrEmpty(filter?.GroupByColumn))
|
||||||
|
{
|
||||||
|
query.GroupBy(filter.GroupByColumn, "it")
|
||||||
|
.Select("new (Key, it as Items)"); // Reshape to { Key: "Value", Items: [...] }
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> ApplySearchFilters<T>(this IQueryable<T> query, List<SearchItem> searchFilters)
|
||||||
|
{
|
||||||
|
// 1. Apply Search Filters (Contains/Text search)
|
||||||
|
if (searchFilters.Any())
|
||||||
|
{
|
||||||
|
foreach (var search in searchFilters)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(search.Column) || string.IsNullOrWhiteSpace(search.Value)) continue;
|
||||||
|
|
||||||
|
// Generates: x.Column.Contains("Value")
|
||||||
|
// Case insensitive logic can be handled here if needed
|
||||||
|
query = query.Where($"{search.Column}.Contains(@0)", search.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> ApplyGroupByFilters<T>(this IQueryable<T> query, string groupByColumn)
|
||||||
|
{
|
||||||
|
query.GroupBy(groupByColumn, "it")
|
||||||
|
.Select("new (Key, it as Items)"); // Reshape to { Key: "Value", Items: [...] }
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1162,35 +1162,23 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
var processedByIds = model.Select(m => m.ProcessedById).ToList();
|
var processedByIds = model.Select(m => m.ProcessedById).ToList();
|
||||||
var paidByIds = model.Select(m => m.PaidById).ToList();
|
var paidByIds = model.Select(m => m.PaidById).ToList();
|
||||||
|
|
||||||
var projectTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync();
|
return await dbContext.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<ProjectBasicMongoDB>(p))
|
||||||
|
.ToListAsync();
|
||||||
});
|
});
|
||||||
var paidByTask = Task.Run(async () =>
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => paidByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
return await dbContext.ServiceProjects
|
||||||
});
|
.AsNoTracking()
|
||||||
var createdByTask = Task.Run(async () =>
|
.Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId)
|
||||||
{
|
.Select(sp => _mapper.Map<ProjectBasicMongoDB>(sp))
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
.ToListAsync();
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => createdByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
|
||||||
});
|
|
||||||
var reviewedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => reviewedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
|
||||||
});
|
|
||||||
var approvedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => approvedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
|
||||||
});
|
|
||||||
var processedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => processedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
|
||||||
});
|
});
|
||||||
var expenseCategoryTask = Task.Run(async () =>
|
var expenseCategoryTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -1202,6 +1190,15 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync();
|
return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask, expenseCategoryTask, paymentModeTask);
|
||||||
|
|
||||||
|
var projects = infraProjectTask.Result;
|
||||||
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
|
||||||
|
var expenseCategories = expenseCategoryTask.Result;
|
||||||
|
var paymentModes = paymentModeTask.Result;
|
||||||
|
|
||||||
var statusMappingTask = Task.Run(async () =>
|
var statusMappingTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -1218,6 +1215,43 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList()
|
NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList()
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
});
|
});
|
||||||
|
var paidByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => paidByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
|
});
|
||||||
|
var createdByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => createdByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(statusMappingTask, paidByTask, createdByTask);
|
||||||
|
var statusMappings = statusMappingTask.Result;
|
||||||
|
var paidBys = paidByTask.Result;
|
||||||
|
var createdBys = createdByTask.Result;
|
||||||
|
|
||||||
|
var reviewedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => reviewedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
|
});
|
||||||
|
var approvedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => approvedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
|
});
|
||||||
|
var processedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().Where(e => processedByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(reviewedByTask, approvedByTask, processedByTask);
|
||||||
|
var reviewedBys = reviewedByTask.Result;
|
||||||
|
var approvedBys = approvedByTask.Result;
|
||||||
|
var processedBy = processedByTask.Result;
|
||||||
|
|
||||||
var statusTask = Task.Run(async () =>
|
var statusTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -1249,26 +1283,17 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Await all prerequisite checks at once.
|
|
||||||
await Task.WhenAll(projectTask, expenseCategoryTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask,
|
|
||||||
processedByTask, statusTask, billAttachmentsTask);
|
|
||||||
|
|
||||||
var projects = projectTask.Result;
|
|
||||||
var expenseCategories = expenseCategoryTask.Result;
|
// Await all prerequisite checks at once.
|
||||||
var paymentModes = paymentModeTask.Result;
|
await Task.WhenAll(statusTask, billAttachmentsTask);
|
||||||
var statusMappings = statusMappingTask.Result;
|
|
||||||
var paidBys = paidByTask.Result;
|
|
||||||
var createdBys = createdByTask.Result;
|
|
||||||
var reviewedBys = reviewedByTask.Result;
|
|
||||||
var approvedBys = approvedByTask.Result;
|
|
||||||
var processedBy = processedByTask.Result;
|
|
||||||
var billAttachments = billAttachmentsTask.Result;
|
var billAttachments = billAttachmentsTask.Result;
|
||||||
|
|
||||||
expenseList = model.Select(m =>
|
expenseList = model.Select(m =>
|
||||||
{
|
{
|
||||||
var response = _mapper.Map<ExpenseDetailsMongoDB>(m);
|
var response = _mapper.Map<ExpenseDetailsMongoDB>(m);
|
||||||
|
|
||||||
response.Project = projects.Where(p => p.Id == m.ProjectId).Select(p => _mapper.Map<ProjectBasicMongoDB>(p)).FirstOrDefault() ?? new ProjectBasicMongoDB();
|
response.Project = projects.Where(p => Guid.Parse(p.Id) == m.ProjectId).FirstOrDefault() ?? new ProjectBasicMongoDB();
|
||||||
response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map<BasicEmployeeMongoDB>(p)).FirstOrDefault() ?? new BasicEmployeeMongoDB();
|
response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map<BasicEmployeeMongoDB>(p)).FirstOrDefault() ?? new BasicEmployeeMongoDB();
|
||||||
response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map<BasicEmployeeMongoDB>(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB();
|
response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map<BasicEmployeeMongoDB>(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB();
|
||||||
response.ReviewedBy = reviewedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map<BasicEmployeeMongoDB>(e)).FirstOrDefault();
|
response.ReviewedBy = reviewedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map<BasicEmployeeMongoDB>(e)).FirstOrDefault();
|
||||||
@ -1292,35 +1317,23 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
}
|
}
|
||||||
private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId)
|
private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId)
|
||||||
{
|
{
|
||||||
var projectTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
|
return await dbContext.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => p.Id == model.ProjectId && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<ProjectBasicMongoDB>(p))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
});
|
});
|
||||||
var paidByTask = Task.Run(async () =>
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.PaidById && e.TenantId == tenantId);
|
return await dbContext.ServiceProjects
|
||||||
});
|
.AsNoTracking()
|
||||||
var createdByTask = Task.Run(async () =>
|
.Where(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId)
|
||||||
{
|
.Select(sp => _mapper.Map<ProjectBasicMongoDB>(sp))
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
.FirstOrDefaultAsync();
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.CreatedById && e.TenantId == tenantId);
|
|
||||||
});
|
|
||||||
var reviewedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ReviewedById && e.TenantId == tenantId);
|
|
||||||
});
|
|
||||||
var approvedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ApprovedById && e.TenantId == tenantId);
|
|
||||||
});
|
|
||||||
var processedByTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ProcessedById && e.TenantId == tenantId);
|
|
||||||
});
|
});
|
||||||
var expenseCategoryTask = Task.Run(async () =>
|
var expenseCategoryTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -1332,6 +1345,12 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId);
|
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask, expenseCategoryTask, paymentModeTask);
|
||||||
|
var project = infraProjectTask.Result ?? serviceProjectTask.Result ?? new ProjectBasicMongoDB();
|
||||||
|
var expenseCategory = expenseCategoryTask.Result;
|
||||||
|
var paymentMode = paymentModeTask.Result;
|
||||||
|
|
||||||
var statusMappingTask = Task.Run(async () =>
|
var statusMappingTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -1348,6 +1367,43 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList()
|
NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList()
|
||||||
}).FirstOrDefaultAsync();
|
}).FirstOrDefaultAsync();
|
||||||
});
|
});
|
||||||
|
var paidByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.PaidById && e.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
var createdByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.CreatedById && e.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(statusMappingTask, paidByTask, createdByTask);
|
||||||
|
var statusMapping = statusMappingTask.Result;
|
||||||
|
var paidBy = paidByTask.Result;
|
||||||
|
var createdBy = createdByTask.Result;
|
||||||
|
|
||||||
|
var reviewedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ReviewedById && e.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
var approvedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ApprovedById && e.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
var processedByTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ProcessedById && e.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(reviewedByTask, approvedByTask, processedByTask);
|
||||||
|
var reviewedBy = reviewedByTask.Result;
|
||||||
|
var approvedBy = approvedByTask.Result;
|
||||||
|
var processedBy = processedByTask.Result;
|
||||||
|
|
||||||
var statusTask = Task.Run(async () =>
|
var statusTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -1378,25 +1434,13 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Await all prerequisite checks at once.
|
await Task.WhenAll(statusTask, billAttachmentsTask);
|
||||||
await Task.WhenAll(projectTask, expenseCategoryTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask,
|
|
||||||
processedByTask, statusTask, billAttachmentsTask);
|
|
||||||
|
|
||||||
var project = projectTask.Result;
|
|
||||||
var expenseCategory = expenseCategoryTask.Result;
|
|
||||||
var paymentMode = paymentModeTask.Result;
|
|
||||||
var statusMapping = statusMappingTask.Result;
|
|
||||||
var paidBy = paidByTask.Result;
|
|
||||||
var createdBy = createdByTask.Result;
|
|
||||||
var reviewedBy = reviewedByTask.Result;
|
|
||||||
var approvedBy = approvedByTask.Result;
|
|
||||||
var processedBy = processedByTask.Result;
|
|
||||||
var billAttachment = billAttachmentsTask.Result;
|
var billAttachment = billAttachmentsTask.Result;
|
||||||
|
|
||||||
|
|
||||||
var response = _mapper.Map<ExpenseDetailsMongoDB>(model);
|
var response = _mapper.Map<ExpenseDetailsMongoDB>(model);
|
||||||
|
|
||||||
response.Project = _mapper.Map<ProjectBasicMongoDB>(project);
|
response.Project = project;
|
||||||
response.PaidBy = _mapper.Map<BasicEmployeeMongoDB>(paidBy);
|
response.PaidBy = _mapper.Map<BasicEmployeeMongoDB>(paidBy);
|
||||||
response.CreatedBy = _mapper.Map<BasicEmployeeMongoDB>(createdBy);
|
response.CreatedBy = _mapper.Map<BasicEmployeeMongoDB>(createdBy);
|
||||||
response.ReviewedBy = _mapper.Map<BasicEmployeeMongoDB>(reviewedBy);
|
response.ReviewedBy = _mapper.Map<BasicEmployeeMongoDB>(reviewedBy);
|
||||||
|
|||||||
@ -25,10 +25,9 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
_cache = cache;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ProjectStatisticReport?> GetDailyProjectReportWithOutTenant(Guid projectId)
|
public async Task<ProjectStatisticReport?> GetDailyProjectReportWithOutTenant(Guid projectId, DateTime reportDate)
|
||||||
{
|
{
|
||||||
// await _cache.GetBuildingAndFloorByWorkAreaId();
|
// await _cache.GetBuildingAndFloorByWorkAreaId();
|
||||||
DateTime reportDate = DateTime.UtcNow.AddDays(-1).Date;
|
|
||||||
var project = await _cache.GetProjectDetailsWithBuildings(projectId);
|
var project = await _cache.GetProjectDetailsWithBuildings(projectId);
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -162,6 +162,10 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
dest => dest.ProjectStatusId,
|
dest => dest.ProjectStatusId,
|
||||||
opt => opt.MapFrom(src => Guid.Empty)
|
opt => opt.MapFrom(src => Guid.Empty)
|
||||||
);
|
);
|
||||||
|
CreateMap<ProjectBasicMongoDB, BasicProjectVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.Id,
|
||||||
|
opt => opt.MapFrom(src => new Guid(src.Id)));
|
||||||
|
|
||||||
CreateMap<ProjectMongoDB, Project>()
|
CreateMap<ProjectMongoDB, Project>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
@ -197,9 +201,17 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
CreateMap<ServiceProject, BasicProjectVM>();
|
CreateMap<ServiceProject, BasicProjectVM>();
|
||||||
CreateMap<ServiceProject, ServiceProjectVM>();
|
CreateMap<ServiceProject, ServiceProjectVM>();
|
||||||
CreateMap<ServiceProject, BasicServiceProjectVM>();
|
CreateMap<ServiceProject, BasicServiceProjectVM>();
|
||||||
|
CreateMap<ServiceProject, ProjectBasicMongoDB>();
|
||||||
CreateMap<ServiceProject, ServiceProjectDetailsVM>();
|
CreateMap<ServiceProject, ServiceProjectDetailsVM>();
|
||||||
CreateMap<ServiceProjectAllocation, ServiceProjectAllocationVM>();
|
CreateMap<ServiceProjectAllocation, ServiceProjectAllocationVM>();
|
||||||
|
|
||||||
|
#region ======================================================= Project Branch =======================================================
|
||||||
|
CreateMap<ProjectBranchDto, ProjectBranch>();
|
||||||
|
CreateMap<ProjectBranch, ProjectBranchVM>();
|
||||||
|
CreateMap<ProjectBranch, ProjectBranchDetailsVM>();
|
||||||
|
CreateMap<ProjectBranch, BasicProjectBranchVM>();
|
||||||
|
#endregion
|
||||||
|
|
||||||
//#region ======================================================= Talking Points =======================================================
|
//#region ======================================================= Talking Points =======================================================
|
||||||
//CreateMap<TalkingPointDto, TalkingPoint>();
|
//CreateMap<TalkingPointDto, TalkingPoint>();
|
||||||
//CreateMap<TalkingPoint, TalkingPointVM>();
|
//CreateMap<TalkingPoint, TalkingPointVM>();
|
||||||
|
|||||||
@ -42,6 +42,7 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.MongoDB" Version="7.0.0" />
|
<PackageReference Include="Serilog.Sinks.MongoDB" Version="7.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -474,6 +474,12 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
return await _dbContext.ContactsEmails.Where(e => contactIds.Contains(e.ContactId)).ToListAsync();
|
return await _dbContext.ContactsEmails.Where(e => contactIds.Contains(e.ContactId)).ToListAsync();
|
||||||
});
|
});
|
||||||
|
await Task.WhenAll(contactTask, phoneTask, emailTask);
|
||||||
|
|
||||||
|
var contacts = contactTask.Result;
|
||||||
|
var phones = phoneTask.Result;
|
||||||
|
var emails = emailTask.Result;
|
||||||
|
|
||||||
var tagTask = Task.Run(async () =>
|
var tagTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var _dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var _dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -493,11 +499,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
return await _dbContext.ContactBucketMappings.Where(cb => contactIds.Contains(cb.ContactId)).ToListAsync();
|
return await _dbContext.ContactBucketMappings.Where(cb => contactIds.Contains(cb.ContactId)).ToListAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
await Task.WhenAll(contactTask);
|
await Task.WhenAll(tagTask, contactProjectTask, contactBucketTask);
|
||||||
|
|
||||||
var contacts = contactTask.Result;
|
|
||||||
var phones = phoneTask.Result;
|
|
||||||
var emails = emailTask.Result;
|
|
||||||
var tags = tagTask.Result;
|
var tags = tagTask.Result;
|
||||||
var contactProjects = contactProjectTask.Result;
|
var contactProjects = contactProjectTask.Result;
|
||||||
var contactBuckets = contactBucketTask.Result;
|
var contactBuckets = contactBucketTask.Result;
|
||||||
@ -587,6 +590,13 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} tries to update contact with ID {ContactId} is not found in database", loggedInEmployeeId);
|
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} tries to update contact with ID {ContactId} is not found in database", loggedInEmployeeId);
|
||||||
return ApiResponse<object>.ErrorResponse("Contact not found", "Contact not found", 404);
|
return ApiResponse<object>.ErrorResponse("Contact not found", "Contact not found", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var projectIds = await dbContext.ContactProjectMappings
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(cp => cp.ContactId == contact.Id && cp.TenantId == tenantId)
|
||||||
|
.Select(cp => cp.ProjectId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
ContactProfileVM contactVM = _mapper.Map<ContactProfileVM>(contact);
|
ContactProfileVM contactVM = _mapper.Map<ContactProfileVM>(contact);
|
||||||
|
|
||||||
var phonesTask = Task.Run(async () =>
|
var phonesTask = Task.Run(async () =>
|
||||||
@ -609,21 +619,26 @@ namespace Marco.Pms.Services.Service
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
var contactProjectsTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var taskDbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await taskDbContext.ContactProjectMappings
|
return await context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).Select(p => _mapper.Map<BasicProjectVM>(p)).ToListAsync();
|
||||||
.AsNoTracking()
|
|
||||||
.Include(cp => cp.Project)
|
|
||||||
.Where(cp => cp.ContactId == contact.Id && cp.Project != null && cp.Project.TenantId == tenantId)
|
|
||||||
.Select(cp => new BasicProjectVM
|
|
||||||
{
|
|
||||||
Id = cp.Project!.Id,
|
|
||||||
Name = cp.Project.Name
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects.Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId).Select(sp => _mapper.Map<BasicProjectVM>(sp)).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(phonesTask, emailsTask, infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
contactVM.ContactPhones = phonesTask.Result;
|
||||||
|
contactVM.ContactEmails = emailsTask.Result;
|
||||||
|
var projects = infraProjectTask.Result;
|
||||||
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
contactVM.Projects = projects;
|
||||||
|
|
||||||
var contactBucketsTask = Task.Run(async () =>
|
var contactBucketsTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var taskDbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var taskDbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -679,12 +694,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
await Task.WhenAll(phonesTask, emailsTask, contactProjectsTask, contactBucketsTask, contactTagsTask, contactNotesTask);
|
await Task.WhenAll(contactBucketsTask, contactTagsTask, contactNotesTask);
|
||||||
contactVM.ContactPhones = phonesTask.Result;
|
|
||||||
contactVM.ContactEmails = emailsTask.Result;
|
|
||||||
contactVM.Tags = contactTagsTask.Result;
|
contactVM.Tags = contactTagsTask.Result;
|
||||||
contactVM.Buckets = contactBucketsTask.Result;
|
contactVM.Buckets = contactBucketsTask.Result;
|
||||||
contactVM.Projects = contactProjectsTask.Result;
|
|
||||||
contactVM.Notes = contactNotesTask.Result;
|
contactVM.Notes = contactNotesTask.Result;
|
||||||
_logger.LogInfo("Employee ID {EmployeeId} fetched profile of contact {ContactId}", loggedInEmployeeId, contact.Id);
|
_logger.LogInfo("Employee ID {EmployeeId} fetched profile of contact {ContactId}", loggedInEmployeeId, contact.Id);
|
||||||
return ApiResponse<object>.SuccessResponse(contactVM, "Contact profile fetched successfully");
|
return ApiResponse<object>.SuccessResponse(contactVM, "Contact profile fetched successfully");
|
||||||
@ -3289,11 +3302,18 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
if (!(dto.ProjectIds?.Any() ?? false)) return new List<ContactProjectMapping>();
|
if (!(dto.ProjectIds?.Any() ?? false)) return new List<ContactProjectMapping>();
|
||||||
|
|
||||||
var validProjectIds = await _context.Projects
|
var infraProjectIds = await _context.Projects
|
||||||
.Where(p => dto.ProjectIds.Contains(p.Id) && p.TenantId == tenantId)
|
.Where(p => dto.ProjectIds.Contains(p.Id) && p.TenantId == tenantId)
|
||||||
.Select(p => p.Id)
|
.Select(p => p.Id)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
var serviceProjectIds = await _context.ServiceProjects
|
||||||
|
.Where(sp => dto.ProjectIds.Contains(sp.Id) && sp.IsActive && sp.TenantId == tenantId)
|
||||||
|
.Select(sp => sp.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var validProjectIds = infraProjectIds.Concat(serviceProjectIds).Distinct().Where(p => p != Guid.Empty).ToList();
|
||||||
|
|
||||||
var mappings = validProjectIds.Select(projectId => new ContactProjectMapping
|
var mappings = validProjectIds.Select(projectId => new ContactProjectMapping
|
||||||
{
|
{
|
||||||
ProjectId = projectId,
|
ProjectId = projectId,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
|
|
||||||
private static readonly Guid Review = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7");
|
private static readonly Guid Review = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7");
|
||||||
private static readonly Guid RejectedByReviewer = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b");
|
private static readonly Guid RejectedByReviewer = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b");
|
||||||
@ -25,10 +26,12 @@ namespace Marco.Pms.Services.Service
|
|||||||
private static readonly Guid Processed = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95");
|
private static readonly Guid Processed = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95");
|
||||||
|
|
||||||
public FirebaseService(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
public FirebaseService(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||||
IServiceScopeFactory serviceScopeFactory)
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
|
ILoggingService logger)
|
||||||
{
|
{
|
||||||
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||||
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
|
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth Controller
|
// Auth Controller
|
||||||
@ -124,171 +127,174 @@ namespace Marco.Pms.Services.Service
|
|||||||
await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data);
|
await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attendance Controller
|
#region =================================================================== Attendance Functions ===================================================================
|
||||||
public async Task SendAttendanceMessageAsync(Guid projectId, string name, ATTENDANCE_MARK_TYPE markType, Guid employeeId, Guid tenantId)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends attendance-related notifications for the specified project and employee attendance action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="projectId">The Id of the project where attendance is marked.</param>
|
||||||
|
/// <param name="name">Name of the employee marking attendance.</param>
|
||||||
|
/// <param name="markType">Type of attendance mark action.</param>
|
||||||
|
/// <param name="employeeId">Employee for whom attendance is marked.</param>
|
||||||
|
/// <param name="origin">Origin of the request (optional), used to filter notifications.</param>
|
||||||
|
/// <param name="loggedInEmployeeId">Employee Id of the caller (to exclude self-notifications).</param>
|
||||||
|
/// <param name="tenantId">Tenant identifier for multi-tenant setup.</param>
|
||||||
|
/// <returns>Task representing the asynchronous operation.</returns>
|
||||||
|
public async Task SendAttendanceMessageAsync(Guid projectId, string name, ATTENDANCE_MARK_TYPE markType, Guid employeeId, string origin, Guid loggedInEmployeeId, Guid tenantId)
|
||||||
{
|
{
|
||||||
await using var _context = await _dbContextFactory.CreateDbContextAsync();
|
try
|
||||||
var projectTask = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.ProjectAllocations
|
|
||||||
.Include(pa => pa.Project)
|
// Fetch project details and assigned employees grouped by ProjectId
|
||||||
.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null)
|
var project = await dbContext.ProjectAllocations
|
||||||
.GroupBy(pa => pa.ProjectId)
|
.Include(pa => pa.Project)
|
||||||
.Select(g => new
|
.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null)
|
||||||
|
.GroupBy(pa => pa.ProjectId)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(),
|
||||||
|
EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList()
|
||||||
|
})
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (project == null)
|
||||||
{
|
{
|
||||||
ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(),
|
_logger.LogWarning("No active project allocations found for ProjectId: {ProjectId}", projectId);
|
||||||
EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList()
|
return; // or throw if critical
|
||||||
}).FirstOrDefaultAsync();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
var teamAttendanceRoleTask = Task.Run(async () =>
|
var projectAssignedEmployeeIds = project.EmployeeIds;
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.RolePermissionMappings
|
|
||||||
.Where(rp => rp.FeaturePermissionId == PermissionsMaster.TeamAttendance)
|
|
||||||
.Select(rp => rp.ApplicationRoleId).ToListAsync();
|
|
||||||
});
|
|
||||||
var regularizeAttendanceRoleTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.RolePermissionMappings
|
|
||||||
.Where(rp => rp.FeaturePermissionId == PermissionsMaster.RegularizeAttendance)
|
|
||||||
.Select(rp => rp.ApplicationRoleId).ToListAsync();
|
|
||||||
});
|
|
||||||
var manageProjectsRoleTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.RolePermissionMappings
|
|
||||||
.Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject)
|
|
||||||
.Select(rp => rp.ApplicationRoleId).ToListAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(projectTask, teamAttendanceRoleTask, manageProjectsRoleTask, regularizeAttendanceRoleTask);
|
// Load required role IDs in parallel for efficiency
|
||||||
|
var teamAttendanceRoleIdsTask = dbContext.RolePermissionMappings.Where(rp => rp.FeaturePermissionId == PermissionsMaster.TeamAttendance).Select(rp => rp.ApplicationRoleId).ToListAsync();
|
||||||
|
var regularizeAttendanceRoleIdsTask = dbContext.RolePermissionMappings.Where(rp => rp.FeaturePermissionId == PermissionsMaster.RegularizeAttendance).Select(rp => rp.ApplicationRoleId).ToListAsync();
|
||||||
|
var manageProjectsRoleIdsTask = dbContext.RolePermissionMappings.Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject).Select(rp => rp.ApplicationRoleId).ToListAsync();
|
||||||
|
|
||||||
var teamAttendanceRoleIds = teamAttendanceRoleTask.Result;
|
await Task.WhenAll(teamAttendanceRoleIdsTask, regularizeAttendanceRoleIdsTask, manageProjectsRoleIdsTask);
|
||||||
var regularizeAttendanceRoleIds = regularizeAttendanceRoleTask.Result;
|
|
||||||
var manageProjectsRoleIds = manageProjectsRoleTask.Result;
|
|
||||||
var project = projectTask.Result;
|
|
||||||
|
|
||||||
List<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
|
var teamAttendanceRoleIds = teamAttendanceRoleIdsTask.Result;
|
||||||
|
var regularizeAttendanceRoleIds = regularizeAttendanceRoleIdsTask.Result;
|
||||||
|
var manageProjectsRoleIds = manageProjectsRoleIdsTask.Result;
|
||||||
|
|
||||||
var employeeIdsTask = Task.Run(async () =>
|
// Fetch employees eligible for attendance notifications
|
||||||
{
|
var employeeIds = await dbContext.EmployeeRoleMappings
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId))
|
||||||
return await dbContext.EmployeeRoleMappings
|
&& teamAttendanceRoleIds.Contains(er.RoleId))
|
||||||
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && teamAttendanceRoleIds.Contains(er.RoleId))
|
.Select(er => er.EmployeeId)
|
||||||
.Select(er => er.EmployeeId)
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
});
|
|
||||||
var teamEmployeeIdsTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await dbContext.EmployeeRoleMappings
|
|
||||||
.Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId))
|
|
||||||
.Select(er => er.EmployeeId)
|
|
||||||
.ToListAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(employeeIdsTask, teamEmployeeIdsTask);
|
// Fetch team employees (for data-only notifications)
|
||||||
|
var teamEmployeeIds = await dbContext.EmployeeRoleMappings
|
||||||
|
.Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId))
|
||||||
|
.Select(er => er.EmployeeId)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
var employeeIds = employeeIdsTask.Result;
|
List<Guid> messageNotificationIds = new();
|
||||||
var teamEmployeeIds = teamEmployeeIdsTask.Result;
|
|
||||||
|
|
||||||
var mesaageNotificationIds = new List<Guid>();
|
// Construct notification content based on attendance mark type
|
||||||
|
Notification notificationFirebase = markType switch
|
||||||
Notification notificationFirebase;
|
{
|
||||||
switch (markType)
|
ATTENDANCE_MARK_TYPE.CHECK_IN => new Notification
|
||||||
{
|
|
||||||
case ATTENDANCE_MARK_TYPE.CHECK_IN:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = "Attendance Update",
|
Title = "Attendance Update",
|
||||||
Body = $" {name} has checked in for project {project?.ProjectName ?? ""}."
|
Body = $"{name} has checked in for project {project.ProjectName}."
|
||||||
};
|
},
|
||||||
mesaageNotificationIds.AddRange(employeeIds);
|
ATTENDANCE_MARK_TYPE.CHECK_OUT => new Notification
|
||||||
break;
|
|
||||||
case ATTENDANCE_MARK_TYPE.CHECK_OUT:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = "Attendance Update",
|
Title = "Attendance Update",
|
||||||
Body = $" {name} has checked out for project {project?.ProjectName ?? ""}."
|
Body = $"{name} has checked out for project {project.ProjectName}."
|
||||||
};
|
},
|
||||||
mesaageNotificationIds.AddRange(employeeIds);
|
ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE => new Notification
|
||||||
break;
|
|
||||||
case ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = "Regularization Request",
|
Title = "Regularization Request",
|
||||||
Body = $" {name} has submitted a regularization request for project {project?.ProjectName ?? ""}."
|
Body = $"{name} has submitted a regularization request for project {project.ProjectName}."
|
||||||
};
|
},
|
||||||
mesaageNotificationIds = await _context.EmployeeRoleMappings
|
ATTENDANCE_MARK_TYPE.REGULARIZE => new Notification
|
||||||
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && regularizeAttendanceRoleIds.Contains(er.RoleId))
|
|
||||||
.Select(er => er.EmployeeId)
|
|
||||||
.ToListAsync();
|
|
||||||
break;
|
|
||||||
case ATTENDANCE_MARK_TYPE.REGULARIZE:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = " Regularization Approved",
|
Title = "Regularization Approved",
|
||||||
Body = $" {name}'s regularization request for project {project?.ProjectName ?? ""} has been accepted."
|
Body = $"{name}'s regularization request for project {project.ProjectName} has been accepted."
|
||||||
};
|
},
|
||||||
mesaageNotificationIds.Add(employeeId);
|
ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT => new Notification
|
||||||
break;
|
|
||||||
case ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = "Regularization Denied",
|
Title = "Regularization Denied",
|
||||||
Body = $" {name}'s regularization request for project {project?.ProjectName ?? ""} has been rejected."
|
Body = $"{name}'s regularization request for project {project.ProjectName} has been rejected."
|
||||||
};
|
},
|
||||||
mesaageNotificationIds.Add(employeeId);
|
_ => new Notification
|
||||||
break;
|
|
||||||
default:
|
|
||||||
notificationFirebase = new Notification
|
|
||||||
{
|
{
|
||||||
Title = "Attendance Update",
|
Title = "Attendance Update",
|
||||||
Body = $" {name} has update his/her attendance for project {project?.ProjectName ?? ""}."
|
Body = $"{name} has updated attendance for project {project.ProjectName}."
|
||||||
};
|
}
|
||||||
break;
|
};
|
||||||
|
|
||||||
|
// Set notification recipients based on type
|
||||||
|
if (markType == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
|
||||||
|
{
|
||||||
|
messageNotificationIds = await dbContext.EmployeeRoleMappings
|
||||||
|
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId))
|
||||||
|
&& regularizeAttendanceRoleIds.Contains(er.RoleId))
|
||||||
|
.Select(er => er.EmployeeId)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
else if (markType == ATTENDANCE_MARK_TYPE.REGULARIZE || markType == ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT)
|
||||||
|
{
|
||||||
|
messageNotificationIds.Add(employeeId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageNotificationIds.AddRange(employeeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataPayload = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Keyword", "Attendance" },
|
||||||
|
{ "ProjectId", projectId.ToString() },
|
||||||
|
{ "Action", markType.ToString() }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter out current (logged-in) employee from notifications if origin is not provided (optional)
|
||||||
|
if (string.IsNullOrWhiteSpace(origin))
|
||||||
|
{
|
||||||
|
messageNotificationIds = messageNotificationIds.Where(e => e != Guid.Empty && e != loggedInEmployeeId).Distinct().ToList();
|
||||||
|
teamEmployeeIds = teamEmployeeIds.Where(e => e != Guid.Empty && e != loggedInEmployeeId).Distinct().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch FCM tokens for notification recipients
|
||||||
|
var registrationTokensForNotification = messageNotificationIds.Count > 0
|
||||||
|
? await dbContext.FCMTokenMappings.Where(ft => messageNotificationIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId).Select(ft => ft.FcmToken).ToListAsync()
|
||||||
|
: new List<string>();
|
||||||
|
|
||||||
|
// Fetch FCM tokens for data-only notification recipients
|
||||||
|
var registrationTokensForData = teamEmployeeIds.Count > 0
|
||||||
|
? await dbContext.FCMTokenMappings.Where(ft => teamEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId).Select(ft => ft.FcmToken).ToListAsync()
|
||||||
|
: new List<string>();
|
||||||
|
|
||||||
|
// Send notifications concurrently
|
||||||
|
var sendNotificationTask = registrationTokensForNotification.Count > 0
|
||||||
|
? SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, dataPayload)
|
||||||
|
: Task.CompletedTask;
|
||||||
|
|
||||||
|
var sendDataOnlyTask = registrationTokensForData.Count > 0
|
||||||
|
? SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, dataPayload)
|
||||||
|
: Task.CompletedTask;
|
||||||
|
|
||||||
|
await Task.WhenAll(sendNotificationTask, sendDataOnlyTask);
|
||||||
|
|
||||||
|
_logger.LogInfo("Attendance message sent successfully for ProjectId {ProjectId}, MarkType {MarkType}, EmployeeId {EmployeeId}, Origin {Origin}",
|
||||||
|
projectId, markType, employeeId, origin);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
// List of device registration tokens to send the message to
|
|
||||||
|
|
||||||
var data = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "Keyword", "Attendance" },
|
|
||||||
{ "ProjectId", projectId.ToString() },
|
|
||||||
{ "Action", markType.ToString() }
|
|
||||||
};
|
|
||||||
|
|
||||||
var registrationTokensForNotificationTask = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
if (mesaageNotificationIds.Any())
|
_logger.LogError(ex, "Error sending attendance message for ProjectId {ProjectId}, MarkType {MarkType}, EmployeeId {EmployeeId}, Origin {Origin}",
|
||||||
{
|
projectId, markType, employeeId, origin);
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
}
|
||||||
var registrationTokensForNotification = await dbContext.FCMTokenMappings
|
|
||||||
.Where(ft => mesaageNotificationIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId)
|
|
||||||
.Select(ft => ft.FcmToken).ToListAsync();
|
|
||||||
|
|
||||||
await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var registrationTokensForDataTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
if (teamEmployeeIds.Any())
|
|
||||||
{
|
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
var registrationTokensForData = await dbContext.FCMTokenMappings
|
|
||||||
.Where(ft => teamEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId)
|
|
||||||
.Select(ft => ft.FcmToken).ToListAsync();
|
|
||||||
|
|
||||||
await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
// Task Controller
|
// Task Controller
|
||||||
public async Task SendAssignTaskMessageAsync(Guid workItemId, string name, List<Guid> teamMembers, Guid tenantId)
|
public async Task SendAssignTaskMessageAsync(Guid workItemId, string name, List<Guid> teamMembers, Guid tenantId)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using Marco.Pms.Model.Employees;
|
|||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Services.Helpers;
|
using Marco.Pms.Services.Helpers;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Marco.Pms.Services.Service
|
namespace Marco.Pms.Services.Service
|
||||||
@ -12,49 +13,18 @@ namespace Marco.Pms.Services.Service
|
|||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly RolesHelper _rolesHelper;
|
private readonly RolesHelper _rolesHelper;
|
||||||
private readonly CacheUpdateHelper _cache;
|
private readonly CacheUpdateHelper _cache;
|
||||||
|
private readonly ILoggingService _logger;
|
||||||
private readonly Guid tenantId;
|
private readonly Guid tenantId;
|
||||||
|
|
||||||
public PermissionServices(ApplicationDbContext context, RolesHelper rolesHelper, CacheUpdateHelper cache, UserHelper userHelper)
|
public PermissionServices(ApplicationDbContext context, RolesHelper rolesHelper, CacheUpdateHelper cache, ILoggingService logger, UserHelper userHelper)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_rolesHelper = rolesHelper;
|
_rolesHelper = rolesHelper;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_logger = logger;
|
||||||
tenantId = userHelper.GetTenantId();
|
tenantId = userHelper.GetTenantId();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public async Task<bool> HasPermission(Guid featurePermissionId, Guid employeeId, Guid? projectId = null)
|
|
||||||
//{
|
|
||||||
// var featurePermissionIds = await _cache.GetPermissions(employeeId);
|
|
||||||
// if (featurePermissionIds == null)
|
|
||||||
// {
|
|
||||||
// List<FeaturePermission> featurePermission = await _rolesHelper.GetFeaturePermissionByEmployeeId(employeeId);
|
|
||||||
// featurePermissionIds = featurePermission.Select(fp => fp.Id).ToList();
|
|
||||||
// }
|
|
||||||
// if (projectId != null)
|
|
||||||
// {
|
|
||||||
// var projectLevelPerissionIds = await _context.ProjectLevelPermissionMappings
|
|
||||||
// .Where(pl => pl.ProjectId == projectId.Value && pl.EmployeeId == employeeId).Select(pl => pl.PermissionId).ToListAsync();
|
|
||||||
|
|
||||||
// var projectLevelModuleIds = new HashSet<Guid>
|
|
||||||
// {
|
|
||||||
// Guid.Parse("53176ebf-c75d-42e5-839f-4508ffac3def"),
|
|
||||||
// Guid.Parse("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
|
|
||||||
// Guid.Parse("81ab8a87-8ccd-4015-a917-0627cee6a100"),
|
|
||||||
// Guid.Parse("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"),
|
|
||||||
// Guid.Parse("a8cf4331-8f04-4961-8360-a3f7c3cc7462")
|
|
||||||
// };
|
|
||||||
|
|
||||||
// var allProjectLevelPermissionIds = await _context.FeaturePermissions
|
|
||||||
// .Where(fp => projectLevelModuleIds.Contains(fp.FeatureId) && !projectLevelPerissionIds.Contains(fp.Id)).Select(fp => fp.Id).ToListAsync();
|
|
||||||
// featurePermissionIds.RemoveRange(allProjectLevelPermissionIds);
|
|
||||||
|
|
||||||
// featurePermissionIds.AddRange(projectLevelPerissionIds);
|
|
||||||
// featurePermissionIds = featurePermissionIds.Distinct().ToList();
|
|
||||||
// }
|
|
||||||
// var hasPermission = featurePermissionIds.Contains(featurePermissionId);
|
|
||||||
// return hasPermission;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether an employee has a specific feature permission, optionally within a project context.
|
/// Checks whether an employee has a specific feature permission, optionally within a project context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -156,5 +126,78 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
return projectIds.Contains(projectId);
|
return projectIds.Contains(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if an employee has permission to access a specific service project.
|
||||||
|
/// Permission is granted if the user is directly allocated to the project OR
|
||||||
|
/// assigned to any active job ticket within the project.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loggedInEmployeeId">The ID of the user requesting access.</param>
|
||||||
|
/// <param name="projectId">The ID of the project to access.</param>
|
||||||
|
/// <returns>True if access is allowed, otherwise False.</returns>
|
||||||
|
public async Task<bool> HasServiceProjectPermission(Guid loggedInEmployeeId, Guid projectId)
|
||||||
|
{
|
||||||
|
Guid ReviewDoneStatus = Guid.Parse("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7");
|
||||||
|
Guid ClosedStatus = Guid.Parse("3ddeefb5-ae3c-4e10-a922-35e0a452bb69");
|
||||||
|
// 1. Input Validation
|
||||||
|
if (loggedInEmployeeId == Guid.Empty || projectId == Guid.Empty)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Permission check failed: Invalid input parameters. EmployeeId: {EmployeeId}, ProjectId: {ProjectId}", loggedInEmployeeId, projectId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Starting permission check for Employee: {EmployeeId} on Project: {ProjectId}", loggedInEmployeeId, projectId);
|
||||||
|
|
||||||
|
// 2. Check Level 1: Is the user a generic Team Member of the project?
|
||||||
|
// This is usually the most common case, so checking this first saves complex query execution.
|
||||||
|
bool isTeamMember = await _context.ServiceProjectAllocations
|
||||||
|
.AsNoTracking() // Optimization: Read-only query does not need tracking
|
||||||
|
.AnyAsync(spa => spa.ProjectId == projectId
|
||||||
|
&& spa.EmployeeId == loggedInEmployeeId
|
||||||
|
&& spa.IsActive
|
||||||
|
&& spa.TenantId == tenantId);
|
||||||
|
|
||||||
|
if (isTeamMember)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Access Granted: User {EmployeeId} is a team member of Project {ProjectId}.", loggedInEmployeeId, projectId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check Level 2: Is the user assigned to any ACTIVE specific Job Ticket?
|
||||||
|
// Optimization: Combined the check for JobTicket and Mapping into a single Join query.
|
||||||
|
// This prevents pulling a list of JobIds into memory (fixing memory bloat) and reduces DB roundtrips.
|
||||||
|
bool hasActiveJobAssignment = await _context.JobTickets
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(jt => jt.ProjectId == projectId
|
||||||
|
&& jt.StatusId != ReviewDoneStatus
|
||||||
|
&& jt.StatusId != ClosedStatus
|
||||||
|
&& jt.IsActive)
|
||||||
|
.Join(_context.JobEmployeeMappings,
|
||||||
|
ticket => ticket.Id,
|
||||||
|
mapping => mapping.JobTicketId,
|
||||||
|
(ticket, mapping) => mapping)
|
||||||
|
.AnyAsync(mapping => mapping.AssigneeId == loggedInEmployeeId
|
||||||
|
&& mapping.TenantId == tenantId);
|
||||||
|
|
||||||
|
if (hasActiveJobAssignment)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Access Granted: User {EmployeeId} is assigned active tickets in Project {ProjectId}.", loggedInEmployeeId, projectId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Default Deny
|
||||||
|
_logger.LogWarning("Access Denied: User {EmployeeId} has no permissions for Project {ProjectId}.", loggedInEmployeeId, projectId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 5. Robust Error Handling
|
||||||
|
// Log the full stack trace for debugging, but return false to maintain security (fail-closed).
|
||||||
|
_logger.LogError(ex, "An error occurred while checking permissions for Employee: {EmployeeId} on Project: {ProjectId}", loggedInEmployeeId, projectId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -220,6 +220,12 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogInfo("Cache HIT. All {ProjectCount} projects found in cache.", projectIds.Count);
|
_logger.LogInfo("Cache HIT. All {ProjectCount} projects found in cache.", projectIds.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pageNumber <= 0 || pageSize <= 0)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Successfully retrieved a total of {ProjectCount} projects.", responseVms.Count);
|
||||||
|
return ApiResponse<object>.SuccessResponse(responseVms, "Projects retrieved successfully.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
var totalEntites = responseVms.Count;
|
var totalEntites = responseVms.Count;
|
||||||
var totalPages = (int)Math.Ceiling((double)totalEntites / pageSize);
|
var totalPages = (int)Math.Ceiling((double)totalEntites / pageSize);
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
|
|
||||||
Task SendEmployeeSuspendMessageAsync(Guid employeeId, Guid tenantId);
|
Task SendEmployeeSuspendMessageAsync(Guid employeeId, Guid tenantId);
|
||||||
|
|
||||||
Task SendAttendanceMessageAsync(Guid projectId, string Name, ATTENDANCE_MARK_TYPE markType, Guid employeeId, Guid tenantId);
|
Task SendAttendanceMessageAsync(Guid projectId, string Name, ATTENDANCE_MARK_TYPE markType, Guid employeeId, string origin, Guid loggedInEmployeeId, Guid tenantId);
|
||||||
Task SendAssignTaskMessageAsync(Guid workItemId, string name, List<Guid> teamMembers, Guid tenantId);
|
Task SendAssignTaskMessageAsync(Guid workItemId, string name, List<Guid> teamMembers, Guid tenantId);
|
||||||
Task SendReportTaskMessageAsync(Guid taskAllocationId, string name, Guid tenantId);
|
Task SendReportTaskMessageAsync(Guid taskAllocationId, string name, Guid tenantId);
|
||||||
Task SendTaskCommentMessageAsync(Guid taskAllocationId, string name, Guid tenantId);
|
Task SendTaskCommentMessageAsync(Guid taskAllocationId, string name, Guid tenantId);
|
||||||
|
|||||||
@ -15,6 +15,15 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<object>> DeActivateServiceProjectAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> DeActivateServiceProjectAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region =================================================================== Project Branch Functions ===================================================================
|
||||||
|
Task<ApiResponse<object>> GetProjectBranchListByProjectAsync(Guid projectId, bool isActive, string? searchString, int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> GetProjectBranchDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> GetBranchTypeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> CreateProjectBranchAsync(ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> UpdateProjectBranchAsync(Guid id, ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> DeleteProjectBranchAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Service Project Allocation Functions ===================================================================
|
#region =================================================================== Service Project Allocation Functions ===================================================================
|
||||||
Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> ManageServiceProjectAllocationAsync(List<ServiceProjectAllocationDto> model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> ManageServiceProjectAllocationAsync(List<ServiceProjectAllocationDto> model, Employee loggedInEmployee, Guid tenantId);
|
||||||
@ -25,7 +34,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Job Tickets Functions ===================================================================
|
#region =================================================================== Job Tickets Functions ===================================================================
|
||||||
Task<ApiResponse<object>> GetJobTicketsListAsync(Guid? projectId, int pageNumber, int pageSize, bool isActive, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetJobTicketsListAsync(Guid? projectId, int pageNumber, int pageSize, bool isActive, bool isArchive, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> GetJobTicketDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetJobTicketDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> GetJobTagListAsync(Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetJobTagListAsync(Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> CreateJobTicketAsync(CreateJobTicketDto model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> CreateJobTicketAsync(CreateJobTicketDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user