From b614ca93e6e588cf6be470bbfb0fd6abea023f42 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 18 Jul 2025 13:00:50 +0530 Subject: [PATCH 01/81] Created an Utility function store logs in mogoDB --- Marco.Pms.CacheHelper/UpdateLogHelper.cs | 91 +++++++++++++++++++ .../MongoDBModels/UpdateLogsObject.cs | 16 ++++ Marco.Pms.Services/Program.cs | 3 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 Marco.Pms.CacheHelper/UpdateLogHelper.cs create mode 100644 Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs diff --git a/Marco.Pms.CacheHelper/UpdateLogHelper.cs b/Marco.Pms.CacheHelper/UpdateLogHelper.cs new file mode 100644 index 0000000..9bc520a --- /dev/null +++ b/Marco.Pms.CacheHelper/UpdateLogHelper.cs @@ -0,0 +1,91 @@ +using Marco.Pms.Model.MongoDBModels; +using Microsoft.Extensions.Configuration; +using MongoDB.Bson; +using MongoDB.Driver; +using System.Collections; + +namespace Marco.Pms.CacheHelper +{ + public class UpdateLogHelper + { + private readonly IMongoDatabase _mongoDatabase; + public UpdateLogHelper(IConfiguration configuration) + { + var connectionString = configuration["MongoDB:ConnectionString"]; + var mongoUrl = new MongoUrl(connectionString); + var client = new MongoClient(mongoUrl); // Your MongoDB connection string + _mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name + } + public async Task PushToUpdateLogs(UpdateLogsObject oldObject, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + await collection.InsertOneAsync(oldObject); + } + + public async Task> GetFromUpdateLogsByEntityId(Guid entityId, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + var filter = Builders.Filter.Eq(p => p.EntityId, entityId.ToString()); + + List result = await collection + .Find(filter) + .ToListAsync(); + + return result; + } + + public async Task> GetFromUpdateLogsByUpdetedById(Guid updatedById, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + var filter = Builders.Filter.Eq(p => p.UpdatedById, updatedById.ToString()); + + List result = await collection + .Find(filter) + .ToListAsync(); + + return result; + } + + public BsonDocument NormalizeGuidsToStrings(object entity) + { + var bson = new BsonDocument(); + + var props = entity.GetType().GetProperties(); + foreach (var prop in props) + { + var value = prop.GetValue(entity); + if (value == null) + { + bson[prop.Name] = BsonNull.Value; + continue; + } + + if (value is Guid guidValue) + { + bson[prop.Name] = guidValue.ToString(); // store Guid as string + } + else if (value is string || value.GetType().IsPrimitive || value is DateTime) + { + bson[prop.Name] = BsonValue.Create(value); // simple types + } + else if (value is IEnumerable list && !(value is string)) + { + var array = new BsonArray(); + foreach (var item in list) + { + array.Add(NormalizeGuidsToStrings(item)); // recursive + } + bson[prop.Name] = array; + } + else + { + // nested object + continue; + } + } + + return bson; + } + + } +} diff --git a/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs b/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs new file mode 100644 index 0000000..3153c78 --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs @@ -0,0 +1,16 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.MongoDBModels +{ + public class UpdateLogsObject + { + [BsonId] + [BsonRepresentation(BsonType.String)] + public Guid Id { get; set; } = Guid.NewGuid(); + public string EntityId { get; set; } = string.Empty; + public BsonDocument? OldObject { get; set; } + public string UpdatedById { get; set; } = string.Empty; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + } +} diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index 30831c6..6d7c8ea 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -1,4 +1,3 @@ -using System.Text; using Marco.Pms.CacheHelper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Authentication; @@ -16,6 +15,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Serilog; +using System.Text; var builder = WebApplication.CreateBuilder(args); @@ -139,6 +139,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); From 1d5b0a9b062cee4219650192612221fdfde1a45a Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 18 Jul 2025 13:00:50 +0530 Subject: [PATCH 02/81] Created an Utility function store logs in mogoDB --- Marco.Pms.CacheHelper/UpdateLogHelper.cs | 91 +++++++++++++++++++ .../MongoDBModels/UpdateLogsObject.cs | 16 ++++ Marco.Pms.Services/Program.cs | 1 + 3 files changed, 108 insertions(+) create mode 100644 Marco.Pms.CacheHelper/UpdateLogHelper.cs create mode 100644 Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs diff --git a/Marco.Pms.CacheHelper/UpdateLogHelper.cs b/Marco.Pms.CacheHelper/UpdateLogHelper.cs new file mode 100644 index 0000000..9bc520a --- /dev/null +++ b/Marco.Pms.CacheHelper/UpdateLogHelper.cs @@ -0,0 +1,91 @@ +using Marco.Pms.Model.MongoDBModels; +using Microsoft.Extensions.Configuration; +using MongoDB.Bson; +using MongoDB.Driver; +using System.Collections; + +namespace Marco.Pms.CacheHelper +{ + public class UpdateLogHelper + { + private readonly IMongoDatabase _mongoDatabase; + public UpdateLogHelper(IConfiguration configuration) + { + var connectionString = configuration["MongoDB:ConnectionString"]; + var mongoUrl = new MongoUrl(connectionString); + var client = new MongoClient(mongoUrl); // Your MongoDB connection string + _mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name + } + public async Task PushToUpdateLogs(UpdateLogsObject oldObject, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + await collection.InsertOneAsync(oldObject); + } + + public async Task> GetFromUpdateLogsByEntityId(Guid entityId, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + var filter = Builders.Filter.Eq(p => p.EntityId, entityId.ToString()); + + List result = await collection + .Find(filter) + .ToListAsync(); + + return result; + } + + public async Task> GetFromUpdateLogsByUpdetedById(Guid updatedById, string collectionName) + { + var collection = _mongoDatabase.GetCollection(collectionName); + var filter = Builders.Filter.Eq(p => p.UpdatedById, updatedById.ToString()); + + List result = await collection + .Find(filter) + .ToListAsync(); + + return result; + } + + public BsonDocument NormalizeGuidsToStrings(object entity) + { + var bson = new BsonDocument(); + + var props = entity.GetType().GetProperties(); + foreach (var prop in props) + { + var value = prop.GetValue(entity); + if (value == null) + { + bson[prop.Name] = BsonNull.Value; + continue; + } + + if (value is Guid guidValue) + { + bson[prop.Name] = guidValue.ToString(); // store Guid as string + } + else if (value is string || value.GetType().IsPrimitive || value is DateTime) + { + bson[prop.Name] = BsonValue.Create(value); // simple types + } + else if (value is IEnumerable list && !(value is string)) + { + var array = new BsonArray(); + foreach (var item in list) + { + array.Add(NormalizeGuidsToStrings(item)); // recursive + } + bson[prop.Name] = array; + } + else + { + // nested object + continue; + } + } + + return bson; + } + + } +} diff --git a/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs b/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs new file mode 100644 index 0000000..3153c78 --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs @@ -0,0 +1,16 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.MongoDBModels +{ + public class UpdateLogsObject + { + [BsonId] + [BsonRepresentation(BsonType.String)] + public Guid Id { get; set; } = Guid.NewGuid(); + public string EntityId { get; set; } = string.Empty; + public BsonDocument? OldObject { get; set; } + public string UpdatedById { get; set; } = string.Empty; + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + } +} diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index 5549702..e67ed7a 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -183,6 +183,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); #endregion #region Cache Services From 51b379916febb2ce83e35aedf2feced7fee13a37 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 18 Jul 2025 18:43:22 +0530 Subject: [PATCH 03/81] Solving the rebase errors --- run_sonar_scan.ps1 | 55 ---------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 run_sonar_scan.ps1 diff --git a/run_sonar_scan.ps1 b/run_sonar_scan.ps1 deleted file mode 100644 index 7753442..0000000 --- a/run_sonar_scan.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -# Filename: run_sonar_scan.ps1 -# -# Description: -# This script automates the SonarQube analysis for a .NET project. -# It performs three main steps: -# 1. Begins the SonarScanner analysis. -# 2. Builds the project (which allows the scanner to analyze the code). -# 3. Ends the analysis and pushes the results to the SonarQube server. -# -# Pre-requisites: -# - .NET SDK must be installed. -# - dotnet-sonarscanner tool must be installed globally. -# - The 'SONAR_TOKEN' environment variable must be set with your SonarQube token. -# -# Usage: -# 1. Open PowerShell. -# 2. Navigate to the root directory of your project. -# 3. Run the script: .\run_sonar_scan.ps1 -# - -# --- Configuration --- -$projectKey = "pms-dotnetcore" -$sonarHost = "https://sonar.marcoaiot.com" - -# --- Script Body --- -try { - # Check if the required environment variable is set - if ([string]::IsNullOrEmpty($env:SONAR_TOKEN)) { - throw "ERROR: The SONAR_TOKEN environment variable is not set. Please set it and restart your terminal." - } - - Write-Host "--- [Step 1/3] Starting SonarScanner analysis... ---" -ForegroundColor Green - dotnet sonarscanner begin /k:"$projectKey" /d:sonar.host.url="$sonarHost" /d:sonar.token="$($env:SONAR_TOKEN)" - - # Check the exit code of the last command. A non-zero code indicates an error. - if ($LASTEXITCODE -ne 0) { throw "SonarScanner 'begin' command failed with exit code $LASTEXITCODE." } - - Write-Host "`n--- [Step 2/3] Building the project... ---" -ForegroundColor Green - dotnet build - if ($LASTEXITCODE -ne 0) { throw "Dotnet 'build' command failed with exit code $LASTEXITCODE." } - - Write-Host "`n--- [Step 3/3] Ending SonarScanner analysis and uploading results... ---" -ForegroundColor Green - dotnet sonarscanner end /d:sonar.token="$($env:SONAR_TOKEN)" - if ($LASTEXITCODE -ne 0) { throw "SonarScanner 'end' command failed with exit code $LASTEXITCODE." } - - Write-Host "`n--- SonarQube analysis completed successfully! ---" -ForegroundColor Green -} -catch { - # This block runs if any of the 'throw' commands are triggered - Write-Host "`n$_" -ForegroundColor Red - Write-Host "Script aborted due to an error." -ForegroundColor Red - - # Exit with a non-zero status code to indicate failure, which is important for CI/CD pipelines - exit 1 -} \ No newline at end of file From cf01fd1138d924d7931da044e3eecafc461a23cb Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 13:12:47 +0530 Subject: [PATCH 04/81] Added models for Expenses management models and migrations --- .../Data/ApplicationDbContext.cs | 410 +- ...19074035_Expenses_tables_Added.Designer.cs | 4180 +++++++++++++++++ .../20250719074035_Expenses_tables_Added.cs | 556 +++ .../ApplicationDbContextModelSnapshot.cs | 754 +++ .../Dtos/Expenses/CreateExpensesDto.cs | 22 + .../Dtos/Master/ExpensesTypeMasterDto.cs | 10 + .../Entitlements/PermissionsMaster.cs | 7 + Marco.Pms.Model/Expenses/BillAttachments.cs | 22 + Marco.Pms.Model/Expenses/Expenses.cs | 49 + Marco.Pms.Model/Expenses/ExpensesReimburse.cs | 20 + .../Expenses/ExpensesReimburseMapping.cs | 20 + Marco.Pms.Model/Expenses/StatusMapping.cs | 22 + .../Expenses/StatusPermissionMapping.cs | 22 + .../Master/ExpensesStatusMaster.cs | 13 + Marco.Pms.Model/Master/ExpensesTypeMaster.cs | 13 + Marco.Pms.Model/Master/PaymentModeMatser.cs | 12 + 16 files changed, 5990 insertions(+), 142 deletions(-) create mode 100644 Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs create mode 100644 Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs create mode 100644 Marco.Pms.Model/Dtos/Master/ExpensesTypeMasterDto.cs create mode 100644 Marco.Pms.Model/Expenses/BillAttachments.cs create mode 100644 Marco.Pms.Model/Expenses/Expenses.cs create mode 100644 Marco.Pms.Model/Expenses/ExpensesReimburse.cs create mode 100644 Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs create mode 100644 Marco.Pms.Model/Expenses/StatusMapping.cs create mode 100644 Marco.Pms.Model/Expenses/StatusPermissionMapping.cs create mode 100644 Marco.Pms.Model/Master/ExpensesStatusMaster.cs create mode 100644 Marco.Pms.Model/Master/ExpensesTypeMaster.cs create mode 100644 Marco.Pms.Model/Master/PaymentModeMatser.cs diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 7601e60..781344e 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -1,11 +1,11 @@ -using System.Globalization; -using Marco.Pms.Model.Activities; +using Marco.Pms.Model.Activities; using Marco.Pms.Model.AttendanceModule; using Marco.Pms.Model.Authentication; using Marco.Pms.Model.Directory; using Marco.Pms.Model.DocumentManager; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Forum; using Marco.Pms.Model.Mail; using Marco.Pms.Model.Master; @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; +using System.Globalization; namespace Marco.Pms.DataAccess.Data { @@ -89,6 +90,15 @@ namespace Marco.Pms.DataAccess.Data public DbSet OTPDetails { get; set; } public DbSet MPINDetails { get; set; } + public DbSet Expenses { get; set; } + public DbSet ExpensesTypeMaster { get; set; } + public DbSet PaymentModeMatser { get; set; } + public DbSet ExpensesStatusMaster { get; set; } + public DbSet BillAttachments { get; set; } + public DbSet ExpensesReimburse { get; set; } + public DbSet ExpensesReimburseMapping { get; set; } + public DbSet StatusPermissionMapping { get; set; } + protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -97,49 +107,6 @@ namespace Marco.Pms.DataAccess.Data ManageApplicationStructure(modelBuilder); - //modelBuilder.Entity().HasData( - // new ApplicationRole - // { - // Id = new Guid("2c8d0808-c421-11ef-9b93-0242ac110002"), - // Role = "Super User", - // Description = "Super User", - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, - // new ApplicationRole - // { - // Id = new Guid("62e0918d-c421-11ef-9b93-0242ac110002"), - // Role = "Welder", - // Description = "", - - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, - // new ApplicationRole - // { - // Id = new Guid("68823f1f-c421-11ef-9b93-0242ac110002"), - // Role = "Helper", - // Description = "", - - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, - // new ApplicationRole - // { - // Id = new Guid("6d3a7c72-c421-11ef-9b93-0242ac110002"), - // Role = "Site Engineer", - // Description = "", - - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // } - // , - // new ApplicationRole - // { - // Id = new Guid("6d3aad72-c421-11ef-9b93-0242ac110002"), - // Role = "Project Manager", - // Description = "", - - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // } - // ); - modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); @@ -196,79 +163,11 @@ namespace Marco.Pms.DataAccess.Data ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") } - //, new Project - //{ - // Id = new Guid("3ef56a12-f5e5-4193-87d6-9e110ed10b86"), - // Name = "Project 2", - // ProjectAddress = "Project 2 Address", - // ContactPerson = "Project 2 Contact Person", - // StartDate = DateTime.ParseExact("2025-04-20 10:11:17.588000", "yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture), - // EndDate = DateTime.ParseExact("2026-04-20 10:11:17.588000", "yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture), - // ProjectStatusId = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - //}, new Project - //{ - // Id = new Guid("54d013e3-0a2b-48be-85c7-5ef03492a18c"), - // Name = "Project 3", - // ProjectAddress = "Project 3 Address", - // ContactPerson = "Project 3 Contact Person", - // StartDate = DateTime.ParseExact("2025-04-20 10:11:17.588000", "yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture), - // EndDate = DateTime.ParseExact("2026-04-20 10:11:17.588000", "yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture), - // ProjectStatusId = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - //} ); var tenantId = _httpContextAccessor.HttpContext?.Items["TenantId"]?.ToString(); - //modelBuilder.Entity() - // .HasData( - // new ActivityMaster - // { - // Id = new Guid("4117b7de-ef6c-461f-a2c2-64eaac5f9a11"), - // ActivityName = "Core Cutting", - // UnitOfMeasurement = UnitOfMeasurement.Number.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("1714f64d-7591-4419-bee5-118d21bb2855"), - // ActivityName = "Fabrication", - // UnitOfMeasurement = UnitOfMeasurement.Meter.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("b3f51a93-dde6-45f9-8b22-f1bf017a640b"), - // ActivityName = "Welding", - // UnitOfMeasurement = UnitOfMeasurement.Meter.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("53eedf44-4076-445f-be93-fedef17117e7"), - // ActivityName = "MS Support Fabrication", - // UnitOfMeasurement = UnitOfMeasurement.Number.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("715b9ddb-d9e2-4afa-8987-d9918905cea4"), - // ActivityName = "MS Support Hanging", - // UnitOfMeasurement = UnitOfMeasurement.Number.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("a3d191a7-a5aa-4dd8-a525-12c99263bbd6"), - // ActivityName = "Hydrant Volve", - // UnitOfMeasurement = UnitOfMeasurement.Number.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // }, new ActivityMaster - // { - // Id = new Guid("c138a7de-713a-4bd4-8292-b0b265be77a3"), - // ActivityName = "Sprinkler Installation", - // UnitOfMeasurement = UnitOfMeasurement.Number.ToString(), - // TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - // } - // ); - modelBuilder.Entity().HasData( new Industry { Id = Guid.Parse("15436ee3-a650-469e-bfc2-59993f7514bb"), Name = "Information Technology (IT) Services" }, new Industry { Id = Guid.Parse("0a63e657-2c5f-49b5-854b-42c978293154"), Name = "Manufacturing & Production" }, @@ -487,6 +386,223 @@ namespace Marco.Pms.DataAccess.Data + modelBuilder.Entity().HasData( + new ExpensesStatusMaster + { + Id = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Name = "Draft", + Description = "Expense has been created but not yet submitted.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Name = "Review Pending", + Description = "Reviewer is currently reviewing the expense.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Name = "Approval Pending", + Description = "Review is completed, waiting for action of approver.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Name = "Rejected", + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Name = "Process Pending", + Description = "Approved expense is awaiting final payment.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), + Name = "Processed", + Description = "Expense has been settled.", + IsSystem = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + } + ); + + modelBuilder.Entity().HasData( + // Process to processed + new StatusMapping + { + Id = Guid.Parse("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Approve to Rejected + new StatusMapping + { + Id = Guid.Parse("36c00548-241c-43ec-bc95-cacebedb925c"), + StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + NextStatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Approve to Process + new StatusMapping + { + Id = Guid.Parse("1fca1700-1266-477d-bba4-9ac3753aa33c"), + StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Review to Rejected + new StatusMapping + { + Id = Guid.Parse("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + NextStatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Review to Aprrove + new StatusMapping + { + Id = Guid.Parse("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + NextStatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Draft to Review + new StatusMapping + { + Id = Guid.Parse("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + StatusId = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"), + NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + } + ); + + modelBuilder.Entity().HasData( + new ExpensesTypeMaster + { + Id = Guid.Parse("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Name = "Procurement", + Description = "Materials, equipment and supplies purchased for site operations.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Name = "Transport", + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Name = "Travelling", + Description = "Delivery of personnel.", + NoOfPersonsRequired = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Name = "Mobilization", + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Name = "Employee Welfare", + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + NoOfPersonsRequired = true, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("77013784-9324-4d8b-bd36-d6f928e68942"), + Name = "Maintenance & Utilities", + Description = "Machinery servicing, electricity, water, and temporary office needs.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Name = "Vendor/Supplier Payments", + Description = "Scheduled payments for external services or goods.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new ExpensesTypeMaster + { + Id = Guid.Parse("4842fa61-64eb-4241-aebd-8282065af9f9"), + Name = "Compliance & Safety", + Description = "Government fees, insurance, inspections and safety-related expenditures.", + NoOfPersonsRequired = false, + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + } + ); + + modelBuilder.Entity().HasData( + new PaymentModeMatser + { + Id = Guid.Parse("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Name = "Cash", + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new PaymentModeMatser + { + Id = Guid.Parse("48d9b462-5d87-4dec-8dec-2bc943943172"), + Name = "Cheque", + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new PaymentModeMatser + { + Id = Guid.Parse("ed667353-8eea-4fd1-8750-719405932480"), + Name = "NetBanking", + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new PaymentModeMatser + { + Id = Guid.Parse("2e919e94-694c-41d9-9489-0a2b4208a027"), + Name = "UPI", + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + } + ); modelBuilder.Entity().HasData(new Module { @@ -508,53 +624,63 @@ namespace Marco.Pms.DataAccess.Data Key = "504ec132-e6a9-422f-8f85-050602cfce05" }); - - modelBuilder.Entity().HasData( + // Project Module new Feature { Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), Description = "Manage Project", Name = "Project Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true }, - //new Feature { Id = new Guid("9666de86-d7c7-4d3d-acaa-fcd6d6b81f3c"), Description = "Manage Infra", Name = "Manage Infra", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true }, + new Feature { Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", Name = "Expense Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true }, new Feature { Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), Description = "Manage Tasks", Name = "Task Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true }, + // Employee Module new Feature { Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), Description = "Manage Employee", Name = "Employee Management", ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), IsActive = true }, new Feature { Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), Description = "Attendance", Name = "Attendance Management", ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), IsActive = true }, - new Feature { Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), Description = "Global Masters", Name = "Masters", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true }, + // Master Module + new Feature { Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), Description = "Global Masters", Name = "Masters", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true }, new Feature { Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), Description = "Managing all directory related rights", Name = "Directory Management", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true } - - //new Feature { Id = new Guid("660131a4-788c-4739-a082-cbbf7879cbf2"), Description = "Tenant Masters", Name = "Tenant Masters", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true } ); modelBuilder.Entity().HasData( + // Project Management Feature new FeaturePermission { Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "View Project", Description = "Access all information related to the project." }, - new FeaturePermission { Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Project", Description = "Potentially edit the project name, description, start/end dates, or status." }, - new FeaturePermission { Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Team", Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects." }, - new FeaturePermission { Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "View Project Infra", Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations" }, - new FeaturePermission { Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Project Infra", Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure." }, + new FeaturePermission { Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Project", Description = "Potentially edit the project name, description, start/end dates, or status." }, + new FeaturePermission { Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Team", Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects." }, + new FeaturePermission { Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "View Project Infra", Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations" }, + new FeaturePermission { Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), IsEnabled = true, Name = "Manage Project Infra", Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure." }, + // Task Management Feature + new FeaturePermission { Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "View Task", Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions." }, + new FeaturePermission { Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Add/Edit Task", Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.)," }, + new FeaturePermission { Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Assign/Report Progress", Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks" }, + new FeaturePermission { Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Approve Task", Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria" }, - new FeaturePermission { Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "View Task", Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions." }, - new FeaturePermission { Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Add/Edit Task", Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.)," }, - new FeaturePermission { Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Assign/Report Progress", Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks" }, - new FeaturePermission { Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), IsEnabled = true, Name = "Approve Task", Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria" }, + // Employee Management Feature + new FeaturePermission { Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "View All Employees", Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data" }, + new FeaturePermission { Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "View Team Members", Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data" }, + new FeaturePermission { Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "Add/Edit Employee", Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data" }, + new FeaturePermission { Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "Assign Roles", Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system." }, + // Attendance Management Feature + new FeaturePermission { Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Team Attendance ", Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager." }, + new FeaturePermission { Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Regularize Attendance", Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records" }, + new FeaturePermission { Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Self Attendance", Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager." }, - new FeaturePermission { Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "View All Employees", Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data" }, - new FeaturePermission { Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "View Team Members", Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data" }, - new FeaturePermission { Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "Add/Edit Employee", Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data" }, - new FeaturePermission { Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), IsEnabled = true, Name = "Assign Roles", Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system." }, + // Masters Feature + new FeaturePermission { Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), IsEnabled = true, Name = "View Masters", Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency" }, + new FeaturePermission { Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), IsEnabled = true, Name = "Manage Masters", Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories" }, + // Directory Management Feature + new FeaturePermission { Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory Admin", Description = "Full control over all directories, including the ability to manage permissions for all directories in the system." }, + new FeaturePermission { Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory Manager", Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories." }, + new FeaturePermission { Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory User", Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created." }, - new FeaturePermission { Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Team Attendance ", Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager." }, - new FeaturePermission { Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Regularize Attendance", Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records" }, - new FeaturePermission { Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), IsEnabled = true, Name = "Self Attendance", Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager." }, - - new FeaturePermission { Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), IsEnabled = true, Name = "View Masters", Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency" }, - new FeaturePermission { Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), IsEnabled = true, Name = "Manage Masters", Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories" }, - - new FeaturePermission { Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory Admin", Description = "Full control over all directories, including the ability to manage permissions for all directories in the system." }, - new FeaturePermission { Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory Manager", Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories." }, - new FeaturePermission { Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory User", Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created." } - //new FeaturePermission { Id = new Guid("6b1a6d97-a951-4de5-9b19-709bac7c4f18"), FeatureId = new Guid("660131a4-788c-4739-a082-cbbf7879cbf2"), IsEnabled = true, Name = "Manage Masters", Description = "" } + // Expense Management Feature + new FeaturePermission { Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "View Self", Description = "Allows a user to view only the expense records that they have personally submitted" }, + new FeaturePermission { Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "View All", Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them" }, + new FeaturePermission { Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Upload", Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices." }, + new FeaturePermission { Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Review", Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected." }, + new FeaturePermission { Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Approve", Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system." }, + new FeaturePermission { Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Process", Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled." }, + new FeaturePermission { Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Manage", Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules." } ); } diff --git a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs new file mode 100644 index 0000000..a126fc0 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs @@ -0,0 +1,4180 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250719074035_Expenses_tables_Added")] + partial class Expenses_tables_Added + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpeStatusIdnsesId") + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpeStatusIdnsesId"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Description = "Expense has been created but not yet submitted.", + IsActive = true, + IsSystem = true, + Name = "Draft", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Description = "Reviewer is currently reviewing the expense.", + IsActive = true, + IsSystem = true, + Name = "Review Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Description = "Review is completed, waiting for action of approver.", + IsActive = true, + IsSystem = true, + Name = "Approval Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsActive = true, + IsSystem = true, + Name = "Rejected", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Description = "Approved expense is awaiting final payment.", + IsActive = true, + IsSystem = true, + Name = "Process Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Description = "Expense has been settled.", + IsActive = true, + IsSystem = true, + Name = "Processed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#6c757d", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("Project"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("ExpeStatusIdnsesId"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs b/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs new file mode 100644 index 0000000..d53b349 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs @@ -0,0 +1,556 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Expenses_tables_Added : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ExpensesReimburse", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ReimburseTransactionId = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ReimburseDate = table.Column(type: "datetime(6)", nullable: false), + ReimburseById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ReimburseNote = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpensesReimburse", x => x.Id); + table.ForeignKey( + name: "FK_ExpensesReimburse_Employees_ReimburseById", + column: x => x.ReimburseById, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpensesReimburse_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "ExpensesStatusMaster", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + IsSystem = table.Column(type: "tinyint(1)", nullable: false), + IsActive = table.Column(type: "tinyint(1)", nullable: false), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpensesStatusMaster", x => x.Id); + table.ForeignKey( + name: "FK_ExpensesStatusMaster_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "ExpensesTypeMaster", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + NoOfPersonsRequired = table.Column(type: "tinyint(1)", nullable: false), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + IsActive = table.Column(type: "tinyint(1)", nullable: false), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpensesTypeMaster", x => x.Id); + table.ForeignKey( + name: "FK_ExpensesTypeMaster_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "PaymentModeMatser", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + IsActive = table.Column(type: "tinyint(1)", nullable: false), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_PaymentModeMatser", x => x.Id); + table.ForeignKey( + name: "FK_PaymentModeMatser_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "StatusMapping", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_StatusMapping", x => x.Id); + table.ForeignKey( + name: "FK_StatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", + column: x => x.ExpeStatusIdnsesId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_StatusMapping_ExpensesStatusMaster_NextStatusId", + column: x => x.NextStatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_StatusMapping_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "StatusPermissionMapping", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + PermissionId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_StatusPermissionMapping", x => x.Id); + table.ForeignKey( + name: "FK_StatusPermissionMapping_ExpensesStatusMaster_StatusId", + column: x => x.StatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_StatusPermissionMapping_FeaturePermissions_PermissionId", + column: x => x.PermissionId, + principalTable: "FeaturePermissions", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Expenses", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ProjectId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpensesTypeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + PaymentModeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + PaidById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TransactionDate = table.Column(type: "datetime(6)", nullable: false), + TransactionId = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Location = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + GSTNumber = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + SupplerName = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Amount = table.Column(type: "double", nullable: false), + NoOfPersons = table.Column(type: "int", nullable: true), + StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + PreApproved = table.Column(type: "tinyint(1)", nullable: false), + IsActive = table.Column(type: "tinyint(1)", nullable: false), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_Expenses", x => x.Id); + table.ForeignKey( + name: "FK_Expenses_Employees_PaidById", + column: x => x.PaidById, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Expenses_ExpensesStatusMaster_StatusId", + column: x => x.StatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Expenses_ExpensesTypeMaster_ExpensesTypeId", + column: x => x.ExpensesTypeId, + principalTable: "ExpensesTypeMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Expenses_PaymentModeMatser_PaymentModeId", + column: x => x.PaymentModeId, + principalTable: "PaymentModeMatser", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Expenses_Projects_ProjectId", + column: x => x.ProjectId, + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Expenses_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "BillAttachments", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpensesId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + DocumentId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_BillAttachments", x => x.Id); + table.ForeignKey( + name: "FK_BillAttachments_Documents_DocumentId", + column: x => x.DocumentId, + principalTable: "Documents", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BillAttachments_Expenses_ExpensesId", + column: x => x.ExpensesId, + principalTable: "Expenses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BillAttachments_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "ExpensesReimburseMapping", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpensesId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpensesReimburseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpensesReimburseMapping", x => x.Id); + table.ForeignKey( + name: "FK_ExpensesReimburseMapping_ExpensesReimburse_ExpensesReimburse~", + column: x => x.ExpensesReimburseId, + principalTable: "ExpensesReimburse", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpensesReimburseMapping_Expenses_ExpensesId", + column: x => x.ExpensesId, + principalTable: "Expenses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "ExpensesStatusMaster", + columns: new[] { "Id", "Description", "IsActive", "IsSystem", "Name", "TenantId" }, + values: new object[,] + { + { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "Expense has been created but not yet submitted.", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "Review is completed, waiting for action of approver.", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "Expense has been settled.", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "Reviewer is currently reviewing the expense.", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "Expense was declined, often with a reason(either review rejected or approval rejected.", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "Approved expense is awaiting final payment.", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.InsertData( + table: "ExpensesTypeMaster", + columns: new[] { "Id", "Description", "IsActive", "Name", "NoOfPersonsRequired", "TenantId" }, + values: new object[,] + { + { new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), "Scheduled payments for external services or goods.", true, "Vendor/Supplier Payments", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), "Vehicle fuel, logistics services and delivery of goods or personnel.", true, "Transport", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), "Government fees, insurance, inspections and safety-related expenditures.", true, "Compliance & Safety", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), "Site setup costs including equipment deployment and temporary infrastructure.", true, "Mobilization", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), "Materials, equipment and supplies purchased for site operations.", true, "Procurement", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), "Machinery servicing, electricity, water, and temporary office needs.", true, "Maintenance & Utilities", false, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), "Delivery of personnel.", true, "Travelling", true, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", true, "Employee Welfare", true, new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.InsertData( + table: "Features", + columns: new[] { "Id", "Description", "IsActive", "ModuleId", "Name" }, + values: new object[] { new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", true, new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), "Expense Management" }); + + migrationBuilder.InsertData( + table: "PaymentModeMatser", + columns: new[] { "Id", "Description", "IsActive", "Name", "TenantId" }, + values: new object[,] + { + { new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), "Physical currency; still used for small or informal transactions.", true, "Cash", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", true, "UPI", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), "Paper-based payment order; less common now due to processing delays and fraud risks.", true, "Cheque", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ed667353-8eea-4fd1-8750-719405932480"), "Online banking portals used to transfer funds directly between accounts", true, "NetBanking", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.InsertData( + table: "FeaturePermissions", + columns: new[] { "Id", "Description", "FeatureId", "IsEnabled", "Name" }, + values: new object[,] + { + { new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "View All" }, + { new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "Upload" }, + { new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "Review" }, + { new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), "Allows a user to view only the expense records that they have personally submitted", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "View Self" }, + { new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "Manage" }, + { new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "Process" }, + { new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), true, "Approve" } + }); + + migrationBuilder.InsertData( + table: "StatusMapping", + columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.CreateIndex( + name: "IX_BillAttachments_DocumentId", + table: "BillAttachments", + column: "DocumentId"); + + migrationBuilder.CreateIndex( + name: "IX_BillAttachments_ExpensesId", + table: "BillAttachments", + column: "ExpensesId"); + + migrationBuilder.CreateIndex( + name: "IX_BillAttachments_TenantId", + table: "BillAttachments", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_ExpensesTypeId", + table: "Expenses", + column: "ExpensesTypeId"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_PaidById", + table: "Expenses", + column: "PaidById"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_PaymentModeId", + table: "Expenses", + column: "PaymentModeId"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_ProjectId", + table: "Expenses", + column: "ProjectId"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_StatusId", + table: "Expenses", + column: "StatusId"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_TenantId", + table: "Expenses", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesReimburse_ReimburseById", + table: "ExpensesReimburse", + column: "ReimburseById"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesReimburse_TenantId", + table: "ExpensesReimburse", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesReimburseMapping_ExpensesId", + table: "ExpensesReimburseMapping", + column: "ExpensesId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesReimburseMapping_ExpensesReimburseId", + table: "ExpensesReimburseMapping", + column: "ExpensesReimburseId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMaster_TenantId", + table: "ExpensesStatusMaster", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesTypeMaster_TenantId", + table: "ExpensesTypeMaster", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_PaymentModeMatser_TenantId", + table: "PaymentModeMatser", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_ExpeStatusIdnsesId", + table: "StatusMapping", + column: "ExpeStatusIdnsesId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_NextStatusId", + table: "StatusMapping", + column: "NextStatusId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_TenantId", + table: "StatusMapping", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusPermissionMapping_PermissionId", + table: "StatusPermissionMapping", + column: "PermissionId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusPermissionMapping_StatusId", + table: "StatusPermissionMapping", + column: "StatusId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "BillAttachments"); + + migrationBuilder.DropTable( + name: "ExpensesReimburseMapping"); + + migrationBuilder.DropTable( + name: "StatusMapping"); + + migrationBuilder.DropTable( + name: "StatusPermissionMapping"); + + migrationBuilder.DropTable( + name: "ExpensesReimburse"); + + migrationBuilder.DropTable( + name: "Expenses"); + + migrationBuilder.DropTable( + name: "ExpensesStatusMaster"); + + migrationBuilder.DropTable( + name: "ExpensesTypeMaster"); + + migrationBuilder.DropTable( + name: "PaymentModeMatser"); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11")); + + migrationBuilder.DeleteData( + table: "FeaturePermissions", + keyColumn: "Id", + keyValue: new Guid("eaafdd76-8aac-45f9-a530-315589c6deca")); + + migrationBuilder.DeleteData( + table: "Features", + keyColumn: "Id", + keyValue: new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7")); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 258f8bd..766e2dd 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1133,6 +1133,62 @@ namespace Marco.Pms.DataAccess.Migrations FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), IsEnabled = true, Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" }); }); @@ -1206,6 +1262,252 @@ namespace Marco.Pms.DataAccess.Migrations }); }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpeStatusIdnsesId") + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpeStatusIdnsesId"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + }); + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => { b.Property("Id") @@ -1496,6 +1798,196 @@ namespace Marco.Pms.DataAccess.Migrations b.ToTable("ActivityMasters"); }); + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Description = "Expense has been created but not yet submitted.", + IsActive = true, + IsSystem = true, + Name = "Draft", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Description = "Reviewer is currently reviewing the expense.", + IsActive = true, + IsSystem = true, + Name = "Review Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Description = "Review is completed, waiting for action of approver.", + IsActive = true, + IsSystem = true, + Name = "Approval Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsActive = true, + IsSystem = true, + Name = "Rejected", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Description = "Approved expense is awaiting final payment.", + IsActive = true, + IsSystem = true, + Name = "Process Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Description = "Expense has been settled.", + IsActive = true, + IsSystem = true, + Name = "Processed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => { b.Property("Id") @@ -1530,6 +2022,14 @@ namespace Marco.Pms.DataAccess.Migrations Name = "Project Management" }, new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new { Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), Description = "Manage Tasks", @@ -1677,6 +2177,67 @@ namespace Marco.Pms.DataAccess.Migrations }); }); + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => { b.Property("Id") @@ -3061,6 +3622,166 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Industry"); }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("Project"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("ExpeStatusIdnsesId"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => { b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") @@ -3165,6 +3886,28 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Tenant"); }); + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => { b.HasOne("Marco.Pms.Model.Master.Module", "Module") @@ -3176,6 +3919,17 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Module"); }); + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => { b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") diff --git a/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs new file mode 100644 index 0000000..d1d8ec4 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs @@ -0,0 +1,22 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Model.Dtos.Expenses +{ + public class CreateExpensesDto + { + public required Guid ProjectId { get; set; } + public Guid ExpensesTypeId { get; set; } + public Guid PaymentModeId { get; set; } + public DateTime TransactionDate { get; set; } = DateTime.Now; + public string? TransactionId { get; set; } + public required string Description { get; set; } + public string? Location { get; set; } + public string? GSTNumber { get; set; } + public required string SupplerName { get; set; } + public required double Amount { get; set; } + public int? NoOfPersons { get; set; } = 0; + public required Guid StatusId { get; set; } + public bool PreApproved { get; set; } = false; + public required List BillAttachments { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Master/ExpensesTypeMasterDto.cs b/Marco.Pms.Model/Dtos/Master/ExpensesTypeMasterDto.cs new file mode 100644 index 0000000..d8f204a --- /dev/null +++ b/Marco.Pms.Model/Dtos/Master/ExpensesTypeMasterDto.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.Dtos.Master +{ + public class ExpensesTypeMasterDto + { + public Guid? Id { get; set; } + public required string Name { get; set; } + public required bool NoOfPersonsRequired { get; set; } + public string? Description { get; set; } + } +} diff --git a/Marco.Pms.Model/Entitlements/PermissionsMaster.cs b/Marco.Pms.Model/Entitlements/PermissionsMaster.cs index d0bef58..07ac1b5 100644 --- a/Marco.Pms.Model/Entitlements/PermissionsMaster.cs +++ b/Marco.Pms.Model/Entitlements/PermissionsMaster.cs @@ -23,6 +23,13 @@ public static readonly Guid SelfAttendance = Guid.Parse("ccb0589f-712b-43de-92ed-5b6088e7dc4e"); public static readonly Guid ViewMasters = Guid.Parse("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"); public static readonly Guid ManageMasters = Guid.Parse("588a8824-f924-4955-82d8-fc51956cf323"); + public static readonly Guid ExpenseViewSelf = Guid.Parse("385be49f-8fde-440e-bdbc-3dffeb8dd116"); + public static readonly Guid ExpenseViewAll = Guid.Parse("01e06444-9ca7-4df4-b900-8c3fa051b92f"); + public static readonly Guid ExpenseUpload = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7"); + public static readonly Guid ExpenseReview = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"); + public static readonly Guid ExpenseApprove = Guid.Parse("eaafdd76-8aac-45f9-a530-315589c6deca"); + public static readonly Guid ExpenseProcess = Guid.Parse("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"); + public static readonly Guid ExpenseManage = Guid.Parse("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"); } } diff --git a/Marco.Pms.Model/Expenses/BillAttachments.cs b/Marco.Pms.Model/Expenses/BillAttachments.cs new file mode 100644 index 0000000..5d62b09 --- /dev/null +++ b/Marco.Pms.Model/Expenses/BillAttachments.cs @@ -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.Expenses +{ + public class BillAttachments : TenantRelation + { + public Guid Id { get; set; } + public Guid ExpensesId { get; set; } + + [ValidateNever] + [ForeignKey("ExpensesId")] + public Expenses? Expenses { get; set; } + public Guid DocumentId { get; set; } + + [ValidateNever] + [ForeignKey("DocumentId")] + public Document? Document { get; set; } + } +} diff --git a/Marco.Pms.Model/Expenses/Expenses.cs b/Marco.Pms.Model/Expenses/Expenses.cs new file mode 100644 index 0000000..19e8333 --- /dev/null +++ b/Marco.Pms.Model/Expenses/Expenses.cs @@ -0,0 +1,49 @@ +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Master; +using Marco.Pms.Model.Projects; +using Marco.Pms.Model.Utilities; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Marco.Pms.Model.Expenses +{ + public class Expenses : TenantRelation + { + public Guid Id { get; set; } + public Guid ProjectId { get; set; } + + [ValidateNever] + [ForeignKey("ProjectId")] + public Project? Project { get; set; } + public Guid ExpensesTypeId { get; set; } + + [ValidateNever] + [ForeignKey("ExpensesTypeId")] + public ExpensesTypeMaster? ExpensesType { get; set; } + public Guid PaymentModeId { get; set; } + + [ValidateNever] + [ForeignKey("PaymentModeId")] + public PaymentModeMatser? PaymentMode { get; set; } + public Guid PaidById { get; set; } + + [ValidateNever] + [ForeignKey("PaidById")] + public Employee? PaidBy { get; set; } + public DateTime TransactionDate { get; set; } + public string? TransactionId { get; set; } + public string Description { get; set; } = string.Empty; + public string? Location { get; set; } + public string? GSTNumber { get; set; } + public string SupplerName { get; set; } = string.Empty; + public double Amount { get; set; } + public int? NoOfPersons { get; set; } + public Guid StatusId { get; set; } + + [ValidateNever] + [ForeignKey("StatusId")] + public ExpensesStatusMaster? Status { get; set; } + public bool PreApproved { get; set; } = false; + public bool IsActive { get; set; } = true; + } +} diff --git a/Marco.Pms.Model/Expenses/ExpensesReimburse.cs b/Marco.Pms.Model/Expenses/ExpensesReimburse.cs new file mode 100644 index 0000000..401ecda --- /dev/null +++ b/Marco.Pms.Model/Expenses/ExpensesReimburse.cs @@ -0,0 +1,20 @@ +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.Expenses +{ + public class ExpensesReimburse : TenantRelation + { + public Guid Id { get; set; } + public string ReimburseTransactionId { get; set; } = string.Empty; + public DateTime ReimburseDate { get; set; } + public Guid ReimburseById { get; set; } + + [ValidateNever] + [ForeignKey("ReimburseById")] + public Employee? ReimburseBy { get; set; } + public string ReimburseNote { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs b/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs new file mode 100644 index 0000000..c1c2be6 --- /dev/null +++ b/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Marco.Pms.Model.Expenses +{ + public class ExpensesReimburseMapping + { + public Guid Id { get; set; } + public Guid ExpensesId { get; set; } + + [ValidateNever] + [ForeignKey("ExpensesId")] + public Expenses? Expenses { get; set; } + public Guid ExpensesReimburseId { get; set; } + + [ValidateNever] + [ForeignKey("ExpensesReimburseId")] + public ExpensesReimburse? ExpensesReimburse { get; set; } + } +} diff --git a/Marco.Pms.Model/Expenses/StatusMapping.cs b/Marco.Pms.Model/Expenses/StatusMapping.cs new file mode 100644 index 0000000..cc683a4 --- /dev/null +++ b/Marco.Pms.Model/Expenses/StatusMapping.cs @@ -0,0 +1,22 @@ +using Marco.Pms.Model.Master; +using Marco.Pms.Model.Utilities; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Marco.Pms.Model.Expenses +{ + public class StatusMapping : TenantRelation + { + public Guid Id { get; set; } + public Guid StatusId { get; set; } + + [ValidateNever] + [ForeignKey("ExpeStatusIdnsesId")] + public ExpensesStatusMaster? Status { get; set; } + public Guid NextStatusId { get; set; } + + [ValidateNever] + [ForeignKey("NextStatusId")] + public ExpensesStatusMaster? NextStatus { get; set; } + } +} diff --git a/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs new file mode 100644 index 0000000..2fe9334 --- /dev/null +++ b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs @@ -0,0 +1,22 @@ +using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Master; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Marco.Pms.Model.Expenses +{ + public class StatusPermissionMapping + { + public Guid Id { get; set; } + public Guid StatusId { get; set; } + + [ValidateNever] + [ForeignKey("StatusId")] + public ExpensesStatusMaster? Status { get; set; } + public Guid PermissionId { get; set; } + + [ValidateNever] + [ForeignKey("PermissionId")] + public FeaturePermission? Permission { get; set; } + } +} diff --git a/Marco.Pms.Model/Master/ExpensesStatusMaster.cs b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs new file mode 100644 index 0000000..dc2556a --- /dev/null +++ b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs @@ -0,0 +1,13 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Model.Master +{ + public class ExpensesStatusMaster : TenantRelation + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public bool IsSystem { get; set; } = false; + public bool IsActive { get; set; } = true; + } +} diff --git a/Marco.Pms.Model/Master/ExpensesTypeMaster.cs b/Marco.Pms.Model/Master/ExpensesTypeMaster.cs new file mode 100644 index 0000000..7e7d682 --- /dev/null +++ b/Marco.Pms.Model/Master/ExpensesTypeMaster.cs @@ -0,0 +1,13 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Model.Master +{ + public class ExpensesTypeMaster : TenantRelation + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public bool NoOfPersonsRequired { get; set; } + public string Description { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + } +} diff --git a/Marco.Pms.Model/Master/PaymentModeMatser.cs b/Marco.Pms.Model/Master/PaymentModeMatser.cs new file mode 100644 index 0000000..e947c55 --- /dev/null +++ b/Marco.Pms.Model/Master/PaymentModeMatser.cs @@ -0,0 +1,12 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Model.Master +{ + public class PaymentModeMatser : TenantRelation + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + } +} From 0b1d2669ca29b42ad6d5a4ec9101bf8ac72731eb Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 14:58:47 +0530 Subject: [PATCH 05/81] Improved the data seeder function --- .../Controllers/TaskController.cs | 6 +- .../Service/StartupDataSeeder.cs | 285 +++++++++++------- 2 files changed, 184 insertions(+), 107 deletions(-) diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index b764f00..6a1921b 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -230,8 +230,8 @@ namespace MarcoBMS.Services.Controllers : image.Base64Data; var fileType = _s3Service.GetContentTypeFromBase64(base64); - var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_report"); - var objectKey = $"tenant-{tenantId}/project-{projectId}/Actitvity/{fileName}"; + var fileName = _s3Service.GenerateFileName(fileType, taskAllocation.Id, "task_report"); + var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); @@ -336,7 +336,7 @@ namespace MarcoBMS.Services.Controllers : image.Base64Data; var fileType = _s3Service.GetContentTypeFromBase64(base64); - var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_comment"); + var fileName = _s3Service.GenerateFileName(fileType, comment.Id, "task_comment"); var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); diff --git a/Marco.Pms.Services/Service/StartupDataSeeder.cs b/Marco.Pms.Services/Service/StartupDataSeeder.cs index 10d6f71..d2496fc 100644 --- a/Marco.Pms.Services/Service/StartupDataSeeder.cs +++ b/Marco.Pms.Services/Service/StartupDataSeeder.cs @@ -4,134 +4,211 @@ using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Roles; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; // For configuration +using System.Linq.Expressions; namespace Marco.Pms.Services.Service { + // A configuration class to hold settings from appsettings.json + // This avoids hardcoding sensitive information. + public class SuperAdminSettings + { + public const string CONFIG_SECTION_NAME = "SuperAdminAccount"; + public string Email { get; set; } = "admin@marcoaiot.com"; + public string Password { get; set; } = "User@123"; + public string TenantId { get; set; } = "b3466e83-7e11-464c-b93a-daf047838b26"; + } + public class StartupUserSeeder : IHostedService { private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; - public StartupUserSeeder(IServiceProvider serviceProvider) + // Constants to avoid "magic strings" + private const string AdminJobRoleName = "Admin"; + private const string SuperUserRoleName = "Super User"; + + public StartupUserSeeder(IServiceProvider serviceProvider, ILogger logger) { _serviceProvider = serviceProvider; + _logger = logger; } public async Task StartAsync(CancellationToken cancellationToken) { + _logger.LogInformation("Starting database seeding process..."); + using var scope = _serviceProvider.CreateScope(); - var userManager = scope.ServiceProvider.GetRequiredService>(); - var dbContext = scope.ServiceProvider.GetRequiredService(); + var serviceProvider = scope.ServiceProvider; - var userEmail = "admin@marcoaiot.com"; + // Get services from the scoped provider + var userManager = serviceProvider.GetRequiredService>(); + var dbContext = serviceProvider.GetRequiredService(); + var adminSettings = serviceProvider.GetRequiredService>().Value; + var tenantId = Guid.Parse(adminSettings.TenantId); - var user = await userManager.FindByEmailAsync(userEmail); - var newUser = new ApplicationUser + // Use a database transaction to ensure all operations succeed or none do. + await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); + + try { - UserName = userEmail, - Email = userEmail, - EmailConfirmed = true, - IsRootUser = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - }; - var result = new IdentityResult(); + // 1. Seed the Application User (Super Admin) + var user = await SeedSuperAdminUserAsync(userManager, adminSettings, tenantId); + // 2. Seed the Job Role + var jobRole = await GetOrCreateAsync( + dbContext.JobRoles, + j => j.Name == AdminJobRoleName && j.TenantId == tenantId, + () => new JobRole + { + Name = AdminJobRoleName, + Description = "Administrator with full system access.", + TenantId = tenantId + }); + + // 3. Seed the Application Role + var appRole = await GetOrCreateAsync( + dbContext.ApplicationRoles, + a => a.Role == SuperUserRoleName && a.TenantId == tenantId, + () => new ApplicationRole + { + Role = SuperUserRoleName, + Description = "System role with all permissions.", + IsSystem = true, + TenantId = tenantId + }); + + // 4. Seed the Employee record linked to the user and job role + var employee = await GetOrCreateAsync( + dbContext.Employees, + e => e.Email == adminSettings.Email && e.TenantId == tenantId, + () => new Employee + { + ApplicationUserId = user.Id, + FirstName = "Admin", + LastName = "User", + Email = adminSettings.Email, + TenantId = tenantId, + PhoneNumber = "9876543210", + JobRoleId = jobRole.Id, + IsSystem = true, + JoiningDate = DateTime.UtcNow, + BirthDate = new DateTime(1970, 1, 1) + // Set other non-nullable fields to sensible defaults + }); + + // 5. Seed the Employee-Role Mapping + await GetOrCreateAsync( + dbContext.EmployeeRoleMappings, + erm => erm.EmployeeId == employee.Id && erm.RoleId == appRole.Id, + () => new EmployeeRoleMapping + { + EmployeeId = employee.Id, + RoleId = appRole.Id, + TenantId = tenantId, + IsEnabled = true + }); + + // 6. Seed Role Permissions (Efficiently) + await SeedRolePermissionsAsync(dbContext, appRole.Id); + + // All entities are now tracked by the DbContext. + // A single SaveChanges call is more efficient. + await dbContext.SaveChangesAsync(cancellationToken); + + // If all operations were successful, commit the transaction. + await transaction.CommitAsync(cancellationToken); + _logger.LogInformation("Database seeding process completed successfully."); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred during database seeding. Rolling back changes."); + await transaction.RollbackAsync(cancellationToken); + // Optionally re-throw or handle the exception as needed + throw; + } + } + + private async Task SeedSuperAdminUserAsync(UserManager userManager, SuperAdminSettings settings, Guid tenantId) + { + _logger.LogInformation("Seeding Super Admin user: {Email}", settings.Email); + var user = await userManager.FindByEmailAsync(settings.Email); if (user == null) { - result = await userManager.CreateAsync(newUser, "User@123"); - } - else - { - newUser = user; - } - - var jobRole = new JobRole - { - Id = Guid.Empty, - Name = "Admin", - Description = "Admin", - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"), - }; - - if (!await dbContext.JobRoles.Where(j => j.Name == "Admin").AnyAsync()) - { - await dbContext.JobRoles.AddAsync(jobRole); - } - else - { - jobRole = await dbContext.JobRoles.Where(j => j.Name == "Admin").FirstOrDefaultAsync(); - } - var role = new ApplicationRole - { - Role = "Super User", - Description = "Super User", - IsSystem = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - }; - if (!await dbContext.ApplicationRoles.Where(a => a.Role == "Super User").AnyAsync()) - { - await dbContext.ApplicationRoles.AddAsync(role); - } - else - { - role = await dbContext.ApplicationRoles.Where(a => a.Role == "Super User").FirstOrDefaultAsync(); - } - await dbContext.SaveChangesAsync(); - var employee = new Employee - { - ApplicationUserId = newUser.Id, - FirstName = "Admin", - LastName = "", - Email = userEmail, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"), - CurrentAddress = "", - BirthDate = Convert.ToDateTime("1965-04-20 10:11:17.588000"), - EmergencyPhoneNumber = "", - EmergencyContactPerson = "", - AadharNumber = "", - Gender = "", - MiddleName = "", - PanNumber = "", - PermanentAddress = "", - PhoneNumber = "9876543210", - Photo = null, // GetFileDetails(model.Photo).Result.FileData, - JobRoleId = jobRole != null ? jobRole.Id : Guid.Empty, - IsSystem = true, - JoiningDate = Convert.ToDateTime("2000-04-20 10:11:17.588000"), - }; - if ((!await dbContext.Employees.Where(e => e.Email == "admin@marcoaiot.com").AnyAsync()) && jobRole?.Id != Guid.Empty) - { - await dbContext.Employees.AddAsync(employee); - } - else - { - employee = await dbContext.Employees.Where(e => e.Email == "admin@marcoaiot.com").FirstOrDefaultAsync(); - } - await dbContext.SaveChangesAsync(); - if (!await dbContext.EmployeeRoleMappings.AnyAsync()) - { - await dbContext.EmployeeRoleMappings.AddAsync(new EmployeeRoleMapping + user = new ApplicationUser { - EmployeeId = employee?.Id ?? Guid.Empty, - IsEnabled = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26"), - RoleId = role?.Id ?? Guid.Empty - }); - } - if (!await dbContext.RolePermissionMappings.AnyAsync()) - { - List permissions = await dbContext.FeaturePermissions.ToListAsync(); - List rolesMapping = new List(); - foreach (var permission in permissions) + UserName = settings.Email, + Email = settings.Email, + EmailConfirmed = true, + IsRootUser = true, + TenantId = tenantId + }; + var result = await userManager.CreateAsync(user, settings.Password); + + if (!result.Succeeded) { - rolesMapping.Add(new RolePermissionMappings - { - ApplicationRoleId = role != null ? role.Id : Guid.Empty, - FeaturePermissionId = permission.Id - }); + // If user creation fails, it's a critical error. + var errors = string.Join(", ", result.Errors.Select(e => e.Description)); + _logger.LogError("Failed to create super admin user. Errors: {Errors}", errors); + throw new InvalidOperationException($"Failed to create super admin user: {errors}"); } - await dbContext.RolePermissionMappings.AddRangeAsync(rolesMapping); + _logger.LogInformation("Super Admin user created successfully."); } - await dbContext.SaveChangesAsync(); + else + { + _logger.LogInformation("Super Admin user already exists."); + } + return user; + } + + private async Task SeedRolePermissionsAsync(ApplicationDbContext dbContext, Guid superUserRoleId) + { + _logger.LogInformation("Seeding permissions for Super User role (ID: {RoleId})", superUserRoleId); + + var allPermissionIds = await dbContext.FeaturePermissions + .Select(p => p.Id) + .ToListAsync(); + + var permissionIdsFromDb = await dbContext.RolePermissionMappings + .Where(pm => pm.ApplicationRoleId == superUserRoleId) + .Select(pm => pm.FeaturePermissionId) + .ToListAsync(); // 1. Fetch data from DB into a List + + var existingPermissionIds = new HashSet(permissionIdsFromDb); // 2. Convert the List to a HashSet in memory + + var missingPermissionIds = allPermissionIds.Except(existingPermissionIds).ToList(); + + if (missingPermissionIds.Any()) + { + var newMappings = missingPermissionIds.Select(permissionId => new RolePermissionMappings + { + ApplicationRoleId = superUserRoleId, + FeaturePermissionId = permissionId + }); + + await dbContext.RolePermissionMappings.AddRangeAsync(newMappings); + _logger.LogInformation("Added {Count} new permission mappings to the Super User role.", missingPermissionIds.Count); + } + else + { + _logger.LogInformation("Super User role already has all available permissions."); + } + } + + /// + /// A generic helper to find an entity by a predicate or create, add, and return it if not found. + /// This promotes code reuse and makes the main logic cleaner. + /// + private async Task GetOrCreateAsync(DbSet dbSet, Expression> predicate, Func factory) where T : class + { + var entity = await dbSet.FirstOrDefaultAsync(predicate); + if (entity == null) + { + entity = factory(); + await dbSet.AddAsync(entity); + _logger.LogInformation("Creating new entity of type {EntityType}.", typeof(T).Name); + } + return entity; } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; From cc2e545442e74695adb85c74dc777540a6e9b9ad Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 15:00:21 +0530 Subject: [PATCH 06/81] Added created by and created at in expenses model --- ...edBy_And_CareatedAt_In_Expense.Designer.cs | 4196 +++++++++++++++++ ...ded_CreatedBy_And_CareatedAt_In_Expense.cs | 63 + .../ApplicationDbContextModelSnapshot.cs | 16 + Marco.Pms.Model/Expenses/Expenses.cs | 6 + 4 files changed, 4281 insertions(+) create mode 100644 Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs diff --git a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs new file mode 100644 index 0000000..47a46cc --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs @@ -0,0 +1,4196 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense")] + partial class Added_CreatedBy_And_CareatedAt_In_Expense + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpeStatusIdnsesId") + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpeStatusIdnsesId"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Description = "Expense has been created but not yet submitted.", + IsActive = true, + IsSystem = true, + Name = "Draft", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Description = "Reviewer is currently reviewing the expense.", + IsActive = true, + IsSystem = true, + Name = "Review Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Description = "Review is completed, waiting for action of approver.", + IsActive = true, + IsSystem = true, + Name = "Approval Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsActive = true, + IsSystem = true, + Name = "Rejected", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Description = "Approved expense is awaiting final payment.", + IsActive = true, + IsSystem = true, + Name = "Process Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Description = "Expense has been settled.", + IsActive = true, + IsSystem = true, + Name = "Processed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#6c757d", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("Project"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("ExpeStatusIdnsesId"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs new file mode 100644 index 0000000..19a5c08 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs @@ -0,0 +1,63 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_CreatedBy_And_CareatedAt_In_Expense : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CreatedAt", + table: "Expenses", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "CreatedById", + table: "Expenses", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_CreatedById", + table: "Expenses", + column: "CreatedById"); + + migrationBuilder.AddForeignKey( + name: "FK_Expenses_Employees_CreatedById", + table: "Expenses", + column: "CreatedById", + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Expenses_Employees_CreatedById", + table: "Expenses"); + + migrationBuilder.DropIndex( + name: "IX_Expenses_CreatedById", + table: "Expenses"); + + migrationBuilder.DropColumn( + name: "CreatedAt", + table: "Expenses"); + + migrationBuilder.DropColumn( + name: "CreatedById", + table: "Expenses"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 766e2dd..182224e 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1297,6 +1297,12 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("Amount") .HasColumnType("double"); + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + b.Property("Description") .IsRequired() .HasColumnType("longtext"); @@ -1346,6 +1352,8 @@ namespace Marco.Pms.DataAccess.Migrations b.HasKey("Id"); + b.HasIndex("CreatedById"); + b.HasIndex("ExpensesTypeId"); b.HasIndex("PaidById"); @@ -3651,6 +3659,12 @@ namespace Marco.Pms.DataAccess.Migrations modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") .WithMany() .HasForeignKey("ExpensesTypeId") @@ -3687,6 +3701,8 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.Navigation("CreatedBy"); + b.Navigation("ExpensesType"); b.Navigation("PaidBy"); diff --git a/Marco.Pms.Model/Expenses/Expenses.cs b/Marco.Pms.Model/Expenses/Expenses.cs index 19e8333..a396715 100644 --- a/Marco.Pms.Model/Expenses/Expenses.cs +++ b/Marco.Pms.Model/Expenses/Expenses.cs @@ -30,7 +30,13 @@ namespace Marco.Pms.Model.Expenses [ValidateNever] [ForeignKey("PaidById")] public Employee? PaidBy { get; set; } + public Guid CreatedById { get; set; } + + [ValidateNever] + [ForeignKey("CreatedById")] + public Employee? CreatedBy { get; set; } public DateTime TransactionDate { get; set; } + public DateTime CreatedAt { get; set; } public string? TransactionId { get; set; } public string Description { get; set; } = string.Empty; public string? Location { get; set; } From 8e69219e73da35856cc711a5c43bfd263093a9bb Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 15:02:48 +0530 Subject: [PATCH 07/81] Added all get lsit for Expenses-Type, Expenses-Status and payment-mode --- .../Controllers/MasterController.cs | 41 +++++++++- Marco.Pms.Services/Helpers/MasterHelper.cs | 57 ++++++------- .../MappingProfiles/MappingProfile.cs | 12 ++- Marco.Pms.Services/Program.cs | 1 + Marco.Pms.Services/Service/MasterService.cs | 80 +++++++++++++++++++ Marco.Pms.Services/Service/S3UploadService.cs | 46 +++++++++-- .../ServiceInterfaces/IMasterService.cs | 11 +++ 7 files changed, 206 insertions(+), 42 deletions(-) create mode 100644 Marco.Pms.Services/Service/MasterService.cs create mode 100644 Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 9000cdf..f115bde 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -10,6 +10,7 @@ using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Forum; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Services.Helpers; +using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; @@ -27,12 +28,14 @@ namespace Marco.Pms.Services.Controllers private readonly UserHelper _userHelper; private readonly ILoggingService _logger; private readonly MasterHelper _masterHelper; - public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, MasterHelper masterHelper) + private readonly IMasterService _masterService; + public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, MasterHelper masterHelper, IMasterService masterService) { _context = context; _userHelper = userHelper; _logger = logger; _masterHelper = masterHelper; + _masterService = masterService; } // -------------------------------- Activity -------------------------------- @@ -846,5 +849,41 @@ namespace Marco.Pms.Services.Controllers var response = await _masterHelper.DeleteContactTag(id); return Ok(response); } + #region =================================================================== Expenses Type APIs =================================================================== + [HttpGet("expenses-types")] + public async Task GetExpenseTypeList() + { + var response = await _masterService.GetExpenseTypeListAsync(); + return StatusCode(response.StatusCode, response); + } + public async Task CreateExpenseType(ExpensesTypeMasterDto dto) + { + var response = await _masterService.GetExpenseTypeListAsync(); + return StatusCode(response.StatusCode, response); + } + + #endregion + + #region =================================================================== Expenses Status APIs =================================================================== + [HttpGet("expenses-status")] + public async Task GetExpenseStatusList() + { + var response = await _masterService.GetExpenseStatusListAsync(); + return StatusCode(response.StatusCode, response); + } + + + #endregion + + #region =================================================================== Payment mode APIs =================================================================== + [HttpGet("payment-modes")] + public async Task GetPaymentModeList() + { + var response = await _masterService.GetPaymentModeListAsync(); + return StatusCode(response.StatusCode, response); + } + + + #endregion } } diff --git a/Marco.Pms.Services/Helpers/MasterHelper.cs b/Marco.Pms.Services/Helpers/MasterHelper.cs index 83bc007..d50a603 100644 --- a/Marco.Pms.Services/Helpers/MasterHelper.cs +++ b/Marco.Pms.Services/Helpers/MasterHelper.cs @@ -19,20 +19,21 @@ namespace Marco.Pms.Services.Helpers private readonly ApplicationDbContext _context; private readonly ILoggingService _logger; private readonly UserHelper _userHelper; - private readonly PermissionServices _permissionService; + private readonly PermissionServices _permission; + private readonly Guid tenantId; - - public MasterHelper(ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permissionServices) + public MasterHelper(ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permission) { _context = context; _logger = logger; _userHelper = userHelper; - _permissionService = permissionServices; + _permission = permission; + tenantId = userHelper.GetTenantId(); } - // -------------------------------- Contact Category -------------------------------- + #region =================================================================== Contact Category APIs =================================================================== + public async Task> CreateContactCategory(CreateContactCategoryDto contactCategoryDto) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (contactCategoryDto != null) { @@ -55,7 +56,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> UpdateContactCategory(Guid id, UpdateContactCategoryDto contactCategoryDto) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (contactCategoryDto != null && id == contactCategoryDto.Id) { @@ -86,7 +86,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> GetContactCategoriesList() { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var categoryList = await _context.ContactCategoryMasters.Where(c => c.TenantId == tenantId).ToListAsync(); @@ -101,7 +100,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> GetContactCategoryById(Guid id) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var category = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); @@ -117,7 +115,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> DeleteContactCategory(Guid id) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); ContactCategoryMaster? contactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); if (contactCategory != null) @@ -148,14 +145,12 @@ namespace Marco.Pms.Services.Helpers _logger.LogWarning("Employee {EmployeeId} tries to delete Category {CategoryId} but not found in database", LoggedInEmployee.Id, id); return ApiResponse.SuccessResponse(new { }, "Category deleted successfully", 200); } + #endregion - // -------------------------------- Contact Tag -------------------------------- - + #region =================================================================== Contact Tag APIs =================================================================== public async Task> GetContactTags() { - Guid tenantId = _userHelper.GetTenantId(); - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var taglist = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync(); @@ -170,7 +165,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> CreateContactTag(CreateContactTagDto contactTagDto) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (contactTagDto != null) { @@ -193,7 +187,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> UpdateContactTag(Guid id, UpdateContactTagDto contactTagDto) { - var tenantId = _userHelper.GetTenantId(); Employee LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (contactTagDto != null && contactTagDto.Id == id) { @@ -226,7 +219,6 @@ namespace Marco.Pms.Services.Helpers } public async Task> DeleteContactTag(Guid id) { - Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); ContactTagMaster? contactTag = await _context.ContactTagMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); if (contactTag != null) @@ -252,19 +244,21 @@ namespace Marco.Pms.Services.Helpers return ApiResponse.SuccessResponse(new { }, "Tag deleted successfully", 200); } - // -------------------------------- Work Status -------------------------------- + #endregion + + #region =================================================================== Work Status APIs =================================================================== + public async Task> GetWorkStatusList() { _logger.LogInfo("GetWorkStatusList called."); try { - // Step 1: Get tenant and logged-in employee info - Guid tenantId = _userHelper.GetTenantId(); + // Step 1: Get logged-in employee info var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Step 2: Check permission to view master data - bool hasViewPermission = await _permissionService.HasPermission(PermissionsMaster.ViewMasters, loggedInEmployee.Id); + bool hasViewPermission = await _permission.HasPermission(PermissionsMaster.ViewMasters, loggedInEmployee.Id); if (!hasViewPermission) { _logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id); @@ -294,7 +288,7 @@ namespace Marco.Pms.Services.Helpers } catch (Exception ex) { - _logger.LogWarning("Error occurred while fetching work status list : {Error}", ex.Message); + _logger.LogError(ex, "Error occurred while fetching work status list"); return ApiResponse.ErrorResponse("An error occurred", "Unable to fetch work status list", 500); } } @@ -304,12 +298,11 @@ namespace Marco.Pms.Services.Helpers try { - // Step 1: Get tenant and logged-in employee - Guid tenantId = _userHelper.GetTenantId(); + // Step 1: Get logged-in employee var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Step 2: Check if user has permission to manage master data - var hasManageMasterPermission = await _permissionService.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); if (!hasManageMasterPermission) { _logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id); @@ -343,7 +336,7 @@ namespace Marco.Pms.Services.Helpers } catch (Exception ex) { - _logger.LogWarning("Error occurred while creating work status : {Error}", ex.Message); + _logger.LogError(ex, "Error occurred while creating work status"); return ApiResponse.ErrorResponse("An error occurred", "Unable to create work status", 500); } } @@ -360,12 +353,11 @@ namespace Marco.Pms.Services.Helpers return ApiResponse.ErrorResponse("Invalid data provided", "The provided work status ID is invalid", 400); } - // Step 2: Get tenant and logged-in employee - Guid tenantId = _userHelper.GetTenantId(); + // Step 2: Get logged-in employee var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Step 3: Check permissions - var hasManageMasterPermission = await _permissionService.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); if (!hasManageMasterPermission) { _logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage Master permission.", loggedInEmployee.Id); @@ -413,12 +405,11 @@ namespace Marco.Pms.Services.Helpers try { - // Step 1: Get current tenant and logged-in employee - Guid tenantId = _userHelper.GetTenantId(); + // Step 1: Get logged-in employee var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Step 2: Check permission to manage master data - var hasManageMasterPermission = await _permissionService.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); if (!hasManageMasterPermission) { _logger.LogWarning("Delete denied. EmployeeId: {EmployeeId} lacks Manage_Master permission.", loggedInEmployee.Id); @@ -462,5 +453,7 @@ namespace Marco.Pms.Services.Helpers return ApiResponse.ErrorResponse("An error occurred", "Unable to delete work status", 500); } } + + #endregion } } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index bf3777c..2706083 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Master; @@ -60,9 +61,18 @@ namespace Marco.Pms.Services.MappingProfiles opt => opt.MapFrom(src => src.Comment)); #endregion - #region ======================================================= Projects ======================================================= + #region ======================================================= Employee ======================================================= CreateMap(); #endregion + + #region ======================================================= Master ======================================================= + CreateMap() + .ForMember( + dest => dest.Id, + // Explicitly and safely convert nullable Guid to non-nullable Guid + opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) + ); + #endregion } } } diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index e67ed7a..a43af8b 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -172,6 +172,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); #endregion #region Helpers diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs new file mode 100644 index 0000000..bd74bce --- /dev/null +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -0,0 +1,80 @@ +using AutoMapper; +using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.Dtos.Master; +using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Master; +using Marco.Pms.Model.Utilities; +using Marco.Pms.Services.Service.ServiceInterfaces; +using MarcoBMS.Services.Helpers; +using MarcoBMS.Services.Service; +using Microsoft.EntityFrameworkCore; + +namespace Marco.Pms.Services.Service +{ + public class MasterService : IMasterService + { + private readonly ApplicationDbContext _context; + private readonly ILoggingService _logger; + private readonly UserHelper _userHelper; + private readonly PermissionServices _permission; + private readonly IMapper _mapper; + private readonly Guid tenantId; + + public MasterService( + ApplicationDbContext context, + ILoggingService logger, + UserHelper userHelper, + PermissionServices permission, + IMapper mapper) + { + _context = context; + _logger = logger; + _userHelper = userHelper; + _permission = permission; + _mapper = mapper; + tenantId = userHelper.GetTenantId(); + } + + #region =================================================================== Expenses Type APIs =================================================================== + + public async Task> GetExpenseTypeListAsync() + { + var typeList = await _context.ExpensesTypeMaster.Where(et => et.TenantId == tenantId).ToListAsync(); + return ApiResponse.SuccessResponse(typeList); + } + public async Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + } + var expensesType = _mapper.Map(dto); + return ApiResponse.SuccessResponse(expensesType); + } + + #endregion + + #region =================================================================== Expenses Status APIs =================================================================== + public async Task> GetExpenseStatusListAsync() + { + var typeList = await _context.ExpensesStatusMaster.Where(et => et.TenantId == tenantId).ToListAsync(); + return ApiResponse.SuccessResponse(typeList); + } + + + #endregion + + #region =================================================================== Payment mode APIs =================================================================== + public async Task> GetPaymentModeListAsync() + { + var typeList = await _context.PaymentModeMatser.Where(et => et.TenantId == tenantId).ToListAsync(); + return ApiResponse.SuccessResponse(typeList); + } + + + #endregion + } +} diff --git a/Marco.Pms.Services/Service/S3UploadService.cs b/Marco.Pms.Services/Service/S3UploadService.cs index 4ce7a4b..1d98a33 100644 --- a/Marco.Pms.Services/Service/S3UploadService.cs +++ b/Marco.Pms.Services/Service/S3UploadService.cs @@ -5,6 +5,7 @@ using Marco.Pms.Model.Utilities; using MarcoBMS.Services.Service; using Microsoft.Extensions.Options; using MimeDetective; +using System.Text.RegularExpressions; namespace Marco.Pms.Services.Service { @@ -12,7 +13,7 @@ namespace Marco.Pms.Services.Service public class S3UploadService { private readonly IAmazonS3 _s3Client; - private readonly string _bucketName = "your-bucket-name"; + private readonly string _bucketName; private readonly ILoggingService _logger; private readonly IConfiguration _configuration; @@ -64,7 +65,7 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) { - _logger.LogError(ex, "error occured while uploading file to S3"); + _logger.LogError(ex, "Error ocurred while uploading file to S3", ex.Message); } @@ -87,7 +88,7 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) { - _logger.LogError(ex, "error occured while requesting presigned url from Amazon S3", ex.Message); + _logger.LogError(ex, "Error occured while requesting presigned url from Amazon S3"); return string.Empty; } } @@ -107,17 +108,17 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) { - _logger.LogError(ex, "error ocured while deleting from Amazon S3"); + _logger.LogError(ex, "while deleting from Amazon S3"); return false; } } - public string GenerateFileName(string contentType, Guid tenantId, string? name) + public string GenerateFileName(string contentType, Guid entityId, string? name) { string extenstion = GetExtensionFromMimeType(contentType); if (string.IsNullOrEmpty(name)) - return $"{tenantId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}"; - return $"{name}_{tenantId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}"; + return $"{entityId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}"; + return $"{name}_{entityId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}"; } public string GetExtensionFromMimeType(string contentType) @@ -220,9 +221,38 @@ namespace Marco.Pms.Services.Service catch (Exception ex) { // Handle other potential errors during decoding or inspection - _logger.LogError(ex, "errors during decoding or inspection"); + _logger.LogError(ex, "An error occurred while decoding base64"); return string.Empty; } } + public bool IsBase64String(string? input) + { + if (string.IsNullOrWhiteSpace(input)) + return false; + + // Normalize string + input = input.Trim(); + + // Length must be multiple of 4 + if (input.Length % 4 != 0) + return false; + + // Valid Base64 characters with correct padding + var base64Regex = new Regex(@"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"); + if (!base64Regex.IsMatch(input)) + return false; + + try + { + // Decode and re-encode to confirm validity + var bytes = Convert.FromBase64String(input); + var reEncoded = Convert.ToBase64String(bytes); + return input == reEncoded; + } + catch + { + return false; + } + } } } \ No newline at end of file diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs new file mode 100644 index 0000000..1b970ca --- /dev/null +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -0,0 +1,11 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Services.Service.ServiceInterfaces +{ + public interface IMasterService + { + Task> GetExpenseTypeListAsync(); + Task> GetExpenseStatusListAsync(); + Task> GetPaymentModeListAsync(); + } +} From 15f100308f1d00a10e51b82518c0e99901501e8d Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 15:41:27 +0530 Subject: [PATCH 08/81] Added created API to create expenses entity --- .../Dtos/Expenses/CreateExpensesDto.cs | 5 +- .../Controllers/ExpanseController.cs | 199 ++++++++++++++++++ .../Controllers/MasterController.cs | 1 + 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 Marco.Pms.Services/Controllers/ExpanseController.cs diff --git a/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs index d1d8ec4..d4e9b8d 100644 --- a/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs +++ b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs @@ -5,8 +5,9 @@ namespace Marco.Pms.Model.Dtos.Expenses public class CreateExpensesDto { public required Guid ProjectId { get; set; } - public Guid ExpensesTypeId { get; set; } - public Guid PaymentModeId { get; set; } + public required Guid ExpensesTypeId { get; set; } + public required Guid PaymentModeId { get; set; } + public required Guid PaidById { get; set; } public DateTime TransactionDate { get; set; } = DateTime.Now; public string? TransactionId { get; set; } public required string Description { get; set; } diff --git a/Marco.Pms.Services/Controllers/ExpanseController.cs b/Marco.Pms.Services/Controllers/ExpanseController.cs new file mode 100644 index 0000000..b642495 --- /dev/null +++ b/Marco.Pms.Services/Controllers/ExpanseController.cs @@ -0,0 +1,199 @@ +using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.Dtos.Expenses; +using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Expenses; +using Marco.Pms.Model.Utilities; +using Marco.Pms.Services.Service; +using MarcoBMS.Services.Helpers; +using MarcoBMS.Services.Service; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Document = Marco.Pms.Model.DocumentManager.Document; + +// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 + +namespace Marco.Pms.Services.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [Authorize] + public class ExpanseController : ControllerBase + { + private readonly ApplicationDbContext _context; + private readonly UserHelper _userHelper; + private readonly PermissionServices _permission; + private readonly ILoggingService _logger; + private readonly S3UploadService _s3Service; + private readonly Guid tenantId; + public ExpanseController( + ApplicationDbContext context, + UserHelper userHelper, + PermissionServices permission, + ILoggingService logger, + S3UploadService s3Service) + { + _context = context; + _userHelper = userHelper; + _permission = permission; + _logger = logger; + tenantId = userHelper.GetTenantId(); + _s3Service = s3Service; + } + + [HttpGet] + public IEnumerable Get() + { + return new string[] { "value1", "value2" }; + } + + [HttpGet("{id}")] + public string Get(int id) + { + return "value"; + } + + [HttpPost] + public async Task Post([FromBody] CreateExpensesDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var hasUploadPermission = await _permission.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, dto.ProjectId); + if (!hasUploadPermission || !hasProjectPermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for uploading expense on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); + return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403)); + } + var isExpensesTypeExist = await _context.ExpensesTypeMaster.AnyAsync(et => et.Id == dto.ExpensesTypeId); + if (!isExpensesTypeExist) + { + _logger.LogWarning("Expenses type not for ID: {ExpensesTypeId} when creating new expense", dto.ExpensesTypeId); + return NotFound(ApiResponse.ErrorResponse("Expanses Type not found", "Expanses Type not found", 404)); + } + var isPaymentModeExist = await _context.PaymentModeMatser.AnyAsync(et => et.Id == dto.PaymentModeId); + if (!isPaymentModeExist) + { + _logger.LogWarning("Payment Mode not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); + return NotFound(ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404)); + } + var isStatusExist = await _context.ExpensesStatusMaster.AnyAsync(et => et.Id == dto.StatusId); + if (!isStatusExist) + { + _logger.LogWarning("Status not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); + return NotFound(ApiResponse.ErrorResponse("Status not found", "Status not found", 404)); + } + var expense = new Expenses + { + ProjectId = dto.ProjectId, + ExpensesTypeId = dto.ExpensesTypeId, + PaymentModeId = dto.PaymentModeId, + PaidById = dto.PaidById, + CreatedById = loggedInEmployee.Id, + TransactionDate = dto.TransactionDate, + CreatedAt = DateTime.UtcNow, + TransactionId = dto.TransactionId, + Description = dto.Description, + Location = dto.Location, + GSTNumber = dto.GSTNumber, + SupplerName = dto.SupplerName, + Amount = dto.Amount, + NoOfPersons = dto.NoOfPersons, + StatusId = dto.StatusId, + PreApproved = dto.PreApproved, + IsActive = true, + TenantId = tenantId + }; + _context.Expenses.Add(expense); + + + Guid batchId = Guid.NewGuid(); + foreach (var attachment in dto.BillAttachments) + { + //if (!_s3Service.IsBase64String(attachment.Base64Data)) + //{ + // _logger.LogWarning("Image upload failed: Base64 data is missing While creating new expense entity for project {ProjectId} by employee {EmployeeId}", expense.ProjectId, expense.PaidById); + // return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); + //} + var base64 = attachment.Base64Data!.Contains(',') + ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] + : attachment.Base64Data; + + var fileType = _s3Service.GetContentTypeFromBase64(base64); + var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); + var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; + try + { + await _s3Service.UploadFileAsync(base64, fileType, objectKey); + _logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while saving image to S3"); + //return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new + //{ + // message = ex.Message, + // innerexcption = ex.InnerException?.Message, + // stackTrace = ex.StackTrace, + // source = ex.Source + //}, 400)); + } + + var document = new Document + { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, + FileName = attachment.FileName ?? "", + ContentType = attachment.ContentType ?? "", + S3Key = objectKey, + //Base64Data = attachment.Base64Data, + FileSize = attachment.FileSize, + UploadedAt = DateTime.UtcNow, + TenantId = tenantId + }; + _context.Documents.Add(document); + + var billAttachement = new BillAttachments + { + DocumentId = document.Id, + ExpensesId = expense.Id, + TenantId = tenantId + }; + _context.BillAttachments.Add(billAttachement); + } + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Error occured while saving Expense, Document and bill attachment entity"); + return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 400)); + } + _logger.LogInfo("Documents and attachments saved for Expense: {ExpenseId}", expense.Id); + + return StatusCode(201, ApiResponse.SuccessResponse(expense, "Expense created Successfully", 201)); + } + + + [HttpPut("{id}")] + public void Put(int id, [FromBody] string value) + { + } + + [HttpDelete("{id}")] + public void Delete(int id) + { + } + } +} diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index f115bde..608caed 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -856,6 +856,7 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.GetExpenseTypeListAsync(); return StatusCode(response.StatusCode, response); } + [HttpPost("expenses-type")] public async Task CreateExpenseType(ExpensesTypeMasterDto dto) { var response = await _masterService.GetExpenseTypeListAsync(); From 84f5da25f6a0ed754fd023be8b4b924f3ccd5fd9 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 15:49:23 +0530 Subject: [PATCH 09/81] Added the get API in Expenses module --- Marco.Pms.Services/Controllers/ExpanseController.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpanseController.cs b/Marco.Pms.Services/Controllers/ExpanseController.cs index b642495..ee05590 100644 --- a/Marco.Pms.Services/Controllers/ExpanseController.cs +++ b/Marco.Pms.Services/Controllers/ExpanseController.cs @@ -42,9 +42,18 @@ namespace Marco.Pms.Services.Controllers } [HttpGet] - public IEnumerable Get() + public async Task Get() { - return new string[] { "value1", "value2" }; + var expensesList = await _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .Where(e => e.TenantId == tenantId) + .ToListAsync(); + return StatusCode(200, ApiResponse.SuccessResponse(expensesList)); } [HttpGet("{id}")] From c27ffe3a28c5c4bb630104ac3c93967640782414 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 16:13:37 +0530 Subject: [PATCH 10/81] Addd a table to save logs of expenses --- .../Data/ApplicationDbContext.cs | 1 + ...9103905_Added_ExpenseLog_Table.Designer.cs | 4243 +++++++++++++++++ .../20250719103905_Added_ExpenseLog_Table.cs | 62 + .../ApplicationDbContextModelSnapshot.cs | 47 + Marco.Pms.Model/Expenses/ExpenseLog.cs | 23 + 5 files changed, 4376 insertions(+) create mode 100644 Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs create mode 100644 Marco.Pms.Model/Expenses/ExpenseLog.cs diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 781344e..bc9ab5d 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -91,6 +91,7 @@ namespace Marco.Pms.DataAccess.Data public DbSet MPINDetails { get; set; } public DbSet Expenses { get; set; } + public DbSet ExpenseLogs { get; set; } public DbSet ExpensesTypeMaster { get; set; } public DbSet PaymentModeMatser { get; set; } public DbSet ExpensesStatusMaster { get; set; } diff --git a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs new file mode 100644 index 0000000..2eaef13 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs @@ -0,0 +1,4243 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250719103905_Added_ExpenseLog_Table")] + partial class Added_ExpenseLog_Table + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpeStatusIdnsesId") + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpeStatusIdnsesId"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Description = "Expense has been created but not yet submitted.", + IsActive = true, + IsSystem = true, + Name = "Draft", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Description = "Reviewer is currently reviewing the expense.", + IsActive = true, + IsSystem = true, + Name = "Review Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Description = "Review is completed, waiting for action of approver.", + IsActive = true, + IsSystem = true, + Name = "Approval Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsActive = true, + IsSystem = true, + Name = "Rejected", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Description = "Approved expense is awaiting final payment.", + IsActive = true, + IsSystem = true, + Name = "Process Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Description = "Expense has been settled.", + IsActive = true, + IsSystem = true, + Name = "Processed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#6c757d", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("Project"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("ExpeStatusIdnsesId"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs new file mode 100644 index 0000000..c4fc528 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_ExpenseLog_Table : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ExpenseLogs", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpenseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + UpdatedById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Action = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Comment = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpenseLogs", x => x.Id); + table.ForeignKey( + name: "FK_ExpenseLogs_Employees_UpdatedById", + column: x => x.UpdatedById, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpenseLogs_Expenses_ExpenseId", + column: x => x.ExpenseId, + principalTable: "Expenses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_ExpenseLogs_ExpenseId", + table: "ExpenseLogs", + column: "ExpenseId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpenseLogs_UpdatedById", + table: "ExpenseLogs", + column: "UpdatedById"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ExpenseLogs"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 182224e..63ff979 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1288,6 +1288,34 @@ namespace Marco.Pms.DataAccess.Migrations b.ToTable("BillAttachments"); }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => { b.Property("Id") @@ -3657,6 +3685,25 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Tenant"); }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("UpdatedBy"); + }); + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => { b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") diff --git a/Marco.Pms.Model/Expenses/ExpenseLog.cs b/Marco.Pms.Model/Expenses/ExpenseLog.cs new file mode 100644 index 0000000..ec3d8fd --- /dev/null +++ b/Marco.Pms.Model/Expenses/ExpenseLog.cs @@ -0,0 +1,23 @@ +using Marco.Pms.Model.Employees; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Marco.Pms.Model.Expenses +{ + public class ExpenseLog + { + public Guid Id { get; set; } + public Guid ExpenseId { get; set; } + + [ValidateNever] + [ForeignKey("ExpenseId")] + public Expenses? Expense { get; set; } + public Guid UpdatedById { get; set; } + + [ValidateNever] + [ForeignKey("UpdatedById")] + public Employee? UpdatedBy { get; set; } + public string Action { get; set; } = string.Empty; + public string? Comment { get; set; } + } +} From 448d586b94d27018f2e1232ff9fed7d7142a2844 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 16:21:54 +0530 Subject: [PATCH 11/81] Changed the endpoint names in expense controller --- Marco.Pms.Services/Controllers/ExpanseController.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpanseController.cs b/Marco.Pms.Services/Controllers/ExpanseController.cs index ee05590..9f85454 100644 --- a/Marco.Pms.Services/Controllers/ExpanseController.cs +++ b/Marco.Pms.Services/Controllers/ExpanseController.cs @@ -41,7 +41,7 @@ namespace Marco.Pms.Services.Controllers _s3Service = s3Service; } - [HttpGet] + [HttpGet("list")] public async Task Get() { var expensesList = await _context.Expenses @@ -56,13 +56,13 @@ namespace Marco.Pms.Services.Controllers return StatusCode(200, ApiResponse.SuccessResponse(expensesList)); } - [HttpGet("{id}")] + [HttpGet("details/{id}")] public string Get(int id) { return "value"; } - [HttpPost] + [HttpPost("create")] public async Task Post([FromBody] CreateExpensesDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); @@ -195,12 +195,12 @@ namespace Marco.Pms.Services.Controllers } - [HttpPut("{id}")] + [HttpPut("edit/{id}")] public void Put(int id, [FromBody] string value) { } - [HttpDelete("{id}")] + [HttpDelete("delete/{id}")] public void Delete(int id) { } From 741acb194e3e3510c2d7eb47e6b2a014429381af Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 17:10:02 +0530 Subject: [PATCH 12/81] Added the status Mapping table in database --- .../Data/ApplicationDbContext.cs | 15 +- ...ded_ExpensesStatusMaping_Table.Designer.cs | 4243 +++++++++++++++++ ...113715_Added_ExpensesStatusMaping_Table.cs | 149 + .../ApplicationDbContextModelSnapshot.cs | 6 +- ...tusMapping.cs => ExpensesStatusMapping.cs} | 2 +- 5 files changed, 4404 insertions(+), 11 deletions(-) create mode 100644 Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs rename Marco.Pms.Model/Expenses/{StatusMapping.cs => ExpensesStatusMapping.cs} (91%) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index bc9ab5d..71dbdfa 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -99,6 +99,7 @@ namespace Marco.Pms.DataAccess.Data public DbSet ExpensesReimburse { get; set; } public DbSet ExpensesReimburseMapping { get; set; } public DbSet StatusPermissionMapping { get; set; } + public DbSet ExpensesStatusMapping { get; set; } @@ -444,9 +445,9 @@ namespace Marco.Pms.DataAccess.Data } ); - modelBuilder.Entity().HasData( + modelBuilder.Entity().HasData( // Process to processed - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("5cf7f1df-9d1f-4289-add0-1775ad614f25"), StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), @@ -454,7 +455,7 @@ namespace Marco.Pms.DataAccess.Data TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Approve to Rejected - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("36c00548-241c-43ec-bc95-cacebedb925c"), StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), @@ -462,7 +463,7 @@ namespace Marco.Pms.DataAccess.Data TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Approve to Process - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("1fca1700-1266-477d-bba4-9ac3753aa33c"), StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), @@ -470,7 +471,7 @@ namespace Marco.Pms.DataAccess.Data TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Review to Rejected - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("fddaaf20-4ccc-4f4e-a724-dd310272b356"), StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), @@ -478,7 +479,7 @@ namespace Marco.Pms.DataAccess.Data TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Review to Aprrove - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), @@ -486,7 +487,7 @@ namespace Marco.Pms.DataAccess.Data TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Draft to Review - new StatusMapping + new ExpensesStatusMapping { Id = Guid.Parse("af1e4492-98ee-4451-8ab7-fd8323f29c32"), StatusId = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"), diff --git a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs new file mode 100644 index 0000000..d5fe0c3 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs @@ -0,0 +1,4243 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250719113715_Added_ExpensesStatusMaping_Table")] + partial class Added_ExpensesStatusMaping_Table + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpeStatusIdnsesId") + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpeStatusIdnsesId"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Description = "Expense has been created but not yet submitted.", + IsActive = true, + IsSystem = true, + Name = "Draft", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Description = "Reviewer is currently reviewing the expense.", + IsActive = true, + IsSystem = true, + Name = "Review Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Description = "Review is completed, waiting for action of approver.", + IsActive = true, + IsSystem = true, + Name = "Approval Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + IsActive = true, + IsSystem = true, + Name = "Rejected", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Description = "Approved expense is awaiting final payment.", + IsActive = true, + IsSystem = true, + Name = "Process Pending", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Description = "Expense has been settled.", + IsActive = true, + IsSystem = true, + Name = "Processed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#6c757d", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("Project"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("ExpeStatusIdnsesId"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs b/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs new file mode 100644 index 0000000..f20e292 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs @@ -0,0 +1,149 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_ExpensesStatusMaping_Table : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "StatusMapping"); + + migrationBuilder.CreateTable( + name: "ExpensesStatusMapping", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpensesStatusMapping", x => x.Id); + table.ForeignKey( + name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", + column: x => x.ExpeStatusIdnsesId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_NextStatusId", + column: x => x.NextStatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpensesStatusMapping_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "ExpensesStatusMapping", + columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_ExpeStatusIdnsesId", + table: "ExpensesStatusMapping", + column: "ExpeStatusIdnsesId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_NextStatusId", + table: "ExpensesStatusMapping", + column: "NextStatusId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_TenantId", + table: "ExpensesStatusMapping", + column: "TenantId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ExpensesStatusMapping"); + + migrationBuilder.CreateTable( + name: "StatusMapping", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_StatusMapping", x => x.Id); + table.ForeignKey( + name: "FK_StatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", + column: x => x.ExpeStatusIdnsesId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_StatusMapping_ExpensesStatusMaster_NextStatusId", + column: x => x.NextStatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_StatusMapping_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "StatusMapping", + columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_ExpeStatusIdnsesId", + table: "StatusMapping", + column: "ExpeStatusIdnsesId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_NextStatusId", + table: "StatusMapping", + column: "NextStatusId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusMapping_TenantId", + table: "StatusMapping", + column: "TenantId"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 63ff979..0151173 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1450,7 +1450,7 @@ namespace Marco.Pms.DataAccess.Migrations b.ToTable("ExpensesReimburseMapping"); }); - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1476,7 +1476,7 @@ namespace Marco.Pms.DataAccess.Migrations b.HasIndex("TenantId"); - b.ToTable("StatusMapping"); + b.ToTable("ExpensesStatusMapping"); b.HasData( new @@ -3801,7 +3801,7 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("ExpensesReimburse"); }); - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => { b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") .WithMany() diff --git a/Marco.Pms.Model/Expenses/StatusMapping.cs b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs similarity index 91% rename from Marco.Pms.Model/Expenses/StatusMapping.cs rename to Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs index cc683a4..e09350d 100644 --- a/Marco.Pms.Model/Expenses/StatusMapping.cs +++ b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Marco.Pms.Model.Expenses { - public class StatusMapping : TenantRelation + public class ExpensesStatusMapping : TenantRelation { public Guid Id { get; set; } public Guid StatusId { get; set; } From c1845dd8b7852a20b974799057fefa614a2094c7 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 19:05:07 +0530 Subject: [PATCH 13/81] Change the ExpanseController to ExpenseController --- .../ViewModels/Expenses/ExpenseList.cs | 23 ++++++ .../Master/ExpensesStatusMasterVM.cs | 10 +++ .../ViewModels/Master/ExpensesTypeMasterVM.cs | 10 +++ .../ViewModels/Master/PaymentModeMatserVM.cs | 9 +++ ...anseController.cs => ExpenseController.cs} | 79 ++++++++++++++++--- .../MappingProfiles/MappingProfile.cs | 18 +++++ 6 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs create mode 100644 Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Master/ExpensesTypeMasterVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Master/PaymentModeMatserVM.cs rename Marco.Pms.Services/Controllers/{ExpanseController.cs => ExpenseController.cs} (73%) diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs new file mode 100644 index 0000000..198102d --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs @@ -0,0 +1,23 @@ +using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.ViewModels.Master; +using Marco.Pms.Model.ViewModels.Projects; + +namespace Marco.Pms.Model.ViewModels.Expanses +{ + public class ExpenseList + { + public Guid Id { get; set; } + public ProjectInfoVM? Project { get; set; } + public ExpensesTypeMasterVM? ExpensesType { get; set; } + public PaymentModeMatserVM? PaymentMode { get; set; } + public BasicEmployeeVM? PaidBy { get; set; } + public BasicEmployeeVM? CreatedBy { get; set; } + public DateTime TransactionDate { get; set; } + public DateTime CreatedAt { get; set; } + public string SupplerName { get; set; } = string.Empty; + public double Amount { get; set; } + public ExpensesStatusMasterVM? Status { get; set; } + public List? NextStatus { get; set; } + public bool PreApproved { get; set; } = false; + } +} diff --git a/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs new file mode 100644 index 0000000..f772695 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.ViewModels.Master +{ + public class ExpensesStatusMasterVM + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public bool IsSystem { get; set; } = false; + } +} diff --git a/Marco.Pms.Model/ViewModels/Master/ExpensesTypeMasterVM.cs b/Marco.Pms.Model/ViewModels/Master/ExpensesTypeMasterVM.cs new file mode 100644 index 0000000..f4551d3 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Master/ExpensesTypeMasterVM.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.ViewModels.Master +{ + public class ExpensesTypeMasterVM + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public bool NoOfPersonsRequired { get; set; } + public string Description { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/ViewModels/Master/PaymentModeMatserVM.cs b/Marco.Pms.Model/ViewModels/Master/PaymentModeMatserVM.cs new file mode 100644 index 0000000..de7716a --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Master/PaymentModeMatserVM.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.ViewModels.Master +{ + public class PaymentModeMatserVM + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Services/Controllers/ExpanseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs similarity index 73% rename from Marco.Pms.Services/Controllers/ExpanseController.cs rename to Marco.Pms.Services/Controllers/ExpenseController.cs index 9f85454..ccde41d 100644 --- a/Marco.Pms.Services/Controllers/ExpanseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -1,8 +1,11 @@ -using Marco.Pms.DataAccess.Data; +using AutoMapper; +using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.ViewModels.Expanses; +using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; @@ -18,42 +21,100 @@ namespace Marco.Pms.Services.Controllers [Route("api/[controller]")] [ApiController] [Authorize] - public class ExpanseController : ControllerBase + public class ExpenseController : ControllerBase { private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; private readonly PermissionServices _permission; private readonly ILoggingService _logger; private readonly S3UploadService _s3Service; + private readonly IMapper _mapper; private readonly Guid tenantId; - public ExpanseController( + public ExpenseController( ApplicationDbContext context, UserHelper userHelper, PermissionServices permission, ILoggingService logger, - S3UploadService s3Service) + S3UploadService s3Service, + IMapper mapper) { _context = context; _userHelper = userHelper; _permission = permission; _logger = logger; - tenantId = userHelper.GetTenantId(); _s3Service = s3Service; + _mapper = mapper; + tenantId = userHelper.GetTenantId(); } [HttpGet("list")] - public async Task Get() + public async Task GetExpensesList() { - var expensesList = await _context.Expenses + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var loggedInEmployeeId = loggedInEmployee.Id; + + List? expensesList = null; + var expensesListQuery = _context.Expenses .Include(e => e.ExpensesType) .Include(e => e.Project) .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) .Include(e => e.PaymentMode) .Include(e => e.Status) .Include(e => e.CreatedBy) - .Where(e => e.TenantId == tenantId) + .Where(e => e.TenantId == tenantId); + + var HasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); + var HasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); + + if (HasViewAllPermission) + { + expensesList = await expensesListQuery.ToListAsync(); + } + else if (HasViewSelfPermission) + { + expensesList = await expensesListQuery.Where(e => e.CreatedById == loggedInEmployeeId).ToListAsync(); + } + + if (expensesList == null) + { + _logger.LogInfo("No Expense found for employee {EmployeeId}", loggedInEmployeeId); + return Ok(ApiResponse.SuccessResponse(new List(), "No Expense found for current user", 200)); + } + + //ImageFilter? imageFilter = null; + //if (!string.IsNullOrWhiteSpace(filter)) + //{ + // try + // { + // var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + // //string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + // //imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + // imageFilter = JsonSerializer.Deserialize(filter, options); + // } + // catch (Exception ex) + // { + // _logger.LogWarning("[GetImageList] Failed to parse filter: {Message}", ex.Message); + // } + //} + + + var response = _mapper.Map>(expensesList); + + var statusIds = expensesList.Select(e => e.StatusId).ToList(); + + var statusMappings = await _context.ExpensesStatusMapping + .Include(sm => sm.NextStatus) + .Where(sm => statusIds.Contains(sm.StatusId)) .ToListAsync(); - return StatusCode(200, ApiResponse.SuccessResponse(expensesList)); + + foreach (var expense in response) + { + var statusMapping = statusMappings.Where(sm => sm.StatusId == expense.Status?.Id).Select(sm => _mapper.Map(sm.NextStatus)).ToList(); + expense.NextStatus = statusMapping; + + } + return StatusCode(200, ApiResponse.SuccessResponse(response, $"{response.Count} records of expenses for you fetched successfully", 200)); } [HttpGet("details/{id}")] diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 2706083..fad5b78 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -2,10 +2,14 @@ using AutoMapper; using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; using Marco.Pms.Model.MongoDBModels; using Marco.Pms.Model.Projects; +using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Employee; +using Marco.Pms.Model.ViewModels.Expanses; +using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; namespace Marco.Pms.Services.MappingProfiles @@ -63,6 +67,17 @@ namespace Marco.Pms.Services.MappingProfiles #region ======================================================= Employee ======================================================= CreateMap(); + CreateMap() + .ForMember( + dest => dest.JobRoleName, + opt => opt.MapFrom(src => src.JobRole != null ? src.JobRole.Name : "")); + #endregion + + #region ======================================================= Expenses ======================================================= + + CreateMap(); + + #endregion #region ======================================================= Master ======================================================= @@ -72,6 +87,9 @@ namespace Marco.Pms.Services.MappingProfiles // Explicitly and safely convert nullable Guid to non-nullable Guid opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) ); + CreateMap(); + CreateMap(); + CreateMap(); #endregion } } From 3b4b09783b09df60ee6c56c996d75d3c3cfc894e Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 19 Jul 2025 20:32:06 +0530 Subject: [PATCH 14/81] Completed the get expenses list API with optimized code --- Marco.Pms.Model/Utilities/ExpensesFilter.cs | 12 + .../Controllers/ExpenseController.cs | 322 ++++++++++++++++-- 2 files changed, 301 insertions(+), 33 deletions(-) create mode 100644 Marco.Pms.Model/Utilities/ExpensesFilter.cs diff --git a/Marco.Pms.Model/Utilities/ExpensesFilter.cs b/Marco.Pms.Model/Utilities/ExpensesFilter.cs new file mode 100644 index 0000000..7a0c397 --- /dev/null +++ b/Marco.Pms.Model/Utilities/ExpensesFilter.cs @@ -0,0 +1,12 @@ +namespace Marco.Pms.Model.Utilities +{ + public class ExpensesFilter + { + public List? ProjectIds { get; set; } + public List? StatusIds { get; set; } + public List? CreatedByIds { get; set; } + public List? PaidById { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index ccde41d..23aae3f 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -12,6 +12,7 @@ using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Text.Json; using Document = Marco.Pms.Model.DocumentManager.Document; // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 @@ -48,7 +49,7 @@ namespace Marco.Pms.Services.Controllers } [HttpGet("list")] - public async Task GetExpensesList() + public async Task GetExpensesList1(string? filter, int pageSize = 20, int pageNumber = 1) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var loggedInEmployeeId = loggedInEmployee.Id; @@ -62,42 +63,78 @@ namespace Marco.Pms.Services.Controllers .Include(e => e.PaymentMode) .Include(e => e.Status) .Include(e => e.CreatedBy) - .Where(e => e.TenantId == tenantId); + .Where(e => e.TenantId == tenantId) + .OrderByDescending(e => e.CreatedAt) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); var HasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); var HasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); - if (HasViewAllPermission) + if (HasViewSelfPermission) { - expensesList = await expensesListQuery.ToListAsync(); + expensesListQuery = expensesListQuery.Where(e => e.CreatedById == loggedInEmployeeId); } - else if (HasViewSelfPermission) + else if (!HasViewAllPermission) { - expensesList = await expensesListQuery.Where(e => e.CreatedById == loggedInEmployeeId).ToListAsync(); - } - - if (expensesList == null) - { - _logger.LogInfo("No Expense found for employee {EmployeeId}", loggedInEmployeeId); + _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expanses list.", loggedInEmployeeId); return Ok(ApiResponse.SuccessResponse(new List(), "No Expense found for current user", 200)); } - //ImageFilter? imageFilter = null; - //if (!string.IsNullOrWhiteSpace(filter)) - //{ - // try - // { - // var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - // //string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; - // //imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); - // imageFilter = JsonSerializer.Deserialize(filter, options); - // } - // catch (Exception ex) - // { - // _logger.LogWarning("[GetImageList] Failed to parse filter: {Message}", ex.Message); - // } - //} + ExpensesFilter? expenesFilter = null; + if (!string.IsNullOrWhiteSpace(filter)) + { + try + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + expenesFilter = JsonSerializer.Deserialize(filter, options); + } + catch (Exception ex) + { + _logger.LogError(ex, "[GetExpensesList] Failed to parse filter came from website or mobile"); + try + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + expenesFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + } + catch (Exception ex1) + { + _logger.LogError(ex1, "[GetExpensesList] Failed to parse filter came from postman"); + } + } + } + + var projectIds = expenesFilter?.ProjectIds; + var filterStatusIds = expenesFilter?.StatusIds; + var createdByIds = expenesFilter?.CreatedByIds; + var paidById = expenesFilter?.PaidById; + var startDate = expenesFilter?.StartDate; + var endDate = expenesFilter?.EndDate; + + if (startDate != null && endDate != null) + { + expensesListQuery = expensesListQuery.Where(e => e.CreatedAt.Date >= startDate && e.CreatedAt.Date <= endDate); + } + else if (projectIds != null && projectIds.Any()) + { + expensesListQuery = expensesListQuery.Where(e => projectIds.Contains(e.ProjectId)); + } + else if (filterStatusIds != null && filterStatusIds.Any()) + { + expensesListQuery = expensesListQuery.Where(e => filterStatusIds.Contains(e.StatusId)); + } + else if (createdByIds != null && createdByIds.Any() && HasViewAllPermission) + { + expensesListQuery = expensesListQuery.Where(e => createdByIds.Contains(e.CreatedById)); + } + else if (paidById != null && paidById.Any()) + { + expensesListQuery = expensesListQuery.Where(e => paidById.Contains(e.PaidById)); + } + + expensesList = await expensesListQuery.ToListAsync(); var response = _mapper.Map>(expensesList); @@ -117,6 +154,225 @@ namespace Marco.Pms.Services.Controllers return StatusCode(200, ApiResponse.SuccessResponse(response, $"{response.Count} records of expenses for you fetched successfully", 200)); } + /// + /// Retrieves a paginated list of expenses based on user permissions and optional filters. + /// + /// A URL-encoded JSON string containing filter criteria. See . + /// The number of records to return per page. + /// The page number to retrieve. + /// A paginated list of expenses. + [HttpGet] // Assuming this is a GET endpoint + public async Task GetExpensesList(string? filter, int pageSize = 20, int pageNumber = 1) + { + try + { + _logger.LogInfo( + "Attempting to fetch expenses list for PageNumber: {PageNumber}, PageSize: {PageSize} with Filter: {Filter}", + pageNumber, pageSize, filter ?? ""); + + // 1. --- Get User and Permissions --- + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + if (loggedInEmployee == null) + { + // This is an authentication/authorization issue. The user should be logged in. + _logger.LogWarning("Could not find an employee for the current logged-in user."); + return Unauthorized(ApiResponse.ErrorResponse("User not found or not authenticated.", 401)); + } + Guid loggedInEmployeeId = loggedInEmployee.Id; + + var hasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); + var hasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); + + // 2. --- Build Base Query and Apply Permissions --- + // Start with a base IQueryable. Filters will be chained onto this. + var expensesQuery = _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. + + // Apply permission-based filtering BEFORE any other filters or pagination. + if (hasViewAllPermission) + { + // User has 'View All' permission, no initial restriction on who created the expense. + _logger.LogInfo("User {EmployeeId} has 'View All' permission.", loggedInEmployeeId); + } + else if (hasViewSelfPermission) + { + // User only has 'View Self' permission, so restrict the query to their own expenses. + _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); + expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); + } + else + { + // User has neither required permission. Deny access. + _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId); + return Ok(ApiResponse.SuccessResponse(new List(), "You do not have permission to view any expenses.", 200)); + } + + // 3. --- Deserialize Filter and Apply --- + ExpensesFilter? expenseFilter = TryDeserializeFilter(filter); + + if (expenseFilter != null) + { + // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + { + expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + } + + if (expenseFilter.ProjectIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.ProjectIds.Contains(e.ProjectId)); + } + + if (expenseFilter.StatusIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.StatusIds.Contains(e.StatusId)); + } + + if (expenseFilter.PaidById?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById)); + } + + // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. + if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermission) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); + } + } + + // 4. --- Apply Ordering and Pagination --- + // This should be the last step before executing the query. + var paginatedQuery = expensesQuery + .OrderByDescending(e => e.CreatedAt) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + // 5. --- Execute Query and Map Results --- + var expensesList = await paginatedQuery.ToListAsync(); + + if (!expensesList.Any()) + { + _logger.LogInfo("No expenses found matching the criteria for employee {EmployeeId}.", loggedInEmployeeId); + return Ok(ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200)); + } + + var response = _mapper.Map>(expensesList); + + // 6. --- Efficiently Fetch and Append 'Next Status' Information --- + var statusIds = expensesList.Select(e => e.StatusId).Distinct().ToList(); + + var statusMappings = await _context.ExpensesStatusMapping + .Include(sm => sm.NextStatus) + .Where(sm => statusIds.Contains(sm.StatusId)) + .ToListAsync(); + + // Use a Lookup for efficient O(1) mapping. This is much better than repeated `.Where()` in a loop. + var statusMapLookup = statusMappings.ToLookup(sm => sm.StatusId); + + foreach (var expense in response) + { + if (expense.Status?.Id != null && statusMapLookup.Contains(expense.Status.Id)) + { + expense.NextStatus = statusMapLookup[expense.Status.Id] + .Select(sm => _mapper.Map(sm.NextStatus)) + .ToList(); + } + else + { + expense.NextStatus = new List(); // Ensure it's never null + } + } + + // 7. --- Return Final Success Response --- + var message = $"{response.Count} expense records fetched successfully."; + _logger.LogInfo(message); + return StatusCode(200, ApiResponse.SuccessResponse(response, message, 200)); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while fetching list expenses"); + return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 400)); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching list expenses"); + return BadRequest(ApiResponse.ErrorResponse("Error Occured", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 400)); + } + } + + /// + /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). + /// + /// The JSON filter string from the request. + /// An object or null if deserialization fails. + private ExpensesFilter? TryDeserializeFilter(string? filter) + { + if (string.IsNullOrWhiteSpace(filter)) + { + return null; + } + + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + ExpensesFilter? expenseFilter = null; + + try + { + // First, try to deserialize directly. This is the expected case (e.g., from a web client). + expenseFilter = JsonSerializer.Deserialize(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(filter, options) ?? ""; + if (!string.IsNullOrWhiteSpace(unescapedJsonString)) + { + expenseFilter = JsonSerializer.Deserialize(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 expenseFilter; + } + [HttpGet("details/{id}")] public string Get(int id) { @@ -199,13 +455,13 @@ namespace Marco.Pms.Services.Controllers catch (Exception ex) { _logger.LogError(ex, "Error occured while saving image to S3"); - //return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new - //{ - // message = ex.Message, - // innerexcption = ex.InnerException?.Message, - // stackTrace = ex.StackTrace, - // source = ex.Source - //}, 400)); + return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new + { + message = ex.Message, + innerexcption = ex.InnerException?.Message, + stackTrace = ex.StackTrace, + source = ex.Source + }, 400)); } var document = new Document From 839bc360f3210710304d8032215b3a70c594d030 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 21 Jul 2025 12:29:33 +0530 Subject: [PATCH 15/81] Added skeleton for action and update API. --- .../Dtos/Expenses/CreateExpensesDto.cs | 1 - .../Dtos/Expenses/ExpenseRecordDto.cs | 9 + .../Dtos/Expenses/UpdateExpensesDto.cs | 23 + .../Controllers/ExpenseController.cs | 715 +++++++++++------- .../MappingProfiles/MappingProfile.cs | 4 +- Marco.Pms.Services/Service/S3UploadService.cs | 1 + 6 files changed, 491 insertions(+), 262 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs create mode 100644 Marco.Pms.Model/Dtos/Expenses/UpdateExpensesDto.cs diff --git a/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs index d4e9b8d..53c8170 100644 --- a/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs +++ b/Marco.Pms.Model/Dtos/Expenses/CreateExpensesDto.cs @@ -16,7 +16,6 @@ namespace Marco.Pms.Model.Dtos.Expenses public required string SupplerName { get; set; } public required double Amount { get; set; } public int? NoOfPersons { get; set; } = 0; - public required Guid StatusId { get; set; } public bool PreApproved { get; set; } = false; public required List BillAttachments { get; set; } } diff --git a/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs new file mode 100644 index 0000000..ef18799 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.Dtos.Expenses +{ + public class ExpenseRecordDto + { + public Guid ExpenseId { get; set; } + public Guid StatusId { get; set; } + public string? Description { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/Expenses/UpdateExpensesDto.cs b/Marco.Pms.Model/Dtos/Expenses/UpdateExpensesDto.cs new file mode 100644 index 0000000..28c4faf --- /dev/null +++ b/Marco.Pms.Model/Dtos/Expenses/UpdateExpensesDto.cs @@ -0,0 +1,23 @@ +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Model.Dtos.Expenses +{ + public class UpdateExpensesDto + { + public required Guid Id { get; set; } + public required Guid ProjectId { get; set; } + public required Guid ExpensesTypeId { get; set; } + public required Guid PaymentModeId { get; set; } + public required Guid PaidById { get; set; } + public DateTime TransactionDate { get; set; } = DateTime.Now; + public string? TransactionId { get; set; } + public required string Description { get; set; } + public string? Location { get; set; } + public string? GSTNumber { get; set; } + public required string SupplerName { get; set; } + public required double Amount { get; set; } + public int? NoOfPersons { get; set; } = 0; + public bool PreApproved { get; set; } = false; + public List? BillAttachments { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 23aae3f..029b65e 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -6,6 +6,7 @@ using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Expanses; using Marco.Pms.Model.ViewModels.Master; +using Marco.Pms.Model.ViewModels.Projects; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; @@ -15,7 +16,6 @@ using Microsoft.EntityFrameworkCore; using System.Text.Json; using Document = Marco.Pms.Model.DocumentManager.Document; -// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 namespace Marco.Pms.Services.Controllers { @@ -24,135 +24,37 @@ namespace Marco.Pms.Services.Controllers [Authorize] public class ExpenseController : ControllerBase { + private readonly IDbContextFactory _dbContextFactory; private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; private readonly PermissionServices _permission; private readonly ILoggingService _logger; private readonly S3UploadService _s3Service; + private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IMapper _mapper; private readonly Guid tenantId; + private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); public ExpenseController( + IDbContextFactory dbContextFactory, ApplicationDbContext context, UserHelper userHelper, PermissionServices permission, + IServiceScopeFactory serviceScopeFactory, ILoggingService logger, S3UploadService s3Service, IMapper mapper) { + _dbContextFactory = dbContextFactory; _context = context; _userHelper = userHelper; _permission = permission; _logger = logger; + _serviceScopeFactory = serviceScopeFactory; _s3Service = s3Service; _mapper = mapper; tenantId = userHelper.GetTenantId(); } - [HttpGet("list")] - public async Task GetExpensesList1(string? filter, int pageSize = 20, int pageNumber = 1) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var loggedInEmployeeId = loggedInEmployee.Id; - - List? expensesList = null; - var expensesListQuery = _context.Expenses - .Include(e => e.ExpensesType) - .Include(e => e.Project) - .Include(e => e.PaidBy) - .ThenInclude(e => e!.JobRole) - .Include(e => e.PaymentMode) - .Include(e => e.Status) - .Include(e => e.CreatedBy) - .Where(e => e.TenantId == tenantId) - .OrderByDescending(e => e.CreatedAt) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize); - - var HasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); - var HasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); - - if (HasViewSelfPermission) - { - expensesListQuery = expensesListQuery.Where(e => e.CreatedById == loggedInEmployeeId); - } - else if (!HasViewAllPermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expanses list.", loggedInEmployeeId); - return Ok(ApiResponse.SuccessResponse(new List(), "No Expense found for current user", 200)); - } - - ExpensesFilter? expenesFilter = null; - if (!string.IsNullOrWhiteSpace(filter)) - { - try - { - var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - expenesFilter = JsonSerializer.Deserialize(filter, options); - } - catch (Exception ex) - { - _logger.LogError(ex, "[GetExpensesList] Failed to parse filter came from website or mobile"); - - try - { - var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; - expenesFilter = JsonSerializer.Deserialize(unescapedJsonString, options); - } - catch (Exception ex1) - { - _logger.LogError(ex1, "[GetExpensesList] Failed to parse filter came from postman"); - } - } - } - - var projectIds = expenesFilter?.ProjectIds; - var filterStatusIds = expenesFilter?.StatusIds; - var createdByIds = expenesFilter?.CreatedByIds; - var paidById = expenesFilter?.PaidById; - var startDate = expenesFilter?.StartDate; - var endDate = expenesFilter?.EndDate; - - if (startDate != null && endDate != null) - { - expensesListQuery = expensesListQuery.Where(e => e.CreatedAt.Date >= startDate && e.CreatedAt.Date <= endDate); - } - else if (projectIds != null && projectIds.Any()) - { - expensesListQuery = expensesListQuery.Where(e => projectIds.Contains(e.ProjectId)); - } - else if (filterStatusIds != null && filterStatusIds.Any()) - { - expensesListQuery = expensesListQuery.Where(e => filterStatusIds.Contains(e.StatusId)); - } - else if (createdByIds != null && createdByIds.Any() && HasViewAllPermission) - { - expensesListQuery = expensesListQuery.Where(e => createdByIds.Contains(e.CreatedById)); - } - else if (paidById != null && paidById.Any()) - { - expensesListQuery = expensesListQuery.Where(e => paidById.Contains(e.PaidById)); - } - - expensesList = await expensesListQuery.ToListAsync(); - - var response = _mapper.Map>(expensesList); - - var statusIds = expensesList.Select(e => e.StatusId).ToList(); - - var statusMappings = await _context.ExpensesStatusMapping - .Include(sm => sm.NextStatus) - .Where(sm => statusIds.Contains(sm.StatusId)) - .ToListAsync(); - - foreach (var expense in response) - { - var statusMapping = statusMappings.Where(sm => sm.StatusId == expense.Status?.Id).Select(sm => _mapper.Map(sm.NextStatus)).ToList(); - expense.NextStatus = statusMapping; - - } - return StatusCode(200, ApiResponse.SuccessResponse(response, $"{response.Count} records of expenses for you fetched successfully", 200)); - } /// /// Retrieves a paginated list of expenses based on user permissions and optional filters. @@ -161,7 +63,7 @@ namespace Marco.Pms.Services.Controllers /// The number of records to return per page. /// The page number to retrieve. /// A paginated list of expenses. - [HttpGet] // Assuming this is a GET endpoint + [HttpGet("list")] // Assuming this is a GET endpoint public async Task GetExpensesList(string? filter, int pageSize = 20, int pageNumber = 1) { try @@ -180,8 +82,21 @@ namespace Marco.Pms.Services.Controllers } Guid loggedInEmployeeId = loggedInEmployee.Id; - var hasViewAllPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); - var hasViewSelfPermission = await _permission.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); + var hasViewSelfPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); + }); + + var hasViewAllPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); + }); + + await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask); // 2. --- Build Base Query and Apply Permissions --- // Start with a base IQueryable. Filters will be chained onto this. @@ -196,12 +111,12 @@ namespace Marco.Pms.Services.Controllers .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. // Apply permission-based filtering BEFORE any other filters or pagination. - if (hasViewAllPermission) + if (hasViewAllPermissionTask.Result) { // User has 'View All' permission, no initial restriction on who created the expense. _logger.LogInfo("User {EmployeeId} has 'View All' permission.", loggedInEmployeeId); } - else if (hasViewSelfPermission) + else if (hasViewSelfPermissionTask.Result) { // User only has 'View Self' permission, so restrict the query to their own expenses. _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); @@ -241,7 +156,7 @@ namespace Marco.Pms.Services.Controllers } // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. - if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermission) + if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermissionTask.Result) { expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); } @@ -329,6 +244,433 @@ namespace Marco.Pms.Services.Controllers } } + [HttpGet("details/{id}")] + public string Get(int id) + { + return "value"; + } + + [HttpPost("create")] + public async Task CreateExpense1([FromBody] CreateExpensesDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var hasUploadPermission = await _permission.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, dto.ProjectId); + if (!hasUploadPermission || !hasProjectPermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for uploading expense on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); + return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403)); + } + var isExpensesTypeExist = await _context.ExpensesTypeMaster.AnyAsync(et => et.Id == dto.ExpensesTypeId); + if (!isExpensesTypeExist) + { + _logger.LogWarning("Expenses type not for ID: {ExpensesTypeId} when creating new expense", dto.ExpensesTypeId); + return NotFound(ApiResponse.ErrorResponse("Expanses Type not found", "Expanses Type not found", 404)); + } + var isPaymentModeExist = await _context.PaymentModeMatser.AnyAsync(et => et.Id == dto.PaymentModeId); + if (!isPaymentModeExist) + { + _logger.LogWarning("Payment Mode not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); + return NotFound(ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404)); + } + var isStatusExist = await _context.ExpensesStatusMaster.AnyAsync(et => et.Id == Draft); + if (!isStatusExist) + { + _logger.LogWarning("Status not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); + return NotFound(ApiResponse.ErrorResponse("Status not found", "Status not found", 404)); + } + + var expense = _mapper.Map(dto); + + expense.CreatedById = loggedInEmployee.Id; + expense.CreatedAt = DateTime.UtcNow; + expense.TenantId = tenantId; + expense.IsActive = true; + expense.StatusId = Draft; + + _context.Expenses.Add(expense); + + Guid batchId = Guid.NewGuid(); + foreach (var attachment in dto.BillAttachments) + { + if (!_s3Service.IsBase64String(attachment.Base64Data)) + { + _logger.LogWarning("Image upload failed: Base64 data is missing While creating new expense entity for project {ProjectId} by employee {EmployeeId}", expense.ProjectId, expense.PaidById); + return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); + } + var base64 = attachment.Base64Data!.Contains(',') + ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] + : attachment.Base64Data; + + var fileType = _s3Service.GetContentTypeFromBase64(base64); + var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); + var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; + try + { + await _s3Service.UploadFileAsync(base64, fileType, objectKey); + _logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while saving image to S3"); + return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new + { + message = ex.Message, + innerexcption = ex.InnerException?.Message, + stackTrace = ex.StackTrace, + source = ex.Source + }, 400)); + } + + var document = new Document + { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, + FileName = attachment.FileName ?? "", + ContentType = attachment.ContentType ?? "", + S3Key = objectKey, + FileSize = attachment.FileSize, + UploadedAt = DateTime.UtcNow, + TenantId = tenantId + }; + _context.Documents.Add(document); + + var billAttachement = new BillAttachments + { + DocumentId = document.Id, + ExpensesId = expense.Id, + TenantId = tenantId + }; + _context.BillAttachments.Add(billAttachement); + } + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Error occured while saving Expense, Document and bill attachment entity"); + return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 400)); + } + _logger.LogInfo("Documents and attachments saved for Expense: {ExpenseId}", expense.Id); + + return StatusCode(201, ApiResponse.SuccessResponse(expense, "Expense created Successfully", 201)); + } + + /// + /// Creates a new expense entry along with its bill attachments. + /// This operation is transactional and performs validations and file uploads in parallel for optimal performance. + /// Permission checks are also run in parallel using IServiceScopeFactory to ensure thread safety. + /// + /// The data transfer object containing expense details and attachments. + /// An IActionResult indicating the result of the creation operation. + [HttpPost] + public async Task CreateExpense([FromBody] CreateExpensesDto dto) + { + _logger.LogDebug("CreateExpense for Project {ProjectId}", dto.ProjectId); + // The entire operation is wrapped in a transaction to ensure data consistency. + await using var transaction = await _context.Database.BeginTransactionAsync(); + + try + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // 1. Authorization: Run permission checks in parallel using a service scope for each task. + // This is crucial for thread-safety as IPermissionService is a scoped service. + var hasUploadPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); + }); + + var hasProjectPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasProjectPermission(loggedInEmployee, dto.ProjectId); + }); + + await Task.WhenAll(hasUploadPermissionTask, hasProjectPermissionTask); + + if (!hasUploadPermissionTask.Result || !hasProjectPermissionTask.Result) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); + return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403)); + } + + + // 2. Validation: Check if prerequisite entities exist. + // The method now returns a tuple indicating success or failure. + // Each task creates its own DbContext instance from the factory, making the parallel calls thread-safe. + var projectGetTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.FirstOrDefaultAsync(p => p.Id == dto.ProjectId); + }); + + var expenseTypeGetTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId); + }); + + var paymentModeGetTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId); + }); + + var statusGetTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster.FirstOrDefaultAsync(es => es.Id == Draft); + }); + + await Task.WhenAll(projectGetTask, expenseTypeGetTask, paymentModeGetTask, statusGetTask); + + var project = await projectGetTask; + var expenseType = await expenseTypeGetTask; + var paymentMode = await paymentModeGetTask; + var status = await statusGetTask; + + if (project == null) + { + await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. + _logger.LogWarning("Expense creation failed due to validation: Project with ID {ProjectId} not found.", dto.ProjectId); + return NotFound(ApiResponse.ErrorResponse("Project not found.", "Project not found.", 404)); + } + else if (expenseType == null) + { + await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. + _logger.LogWarning("Expense creation failed due to validation: Expense Type with ID {ExpensesTypeId} not found.", dto.ExpensesTypeId); + return NotFound(ApiResponse.ErrorResponse("Expense Type not found.", "Expense Type not found.", 404)); + } + else if (paymentMode == null) + { + await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. + _logger.LogWarning("Expense creation failed due to validation: Payment Mode with ID {PaymentModeId} not found.", dto.PaymentModeId); + return NotFound(ApiResponse.ErrorResponse("Payment Mode not found.", "Payment Mode not found.", 404)); + } + else if (status == null) + { + await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. + _logger.LogWarning("Expense creation failed due to validation: Status with ID {StatusId} not found.", Draft); + return NotFound(ApiResponse.ErrorResponse("Status not found.", "Status not found.", 404)); + } + + // 3. Entity Creation + var expense = _mapper.Map(dto); + expense.CreatedById = loggedInEmployee.Id; + expense.CreatedAt = DateTime.UtcNow; + expense.TenantId = tenantId; + expense.IsActive = true; + expense.StatusId = Draft; + + _context.Expenses.Add(expense); + + // 4. Process Attachments + if (dto.BillAttachments?.Any() ?? false) + { + await ProcessAndUploadAttachmentsAsync(dto.BillAttachments, expense, loggedInEmployee.Id, tenantId); + } + + // 5. Database Commit + await _context.SaveChangesAsync(); + + + // 6. Transaction Commit + await transaction.CommitAsync(); + + var response = _mapper.Map(expense); + + response.Project = _mapper.Map(project); + response.Status = _mapper.Map(status); + response.PaymentMode = _mapper.Map(paymentMode); + response.ExpensesType = _mapper.Map(expenseType); + + _logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId); + return StatusCode(201, ApiResponse.SuccessResponse(response, "Expense created successfully.", 201)); + } + catch (ArgumentException ex) // For invalid Base64 or other bad arguments. + { + await transaction.RollbackAsync(); + _logger.LogError(ex, "Invalid argument provided during expense creation for project {ProjectId}.", dto.ProjectId); + return BadRequest(ApiResponse.ErrorResponse("Invalid Request Data", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 400)); + } + catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 failure). + { + await transaction.RollbackAsync(); + _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); + return StatusCode(500, ApiResponse.ErrorResponse("An internal server error occurred.", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500)); + } + } + + /// + /// Processes and uploads attachments in parallel, then adds the resulting entities to the main DbContext. + /// + private async Task ProcessAndUploadAttachmentsAsync(IEnumerable attachments, Expenses expense, Guid employeeId, Guid tenantId) + { + var batchId = Guid.NewGuid(); + + var processingTasks = attachments.Select(attachment => Task.Run(async () => + { + if (string.IsNullOrWhiteSpace(attachment.Base64Data) || !_s3Service.IsBase64String(attachment.Base64Data)) + throw new ArgumentException("Invalid or missing Base64 data for an attachment."); + + var base64Data = attachment.Base64Data!.Contains(',') ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] : attachment.Base64Data; + var fileType = _s3Service.GetContentTypeFromBase64(base64Data); + var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); + var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; + + // Upload and create entities + await _s3Service.UploadFileAsync(base64Data, fileType, objectKey); + _logger.LogInfo("Uploaded file to S3 with key: {ObjectKey}", objectKey); + + return CreateAttachmentEntities(batchId, expense.Id, employeeId, tenantId, objectKey, attachment); + })).ToList(); + + var results = await Task.WhenAll(processingTasks); + + // This part is thread-safe as it runs after all parallel tasks are complete. + foreach (var (document, billAttachment) in results) + { + _context.Documents.Add(document); + _context.BillAttachments.Add(billAttachment); + } + _logger.LogInfo("{AttachmentCount} attachments processed and staged for saving.", results.Length); + } + + /// + /// A private static helper method to create Document and BillAttachment entities. + /// + private static (Document document, BillAttachments billAttachment) CreateAttachmentEntities( + Guid batchId, Guid expenseId, Guid uploadedById, Guid tenantId, string s3Key, FileUploadModel attachmentDto) + { + var document = new Document + { + BatchId = batchId, + UploadedById = uploadedById, + FileName = attachmentDto.FileName ?? "", + ContentType = attachmentDto.ContentType ?? "", + S3Key = s3Key, + FileSize = attachmentDto.FileSize, + UploadedAt = DateTime.UtcNow, + TenantId = tenantId + }; + var billAttachment = new BillAttachments { Document = document, ExpensesId = expenseId, TenantId = tenantId }; + return (document, billAttachment); + } + + [HttpPost("action")] + public async Task ChangeStatus([FromBody] ExpenseRecordDto model) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var exsitingExpenses = await _context.Expenses + .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.TenantId == tenantId); + + if (exsitingExpenses == null) + { + return NotFound(ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404)); + } + + exsitingExpenses.StatusId = model.StatusId; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException dbEx) + { + // --- Step 3: Handle Concurrency Conflicts --- + // This happens if another user modified the project after we fetched it. + _logger.LogError(dbEx, "Error occured while update status of expanse."); + return StatusCode(500, ApiResponse.ErrorResponse("Error occured while update status of expanse.", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500)); + } + var response = _mapper.Map(exsitingExpenses); + return Ok(ApiResponse.SuccessResponse(response)); + } + + [HttpPut("edit/{id}")] + public async Task UpdateExpanse(Guid id, [FromBody] UpdateExpensesDto model) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var exsitingExpense = await _context.Expenses.FirstOrDefaultAsync(e => e.Id == model.Id && e.TenantId == tenantId); + + + if (exsitingExpense == null) + { + return NotFound(ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404)); + } + _mapper.Map(model, exsitingExpense); + _context.Entry(exsitingExpense).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + _logger.LogInfo("Successfully updated project {ProjectId} by user {UserId}.", id, loggedInEmployee.Id); + } + catch (DbUpdateConcurrencyException ex) + { + // --- Step 3: Handle Concurrency Conflicts --- + // This happens if another user modified the project after we fetched it. + _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); + return StatusCode(409, ApiResponse.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409)); + } + var response = _mapper.Map(exsitingExpense); + return Ok(ApiResponse.SuccessResponse(response)); + } + + [HttpDelete("delete/{id}")] + public void Delete(int id) + { + } + #region =================================================================== Helper Functions =================================================================== + /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). /// @@ -373,153 +715,6 @@ namespace Marco.Pms.Services.Controllers return expenseFilter; } - [HttpGet("details/{id}")] - public string Get(int id) - { - return "value"; - } - - [HttpPost("create")] - public async Task Post([FromBody] CreateExpensesDto dto) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var hasUploadPermission = await _permission.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); - var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, dto.ProjectId); - if (!hasUploadPermission || !hasProjectPermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for uploading expense on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); - return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403)); - } - var isExpensesTypeExist = await _context.ExpensesTypeMaster.AnyAsync(et => et.Id == dto.ExpensesTypeId); - if (!isExpensesTypeExist) - { - _logger.LogWarning("Expenses type not for ID: {ExpensesTypeId} when creating new expense", dto.ExpensesTypeId); - return NotFound(ApiResponse.ErrorResponse("Expanses Type not found", "Expanses Type not found", 404)); - } - var isPaymentModeExist = await _context.PaymentModeMatser.AnyAsync(et => et.Id == dto.PaymentModeId); - if (!isPaymentModeExist) - { - _logger.LogWarning("Payment Mode not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); - return NotFound(ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404)); - } - var isStatusExist = await _context.ExpensesStatusMaster.AnyAsync(et => et.Id == dto.StatusId); - if (!isStatusExist) - { - _logger.LogWarning("Status not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); - return NotFound(ApiResponse.ErrorResponse("Status not found", "Status not found", 404)); - } - var expense = new Expenses - { - ProjectId = dto.ProjectId, - ExpensesTypeId = dto.ExpensesTypeId, - PaymentModeId = dto.PaymentModeId, - PaidById = dto.PaidById, - CreatedById = loggedInEmployee.Id, - TransactionDate = dto.TransactionDate, - CreatedAt = DateTime.UtcNow, - TransactionId = dto.TransactionId, - Description = dto.Description, - Location = dto.Location, - GSTNumber = dto.GSTNumber, - SupplerName = dto.SupplerName, - Amount = dto.Amount, - NoOfPersons = dto.NoOfPersons, - StatusId = dto.StatusId, - PreApproved = dto.PreApproved, - IsActive = true, - TenantId = tenantId - }; - _context.Expenses.Add(expense); - - - Guid batchId = Guid.NewGuid(); - foreach (var attachment in dto.BillAttachments) - { - //if (!_s3Service.IsBase64String(attachment.Base64Data)) - //{ - // _logger.LogWarning("Image upload failed: Base64 data is missing While creating new expense entity for project {ProjectId} by employee {EmployeeId}", expense.ProjectId, expense.PaidById); - // return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); - //} - var base64 = attachment.Base64Data!.Contains(',') - ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] - : attachment.Base64Data; - - var fileType = _s3Service.GetContentTypeFromBase64(base64); - var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); - var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; - try - { - await _s3Service.UploadFileAsync(base64, fileType, objectKey); - _logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occured while saving image to S3"); - return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new - { - message = ex.Message, - innerexcption = ex.InnerException?.Message, - stackTrace = ex.StackTrace, - source = ex.Source - }, 400)); - } - - var document = new Document - { - BatchId = batchId, - UploadedById = loggedInEmployee.Id, - FileName = attachment.FileName ?? "", - ContentType = attachment.ContentType ?? "", - S3Key = objectKey, - //Base64Data = attachment.Base64Data, - FileSize = attachment.FileSize, - UploadedAt = DateTime.UtcNow, - TenantId = tenantId - }; - _context.Documents.Add(document); - - var billAttachement = new BillAttachments - { - DocumentId = document.Id, - ExpensesId = expense.Id, - TenantId = tenantId - }; - _context.BillAttachments.Add(billAttachement); - } - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Error occured while saving Expense, Document and bill attachment entity"); - return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - innerexcption = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 400)); - } - _logger.LogInfo("Documents and attachments saved for Expense: {ExpenseId}", expense.Id); - - return StatusCode(201, ApiResponse.SuccessResponse(expense, "Expense created Successfully", 201)); - } - - - [HttpPut("edit/{id}")] - public void Put(int id, [FromBody] string value) - { - } - - [HttpDelete("delete/{id}")] - public void Delete(int id) - { - } + #endregion } } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index fad5b78..ea34613 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; @@ -76,7 +77,8 @@ namespace Marco.Pms.Services.MappingProfiles #region ======================================================= Expenses ======================================================= CreateMap(); - + CreateMap(); + CreateMap(); #endregion diff --git a/Marco.Pms.Services/Service/S3UploadService.cs b/Marco.Pms.Services/Service/S3UploadService.cs index 1d98a33..b07093c 100644 --- a/Marco.Pms.Services/Service/S3UploadService.cs +++ b/Marco.Pms.Services/Service/S3UploadService.cs @@ -41,6 +41,7 @@ namespace Marco.Pms.Services.Service if (allowedFilesType == null || !allowedFilesType.Contains(fileType)) { + _logger.LogWarning("Unsupported file type. {FileType}", fileType); throw new InvalidOperationException("Unsupported file type."); } From 282d33d8b261a4c9bf03af880f08fef9c57129ca Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 21 Jul 2025 13:05:04 +0530 Subject: [PATCH 16/81] Optimized and enchance the created expense API --- .../Controllers/ExpenseController.cs | 387 +++++++----------- 1 file changed, 139 insertions(+), 248 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 029b65e..4501c61 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -27,7 +27,6 @@ namespace Marco.Pms.Services.Controllers private readonly IDbContextFactory _dbContextFactory; private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; - private readonly PermissionServices _permission; private readonly ILoggingService _logger; private readonly S3UploadService _s3Service; private readonly IServiceScopeFactory _serviceScopeFactory; @@ -38,7 +37,6 @@ namespace Marco.Pms.Services.Controllers IDbContextFactory dbContextFactory, ApplicationDbContext context, UserHelper userHelper, - PermissionServices permission, IServiceScopeFactory serviceScopeFactory, ILoggingService logger, S3UploadService s3Service, @@ -47,7 +45,6 @@ namespace Marco.Pms.Services.Controllers _dbContextFactory = dbContextFactory; _context = context; _userHelper = userHelper; - _permission = permission; _logger = logger; _serviceScopeFactory = serviceScopeFactory; _s3Service = s3Service; @@ -63,7 +60,8 @@ namespace Marco.Pms.Services.Controllers /// The number of records to return per page. /// The page number to retrieve. /// A paginated list of expenses. - [HttpGet("list")] // Assuming this is a GET endpoint + + [HttpGet("list")] public async Task GetExpensesList(string? filter, int pageSize = 20, int pageNumber = 1) { try @@ -250,135 +248,18 @@ namespace Marco.Pms.Services.Controllers return "value"; } - [HttpPost("create")] - public async Task CreateExpense1([FromBody] CreateExpensesDto dto) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var hasUploadPermission = await _permission.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); - var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, dto.ProjectId); - if (!hasUploadPermission || !hasProjectPermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for uploading expense on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); - return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403)); - } - var isExpensesTypeExist = await _context.ExpensesTypeMaster.AnyAsync(et => et.Id == dto.ExpensesTypeId); - if (!isExpensesTypeExist) - { - _logger.LogWarning("Expenses type not for ID: {ExpensesTypeId} when creating new expense", dto.ExpensesTypeId); - return NotFound(ApiResponse.ErrorResponse("Expanses Type not found", "Expanses Type not found", 404)); - } - var isPaymentModeExist = await _context.PaymentModeMatser.AnyAsync(et => et.Id == dto.PaymentModeId); - if (!isPaymentModeExist) - { - _logger.LogWarning("Payment Mode not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); - return NotFound(ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404)); - } - var isStatusExist = await _context.ExpensesStatusMaster.AnyAsync(et => et.Id == Draft); - if (!isStatusExist) - { - _logger.LogWarning("Status not for ID: {PaymentModeId} when creating new expense", dto.PaymentModeId); - return NotFound(ApiResponse.ErrorResponse("Status not found", "Status not found", 404)); - } - - var expense = _mapper.Map(dto); - - expense.CreatedById = loggedInEmployee.Id; - expense.CreatedAt = DateTime.UtcNow; - expense.TenantId = tenantId; - expense.IsActive = true; - expense.StatusId = Draft; - - _context.Expenses.Add(expense); - - Guid batchId = Guid.NewGuid(); - foreach (var attachment in dto.BillAttachments) - { - if (!_s3Service.IsBase64String(attachment.Base64Data)) - { - _logger.LogWarning("Image upload failed: Base64 data is missing While creating new expense entity for project {ProjectId} by employee {EmployeeId}", expense.ProjectId, expense.PaidById); - return BadRequest(ApiResponse.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400)); - } - var base64 = attachment.Base64Data!.Contains(',') - ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] - : attachment.Base64Data; - - var fileType = _s3Service.GetContentTypeFromBase64(base64); - var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); - var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; - try - { - await _s3Service.UploadFileAsync(base64, fileType, objectKey); - _logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occured while saving image to S3"); - return BadRequest(ApiResponse.ErrorResponse("Cannot upload attachment to S3", new - { - message = ex.Message, - innerexcption = ex.InnerException?.Message, - stackTrace = ex.StackTrace, - source = ex.Source - }, 400)); - } - - var document = new Document - { - BatchId = batchId, - UploadedById = loggedInEmployee.Id, - FileName = attachment.FileName ?? "", - ContentType = attachment.ContentType ?? "", - S3Key = objectKey, - FileSize = attachment.FileSize, - UploadedAt = DateTime.UtcNow, - TenantId = tenantId - }; - _context.Documents.Add(document); - - var billAttachement = new BillAttachments - { - DocumentId = document.Id, - ExpensesId = expense.Id, - TenantId = tenantId - }; - _context.BillAttachments.Add(billAttachement); - } - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Error occured while saving Expense, Document and bill attachment entity"); - return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - innerexcption = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 400)); - } - _logger.LogInfo("Documents and attachments saved for Expense: {ExpenseId}", expense.Id); - - return StatusCode(201, ApiResponse.SuccessResponse(expense, "Expense created Successfully", 201)); - } - /// /// Creates a new expense entry along with its bill attachments. - /// This operation is transactional and performs validations and file uploads in parallel for optimal performance. - /// Permission checks are also run in parallel using IServiceScopeFactory to ensure thread safety. + /// This operation is transactional and performs validations and file uploads concurrently for optimal performance + /// by leveraging async/await without unnecessary thread-pool switching via Task.Run. /// /// The data transfer object containing expense details and attachments. /// An IActionResult indicating the result of the creation operation. - [HttpPost] + + [HttpPost("create")] public async Task CreateExpense([FromBody] CreateExpensesDto dto) { - _logger.LogDebug("CreateExpense for Project {ProjectId}", dto.ProjectId); + _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); // The entire operation is wrapped in a transaction to ensure data consistency. await using var transaction = await _context.Database.BeginTransactionAsync(); @@ -386,9 +267,10 @@ namespace Marco.Pms.Services.Controllers { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - // 1. Authorization: Run permission checks in parallel using a service scope for each task. - // This is crucial for thread-safety as IPermissionService is a scoped service. - var hasUploadPermissionTask = Task.Run(async () => + // 1. Authorization & Validation: Run all I/O-bound checks concurrently using factories for safety. + + // PERMISSION CHECKS: Use IServiceScopeFactory for thread-safe access to scoped services. + var hasUploadPermissionTask = Task.Run(async () => // Task.Run is acceptable here to create a new scope, but let's do it cleaner. { using var scope = _serviceScopeFactory.CreateScope(); var permissionService = scope.ServiceProvider.GetRequiredService(); @@ -402,72 +284,66 @@ namespace Marco.Pms.Services.Controllers return await permissionService.HasProjectPermission(loggedInEmployee, dto.ProjectId); }); - await Task.WhenAll(hasUploadPermissionTask, hasProjectPermissionTask); + // VALIDATION CHECKS: Use IDbContextFactory for thread-safe, parallel database queries. + // Each task gets its own DbContext instance. + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == dto.ProjectId); + }); + var expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId); + }); + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster.AsNoTracking().FirstOrDefaultAsync(es => es.Id == Draft); + }); - if (!hasUploadPermissionTask.Result || !hasProjectPermissionTask.Result) + + // Await all prerequisite checks at once. + await Task.WhenAll( + hasUploadPermissionTask, hasProjectPermissionTask, + projectTask, expenseTypeTask, paymentModeTask, statusTask + ); + + // Await all prerequisite checks at once. + await Task.WhenAll( + hasUploadPermissionTask, hasProjectPermissionTask, + projectTask, expenseTypeTask, paymentModeTask, statusTask + ); + + // 2. Aggregate and Check Results + if (!await hasUploadPermissionTask || !await hasProjectPermissionTask) { _logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403)); } + var validationErrors = new List(); + var project = await projectTask; + var expenseType = await expenseTypeTask; + var paymentMode = await paymentModeTask; + var status = await statusTask; - // 2. Validation: Check if prerequisite entities exist. - // The method now returns a tuple indicating success or failure. - // Each task creates its own DbContext instance from the factory, making the parallel calls thread-safe. - var projectGetTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.FirstOrDefaultAsync(p => p.Id == dto.ProjectId); - }); + if (project == null) validationErrors.Add("Project not found."); + if (expenseType == null) validationErrors.Add("Expense Type not found."); + if (paymentMode == null) validationErrors.Add("Payment Mode not found."); + if (status == null) validationErrors.Add("Default status 'Draft' not found."); - var expenseTypeGetTask = Task.Run(async () => + if (validationErrors.Any()) { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId); - }); - - var paymentModeGetTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.PaymentModeMatser.FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId); - }); - - var statusGetTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMaster.FirstOrDefaultAsync(es => es.Id == Draft); - }); - - await Task.WhenAll(projectGetTask, expenseTypeGetTask, paymentModeGetTask, statusGetTask); - - var project = await projectGetTask; - var expenseType = await expenseTypeGetTask; - var paymentMode = await paymentModeGetTask; - var status = await statusGetTask; - - if (project == null) - { - await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. - _logger.LogWarning("Expense creation failed due to validation: Project with ID {ProjectId} not found.", dto.ProjectId); - return NotFound(ApiResponse.ErrorResponse("Project not found.", "Project not found.", 404)); - } - else if (expenseType == null) - { - await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. - _logger.LogWarning("Expense creation failed due to validation: Expense Type with ID {ExpensesTypeId} not found.", dto.ExpensesTypeId); - return NotFound(ApiResponse.ErrorResponse("Expense Type not found.", "Expense Type not found.", 404)); - } - else if (paymentMode == null) - { - await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. - _logger.LogWarning("Expense creation failed due to validation: Payment Mode with ID {PaymentModeId} not found.", dto.PaymentModeId); - return NotFound(ApiResponse.ErrorResponse("Payment Mode not found.", "Payment Mode not found.", 404)); - } - else if (status == null) - { - await transaction.RollbackAsync(); // Ensure transaction is terminated before returning. - _logger.LogWarning("Expense creation failed due to validation: Status with ID {StatusId} not found.", Draft); - return NotFound(ApiResponse.ErrorResponse("Status not found.", "Status not found.", 404)); + await transaction.RollbackAsync(); + var errorMessage = string.Join(" ", validationErrors); + _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); + return BadRequest(ApiResponse.ErrorResponse("Invalid input data.", errorMessage, 400)); } // 3. Entity Creation @@ -489,12 +365,10 @@ namespace Marco.Pms.Services.Controllers // 5. Database Commit await _context.SaveChangesAsync(); - // 6. Transaction Commit await transaction.CommitAsync(); var response = _mapper.Map(expense); - response.Project = _mapper.Map(project); response.Status = _mapper.Map(status); response.PaymentMode = _mapper.Map(paymentMode); @@ -503,11 +377,11 @@ namespace Marco.Pms.Services.Controllers _logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId); return StatusCode(201, ApiResponse.SuccessResponse(response, "Expense created successfully.", 201)); } - catch (ArgumentException ex) // For invalid Base64 or other bad arguments. + catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation { await transaction.RollbackAsync(); - _logger.LogError(ex, "Invalid argument provided during expense creation for project {ProjectId}.", dto.ProjectId); - return BadRequest(ApiResponse.ErrorResponse("Invalid Request Data", new + _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); + return BadRequest(ApiResponse.ErrorResponse("Invalid Request Data.", new { Message = ex.Message, StackTrace = ex.StackTrace, @@ -520,7 +394,7 @@ namespace Marco.Pms.Services.Controllers } }, 400)); } - catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 failure). + catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) { await transaction.RollbackAsync(); _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); @@ -539,62 +413,6 @@ namespace Marco.Pms.Services.Controllers } } - /// - /// Processes and uploads attachments in parallel, then adds the resulting entities to the main DbContext. - /// - private async Task ProcessAndUploadAttachmentsAsync(IEnumerable attachments, Expenses expense, Guid employeeId, Guid tenantId) - { - var batchId = Guid.NewGuid(); - - var processingTasks = attachments.Select(attachment => Task.Run(async () => - { - if (string.IsNullOrWhiteSpace(attachment.Base64Data) || !_s3Service.IsBase64String(attachment.Base64Data)) - throw new ArgumentException("Invalid or missing Base64 data for an attachment."); - - var base64Data = attachment.Base64Data!.Contains(',') ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] : attachment.Base64Data; - var fileType = _s3Service.GetContentTypeFromBase64(base64Data); - var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); - var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; - - // Upload and create entities - await _s3Service.UploadFileAsync(base64Data, fileType, objectKey); - _logger.LogInfo("Uploaded file to S3 with key: {ObjectKey}", objectKey); - - return CreateAttachmentEntities(batchId, expense.Id, employeeId, tenantId, objectKey, attachment); - })).ToList(); - - var results = await Task.WhenAll(processingTasks); - - // This part is thread-safe as it runs after all parallel tasks are complete. - foreach (var (document, billAttachment) in results) - { - _context.Documents.Add(document); - _context.BillAttachments.Add(billAttachment); - } - _logger.LogInfo("{AttachmentCount} attachments processed and staged for saving.", results.Length); - } - - /// - /// A private static helper method to create Document and BillAttachment entities. - /// - private static (Document document, BillAttachments billAttachment) CreateAttachmentEntities( - Guid batchId, Guid expenseId, Guid uploadedById, Guid tenantId, string s3Key, FileUploadModel attachmentDto) - { - var document = new Document - { - BatchId = batchId, - UploadedById = uploadedById, - FileName = attachmentDto.FileName ?? "", - ContentType = attachmentDto.ContentType ?? "", - S3Key = s3Key, - FileSize = attachmentDto.FileSize, - UploadedAt = DateTime.UtcNow, - TenantId = tenantId - }; - var billAttachment = new BillAttachments { Document = document, ExpensesId = expenseId, TenantId = tenantId }; - return (document, billAttachment); - } - [HttpPost("action")] public async Task ChangeStatus([FromBody] ExpenseRecordDto model) { @@ -715,6 +533,79 @@ namespace Marco.Pms.Services.Controllers return expenseFilter; } + /// + /// Processes and uploads attachments concurrently, then adds the resulting entities to the main DbContext. + /// + private async Task ProcessAndUploadAttachmentsAsync(IEnumerable attachments, Expenses expense, Guid employeeId, Guid tenantId) + { + // Pre-validate all attachments to fail fast before any uploads. + foreach (var attachment in attachments) + { + if (string.IsNullOrWhiteSpace(attachment.Base64Data) || !_s3Service.IsBase64String(attachment.Base64Data)) + { + throw new ArgumentException($"Invalid or missing Base64 data for attachment: {attachment.FileName ?? "N/A"}"); + } + } + + var batchId = Guid.NewGuid(); + + // Create a list of tasks to be executed concurrently. + var processingTasks = attachments.Select(attachment => + ProcessSingleAttachmentAsync(attachment, expense, employeeId, tenantId, batchId) + ).ToList(); + + var results = await Task.WhenAll(processingTasks); + + // This part is thread-safe as it runs after all concurrent tasks are complete. + foreach (var (document, billAttachment) in results) + { + _context.Documents.Add(document); + _context.BillAttachments.Add(billAttachment); + } + _logger.LogInfo("{AttachmentCount} attachments processed and staged for saving.", results.Length); + } + + /// + /// Handles the logic for a single attachment: upload to S3 and create corresponding entities. + /// + private async Task<(Document document, BillAttachments billAttachment)> ProcessSingleAttachmentAsync( + FileUploadModel attachment, Expenses expense, Guid employeeId, Guid tenantId, Guid batchId) + { + var base64Data = attachment.Base64Data!.Contains(',') ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] : attachment.Base64Data; + var fileType = _s3Service.GetContentTypeFromBase64(base64Data); + var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); + var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; + + // Await the I/O-bound upload operation directly. + await _s3Service.UploadFileAsync(base64Data, fileType, objectKey); + _logger.LogInfo("Uploaded file to S3 with key: {ObjectKey}", objectKey); + + return CreateAttachmentEntities(batchId, expense.Id, employeeId, tenantId, objectKey, attachment); + } + + + /// + /// A private static helper method to create Document and BillAttachment entities. + /// This remains unchanged as it's a pure data-shaping method. + /// + private static (Document document, BillAttachments billAttachment) CreateAttachmentEntities( + Guid batchId, Guid expenseId, Guid uploadedById, Guid tenantId, string s3Key, FileUploadModel attachmentDto) + { + var document = new Document + { + BatchId = batchId, + UploadedById = uploadedById, + FileName = attachmentDto.FileName ?? "", + ContentType = attachmentDto.ContentType ?? "", + S3Key = s3Key, + FileSize = attachmentDto.FileSize, + UploadedAt = DateTime.UtcNow, + TenantId = tenantId + }; + var billAttachment = new BillAttachments { Document = document, ExpensesId = expenseId, TenantId = tenantId }; + return (document, billAttachment); + } + #endregion } } From f9213b6040b6980b30729ce91a2763f6d0d57bc7 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 21 Jul 2025 18:21:51 +0530 Subject: [PATCH 17/81] Completely optimmized the Action API --- Marco.Pms.CacheHelper/UpdateLogHelper.cs | 12 +- .../Data/ApplicationDbContext.cs | 64 +- ...19074035_Expenses_tables_Added.Designer.cs | 4180 ---------------- ...edBy_And_CareatedAt_In_Expense.Designer.cs | 4196 ---------------- ...ded_CreatedBy_And_CareatedAt_In_Expense.cs | 63 - ...9103905_Added_ExpenseLog_Table.Designer.cs | 4243 ----------------- .../20250719103905_Added_ExpenseLog_Table.cs | 62 - ...113715_Added_ExpensesStatusMaping_Table.cs | 149 - ..._Added_Expense_Related_Tables.Designer.cs} | 126 +- ...721124928_Added_Expense_Related_Tables.cs} | 197 +- .../ApplicationDbContextModelSnapshot.cs | 122 +- .../Dtos/Expenses/ExpenseRecordDto.cs | 2 +- Marco.Pms.Model/Expenses/ExpenseLog.cs | 3 +- .../Expenses/ExpensesReimburseMapping.cs | 5 +- .../Expenses/ExpensesStatusMapping.cs | 2 +- .../Expenses/StatusPermissionMapping.cs | 3 +- .../Master/ExpensesStatusMaster.cs | 2 + .../Master/ExpensesStatusMasterVM.cs | 2 + .../Controllers/ExpenseController.cs | 559 +-- Marco.Pms.Services/Program.cs | 1 + Marco.Pms.Services/Service/ExpensesService.cs | 895 ++++ .../ServiceInterfaces/IExpensesService.cs | 14 + .../appsettings.Development.json | 9 +- 23 files changed, 1399 insertions(+), 13512 deletions(-) delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs delete mode 100644 Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs rename Marco.Pms.DataAccess/Migrations/{20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs => 20250721124928_Added_Expense_Related_Tables.Designer.cs} (96%) rename Marco.Pms.DataAccess/Migrations/{20250719074035_Expenses_tables_Added.cs => 20250721124928_Added_Expense_Related_Tables.cs} (74%) create mode 100644 Marco.Pms.Services/Service/ExpensesService.cs create mode 100644 Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs diff --git a/Marco.Pms.CacheHelper/UpdateLogHelper.cs b/Marco.Pms.CacheHelper/UpdateLogHelper.cs index 9bc520a..ddea104 100644 --- a/Marco.Pms.CacheHelper/UpdateLogHelper.cs +++ b/Marco.Pms.CacheHelper/UpdateLogHelper.cs @@ -11,18 +11,18 @@ namespace Marco.Pms.CacheHelper private readonly IMongoDatabase _mongoDatabase; public UpdateLogHelper(IConfiguration configuration) { - var connectionString = configuration["MongoDB:ConnectionString"]; + var connectionString = configuration["MongoDB:ModificationConnectionString"]; var mongoUrl = new MongoUrl(connectionString); var client = new MongoClient(mongoUrl); // Your MongoDB connection string _mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name } - public async Task PushToUpdateLogs(UpdateLogsObject oldObject, string collectionName) + public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName) { var collection = _mongoDatabase.GetCollection(collectionName); await collection.InsertOneAsync(oldObject); } - public async Task> GetFromUpdateLogsByEntityId(Guid entityId, string collectionName) + public async Task> GetFromUpdateLogsByEntityIdAsync(Guid entityId, string collectionName) { var collection = _mongoDatabase.GetCollection(collectionName); var filter = Builders.Filter.Eq(p => p.EntityId, entityId.ToString()); @@ -34,7 +34,7 @@ namespace Marco.Pms.CacheHelper return result; } - public async Task> GetFromUpdateLogsByUpdetedById(Guid updatedById, string collectionName) + public async Task> GetFromUpdateLogsByUpdetedByIdAsync(Guid updatedById, string collectionName) { var collection = _mongoDatabase.GetCollection(collectionName); var filter = Builders.Filter.Eq(p => p.UpdatedById, updatedById.ToString()); @@ -46,7 +46,7 @@ namespace Marco.Pms.CacheHelper return result; } - public BsonDocument NormalizeGuidsToStrings(object entity) + public BsonDocument EntityToBsonDocument(object entity) { var bson = new BsonDocument(); @@ -73,7 +73,7 @@ namespace Marco.Pms.CacheHelper var array = new BsonArray(); foreach (var item in list) { - array.Add(NormalizeGuidsToStrings(item)); // recursive + array.Add(EntityToBsonDocument(item)); // recursive } bson[prop.Name] = array; } diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 71dbdfa..85ea792 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -393,7 +393,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"), Name = "Draft", + DisplayName = "Draft", Description = "Expense has been created but not yet submitted.", + Color = "#212529", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -402,7 +404,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), Name = "Review Pending", + DisplayName = "Review", Description = "Reviewer is currently reviewing the expense.", + Color = "#0d6efd", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -411,7 +415,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Name = "Approval Pending", + DisplayName = "Approve", Description = "Review is completed, waiting for action of approver.", + Color = "#0dcaf0", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -420,7 +426,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), Name = "Rejected", + DisplayName = "Reject", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + Color = "#dc3545", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -429,7 +437,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Name = "Process Pending", + DisplayName = "Process", Description = "Approved expense is awaiting final payment.", + Color = "#ffc107", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -438,7 +448,9 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), Name = "Processed", + DisplayName = "Paid", Description = "Expense has been settled.", + Color = "#198754", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -451,7 +463,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("5cf7f1df-9d1f-4289-add0-1775ad614f25"), StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + NextStatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, // Approve to Rejected @@ -470,6 +482,14 @@ namespace Marco.Pms.DataAccess.Data NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, + // Rejected to Review + new ExpensesStatusMapping + { + Id = Guid.Parse("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), + StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, // Review to Rejected new ExpensesStatusMapping { @@ -496,6 +516,48 @@ namespace Marco.Pms.DataAccess.Data } ); + modelBuilder.Entity().HasData( + + // Approval Pending Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("ed893799-1a5f-4311-a077-de93c86ca8fd"), + PermissionId = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Rejected Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), + PermissionId = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new StatusPermissionMapping + { + Id = Guid.Parse("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = Guid.Parse("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Process Pending Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = Guid.Parse("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }, + // Processed Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = Guid.Parse("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), + TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + }); + modelBuilder.Entity().HasData( new ExpensesTypeMaster { diff --git a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs deleted file mode 100644 index a126fc0..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.Designer.cs +++ /dev/null @@ -1,4180 +0,0 @@ -// -using System; -using Marco.Pms.DataAccess.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Marco.Pms.DataAccess.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20250719074035_Expenses_tables_Added")] - partial class Expenses_tables_Added - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.12") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ApprovedById") - .HasColumnType("char(36)"); - - b.Property("ApprovedDate") - .HasColumnType("datetime(6)"); - - b.Property("AssignedBy") - .HasColumnType("char(36)"); - - b.Property("AssignmentDate") - .HasColumnType("datetime(6)"); - - b.Property("CompletedTask") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedTask") - .HasColumnType("double"); - - b.Property("ReportedById") - .HasColumnType("char(36)"); - - b.Property("ReportedDate") - .HasColumnType("datetime(6)"); - - b.Property("ReportedTask") - .HasColumnType("double"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkItemId") - .HasColumnType("char(36)"); - - b.Property("WorkStatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApprovedById"); - - b.HasIndex("AssignedBy"); - - b.HasIndex("ReportedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkItemId"); - - b.HasIndex("WorkStatusId"); - - b.ToTable("TaskAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ReferenceId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TaskAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("CommentDate") - .HasColumnType("datetime(6)"); - - b.Property("CommentedBy") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentedBy"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskMembers"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ApprovedBy") - .HasColumnType("char(36)"); - - b.Property("AttendanceDate") - .HasColumnType("datetime(6)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Date") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("InTime") - .HasColumnType("datetime(6)"); - - b.Property("IsApproved") - .HasColumnType("tinyint(1)"); - - b.Property("OutTime") - .HasColumnType("datetime(6)"); - - b.Property("ProjectID") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.ToTable("Attendes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ActivityTime") - .HasColumnType("datetime(6)"); - - b.Property("AttendanceId") - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("Latitude") - .HasColumnType("longtext"); - - b.Property("Longitude") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedBy") - .HasColumnType("char(36)"); - - b.Property("UpdatedOn") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.HasIndex("AttendanceId"); - - b.HasIndex("DocumentId"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedBy"); - - b.ToTable("AttendanceLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MPIN") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("MPINToken") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("MPINDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpriesInSec") - .HasColumnType("int"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("OTP") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("OTPDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("ExpiryDate") - .HasColumnType("datetime(6)"); - - b.Property("IsRevoked") - .HasColumnType("tinyint(1)"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("RevokedAt") - .HasColumnType("datetime(6)"); - - b.Property("Token") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedByID") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedByID"); - - b.HasIndex("TenantId"); - - b.ToTable("Buckets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ContactCategoryId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Organization") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactCategoryId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("Contacts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactCategoryMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("EmailAddress") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsEmails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Note") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("ContactNotes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsPhones"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactProjectMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ContactTagId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ContactTagId"); - - b.ToTable("ContactTagMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactTagMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("RefereanceId") - .HasColumnType("char(36)"); - - b.Property("UpdateAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UpdatedById"); - - b.ToTable("DirectoryUpdateLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("EmployeeId"); - - b.ToTable("EmployeeBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Base64Data") - .HasColumnType("longtext"); - - b.Property("BatchId") - .HasColumnType("char(36)"); - - b.Property("ContentType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileSize") - .HasColumnType("bigint"); - - b.Property("S3Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("ThumbS3Key") - .HasColumnType("longtext"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)"); - - b.Property("UploadedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.HasIndex("UploadedById"); - - b.ToTable("Documents"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AadharNumber") - .HasColumnType("longtext"); - - b.Property("ApplicationUserId") - .HasColumnType("varchar(255)"); - - b.Property("BirthDate") - .HasColumnType("datetime(6)"); - - b.Property("CurrentAddress") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("EmergencyContactPerson") - .HasColumnType("longtext"); - - b.Property("EmergencyPhoneNumber") - .HasColumnType("longtext"); - - b.Property("FirstName") - .HasColumnType("longtext"); - - b.Property("Gender") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("JoiningDate") - .HasColumnType("datetime(6)"); - - b.Property("LastName") - .HasColumnType("longtext"); - - b.Property("MiddleName") - .HasColumnType("longtext"); - - b.Property("PanNumber") - .HasColumnType("longtext"); - - b.Property("PermanentAddress") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationUserId"); - - b.HasIndex("JobRoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("Employees"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("RoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("EmployeeRoleMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EndTime") - .HasColumnType("time(6)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("StartTime") - .HasColumnType("time(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkShifts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsChecked") - .HasColumnType("tinyint(1)"); - - b.Property("IsMandatory") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("ActivityCheckLists"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CheckListId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("CheckListMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("FeatureId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("FeatureId"); - - b.ToTable("FeaturePermissions"); - - b.HasData( - new - { - Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), - Description = "Access all information related to the project.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project" - }, - new - { - Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), - Description = "Potentially edit the project name, description, start/end dates, or status.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project" - }, - new - { - Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), - Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Team" - }, - new - { - Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), - Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project Infra" - }, - new - { - Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), - Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project Infra" - }, - new - { - Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), - Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "View Task" - }, - new - { - Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), - Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Add/Edit Task" - }, - new - { - Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), - Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Assign/Report Progress" - }, - new - { - Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), - Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Approve Task" - }, - new - { - Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), - Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View All Employees" - }, - new - { - Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), - Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View Team Members" - }, - new - { - Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), - Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Add/Edit Employee" - }, - new - { - Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), - Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Assign Roles" - }, - new - { - Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Team Attendance " - }, - new - { - Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), - Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Regularize Attendance" - }, - new - { - Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Self Attendance" - }, - new - { - Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), - Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "View Masters" - }, - new - { - Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), - Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "Manage Masters" - }, - new - { - Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), - Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Admin" - }, - new - { - Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), - Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Manager" - }, - new - { - Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), - Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory User" - }, - new - { - Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), - Description = "Allows a user to view only the expense records that they have personally submitted", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View Self" - }, - new - { - Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), - Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View All" - }, - new - { - Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), - Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Upload" - }, - new - { - Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), - Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Review" - }, - new - { - Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), - Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Approve" - }, - new - { - Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), - Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Process" - }, - new - { - Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), - Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Manage" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.Property("ApplicationRoleId") - .HasColumnType("char(36)"); - - b.Property("FeaturePermissionId") - .HasColumnType("char(36)"); - - b.HasKey("ApplicationRoleId", "FeaturePermissionId"); - - b.HasIndex("FeaturePermissionId"); - - b.ToTable("RolePermissionMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactName") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("DomainName") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("OnBoardingDate") - .HasColumnType("datetime(6)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("IndustryId"); - - b.ToTable("Tenants"); - - b.HasData( - new - { - Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), - ContactName = "Admin", - ContactNumber = "123456789", - Description = "", - DomainName = "www.marcobms.org", - IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - IsActive = true, - Name = "MarcoBMS", - OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - OragnizationSize = "100-200" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("DocumentId"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("TenantId"); - - b.ToTable("BillAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Amount") - .HasColumnType("double"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ExpensesTypeId") - .HasColumnType("char(36)"); - - b.Property("GSTNumber") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Location") - .HasColumnType("longtext"); - - b.Property("NoOfPersons") - .HasColumnType("int"); - - b.Property("PaidById") - .HasColumnType("char(36)"); - - b.Property("PaymentModeId") - .HasColumnType("char(36)"); - - b.Property("PreApproved") - .HasColumnType("tinyint(1)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("SupplerName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TransactionDate") - .HasColumnType("datetime(6)"); - - b.Property("TransactionId") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("ExpensesTypeId"); - - b.HasIndex("PaidById"); - - b.HasIndex("PaymentModeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Expenses"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ReimburseById") - .HasColumnType("char(36)"); - - b.Property("ReimburseDate") - .HasColumnType("datetime(6)"); - - b.Property("ReimburseNote") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ReimburseTransactionId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ReimburseById"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("ExpensesReimburseId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("ExpensesReimburseId"); - - b.ToTable("ExpensesReimburseMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpeStatusIdnsesId") - .HasColumnType("char(36)"); - - b.Property("NextStatusId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpeStatusIdnsesId"); - - b.HasIndex("NextStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMapping"); - - b.HasData( - new - { - Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), - NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), - NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("PermissionId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PermissionId"); - - b.HasIndex("StatusId"); - - b.ToTable("StatusPermissionMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CommentId") - .HasColumnType("char(36)"); - - b.Property("FileId") - .HasColumnType("char(36)"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AuthorId") - .HasColumnType("char(36)"); - - b.Property("MessageText") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ParentMessageId") - .HasColumnType("char(36)"); - - b.Property("SentAt") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("TicketComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("LinkedActivityId") - .HasColumnType("char(36)"); - - b.Property("LinkedProjectId") - .HasColumnType("char(36)"); - - b.Property("PriorityId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TypeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PriorityId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.HasIndex("TypeId"); - - b.ToTable("Tickets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("TagId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TagId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketTags"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTypeMasters"); - - b.HasData( - new - { - Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), - Description = "An identified problem that affects the performance, reliability, or standards of a product or service", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), - Description = "A support service that assists users with technical issues, requests, or inquiries.", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MailListId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("Recipient") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Schedule") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("MailListId"); - - b.ToTable("MailDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmailId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.ToTable("MailLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Keywords") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("MailingList"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityName") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UnitOfMeasurement") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ActivityMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesStatusMaster"); - - b.HasData( - new - { - Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Description = "Expense has been created but not yet submitted.", - IsActive = true, - IsSystem = true, - Name = "Draft", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - Description = "Reviewer is currently reviewing the expense.", - IsActive = true, - IsSystem = true, - Name = "Review Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - Description = "Review is completed, waiting for action of approver.", - IsActive = true, - IsSystem = true, - Name = "Approval Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", - IsActive = true, - IsSystem = true, - Name = "Rejected", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Description = "Approved expense is awaiting final payment.", - IsActive = true, - IsSystem = true, - Name = "Process Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - Description = "Expense has been settled.", - IsActive = true, - IsSystem = true, - Name = "Processed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("NoOfPersonsRequired") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesTypeMaster"); - - b.HasData( - new - { - Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), - Description = "Materials, equipment and supplies purchased for site operations.", - IsActive = true, - Name = "Procurement", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), - Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", - IsActive = true, - Name = "Transport", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), - Description = "Delivery of personnel.", - IsActive = true, - Name = "Travelling", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), - Description = "Site setup costs including equipment deployment and temporary infrastructure.", - IsActive = true, - Name = "Mobilization", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), - Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", - IsActive = true, - Name = "Employee Welfare", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), - Description = "Machinery servicing, electricity, water, and temporary office needs.", - IsActive = true, - Name = "Maintenance & Utilities", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), - Description = "Scheduled payments for external services or goods.", - IsActive = true, - Name = "Vendor/Supplier Payments", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), - Description = "Government fees, insurance, inspections and safety-related expenditures.", - IsActive = true, - Name = "Compliance & Safety", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("ModuleId") - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("ModuleId"); - - b.ToTable("Features"); - - b.HasData( - new - { - Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - Description = "Manage Project", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Project Management" - }, - new - { - Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Expense Management" - }, - new - { - Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - Description = "Manage Tasks", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Task Management" - }, - new - { - Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - Description = "Manage Employee", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Employee Management" - }, - new - { - Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - Description = "Attendance", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Attendance Management" - }, - new - { - Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - Description = "Global Masters", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Masters" - }, - new - { - Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - Description = "Managing all directory related rights", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Directory Management" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - - b.HasData( - new - { - Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - Name = "Information Technology (IT) Services" - }, - new - { - Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), - Name = "Manufacturing & Production" - }, - new - { - Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), - Name = "Energy & Resources" - }, - new - { - Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), - Name = "Finance & Professional Services" - }, - new - { - Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), - Name = "Hospitals and Healthcare Services" - }, - new - { - Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), - Name = "Social Services" - }, - new - { - Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), - Name = "Retail & Consumer Services" - }, - new - { - Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), - Name = "Transportation & Logistics" - }, - new - { - Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), - Name = "Education & Training" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Modules"); - - b.HasData( - new - { - Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Description = "Project Module", - Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", - Name = "Project" - }, - new - { - Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Description = "Employee Module", - Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", - Name = "Employee" - }, - new - { - Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Description = "Masters Module", - Key = "504ec132-e6a9-422f-8f85-050602cfce05", - Name = "Masters" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("PaymentModeMatser"); - - b.HasData( - new - { - Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), - Description = "Physical currency; still used for small or informal transactions.", - IsActive = true, - Name = "Cash", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), - Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", - IsActive = true, - Name = "Cheque", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), - Description = "Online banking portals used to transfer funds directly between accounts", - IsActive = true, - Name = "NetBanking", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), - Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", - IsActive = true, - Name = "UPI", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Status") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMasters"); - - b.HasData( - new - { - Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - Status = "Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), - Status = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), - Status = "On Hold", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), - Status = "In Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), - Status = "Completed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Level") - .HasColumnType("int"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketPriorityMasters"); - - b.HasData( - new - { - Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), - ColorCode = "008000", - IsDefault = true, - Level = 1, - Name = "Low", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), - ColorCode = "FFFF00", - IsDefault = true, - Level = 2, - Name = "Medium", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 3, - Name = "High", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 4, - Name = "Critical", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), - ColorCode = "#FF0000", - IsDefault = true, - Level = 5, - Name = "Urgent", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketStatusMasters"); - - b.HasData( - new - { - Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), - ColorCode = "#FFCC99", - Description = "This is a newly created issue.", - IsDefault = true, - Name = "New", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), - ColorCode = "#E6FF99", - Description = "Assigned to employee or team of employees", - IsDefault = true, - Name = "Assigned", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), - ColorCode = "#99E6FF", - Description = "These issues are currently in progress", - IsDefault = true, - Name = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", - Description = "These issues are currently under review", - IsDefault = true, - Name = "In Review", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), - ColorCode = "#B399FF", - Description = "The following issues are resolved and closed", - IsDefault = true, - Name = "Done", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTagMasters"); - - b.HasData( - new - { - Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), - ColorCode = "#e59866", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), - ColorCode = "#85c1e9", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkCategoryMasters"); - - b.HasData( - new - { - Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), - Description = "Created new task in a professional or creative context", - IsSystem = true, - Name = "Fresh Work", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), - Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", - IsSystem = true, - Name = "Rework", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), - Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", - IsSystem = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkStatusMasters"); - - b.HasData( - new - { - Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), - Description = "Confirm the tasks are actually finished as reported", - IsSystem = true, - Name = "Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), - Description = "Not all tasks are actually finished as reported", - IsSystem = true, - Name = "Partially Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), - Description = "Tasks are not finished as reported or have any issues in al the tasks", - IsSystem = true, - Name = "NCR", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("Buildings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BuildingId") - .HasColumnType("char(36)"); - - b.Property("FloorName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BuildingId"); - - b.HasIndex("TenantId"); - - b.ToTable("Floor"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("EndDate") - .HasColumnType("datetime(6)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectAddress") - .HasColumnType("longtext"); - - b.Property("ProjectStatusId") - .HasColumnType("char(36)"); - - b.Property("ShortName") - .HasColumnType("longtext"); - - b.Property("StartDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ProjectStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Projects"); - - b.HasData( - new - { - Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), - ContactPerson = "Project 1 Contact Person", - EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - Name = "Project 1", - ProjectAddress = "Project 1 Address", - ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("ReAllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ProjectAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AreaName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FloorId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("FloorId"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkAreas"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("CompletedWork") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedWork") - .HasColumnType("double"); - - b.Property("TaskDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkAreaId") - .HasColumnType("char(36)"); - - b.Property("WorkCategoryId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ActivityId"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkAreaId"); - - b.HasIndex("WorkCategoryId"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Role") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ApplicationRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("JobRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("About") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.Property("OrganizatioinName") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Inquiries"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Discriminator") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("varchar(21)"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - - b.HasDiscriminator().HasValue("IdentityUser"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("RoleId") - .HasColumnType("varchar(255)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => - { - b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsRootUser") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasDiscriminator().HasValue("ApplicationUser"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") - .WithMany() - .HasForeignKey("ApprovedById"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("AssignedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") - .WithMany() - .HasForeignKey("ReportedById"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") - .WithMany() - .HasForeignKey("WorkItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") - .WithMany() - .HasForeignKey("WorkStatusId"); - - b.Navigation("ApprovedBy"); - - b.Navigation("Employee"); - - b.Navigation("ReportedBy"); - - b.Navigation("Tenant"); - - b.Navigation("WorkItem"); - - b.Navigation("WorkStatus"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("CommentedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Approver"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") - .WithMany() - .HasForeignKey("AttendanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") - .WithMany() - .HasForeignKey("UpdatedBy"); - - b.Navigation("Attendance"); - - b.Navigation("Document"); - - b.Navigation("Employee"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedByEmployee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedByID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") - .WithMany() - .HasForeignKey("ContactCategoryId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("ContactCategory"); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("Contact"); - - b.Navigation("Createdby"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") - .WithMany() - .HasForeignKey("ContactTagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("ContactTag"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("UpdatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") - .WithMany() - .HasForeignKey("UploadedById"); - - b.Navigation("Tenant"); - - b.Navigation("UploadedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") - .WithMany() - .HasForeignKey("ApplicationUserId"); - - b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") - .WithMany() - .HasForeignKey("JobRoleId"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ApplicationUser"); - - b.Navigation("JobRole"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Role"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") - .WithMany("FeaturePermissions") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Feature"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) - .WithMany() - .HasForeignKey("ApplicationRoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) - .WithMany() - .HasForeignKey("FeaturePermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") - .WithMany() - .HasForeignKey("IndustryId"); - - b.Navigation("Industry"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Document"); - - b.Navigation("Expenses"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") - .WithMany() - .HasForeignKey("ExpensesTypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") - .WithMany() - .HasForeignKey("PaidById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") - .WithMany() - .HasForeignKey("PaymentModeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ExpensesType"); - - b.Navigation("PaidBy"); - - b.Navigation("PaymentMode"); - - b.Navigation("Project"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") - .WithMany() - .HasForeignKey("ReimburseById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ReimburseBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") - .WithMany() - .HasForeignKey("ExpensesReimburseId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Expenses"); - - b.Navigation("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("ExpeStatusIdnsesId"); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") - .WithMany() - .HasForeignKey("NextStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("NextStatus"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") - .WithMany() - .HasForeignKey("PermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Permission"); - - b.Navigation("Status"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") - .WithMany("Attachments") - .HasForeignKey("CommentId"); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Ticket"); - - b.Navigation("TicketComment"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") - .WithMany() - .HasForeignKey("PriorityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") - .WithMany() - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Priority"); - - b.Navigation("Tenant"); - - b.Navigation("TicketStatusMaster"); - - b.Navigation("TicketTypeMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") - .WithMany() - .HasForeignKey("TagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tag"); - - b.Navigation("Ticket"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") - .WithMany() - .HasForeignKey("MailListId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MailBody"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.HasOne("Marco.Pms.Model.Master.Module", "Module") - .WithMany() - .HasForeignKey("ModuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Module"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.HasOne("Marco.Pms.Model.Projects.Building", "Building") - .WithMany() - .HasForeignKey("BuildingId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Building"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") - .WithMany() - .HasForeignKey("ProjectStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ProjectStatus"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") - .WithMany() - .HasForeignKey("FloorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Floor"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") - .WithMany() - .HasForeignKey("ActivityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") - .WithMany() - .HasForeignKey("WorkAreaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") - .WithMany() - .HasForeignKey("WorkCategoryId"); - - b.Navigation("ActivityMaster"); - - b.Navigation("Tenant"); - - b.Navigation("WorkArea"); - - b.Navigation("WorkCategoryMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Navigation("Attachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Navigation("FeaturePermissions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs deleted file mode 100644 index 47a46cc..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.Designer.cs +++ /dev/null @@ -1,4196 +0,0 @@ -// -using System; -using Marco.Pms.DataAccess.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Marco.Pms.DataAccess.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense")] - partial class Added_CreatedBy_And_CareatedAt_In_Expense - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.12") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ApprovedById") - .HasColumnType("char(36)"); - - b.Property("ApprovedDate") - .HasColumnType("datetime(6)"); - - b.Property("AssignedBy") - .HasColumnType("char(36)"); - - b.Property("AssignmentDate") - .HasColumnType("datetime(6)"); - - b.Property("CompletedTask") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedTask") - .HasColumnType("double"); - - b.Property("ReportedById") - .HasColumnType("char(36)"); - - b.Property("ReportedDate") - .HasColumnType("datetime(6)"); - - b.Property("ReportedTask") - .HasColumnType("double"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkItemId") - .HasColumnType("char(36)"); - - b.Property("WorkStatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApprovedById"); - - b.HasIndex("AssignedBy"); - - b.HasIndex("ReportedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkItemId"); - - b.HasIndex("WorkStatusId"); - - b.ToTable("TaskAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ReferenceId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TaskAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("CommentDate") - .HasColumnType("datetime(6)"); - - b.Property("CommentedBy") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentedBy"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskMembers"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ApprovedBy") - .HasColumnType("char(36)"); - - b.Property("AttendanceDate") - .HasColumnType("datetime(6)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Date") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("InTime") - .HasColumnType("datetime(6)"); - - b.Property("IsApproved") - .HasColumnType("tinyint(1)"); - - b.Property("OutTime") - .HasColumnType("datetime(6)"); - - b.Property("ProjectID") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.ToTable("Attendes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ActivityTime") - .HasColumnType("datetime(6)"); - - b.Property("AttendanceId") - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("Latitude") - .HasColumnType("longtext"); - - b.Property("Longitude") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedBy") - .HasColumnType("char(36)"); - - b.Property("UpdatedOn") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.HasIndex("AttendanceId"); - - b.HasIndex("DocumentId"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedBy"); - - b.ToTable("AttendanceLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MPIN") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("MPINToken") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("MPINDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpriesInSec") - .HasColumnType("int"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("OTP") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("OTPDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("ExpiryDate") - .HasColumnType("datetime(6)"); - - b.Property("IsRevoked") - .HasColumnType("tinyint(1)"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("RevokedAt") - .HasColumnType("datetime(6)"); - - b.Property("Token") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedByID") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedByID"); - - b.HasIndex("TenantId"); - - b.ToTable("Buckets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ContactCategoryId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Organization") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactCategoryId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("Contacts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactCategoryMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("EmailAddress") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsEmails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Note") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("ContactNotes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsPhones"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactProjectMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ContactTagId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ContactTagId"); - - b.ToTable("ContactTagMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactTagMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("RefereanceId") - .HasColumnType("char(36)"); - - b.Property("UpdateAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UpdatedById"); - - b.ToTable("DirectoryUpdateLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("EmployeeId"); - - b.ToTable("EmployeeBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Base64Data") - .HasColumnType("longtext"); - - b.Property("BatchId") - .HasColumnType("char(36)"); - - b.Property("ContentType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileSize") - .HasColumnType("bigint"); - - b.Property("S3Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("ThumbS3Key") - .HasColumnType("longtext"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)"); - - b.Property("UploadedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.HasIndex("UploadedById"); - - b.ToTable("Documents"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AadharNumber") - .HasColumnType("longtext"); - - b.Property("ApplicationUserId") - .HasColumnType("varchar(255)"); - - b.Property("BirthDate") - .HasColumnType("datetime(6)"); - - b.Property("CurrentAddress") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("EmergencyContactPerson") - .HasColumnType("longtext"); - - b.Property("EmergencyPhoneNumber") - .HasColumnType("longtext"); - - b.Property("FirstName") - .HasColumnType("longtext"); - - b.Property("Gender") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("JoiningDate") - .HasColumnType("datetime(6)"); - - b.Property("LastName") - .HasColumnType("longtext"); - - b.Property("MiddleName") - .HasColumnType("longtext"); - - b.Property("PanNumber") - .HasColumnType("longtext"); - - b.Property("PermanentAddress") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationUserId"); - - b.HasIndex("JobRoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("Employees"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("RoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("EmployeeRoleMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EndTime") - .HasColumnType("time(6)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("StartTime") - .HasColumnType("time(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkShifts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsChecked") - .HasColumnType("tinyint(1)"); - - b.Property("IsMandatory") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("ActivityCheckLists"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CheckListId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("CheckListMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("FeatureId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("FeatureId"); - - b.ToTable("FeaturePermissions"); - - b.HasData( - new - { - Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), - Description = "Access all information related to the project.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project" - }, - new - { - Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), - Description = "Potentially edit the project name, description, start/end dates, or status.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project" - }, - new - { - Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), - Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Team" - }, - new - { - Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), - Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project Infra" - }, - new - { - Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), - Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project Infra" - }, - new - { - Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), - Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "View Task" - }, - new - { - Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), - Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Add/Edit Task" - }, - new - { - Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), - Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Assign/Report Progress" - }, - new - { - Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), - Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Approve Task" - }, - new - { - Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), - Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View All Employees" - }, - new - { - Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), - Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View Team Members" - }, - new - { - Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), - Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Add/Edit Employee" - }, - new - { - Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), - Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Assign Roles" - }, - new - { - Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Team Attendance " - }, - new - { - Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), - Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Regularize Attendance" - }, - new - { - Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Self Attendance" - }, - new - { - Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), - Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "View Masters" - }, - new - { - Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), - Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "Manage Masters" - }, - new - { - Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), - Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Admin" - }, - new - { - Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), - Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Manager" - }, - new - { - Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), - Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory User" - }, - new - { - Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), - Description = "Allows a user to view only the expense records that they have personally submitted", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View Self" - }, - new - { - Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), - Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View All" - }, - new - { - Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), - Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Upload" - }, - new - { - Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), - Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Review" - }, - new - { - Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), - Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Approve" - }, - new - { - Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), - Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Process" - }, - new - { - Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), - Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Manage" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.Property("ApplicationRoleId") - .HasColumnType("char(36)"); - - b.Property("FeaturePermissionId") - .HasColumnType("char(36)"); - - b.HasKey("ApplicationRoleId", "FeaturePermissionId"); - - b.HasIndex("FeaturePermissionId"); - - b.ToTable("RolePermissionMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactName") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("DomainName") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("OnBoardingDate") - .HasColumnType("datetime(6)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("IndustryId"); - - b.ToTable("Tenants"); - - b.HasData( - new - { - Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), - ContactName = "Admin", - ContactNumber = "123456789", - Description = "", - DomainName = "www.marcobms.org", - IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - IsActive = true, - Name = "MarcoBMS", - OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - OragnizationSize = "100-200" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("DocumentId"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("TenantId"); - - b.ToTable("BillAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Amount") - .HasColumnType("double"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ExpensesTypeId") - .HasColumnType("char(36)"); - - b.Property("GSTNumber") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Location") - .HasColumnType("longtext"); - - b.Property("NoOfPersons") - .HasColumnType("int"); - - b.Property("PaidById") - .HasColumnType("char(36)"); - - b.Property("PaymentModeId") - .HasColumnType("char(36)"); - - b.Property("PreApproved") - .HasColumnType("tinyint(1)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("SupplerName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TransactionDate") - .HasColumnType("datetime(6)"); - - b.Property("TransactionId") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("CreatedById"); - - b.HasIndex("ExpensesTypeId"); - - b.HasIndex("PaidById"); - - b.HasIndex("PaymentModeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Expenses"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ReimburseById") - .HasColumnType("char(36)"); - - b.Property("ReimburseDate") - .HasColumnType("datetime(6)"); - - b.Property("ReimburseNote") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ReimburseTransactionId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ReimburseById"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("ExpensesReimburseId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("ExpensesReimburseId"); - - b.ToTable("ExpensesReimburseMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpeStatusIdnsesId") - .HasColumnType("char(36)"); - - b.Property("NextStatusId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpeStatusIdnsesId"); - - b.HasIndex("NextStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMapping"); - - b.HasData( - new - { - Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), - NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), - NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("PermissionId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PermissionId"); - - b.HasIndex("StatusId"); - - b.ToTable("StatusPermissionMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CommentId") - .HasColumnType("char(36)"); - - b.Property("FileId") - .HasColumnType("char(36)"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AuthorId") - .HasColumnType("char(36)"); - - b.Property("MessageText") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ParentMessageId") - .HasColumnType("char(36)"); - - b.Property("SentAt") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("TicketComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("LinkedActivityId") - .HasColumnType("char(36)"); - - b.Property("LinkedProjectId") - .HasColumnType("char(36)"); - - b.Property("PriorityId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TypeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PriorityId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.HasIndex("TypeId"); - - b.ToTable("Tickets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("TagId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TagId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketTags"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTypeMasters"); - - b.HasData( - new - { - Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), - Description = "An identified problem that affects the performance, reliability, or standards of a product or service", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), - Description = "A support service that assists users with technical issues, requests, or inquiries.", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MailListId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("Recipient") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Schedule") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("MailListId"); - - b.ToTable("MailDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmailId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.ToTable("MailLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Keywords") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("MailingList"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityName") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UnitOfMeasurement") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ActivityMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesStatusMaster"); - - b.HasData( - new - { - Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Description = "Expense has been created but not yet submitted.", - IsActive = true, - IsSystem = true, - Name = "Draft", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - Description = "Reviewer is currently reviewing the expense.", - IsActive = true, - IsSystem = true, - Name = "Review Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - Description = "Review is completed, waiting for action of approver.", - IsActive = true, - IsSystem = true, - Name = "Approval Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", - IsActive = true, - IsSystem = true, - Name = "Rejected", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Description = "Approved expense is awaiting final payment.", - IsActive = true, - IsSystem = true, - Name = "Process Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - Description = "Expense has been settled.", - IsActive = true, - IsSystem = true, - Name = "Processed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("NoOfPersonsRequired") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesTypeMaster"); - - b.HasData( - new - { - Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), - Description = "Materials, equipment and supplies purchased for site operations.", - IsActive = true, - Name = "Procurement", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), - Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", - IsActive = true, - Name = "Transport", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), - Description = "Delivery of personnel.", - IsActive = true, - Name = "Travelling", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), - Description = "Site setup costs including equipment deployment and temporary infrastructure.", - IsActive = true, - Name = "Mobilization", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), - Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", - IsActive = true, - Name = "Employee Welfare", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), - Description = "Machinery servicing, electricity, water, and temporary office needs.", - IsActive = true, - Name = "Maintenance & Utilities", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), - Description = "Scheduled payments for external services or goods.", - IsActive = true, - Name = "Vendor/Supplier Payments", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), - Description = "Government fees, insurance, inspections and safety-related expenditures.", - IsActive = true, - Name = "Compliance & Safety", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("ModuleId") - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("ModuleId"); - - b.ToTable("Features"); - - b.HasData( - new - { - Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - Description = "Manage Project", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Project Management" - }, - new - { - Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Expense Management" - }, - new - { - Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - Description = "Manage Tasks", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Task Management" - }, - new - { - Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - Description = "Manage Employee", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Employee Management" - }, - new - { - Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - Description = "Attendance", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Attendance Management" - }, - new - { - Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - Description = "Global Masters", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Masters" - }, - new - { - Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - Description = "Managing all directory related rights", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Directory Management" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - - b.HasData( - new - { - Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - Name = "Information Technology (IT) Services" - }, - new - { - Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), - Name = "Manufacturing & Production" - }, - new - { - Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), - Name = "Energy & Resources" - }, - new - { - Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), - Name = "Finance & Professional Services" - }, - new - { - Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), - Name = "Hospitals and Healthcare Services" - }, - new - { - Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), - Name = "Social Services" - }, - new - { - Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), - Name = "Retail & Consumer Services" - }, - new - { - Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), - Name = "Transportation & Logistics" - }, - new - { - Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), - Name = "Education & Training" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Modules"); - - b.HasData( - new - { - Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Description = "Project Module", - Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", - Name = "Project" - }, - new - { - Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Description = "Employee Module", - Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", - Name = "Employee" - }, - new - { - Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Description = "Masters Module", - Key = "504ec132-e6a9-422f-8f85-050602cfce05", - Name = "Masters" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("PaymentModeMatser"); - - b.HasData( - new - { - Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), - Description = "Physical currency; still used for small or informal transactions.", - IsActive = true, - Name = "Cash", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), - Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", - IsActive = true, - Name = "Cheque", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), - Description = "Online banking portals used to transfer funds directly between accounts", - IsActive = true, - Name = "NetBanking", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), - Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", - IsActive = true, - Name = "UPI", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Status") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMasters"); - - b.HasData( - new - { - Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - Status = "Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), - Status = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), - Status = "On Hold", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), - Status = "In Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), - Status = "Completed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Level") - .HasColumnType("int"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketPriorityMasters"); - - b.HasData( - new - { - Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), - ColorCode = "008000", - IsDefault = true, - Level = 1, - Name = "Low", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), - ColorCode = "FFFF00", - IsDefault = true, - Level = 2, - Name = "Medium", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 3, - Name = "High", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 4, - Name = "Critical", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), - ColorCode = "#FF0000", - IsDefault = true, - Level = 5, - Name = "Urgent", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketStatusMasters"); - - b.HasData( - new - { - Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), - ColorCode = "#FFCC99", - Description = "This is a newly created issue.", - IsDefault = true, - Name = "New", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), - ColorCode = "#E6FF99", - Description = "Assigned to employee or team of employees", - IsDefault = true, - Name = "Assigned", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), - ColorCode = "#99E6FF", - Description = "These issues are currently in progress", - IsDefault = true, - Name = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", - Description = "These issues are currently under review", - IsDefault = true, - Name = "In Review", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), - ColorCode = "#B399FF", - Description = "The following issues are resolved and closed", - IsDefault = true, - Name = "Done", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTagMasters"); - - b.HasData( - new - { - Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), - ColorCode = "#e59866", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), - ColorCode = "#85c1e9", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkCategoryMasters"); - - b.HasData( - new - { - Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), - Description = "Created new task in a professional or creative context", - IsSystem = true, - Name = "Fresh Work", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), - Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", - IsSystem = true, - Name = "Rework", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), - Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", - IsSystem = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkStatusMasters"); - - b.HasData( - new - { - Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), - Description = "Confirm the tasks are actually finished as reported", - IsSystem = true, - Name = "Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), - Description = "Not all tasks are actually finished as reported", - IsSystem = true, - Name = "Partially Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), - Description = "Tasks are not finished as reported or have any issues in al the tasks", - IsSystem = true, - Name = "NCR", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("Buildings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BuildingId") - .HasColumnType("char(36)"); - - b.Property("FloorName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BuildingId"); - - b.HasIndex("TenantId"); - - b.ToTable("Floor"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("EndDate") - .HasColumnType("datetime(6)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectAddress") - .HasColumnType("longtext"); - - b.Property("ProjectStatusId") - .HasColumnType("char(36)"); - - b.Property("ShortName") - .HasColumnType("longtext"); - - b.Property("StartDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ProjectStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Projects"); - - b.HasData( - new - { - Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), - ContactPerson = "Project 1 Contact Person", - EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - Name = "Project 1", - ProjectAddress = "Project 1 Address", - ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("ReAllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ProjectAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AreaName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FloorId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("FloorId"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkAreas"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("CompletedWork") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedWork") - .HasColumnType("double"); - - b.Property("TaskDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkAreaId") - .HasColumnType("char(36)"); - - b.Property("WorkCategoryId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ActivityId"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkAreaId"); - - b.HasIndex("WorkCategoryId"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Role") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ApplicationRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("JobRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("About") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.Property("OrganizatioinName") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Inquiries"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Discriminator") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("varchar(21)"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - - b.HasDiscriminator().HasValue("IdentityUser"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("RoleId") - .HasColumnType("varchar(255)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => - { - b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsRootUser") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasDiscriminator().HasValue("ApplicationUser"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") - .WithMany() - .HasForeignKey("ApprovedById"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("AssignedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") - .WithMany() - .HasForeignKey("ReportedById"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") - .WithMany() - .HasForeignKey("WorkItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") - .WithMany() - .HasForeignKey("WorkStatusId"); - - b.Navigation("ApprovedBy"); - - b.Navigation("Employee"); - - b.Navigation("ReportedBy"); - - b.Navigation("Tenant"); - - b.Navigation("WorkItem"); - - b.Navigation("WorkStatus"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("CommentedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Approver"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") - .WithMany() - .HasForeignKey("AttendanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") - .WithMany() - .HasForeignKey("UpdatedBy"); - - b.Navigation("Attendance"); - - b.Navigation("Document"); - - b.Navigation("Employee"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedByEmployee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedByID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") - .WithMany() - .HasForeignKey("ContactCategoryId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("ContactCategory"); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("Contact"); - - b.Navigation("Createdby"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") - .WithMany() - .HasForeignKey("ContactTagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("ContactTag"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("UpdatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") - .WithMany() - .HasForeignKey("UploadedById"); - - b.Navigation("Tenant"); - - b.Navigation("UploadedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") - .WithMany() - .HasForeignKey("ApplicationUserId"); - - b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") - .WithMany() - .HasForeignKey("JobRoleId"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ApplicationUser"); - - b.Navigation("JobRole"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Role"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") - .WithMany("FeaturePermissions") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Feature"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) - .WithMany() - .HasForeignKey("ApplicationRoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) - .WithMany() - .HasForeignKey("FeaturePermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") - .WithMany() - .HasForeignKey("IndustryId"); - - b.Navigation("Industry"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Document"); - - b.Navigation("Expenses"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") - .WithMany() - .HasForeignKey("ExpensesTypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") - .WithMany() - .HasForeignKey("PaidById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") - .WithMany() - .HasForeignKey("PaymentModeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("CreatedBy"); - - b.Navigation("ExpensesType"); - - b.Navigation("PaidBy"); - - b.Navigation("PaymentMode"); - - b.Navigation("Project"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") - .WithMany() - .HasForeignKey("ReimburseById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ReimburseBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") - .WithMany() - .HasForeignKey("ExpensesReimburseId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Expenses"); - - b.Navigation("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("ExpeStatusIdnsesId"); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") - .WithMany() - .HasForeignKey("NextStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("NextStatus"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") - .WithMany() - .HasForeignKey("PermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Permission"); - - b.Navigation("Status"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") - .WithMany("Attachments") - .HasForeignKey("CommentId"); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Ticket"); - - b.Navigation("TicketComment"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") - .WithMany() - .HasForeignKey("PriorityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") - .WithMany() - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Priority"); - - b.Navigation("Tenant"); - - b.Navigation("TicketStatusMaster"); - - b.Navigation("TicketTypeMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") - .WithMany() - .HasForeignKey("TagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tag"); - - b.Navigation("Ticket"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") - .WithMany() - .HasForeignKey("MailListId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MailBody"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.HasOne("Marco.Pms.Model.Master.Module", "Module") - .WithMany() - .HasForeignKey("ModuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Module"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.HasOne("Marco.Pms.Model.Projects.Building", "Building") - .WithMany() - .HasForeignKey("BuildingId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Building"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") - .WithMany() - .HasForeignKey("ProjectStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ProjectStatus"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") - .WithMany() - .HasForeignKey("FloorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Floor"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") - .WithMany() - .HasForeignKey("ActivityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") - .WithMany() - .HasForeignKey("WorkAreaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") - .WithMany() - .HasForeignKey("WorkCategoryId"); - - b.Navigation("ActivityMaster"); - - b.Navigation("Tenant"); - - b.Navigation("WorkArea"); - - b.Navigation("WorkCategoryMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Navigation("Attachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Navigation("FeaturePermissions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs b/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs deleted file mode 100644 index 19a5c08..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719091116_Added_CreatedBy_And_CareatedAt_In_Expense.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Marco.Pms.DataAccess.Migrations -{ - /// - public partial class Added_CreatedBy_And_CareatedAt_In_Expense : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "CreatedAt", - table: "Expenses", - type: "datetime(6)", - nullable: false, - defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); - - migrationBuilder.AddColumn( - name: "CreatedById", - table: "Expenses", - type: "char(36)", - nullable: false, - defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), - collation: "ascii_general_ci"); - - migrationBuilder.CreateIndex( - name: "IX_Expenses_CreatedById", - table: "Expenses", - column: "CreatedById"); - - migrationBuilder.AddForeignKey( - name: "FK_Expenses_Employees_CreatedById", - table: "Expenses", - column: "CreatedById", - principalTable: "Employees", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Expenses_Employees_CreatedById", - table: "Expenses"); - - migrationBuilder.DropIndex( - name: "IX_Expenses_CreatedById", - table: "Expenses"); - - migrationBuilder.DropColumn( - name: "CreatedAt", - table: "Expenses"); - - migrationBuilder.DropColumn( - name: "CreatedById", - table: "Expenses"); - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs deleted file mode 100644 index 2eaef13..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.Designer.cs +++ /dev/null @@ -1,4243 +0,0 @@ -// -using System; -using Marco.Pms.DataAccess.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace Marco.Pms.DataAccess.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20250719103905_Added_ExpenseLog_Table")] - partial class Added_ExpenseLog_Table - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.12") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ApprovedById") - .HasColumnType("char(36)"); - - b.Property("ApprovedDate") - .HasColumnType("datetime(6)"); - - b.Property("AssignedBy") - .HasColumnType("char(36)"); - - b.Property("AssignmentDate") - .HasColumnType("datetime(6)"); - - b.Property("CompletedTask") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedTask") - .HasColumnType("double"); - - b.Property("ReportedById") - .HasColumnType("char(36)"); - - b.Property("ReportedDate") - .HasColumnType("datetime(6)"); - - b.Property("ReportedTask") - .HasColumnType("double"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkItemId") - .HasColumnType("char(36)"); - - b.Property("WorkStatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApprovedById"); - - b.HasIndex("AssignedBy"); - - b.HasIndex("ReportedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkItemId"); - - b.HasIndex("WorkStatusId"); - - b.ToTable("TaskAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ReferenceId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TaskAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("CommentDate") - .HasColumnType("datetime(6)"); - - b.Property("CommentedBy") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentedBy"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("TaskAllocationId"); - - b.HasIndex("TenantId"); - - b.ToTable("TaskMembers"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ApprovedBy") - .HasColumnType("char(36)"); - - b.Property("AttendanceDate") - .HasColumnType("datetime(6)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Date") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("InTime") - .HasColumnType("datetime(6)"); - - b.Property("IsApproved") - .HasColumnType("tinyint(1)"); - - b.Property("OutTime") - .HasColumnType("datetime(6)"); - - b.Property("ProjectID") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.ToTable("Attendes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Activity") - .HasColumnType("int"); - - b.Property("ActivityTime") - .HasColumnType("datetime(6)"); - - b.Property("AttendanceId") - .HasColumnType("char(36)"); - - b.Property("Comment") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("EmployeeID") - .HasColumnType("char(36)"); - - b.Property("Latitude") - .HasColumnType("longtext"); - - b.Property("Longitude") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedBy") - .HasColumnType("char(36)"); - - b.Property("UpdatedOn") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.HasIndex("AttendanceId"); - - b.HasIndex("DocumentId"); - - b.HasIndex("EmployeeID"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedBy"); - - b.ToTable("AttendanceLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MPIN") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("MPINToken") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("MPINDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpriesInSec") - .HasColumnType("int"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("OTP") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("OTPDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("ExpiryDate") - .HasColumnType("datetime(6)"); - - b.Property("IsRevoked") - .HasColumnType("tinyint(1)"); - - b.Property("IsUsed") - .HasColumnType("tinyint(1)"); - - b.Property("RevokedAt") - .HasColumnType("datetime(6)"); - - b.Property("Token") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("RefreshTokens"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedByID") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedByID"); - - b.HasIndex("TenantId"); - - b.ToTable("Buckets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ContactCategoryId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Organization") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactCategoryId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("Contacts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactCategoryMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("EmailAddress") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsEmails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Note") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("CreatedById"); - - b.HasIndex("TenantId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("ContactNotes"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("IsPrimary") - .HasColumnType("tinyint(1)"); - - b.Property("Label") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.ToTable("ContactsPhones"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactProjectMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactId") - .HasColumnType("char(36)"); - - b.Property("ContactTagId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ContactId"); - - b.HasIndex("ContactTagId"); - - b.ToTable("ContactTagMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ContactTagMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("RefereanceId") - .HasColumnType("char(36)"); - - b.Property("UpdateAt") - .HasColumnType("datetime(6)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UpdatedById"); - - b.ToTable("DirectoryUpdateLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BucketId") - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BucketId"); - - b.HasIndex("EmployeeId"); - - b.ToTable("EmployeeBucketMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Base64Data") - .HasColumnType("longtext"); - - b.Property("BatchId") - .HasColumnType("char(36)"); - - b.Property("ContentType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FileSize") - .HasColumnType("bigint"); - - b.Property("S3Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("ThumbS3Key") - .HasColumnType("longtext"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)"); - - b.Property("UploadedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.HasIndex("UploadedById"); - - b.ToTable("Documents"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AadharNumber") - .HasColumnType("longtext"); - - b.Property("ApplicationUserId") - .HasColumnType("varchar(255)"); - - b.Property("BirthDate") - .HasColumnType("datetime(6)"); - - b.Property("CurrentAddress") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("EmergencyContactPerson") - .HasColumnType("longtext"); - - b.Property("EmergencyPhoneNumber") - .HasColumnType("longtext"); - - b.Property("FirstName") - .HasColumnType("longtext"); - - b.Property("Gender") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("JoiningDate") - .HasColumnType("datetime(6)"); - - b.Property("LastName") - .HasColumnType("longtext"); - - b.Property("MiddleName") - .HasColumnType("longtext"); - - b.Property("PanNumber") - .HasColumnType("longtext"); - - b.Property("PermanentAddress") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("Photo") - .HasColumnType("longblob"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationUserId"); - - b.HasIndex("JobRoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("Employees"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("RoleId"); - - b.HasIndex("TenantId"); - - b.ToTable("EmployeeRoleMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("EndTime") - .HasColumnType("time(6)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("StartTime") - .HasColumnType("time(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkShifts"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsChecked") - .HasColumnType("tinyint(1)"); - - b.Property("IsMandatory") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("ActivityCheckLists"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CheckListId") - .HasColumnType("char(36)"); - - b.Property("TaskAllocationId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("CheckListMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("FeatureId") - .HasColumnType("char(36)"); - - b.Property("IsEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("FeatureId"); - - b.ToTable("FeaturePermissions"); - - b.HasData( - new - { - Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), - Description = "Access all information related to the project.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project" - }, - new - { - Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), - Description = "Potentially edit the project name, description, start/end dates, or status.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project" - }, - new - { - Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), - Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Team" - }, - new - { - Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), - Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "View Project Infra" - }, - new - { - Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), - Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", - FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - IsEnabled = true, - Name = "Manage Project Infra" - }, - new - { - Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), - Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "View Task" - }, - new - { - Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), - Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Add/Edit Task" - }, - new - { - Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), - Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Assign/Report Progress" - }, - new - { - Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), - Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", - FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - IsEnabled = true, - Name = "Approve Task" - }, - new - { - Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), - Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View All Employees" - }, - new - { - Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), - Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "View Team Members" - }, - new - { - Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), - Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Add/Edit Employee" - }, - new - { - Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), - Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", - FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - IsEnabled = true, - Name = "Assign Roles" - }, - new - { - Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Team Attendance " - }, - new - { - Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), - Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Regularize Attendance" - }, - new - { - Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), - Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", - FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - IsEnabled = true, - Name = "Self Attendance" - }, - new - { - Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), - Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "View Masters" - }, - new - { - Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), - Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", - FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - IsEnabled = true, - Name = "Manage Masters" - }, - new - { - Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), - Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Admin" - }, - new - { - Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), - Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory Manager" - }, - new - { - Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), - Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", - FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - IsEnabled = true, - Name = "Directory User" - }, - new - { - Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), - Description = "Allows a user to view only the expense records that they have personally submitted", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View Self" - }, - new - { - Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), - Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "View All" - }, - new - { - Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), - Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Upload" - }, - new - { - Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), - Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Review" - }, - new - { - Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), - Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Approve" - }, - new - { - Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), - Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Process" - }, - new - { - Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), - Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", - FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - IsEnabled = true, - Name = "Manage" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.Property("ApplicationRoleId") - .HasColumnType("char(36)"); - - b.Property("FeaturePermissionId") - .HasColumnType("char(36)"); - - b.HasKey("ApplicationRoleId", "FeaturePermissionId"); - - b.HasIndex("FeaturePermissionId"); - - b.ToTable("RolePermissionMappings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactName") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("DomainName") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("OnBoardingDate") - .HasColumnType("datetime(6)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("IndustryId"); - - b.ToTable("Tenants"); - - b.HasData( - new - { - Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), - ContactName = "Admin", - ContactNumber = "123456789", - Description = "", - DomainName = "www.marcobms.org", - IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - IsActive = true, - Name = "MarcoBMS", - OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - OragnizationSize = "100-200" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("DocumentId") - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("DocumentId"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("TenantId"); - - b.ToTable("BillAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Action") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Comment") - .HasColumnType("longtext"); - - b.Property("ExpenseId") - .HasColumnType("char(36)"); - - b.Property("UpdatedById") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpenseId"); - - b.HasIndex("UpdatedById"); - - b.ToTable("ExpenseLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Amount") - .HasColumnType("double"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ExpensesTypeId") - .HasColumnType("char(36)"); - - b.Property("GSTNumber") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Location") - .HasColumnType("longtext"); - - b.Property("NoOfPersons") - .HasColumnType("int"); - - b.Property("PaidById") - .HasColumnType("char(36)"); - - b.Property("PaymentModeId") - .HasColumnType("char(36)"); - - b.Property("PreApproved") - .HasColumnType("tinyint(1)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("SupplerName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TransactionDate") - .HasColumnType("datetime(6)"); - - b.Property("TransactionId") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("CreatedById"); - - b.HasIndex("ExpensesTypeId"); - - b.HasIndex("PaidById"); - - b.HasIndex("PaymentModeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Expenses"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ReimburseById") - .HasColumnType("char(36)"); - - b.Property("ReimburseDate") - .HasColumnType("datetime(6)"); - - b.Property("ReimburseNote") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ReimburseTransactionId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ReimburseById"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpensesId") - .HasColumnType("char(36)"); - - b.Property("ExpensesReimburseId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpensesId"); - - b.HasIndex("ExpensesReimburseId"); - - b.ToTable("ExpensesReimburseMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ExpeStatusIdnsesId") - .HasColumnType("char(36)"); - - b.Property("NextStatusId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ExpeStatusIdnsesId"); - - b.HasIndex("NextStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMapping"); - - b.HasData( - new - { - Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), - NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), - NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("PermissionId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PermissionId"); - - b.HasIndex("StatusId"); - - b.ToTable("StatusPermissionMapping"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CommentId") - .HasColumnType("char(36)"); - - b.Property("FileId") - .HasColumnType("char(36)"); - - b.Property("FileName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CommentId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketAttachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AuthorId") - .HasColumnType("char(36)"); - - b.Property("MessageText") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ParentMessageId") - .HasColumnType("char(36)"); - - b.Property("SentAt") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("TicketComments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)"); - - b.Property("CreatedById") - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("LinkedActivityId") - .HasColumnType("char(36)"); - - b.Property("LinkedProjectId") - .HasColumnType("char(36)"); - - b.Property("PriorityId") - .HasColumnType("char(36)"); - - b.Property("StatusId") - .HasColumnType("char(36)"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TypeId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("PriorityId"); - - b.HasIndex("StatusId"); - - b.HasIndex("TenantId"); - - b.HasIndex("TypeId"); - - b.ToTable("Tickets"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("TagId") - .HasColumnType("char(36)"); - - b.Property("TicketId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TagId"); - - b.HasIndex("TicketId"); - - b.ToTable("TicketTags"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTypeMasters"); - - b.HasData( - new - { - Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), - Description = "An identified problem that affects the performance, reliability, or standards of a product or service", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), - Description = "A support service that assists users with technical issues, requests, or inquiries.", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("MailListId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("Recipient") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Schedule") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("MailListId"); - - b.ToTable("MailDetails"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmailId") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("TimeStamp") - .HasColumnType("datetime(6)"); - - b.HasKey("Id"); - - b.ToTable("MailLogs"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Body") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Keywords") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Subject") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("MailingList"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityName") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("UnitOfMeasurement") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ActivityMasters"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesStatusMaster"); - - b.HasData( - new - { - Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Description = "Expense has been created but not yet submitted.", - IsActive = true, - IsSystem = true, - Name = "Draft", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - Description = "Reviewer is currently reviewing the expense.", - IsActive = true, - IsSystem = true, - Name = "Review Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - Description = "Review is completed, waiting for action of approver.", - IsActive = true, - IsSystem = true, - Name = "Approval Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", - IsActive = true, - IsSystem = true, - Name = "Rejected", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Description = "Approved expense is awaiting final payment.", - IsActive = true, - IsSystem = true, - Name = "Process Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - Description = "Expense has been settled.", - IsActive = true, - IsSystem = true, - Name = "Processed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("NoOfPersonsRequired") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ExpensesTypeMaster"); - - b.HasData( - new - { - Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), - Description = "Materials, equipment and supplies purchased for site operations.", - IsActive = true, - Name = "Procurement", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), - Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", - IsActive = true, - Name = "Transport", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), - Description = "Delivery of personnel.", - IsActive = true, - Name = "Travelling", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), - Description = "Site setup costs including equipment deployment and temporary infrastructure.", - IsActive = true, - Name = "Mobilization", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), - Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", - IsActive = true, - Name = "Employee Welfare", - NoOfPersonsRequired = true, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), - Description = "Machinery servicing, electricity, water, and temporary office needs.", - IsActive = true, - Name = "Maintenance & Utilities", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), - Description = "Scheduled payments for external services or goods.", - IsActive = true, - Name = "Vendor/Supplier Payments", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), - Description = "Government fees, insurance, inspections and safety-related expenditures.", - IsActive = true, - Name = "Compliance & Safety", - NoOfPersonsRequired = false, - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("ModuleId") - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("ModuleId"); - - b.ToTable("Features"); - - b.HasData( - new - { - Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), - Description = "Manage Project", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Project Management" - }, - new - { - Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), - Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Expense Management" - }, - new - { - Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), - Description = "Manage Tasks", - IsActive = true, - ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Name = "Task Management" - }, - new - { - Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), - Description = "Manage Employee", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Employee Management" - }, - new - { - Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), - Description = "Attendance", - IsActive = true, - ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Name = "Attendance Management" - }, - new - { - Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), - Description = "Global Masters", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Masters" - }, - new - { - Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), - Description = "Managing all directory related rights", - IsActive = true, - ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Name = "Directory Management" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - - b.HasData( - new - { - Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), - Name = "Information Technology (IT) Services" - }, - new - { - Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), - Name = "Manufacturing & Production" - }, - new - { - Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), - Name = "Energy & Resources" - }, - new - { - Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), - Name = "Finance & Professional Services" - }, - new - { - Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), - Name = "Hospitals and Healthcare Services" - }, - new - { - Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), - Name = "Social Services" - }, - new - { - Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), - Name = "Retail & Consumer Services" - }, - new - { - Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), - Name = "Transportation & Logistics" - }, - new - { - Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), - Name = "Education & Training" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Key") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Modules"); - - b.HasData( - new - { - Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), - Description = "Project Module", - Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", - Name = "Project" - }, - new - { - Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), - Description = "Employee Module", - Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", - Name = "Employee" - }, - new - { - Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), - Description = "Masters Module", - Key = "504ec132-e6a9-422f-8f85-050602cfce05", - Name = "Masters" - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("PaymentModeMatser"); - - b.HasData( - new - { - Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), - Description = "Physical currency; still used for small or informal transactions.", - IsActive = true, - Name = "Cash", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), - Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", - IsActive = true, - Name = "Cheque", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), - Description = "Online banking portals used to transfer funds directly between accounts", - IsActive = true, - Name = "NetBanking", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), - Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", - IsActive = true, - Name = "UPI", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Status") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("StatusMasters"); - - b.HasData( - new - { - Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - Status = "Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), - Status = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), - Status = "On Hold", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), - Status = "In Active", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), - Status = "Completed", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Level") - .HasColumnType("int"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketPriorityMasters"); - - b.HasData( - new - { - Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), - ColorCode = "008000", - IsDefault = true, - Level = 1, - Name = "Low", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), - ColorCode = "FFFF00", - IsDefault = true, - Level = 2, - Name = "Medium", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 3, - Name = "High", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), - ColorCode = "#FFA500", - IsDefault = true, - Level = 4, - Name = "Critical", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), - ColorCode = "#FF0000", - IsDefault = true, - Level = 5, - Name = "Urgent", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketStatusMasters"); - - b.HasData( - new - { - Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), - ColorCode = "#FFCC99", - Description = "This is a newly created issue.", - IsDefault = true, - Name = "New", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), - ColorCode = "#E6FF99", - Description = "Assigned to employee or team of employees", - IsDefault = true, - Name = "Assigned", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), - ColorCode = "#99E6FF", - Description = "These issues are currently in progress", - IsDefault = true, - Name = "In Progress", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", - Description = "These issues are currently under review", - IsDefault = true, - Name = "In Review", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), - ColorCode = "#B399FF", - Description = "The following issues are resolved and closed", - IsDefault = true, - Name = "Done", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ColorCode") - .HasColumnType("longtext"); - - b.Property("IsDefault") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.ToTable("TicketTagMasters"); - - b.HasData( - new - { - Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), - ColorCode = "#e59866", - IsDefault = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), - ColorCode = "#85c1e9", - IsDefault = true, - Name = "Help Desk", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkCategoryMasters"); - - b.HasData( - new - { - Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), - Description = "Created new task in a professional or creative context", - IsSystem = true, - Name = "Fresh Work", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), - Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", - IsSystem = true, - Name = "Rework", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), - Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", - IsSystem = true, - Name = "Quality Issue", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkStatusMasters"); - - b.HasData( - new - { - Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), - Description = "Confirm the tasks are actually finished as reported", - IsSystem = true, - Name = "Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), - Description = "Not all tasks are actually finished as reported", - IsSystem = true, - Name = "Partially Approve", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }, - new - { - Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), - Description = "Tasks are not finished as reported or have any issues in al the tasks", - IsSystem = true, - Name = "NCR", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("Buildings"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("BuildingId") - .HasColumnType("char(36)"); - - b.Property("FloorName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("BuildingId"); - - b.HasIndex("TenantId"); - - b.ToTable("Floor"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("EndDate") - .HasColumnType("datetime(6)"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("ProjectAddress") - .HasColumnType("longtext"); - - b.Property("ProjectStatusId") - .HasColumnType("char(36)"); - - b.Property("ShortName") - .HasColumnType("longtext"); - - b.Property("StartDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ProjectStatusId"); - - b.HasIndex("TenantId"); - - b.ToTable("Projects"); - - b.HasData( - new - { - Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), - ContactPerson = "Project 1 Contact Person", - EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - Name = "Project 1", - ProjectAddress = "Project 1 Address", - ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), - StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") - }); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("EmployeeId") - .HasColumnType("char(36)"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("JobRoleId") - .HasColumnType("char(36)"); - - b.Property("ProjectId") - .HasColumnType("char(36)"); - - b.Property("ReAllocationDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("EmployeeId"); - - b.HasIndex("ProjectId"); - - b.HasIndex("TenantId"); - - b.ToTable("ProjectAllocations"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AreaName") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("FloorId") - .HasColumnType("char(36)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("FloorId"); - - b.HasIndex("TenantId"); - - b.ToTable("WorkAreas"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ActivityId") - .HasColumnType("char(36)"); - - b.Property("CompletedWork") - .HasColumnType("double"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("ParentTaskId") - .HasColumnType("char(36)"); - - b.Property("PlannedWork") - .HasColumnType("double"); - - b.Property("TaskDate") - .HasColumnType("datetime(6)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.Property("WorkAreaId") - .HasColumnType("char(36)"); - - b.Property("WorkCategoryId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("ActivityId"); - - b.HasIndex("TenantId"); - - b.HasIndex("WorkAreaId"); - - b.HasIndex("WorkCategoryId"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("IsSystem") - .HasColumnType("tinyint(1)"); - - b.Property("Role") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ApplicationRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .HasColumnType("longtext"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("JobRoles"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("About") - .HasColumnType("longtext"); - - b.Property("ContactNumber") - .HasColumnType("longtext"); - - b.Property("ContactPerson") - .HasColumnType("longtext"); - - b.Property("Email") - .HasColumnType("longtext"); - - b.Property("IndustryId") - .HasColumnType("char(36)"); - - b.Property("OragnizationSize") - .HasColumnType("longtext"); - - b.Property("OrganizatioinName") - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("Inquiries"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("varchar(255)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Discriminator") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("varchar(21)"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - - b.HasDiscriminator().HasValue("IdentityUser"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("varchar(255)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("RoleId") - .HasColumnType("varchar(255)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("varchar(255)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => - { - b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); - - b.Property("IsActive") - .HasColumnType("tinyint(1)"); - - b.Property("IsRootUser") - .HasColumnType("tinyint(1)"); - - b.Property("TenantId") - .HasColumnType("char(36)"); - - b.HasDiscriminator().HasValue("ApplicationUser"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") - .WithMany() - .HasForeignKey("ApprovedById"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("AssignedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") - .WithMany() - .HasForeignKey("ReportedById"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") - .WithMany() - .HasForeignKey("WorkItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") - .WithMany() - .HasForeignKey("WorkStatusId"); - - b.Navigation("ApprovedBy"); - - b.Navigation("Employee"); - - b.Navigation("ReportedBy"); - - b.Navigation("Tenant"); - - b.Navigation("WorkItem"); - - b.Navigation("WorkStatus"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("CommentedBy") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") - .WithMany() - .HasForeignKey("TaskAllocationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("TaskAllocation"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Approver"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => - { - b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") - .WithMany() - .HasForeignKey("AttendanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") - .WithMany() - .HasForeignKey("UpdatedBy"); - - b.Navigation("Attendance"); - - b.Navigation("Document"); - - b.Navigation("Employee"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedByEmployee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedByID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => - { - b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") - .WithMany() - .HasForeignKey("ContactCategoryId"); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("ContactCategory"); - - b.Navigation("CreatedBy"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById"); - - b.Navigation("Contact"); - - b.Navigation("Createdby"); - - b.Navigation("Tenant"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") - .WithMany() - .HasForeignKey("ContactId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") - .WithMany() - .HasForeignKey("ContactTagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Contact"); - - b.Navigation("ContactTag"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("UpdatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => - { - b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") - .WithMany() - .HasForeignKey("BucketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Bucket"); - - b.Navigation("Employee"); - }); - - modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") - .WithMany() - .HasForeignKey("UploadedById"); - - b.Navigation("Tenant"); - - b.Navigation("UploadedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") - .WithMany() - .HasForeignKey("ApplicationUserId"); - - b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") - .WithMany() - .HasForeignKey("JobRoleId"); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ApplicationUser"); - - b.Navigation("JobRole"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Role"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => - { - b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") - .WithMany("FeaturePermissions") - .HasForeignKey("FeatureId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Feature"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => - { - b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) - .WithMany() - .HasForeignKey("ApplicationRoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) - .WithMany() - .HasForeignKey("FeaturePermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => - { - b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") - .WithMany() - .HasForeignKey("IndustryId"); - - b.Navigation("Industry"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => - { - b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") - .WithMany() - .HasForeignKey("DocumentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Document"); - - b.Navigation("Expenses"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => - { - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") - .WithMany() - .HasForeignKey("ExpenseId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") - .WithMany() - .HasForeignKey("UpdatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Expense"); - - b.Navigation("UpdatedBy"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") - .WithMany() - .HasForeignKey("CreatedById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") - .WithMany() - .HasForeignKey("ExpensesTypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") - .WithMany() - .HasForeignKey("PaidById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") - .WithMany() - .HasForeignKey("PaymentModeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("CreatedBy"); - - b.Navigation("ExpensesType"); - - b.Navigation("PaidBy"); - - b.Navigation("PaymentMode"); - - b.Navigation("Project"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") - .WithMany() - .HasForeignKey("ReimburseById") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ReimburseBy"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => - { - b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") - .WithMany() - .HasForeignKey("ExpensesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") - .WithMany() - .HasForeignKey("ExpensesReimburseId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Expenses"); - - b.Navigation("ExpensesReimburse"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusMapping", b => - { - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("ExpeStatusIdnsesId"); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") - .WithMany() - .HasForeignKey("NextStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("NextStatus"); - - b.Navigation("Status"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") - .WithMany() - .HasForeignKey("PermissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Permission"); - - b.Navigation("Status"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => - { - b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") - .WithMany("Attachments") - .HasForeignKey("CommentId"); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Ticket"); - - b.Navigation("TicketComment"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") - .WithMany() - .HasForeignKey("PriorityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") - .WithMany() - .HasForeignKey("StatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") - .WithMany() - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Priority"); - - b.Navigation("Tenant"); - - b.Navigation("TicketStatusMaster"); - - b.Navigation("TicketTypeMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => - { - b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") - .WithMany() - .HasForeignKey("TagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") - .WithMany() - .HasForeignKey("TicketId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tag"); - - b.Navigation("Ticket"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => - { - b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") - .WithMany() - .HasForeignKey("MailListId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MailBody"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.HasOne("Marco.Pms.Model.Master.Module", "Module") - .WithMany() - .HasForeignKey("ModuleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Module"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => - { - b.HasOne("Marco.Pms.Model.Projects.Building", "Building") - .WithMany() - .HasForeignKey("BuildingId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Building"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => - { - b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") - .WithMany() - .HasForeignKey("ProjectStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ProjectStatus"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => - { - b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") - .WithMany() - .HasForeignKey("EmployeeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.Project", "Project") - .WithMany() - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Employee"); - - b.Navigation("Project"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => - { - b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") - .WithMany() - .HasForeignKey("FloorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Floor"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => - { - b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") - .WithMany() - .HasForeignKey("ActivityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") - .WithMany() - .HasForeignKey("WorkAreaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") - .WithMany() - .HasForeignKey("WorkCategoryId"); - - b.Navigation("ActivityMaster"); - - b.Navigation("Tenant"); - - b.Navigation("WorkArea"); - - b.Navigation("WorkCategoryMaster"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => - { - b.Navigation("Attachments"); - }); - - modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => - { - b.Navigation("FeaturePermissions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs b/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs deleted file mode 100644 index c4fc528..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719103905_Added_ExpenseLog_Table.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Marco.Pms.DataAccess.Migrations -{ - /// - public partial class Added_ExpenseLog_Table : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ExpenseLogs", - columns: table => new - { - Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - ExpenseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - UpdatedById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - Action = table.Column(type: "longtext", nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - Comment = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4") - }, - constraints: table => - { - table.PrimaryKey("PK_ExpenseLogs", x => x.Id); - table.ForeignKey( - name: "FK_ExpenseLogs_Employees_UpdatedById", - column: x => x.UpdatedById, - principalTable: "Employees", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_ExpenseLogs_Expenses_ExpenseId", - column: x => x.ExpenseId, - principalTable: "Expenses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.CreateIndex( - name: "IX_ExpenseLogs_ExpenseId", - table: "ExpenseLogs", - column: "ExpenseId"); - - migrationBuilder.CreateIndex( - name: "IX_ExpenseLogs_UpdatedById", - table: "ExpenseLogs", - column: "UpdatedById"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ExpenseLogs"); - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs b/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs deleted file mode 100644 index f20e292..0000000 --- a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace Marco.Pms.DataAccess.Migrations -{ - /// - public partial class Added_ExpensesStatusMaping_Table : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "StatusMapping"); - - migrationBuilder.CreateTable( - name: "ExpensesStatusMapping", - columns: table => new - { - Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") - }, - constraints: table => - { - table.PrimaryKey("PK_ExpensesStatusMapping", x => x.Id); - table.ForeignKey( - name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", - column: x => x.ExpeStatusIdnsesId, - principalTable: "ExpensesStatusMaster", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_NextStatusId", - column: x => x.NextStatusId, - principalTable: "ExpensesStatusMaster", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_ExpensesStatusMapping_Tenants_TenantId", - column: x => x.TenantId, - principalTable: "Tenants", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.InsertData( - table: "ExpensesStatusMapping", - columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, - values: new object[,] - { - { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } - }); - - migrationBuilder.CreateIndex( - name: "IX_ExpensesStatusMapping_ExpeStatusIdnsesId", - table: "ExpensesStatusMapping", - column: "ExpeStatusIdnsesId"); - - migrationBuilder.CreateIndex( - name: "IX_ExpensesStatusMapping_NextStatusId", - table: "ExpensesStatusMapping", - column: "NextStatusId"); - - migrationBuilder.CreateIndex( - name: "IX_ExpensesStatusMapping_TenantId", - table: "ExpensesStatusMapping", - column: "TenantId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ExpensesStatusMapping"); - - migrationBuilder.CreateTable( - name: "StatusMapping", - columns: table => new - { - Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") - }, - constraints: table => - { - table.PrimaryKey("PK_StatusMapping", x => x.Id); - table.ForeignKey( - name: "FK_StatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", - column: x => x.ExpeStatusIdnsesId, - principalTable: "ExpensesStatusMaster", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_StatusMapping_ExpensesStatusMaster_NextStatusId", - column: x => x.NextStatusId, - principalTable: "ExpensesStatusMaster", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_StatusMapping_Tenants_TenantId", - column: x => x.TenantId, - principalTable: "Tenants", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.InsertData( - table: "StatusMapping", - columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, - values: new object[,] - { - { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } - }); - - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_ExpeStatusIdnsesId", - table: "StatusMapping", - column: "ExpeStatusIdnsesId"); - - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_NextStatusId", - table: "StatusMapping", - column: "NextStatusId"); - - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_TenantId", - table: "StatusMapping", - column: "TenantId"); - } - } -} diff --git a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs similarity index 96% rename from Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs rename to Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index d5fe0c3..ad83f62 100644 --- a/Marco.Pms.DataAccess/Migrations/20250719113715_Added_ExpensesStatusMaping_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -12,8 +12,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Marco.Pms.DataAccess.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20250719113715_Added_ExpensesStatusMaping_Table")] - partial class Added_ExpensesStatusMaping_Table + [Migration("20250721124928_Added_Expense_Related_Tables")] + partial class Added_Expense_Related_Tables { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1307,6 +1307,9 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("ExpenseId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.Property("UpdatedById") .HasColumnType("char(36)"); @@ -1314,6 +1317,8 @@ namespace Marco.Pms.DataAccess.Migrations b.HasIndex("ExpenseId"); + b.HasIndex("TenantId"); + b.HasIndex("UpdatedById"); b.ToTable("ExpenseLogs"); @@ -1444,12 +1449,17 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("ExpensesReimburseId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.HasKey("Id"); b.HasIndex("ExpensesId"); b.HasIndex("ExpensesReimburseId"); + b.HasIndex("TenantId"); + b.ToTable("ExpensesReimburseMapping"); }); @@ -1459,9 +1469,6 @@ namespace Marco.Pms.DataAccess.Migrations .ValueGeneratedOnAdd() .HasColumnType("char(36)"); - b.Property("ExpeStatusIdnsesId") - .HasColumnType("char(36)"); - b.Property("NextStatusId") .HasColumnType("char(36)"); @@ -1473,10 +1480,10 @@ namespace Marco.Pms.DataAccess.Migrations b.HasKey("Id"); - b.HasIndex("ExpeStatusIdnsesId"); - b.HasIndex("NextStatusId"); + b.HasIndex("StatusId"); + b.HasIndex("TenantId"); b.ToTable("ExpensesStatusMapping"); @@ -1485,7 +1492,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, @@ -1504,6 +1511,13 @@ namespace Marco.Pms.DataAccess.Migrations TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, new + { + Id = new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new { Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), @@ -1538,13 +1552,55 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("StatusId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.HasKey("Id"); b.HasIndex("PermissionId"); b.HasIndex("StatusId"); + b.HasIndex("TenantId"); + b.ToTable("StatusPermissionMapping"); + + b.HasData( + new + { + Id = new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); }); modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => @@ -1843,10 +1899,18 @@ namespace Marco.Pms.DataAccess.Migrations .ValueGeneratedOnAdd() .HasColumnType("char(36)"); + b.Property("Color") + .IsRequired() + .HasColumnType("longtext"); + b.Property("Description") .IsRequired() .HasColumnType("longtext"); + b.Property("DisplayName") + .IsRequired() + .HasColumnType("longtext"); + b.Property("IsActive") .HasColumnType("tinyint(1)"); @@ -1870,7 +1934,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Color = "#212529", Description = "Expense has been created but not yet submitted.", + DisplayName = "Draft", IsActive = true, IsSystem = true, Name = "Draft", @@ -1879,7 +1945,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Color = "#0d6efd", Description = "Reviewer is currently reviewing the expense.", + DisplayName = "Review", IsActive = true, IsSystem = true, Name = "Review Pending", @@ -1888,7 +1956,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Color = "#0dcaf0", Description = "Review is completed, waiting for action of approver.", + DisplayName = "Approve", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1897,7 +1967,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Color = "#dc3545", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + DisplayName = "Reject", IsActive = true, IsSystem = true, Name = "Rejected", @@ -1906,7 +1978,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Color = "#ffc107", Description = "Approved expense is awaiting final payment.", + DisplayName = "Process", IsActive = true, IsSystem = true, Name = "Process Pending", @@ -1915,7 +1989,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Color = "#198754", Description = "Expense has been settled.", + DisplayName = "Paid", IsActive = true, IsSystem = true, Name = "Processed", @@ -3696,6 +3772,12 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") .WithMany() .HasForeignKey("UpdatedById") @@ -3704,6 +3786,8 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Expense"); + b.Navigation("Tenant"); + b.Navigation("UpdatedBy"); }); @@ -3799,23 +3883,33 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("Expenses"); b.Navigation("ExpensesReimburse"); + + b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => { - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("ExpeStatusIdnsesId"); - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") .WithMany() .HasForeignKey("NextStatusId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") .WithMany() .HasForeignKey("TenantId") @@ -3843,9 +3937,17 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("Permission"); b.Navigation("Status"); + + b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => diff --git a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs similarity index 74% rename from Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs rename to Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index d53b349..1d1e2f9 100644 --- a/Marco.Pms.DataAccess/Migrations/20250719074035_Expenses_tables_Added.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Marco.Pms.DataAccess.Migrations { /// - public partial class Expenses_tables_Added : Migration + public partial class Added_Expense_Related_Tables : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -51,8 +51,12 @@ namespace Marco.Pms.DataAccess.Migrations Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), Name = table.Column(type: "longtext", nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), Description = table.Column(type: "longtext", nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), + Color = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), IsSystem = table.Column(type: "tinyint(1)", nullable: false), IsActive = table.Column(type: "tinyint(1)", nullable: false), TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") @@ -119,31 +123,31 @@ namespace Marco.Pms.DataAccess.Migrations .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.CreateTable( - name: "StatusMapping", + name: "ExpensesStatusMapping", columns: table => new { Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - ExpeStatusIdnsesId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), NextStatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") }, constraints: table => { - table.PrimaryKey("PK_StatusMapping", x => x.Id); + table.PrimaryKey("PK_ExpensesStatusMapping", x => x.Id); table.ForeignKey( - name: "FK_StatusMapping_ExpensesStatusMaster_ExpeStatusIdnsesId", - column: x => x.ExpeStatusIdnsesId, - principalTable: "ExpensesStatusMaster", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_StatusMapping_ExpensesStatusMaster_NextStatusId", + name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_NextStatusId", column: x => x.NextStatusId, principalTable: "ExpensesStatusMaster", principalColumn: "Id", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_StatusMapping_Tenants_TenantId", + name: "FK_ExpensesStatusMapping_ExpensesStatusMaster_StatusId", + column: x => x.StatusId, + principalTable: "ExpensesStatusMaster", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpensesStatusMapping_Tenants_TenantId", column: x => x.TenantId, principalTable: "Tenants", principalColumn: "Id", @@ -157,7 +161,8 @@ namespace Marco.Pms.DataAccess.Migrations { Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), StatusId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - PermissionId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + PermissionId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") }, constraints: table => { @@ -174,6 +179,12 @@ namespace Marco.Pms.DataAccess.Migrations principalTable: "FeaturePermissions", principalColumn: "Id", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_StatusPermissionMapping_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -186,7 +197,9 @@ namespace Marco.Pms.DataAccess.Migrations ExpensesTypeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), PaymentModeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), PaidById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + CreatedById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), TransactionDate = table.Column(type: "datetime(6)", nullable: false), + CreatedAt = table.Column(type: "datetime(6)", nullable: false), TransactionId = table.Column(type: "longtext", nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), Description = table.Column(type: "longtext", nullable: false) @@ -207,6 +220,12 @@ namespace Marco.Pms.DataAccess.Migrations constraints: table => { table.PrimaryKey("PK_Expenses", x => x.Id); + table.ForeignKey( + name: "FK_Expenses_Employees_CreatedById", + column: x => x.CreatedById, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_Expenses_Employees_PaidById", column: x => x.PaidById, @@ -279,13 +298,51 @@ namespace Marco.Pms.DataAccess.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "ExpenseLogs", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + ExpenseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + UpdatedById = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Action = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Comment = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_ExpenseLogs", x => x.Id); + table.ForeignKey( + name: "FK_ExpenseLogs_Employees_UpdatedById", + column: x => x.UpdatedById, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpenseLogs_Expenses_ExpenseId", + column: x => x.ExpenseId, + principalTable: "Expenses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpenseLogs_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "ExpensesReimburseMapping", columns: table => new { Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), ExpensesId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - ExpensesReimburseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + ExpensesReimburseId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") }, constraints: table => { @@ -302,20 +359,26 @@ namespace Marco.Pms.DataAccess.Migrations principalTable: "Expenses", principalColumn: "Id", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ExpensesReimburseMapping_Tenants_TenantId", + column: x => x.TenantId, + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.InsertData( table: "ExpensesStatusMaster", - columns: new[] { "Id", "Description", "IsActive", "IsSystem", "Name", "TenantId" }, + columns: new[] { "Id", "Color", "Description", "DisplayName", "IsActive", "IsSystem", "Name", "TenantId" }, values: new object[,] { - { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "Expense has been created but not yet submitted.", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "Review is completed, waiting for action of approver.", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "Expense has been settled.", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "Reviewer is currently reviewing the expense.", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "Expense was declined, often with a reason(either review rejected or approval rejected.", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "Approved expense is awaiting final payment.", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#212529", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#0dcaf0", "Review is completed, waiting for action of approver.", "Approve", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#198754", "Expense has been settled.", "Paid", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#0d6efd", "Reviewer is currently reviewing the expense.", "Review", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#dc3545", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffc107", "Approved expense is awaiting final payment.", "Process", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); migrationBuilder.InsertData( @@ -349,6 +412,20 @@ namespace Marco.Pms.DataAccess.Migrations { new Guid("ed667353-8eea-4fd1-8750-719405932480"), "Online banking portals used to transfer funds directly between accounts", true, "NetBanking", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); + migrationBuilder.InsertData( + table: "ExpensesStatusMapping", + columns: new[] { "Id", "NextStatusId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + migrationBuilder.InsertData( table: "FeaturePermissions", columns: new[] { "Id", "Description", "FeatureId", "IsEnabled", "Name" }, @@ -364,16 +441,15 @@ namespace Marco.Pms.DataAccess.Migrations }); migrationBuilder.InsertData( - table: "StatusMapping", - columns: new[] { "Id", "ExpeStatusIdnsesId", "NextStatusId", "StatusId", "TenantId" }, + table: "StatusPermissionMapping", + columns: new[] { "Id", "PermissionId", "StatusId", "TenantId" }, values: new object[,] { - { new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), null, new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), null, new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), null, new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), null, new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + { new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); migrationBuilder.CreateIndex( @@ -391,6 +467,26 @@ namespace Marco.Pms.DataAccess.Migrations table: "BillAttachments", column: "TenantId"); + migrationBuilder.CreateIndex( + name: "IX_ExpenseLogs_ExpenseId", + table: "ExpenseLogs", + column: "ExpenseId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpenseLogs_TenantId", + table: "ExpenseLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpenseLogs_UpdatedById", + table: "ExpenseLogs", + column: "UpdatedById"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_CreatedById", + table: "Expenses", + column: "CreatedById"); + migrationBuilder.CreateIndex( name: "IX_Expenses_ExpensesTypeId", table: "Expenses", @@ -441,6 +537,26 @@ namespace Marco.Pms.DataAccess.Migrations table: "ExpensesReimburseMapping", column: "ExpensesReimburseId"); + migrationBuilder.CreateIndex( + name: "IX_ExpensesReimburseMapping_TenantId", + table: "ExpensesReimburseMapping", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_NextStatusId", + table: "ExpensesStatusMapping", + column: "NextStatusId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_StatusId", + table: "ExpensesStatusMapping", + column: "StatusId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_TenantId", + table: "ExpensesStatusMapping", + column: "TenantId"); + migrationBuilder.CreateIndex( name: "IX_ExpensesStatusMaster_TenantId", table: "ExpensesStatusMaster", @@ -456,21 +572,6 @@ namespace Marco.Pms.DataAccess.Migrations table: "PaymentModeMatser", column: "TenantId"); - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_ExpeStatusIdnsesId", - table: "StatusMapping", - column: "ExpeStatusIdnsesId"); - - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_NextStatusId", - table: "StatusMapping", - column: "NextStatusId"); - - migrationBuilder.CreateIndex( - name: "IX_StatusMapping_TenantId", - table: "StatusMapping", - column: "TenantId"); - migrationBuilder.CreateIndex( name: "IX_StatusPermissionMapping_PermissionId", table: "StatusPermissionMapping", @@ -480,6 +581,11 @@ namespace Marco.Pms.DataAccess.Migrations name: "IX_StatusPermissionMapping_StatusId", table: "StatusPermissionMapping", column: "StatusId"); + + migrationBuilder.CreateIndex( + name: "IX_StatusPermissionMapping_TenantId", + table: "StatusPermissionMapping", + column: "TenantId"); } /// @@ -488,11 +594,14 @@ namespace Marco.Pms.DataAccess.Migrations migrationBuilder.DropTable( name: "BillAttachments"); + migrationBuilder.DropTable( + name: "ExpenseLogs"); + migrationBuilder.DropTable( name: "ExpensesReimburseMapping"); migrationBuilder.DropTable( - name: "StatusMapping"); + name: "ExpensesStatusMapping"); migrationBuilder.DropTable( name: "StatusPermissionMapping"); diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 0151173..c15054f 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1304,6 +1304,9 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("ExpenseId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.Property("UpdatedById") .HasColumnType("char(36)"); @@ -1311,6 +1314,8 @@ namespace Marco.Pms.DataAccess.Migrations b.HasIndex("ExpenseId"); + b.HasIndex("TenantId"); + b.HasIndex("UpdatedById"); b.ToTable("ExpenseLogs"); @@ -1441,12 +1446,17 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("ExpensesReimburseId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.HasKey("Id"); b.HasIndex("ExpensesId"); b.HasIndex("ExpensesReimburseId"); + b.HasIndex("TenantId"); + b.ToTable("ExpensesReimburseMapping"); }); @@ -1456,9 +1466,6 @@ namespace Marco.Pms.DataAccess.Migrations .ValueGeneratedOnAdd() .HasColumnType("char(36)"); - b.Property("ExpeStatusIdnsesId") - .HasColumnType("char(36)"); - b.Property("NextStatusId") .HasColumnType("char(36)"); @@ -1470,10 +1477,10 @@ namespace Marco.Pms.DataAccess.Migrations b.HasKey("Id"); - b.HasIndex("ExpeStatusIdnsesId"); - b.HasIndex("NextStatusId"); + b.HasIndex("StatusId"); + b.HasIndex("TenantId"); b.ToTable("ExpensesStatusMapping"); @@ -1482,7 +1489,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), - NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, @@ -1501,6 +1508,13 @@ namespace Marco.Pms.DataAccess.Migrations TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, new + { + Id = new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new { Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), @@ -1535,13 +1549,55 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("StatusId") .HasColumnType("char(36)"); + b.Property("TenantId") + .HasColumnType("char(36)"); + b.HasKey("Id"); b.HasIndex("PermissionId"); b.HasIndex("StatusId"); + b.HasIndex("TenantId"); + b.ToTable("StatusPermissionMapping"); + + b.HasData( + new + { + Id = new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); }); modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => @@ -1840,10 +1896,18 @@ namespace Marco.Pms.DataAccess.Migrations .ValueGeneratedOnAdd() .HasColumnType("char(36)"); + b.Property("Color") + .IsRequired() + .HasColumnType("longtext"); + b.Property("Description") .IsRequired() .HasColumnType("longtext"); + b.Property("DisplayName") + .IsRequired() + .HasColumnType("longtext"); + b.Property("IsActive") .HasColumnType("tinyint(1)"); @@ -1867,7 +1931,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Color = "#212529", Description = "Expense has been created but not yet submitted.", + DisplayName = "Draft", IsActive = true, IsSystem = true, Name = "Draft", @@ -1876,7 +1942,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Color = "#0d6efd", Description = "Reviewer is currently reviewing the expense.", + DisplayName = "Review", IsActive = true, IsSystem = true, Name = "Review Pending", @@ -1885,7 +1953,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Color = "#0dcaf0", Description = "Review is completed, waiting for action of approver.", + DisplayName = "Approve", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1894,7 +1964,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Color = "#dc3545", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + DisplayName = "Reject", IsActive = true, IsSystem = true, Name = "Rejected", @@ -1903,7 +1975,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Color = "#ffc107", Description = "Approved expense is awaiting final payment.", + DisplayName = "Process", IsActive = true, IsSystem = true, Name = "Process Pending", @@ -1912,7 +1986,9 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Color = "#198754", Description = "Expense has been settled.", + DisplayName = "Paid", IsActive = true, IsSystem = true, Name = "Processed", @@ -3693,6 +3769,12 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") .WithMany() .HasForeignKey("UpdatedById") @@ -3701,6 +3783,8 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Expense"); + b.Navigation("Tenant"); + b.Navigation("UpdatedBy"); }); @@ -3796,23 +3880,33 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("Expenses"); b.Navigation("ExpensesReimburse"); + + b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => { - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") - .WithMany() - .HasForeignKey("ExpeStatusIdnsesId"); - b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") .WithMany() .HasForeignKey("NextStatusId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") .WithMany() .HasForeignKey("TenantId") @@ -3840,9 +3934,17 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("Permission"); b.Navigation("Status"); + + b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => diff --git a/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs index ef18799..3731f3b 100644 --- a/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs +++ b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs @@ -4,6 +4,6 @@ { public Guid ExpenseId { get; set; } public Guid StatusId { get; set; } - public string? Description { get; set; } + public string? Comment { get; set; } } } diff --git a/Marco.Pms.Model/Expenses/ExpenseLog.cs b/Marco.Pms.Model/Expenses/ExpenseLog.cs index ec3d8fd..e0eaa21 100644 --- a/Marco.Pms.Model/Expenses/ExpenseLog.cs +++ b/Marco.Pms.Model/Expenses/ExpenseLog.cs @@ -1,10 +1,11 @@ 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.Expenses { - public class ExpenseLog + public class ExpenseLog : TenantRelation { public Guid Id { get; set; } public Guid ExpenseId { get; set; } diff --git a/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs b/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs index c1c2be6..16237de 100644 --- a/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs +++ b/Marco.Pms.Model/Expenses/ExpensesReimburseMapping.cs @@ -1,9 +1,10 @@ -using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using Marco.Pms.Model.Utilities; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using System.ComponentModel.DataAnnotations.Schema; namespace Marco.Pms.Model.Expenses { - public class ExpensesReimburseMapping + public class ExpensesReimburseMapping : TenantRelation { public Guid Id { get; set; } public Guid ExpensesId { get; set; } diff --git a/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs index e09350d..1eb7470 100644 --- a/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs +++ b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs @@ -11,7 +11,7 @@ namespace Marco.Pms.Model.Expenses public Guid StatusId { get; set; } [ValidateNever] - [ForeignKey("ExpeStatusIdnsesId")] + [ForeignKey("StatusId")] public ExpensesStatusMaster? Status { get; set; } public Guid NextStatusId { get; set; } diff --git a/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs index 2fe9334..9333412 100644 --- a/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs +++ b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs @@ -1,11 +1,12 @@ using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Master; +using Marco.Pms.Model.Utilities; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using System.ComponentModel.DataAnnotations.Schema; namespace Marco.Pms.Model.Expenses { - public class StatusPermissionMapping + public class StatusPermissionMapping : TenantRelation { public Guid Id { get; set; } public Guid StatusId { get; set; } diff --git a/Marco.Pms.Model/Master/ExpensesStatusMaster.cs b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs index dc2556a..dc393cd 100644 --- a/Marco.Pms.Model/Master/ExpensesStatusMaster.cs +++ b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs @@ -6,7 +6,9 @@ namespace Marco.Pms.Model.Master { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; + public string Color { get; set; } = string.Empty; public bool IsSystem { get; set; } = false; public bool IsActive { get; set; } = true; } diff --git a/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs index f772695..73a6487 100644 --- a/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs +++ b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs @@ -4,7 +4,9 @@ { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; + public string? Color { get; set; } public bool IsSystem { get; set; } = false; } } diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 4501c61..8f3351d 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -1,20 +1,9 @@ -using AutoMapper; -using Marco.Pms.DataAccess.Data; -using Marco.Pms.Model.Dtos.Expenses; -using Marco.Pms.Model.Entitlements; -using Marco.Pms.Model.Expenses; +using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Utilities; -using Marco.Pms.Model.ViewModels.Expanses; -using Marco.Pms.Model.ViewModels.Master; -using Marco.Pms.Model.ViewModels.Projects; -using Marco.Pms.Services.Service; +using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Helpers; -using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using System.Text.Json; -using Document = Marco.Pms.Model.DocumentManager.Document; namespace Marco.Pms.Services.Controllers @@ -24,31 +13,19 @@ namespace Marco.Pms.Services.Controllers [Authorize] public class ExpenseController : ControllerBase { - private readonly IDbContextFactory _dbContextFactory; - private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; - private readonly ILoggingService _logger; - private readonly S3UploadService _s3Service; - private readonly IServiceScopeFactory _serviceScopeFactory; - private readonly IMapper _mapper; + private readonly IExpensesService _expensesService; + private readonly ISignalRService _signalR; private readonly Guid tenantId; - private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); public ExpenseController( - IDbContextFactory dbContextFactory, - ApplicationDbContext context, UserHelper userHelper, - IServiceScopeFactory serviceScopeFactory, - ILoggingService logger, - S3UploadService s3Service, - IMapper mapper) + IExpensesService expensesService, + ISignalRService signalR + ) { - _dbContextFactory = dbContextFactory; - _context = context; _userHelper = userHelper; - _logger = logger; - _serviceScopeFactory = serviceScopeFactory; - _s3Service = s3Service; - _mapper = mapper; + _expensesService = expensesService; + _signalR = signalR; tenantId = userHelper.GetTenantId(); } @@ -64,182 +41,9 @@ namespace Marco.Pms.Services.Controllers [HttpGet("list")] public async Task GetExpensesList(string? filter, int pageSize = 20, int pageNumber = 1) { - try - { - _logger.LogInfo( - "Attempting to fetch expenses list for PageNumber: {PageNumber}, PageSize: {PageSize} with Filter: {Filter}", - pageNumber, pageSize, filter ?? ""); - - // 1. --- Get User and Permissions --- - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - if (loggedInEmployee == null) - { - // This is an authentication/authorization issue. The user should be logged in. - _logger.LogWarning("Could not find an employee for the current logged-in user."); - return Unauthorized(ApiResponse.ErrorResponse("User not found or not authenticated.", 401)); - } - Guid loggedInEmployeeId = loggedInEmployee.Id; - - var hasViewSelfPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); - }); - - var hasViewAllPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); - }); - - await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask); - - // 2. --- Build Base Query and Apply Permissions --- - // Start with a base IQueryable. Filters will be chained onto this. - var expensesQuery = _context.Expenses - .Include(e => e.ExpensesType) - .Include(e => e.Project) - .Include(e => e.PaidBy) - .ThenInclude(e => e!.JobRole) - .Include(e => e.PaymentMode) - .Include(e => e.Status) - .Include(e => e.CreatedBy) - .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. - - // Apply permission-based filtering BEFORE any other filters or pagination. - if (hasViewAllPermissionTask.Result) - { - // User has 'View All' permission, no initial restriction on who created the expense. - _logger.LogInfo("User {EmployeeId} has 'View All' permission.", loggedInEmployeeId); - } - else if (hasViewSelfPermissionTask.Result) - { - // User only has 'View Self' permission, so restrict the query to their own expenses. - _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); - expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); - } - else - { - // User has neither required permission. Deny access. - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId); - return Ok(ApiResponse.SuccessResponse(new List(), "You do not have permission to view any expenses.", 200)); - } - - // 3. --- Deserialize Filter and Apply --- - ExpensesFilter? expenseFilter = TryDeserializeFilter(filter); - - if (expenseFilter != null) - { - // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. - if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) - { - expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); - } - - if (expenseFilter.ProjectIds?.Any() == true) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.ProjectIds.Contains(e.ProjectId)); - } - - if (expenseFilter.StatusIds?.Any() == true) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.StatusIds.Contains(e.StatusId)); - } - - if (expenseFilter.PaidById?.Any() == true) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById)); - } - - // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. - if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermissionTask.Result) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); - } - } - - // 4. --- Apply Ordering and Pagination --- - // This should be the last step before executing the query. - var paginatedQuery = expensesQuery - .OrderByDescending(e => e.CreatedAt) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize); - - // 5. --- Execute Query and Map Results --- - var expensesList = await paginatedQuery.ToListAsync(); - - if (!expensesList.Any()) - { - _logger.LogInfo("No expenses found matching the criteria for employee {EmployeeId}.", loggedInEmployeeId); - return Ok(ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200)); - } - - var response = _mapper.Map>(expensesList); - - // 6. --- Efficiently Fetch and Append 'Next Status' Information --- - var statusIds = expensesList.Select(e => e.StatusId).Distinct().ToList(); - - var statusMappings = await _context.ExpensesStatusMapping - .Include(sm => sm.NextStatus) - .Where(sm => statusIds.Contains(sm.StatusId)) - .ToListAsync(); - - // Use a Lookup for efficient O(1) mapping. This is much better than repeated `.Where()` in a loop. - var statusMapLookup = statusMappings.ToLookup(sm => sm.StatusId); - - foreach (var expense in response) - { - if (expense.Status?.Id != null && statusMapLookup.Contains(expense.Status.Id)) - { - expense.NextStatus = statusMapLookup[expense.Status.Id] - .Select(sm => _mapper.Map(sm.NextStatus)) - .ToList(); - } - else - { - expense.NextStatus = new List(); // Ensure it's never null - } - } - - // 7. --- Return Final Success Response --- - var message = $"{response.Count} expense records fetched successfully."; - _logger.LogInfo(message); - return StatusCode(200, ApiResponse.SuccessResponse(response, message, 200)); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Databsae Exception occured while fetching list expenses"); - return BadRequest(ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - innerexcption = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 400)); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occured while fetching list expenses"); - return BadRequest(ApiResponse.ErrorResponse("Error Occured", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - innerexcption = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 400)); - } + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetExpensesListAsync(loggedInEmployee, tenantId, filter, pageSize, pageNumber); + return StatusCode(response.StatusCode, response); } [HttpGet("details/{id}")] @@ -257,355 +61,38 @@ namespace Marco.Pms.Services.Controllers /// An IActionResult indicating the result of the creation operation. [HttpPost("create")] - public async Task CreateExpense([FromBody] CreateExpensesDto dto) + public async Task CreateExpense([FromBody] CreateExpensesDto model) { - _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); - // The entire operation is wrapped in a transaction to ensure data consistency. - await using var transaction = await _context.Database.BeginTransactionAsync(); - - try - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - // 1. Authorization & Validation: Run all I/O-bound checks concurrently using factories for safety. - - // PERMISSION CHECKS: Use IServiceScopeFactory for thread-safe access to scoped services. - var hasUploadPermissionTask = Task.Run(async () => // Task.Run is acceptable here to create a new scope, but let's do it cleaner. - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); - }); - - var hasProjectPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasProjectPermission(loggedInEmployee, dto.ProjectId); - }); - - // VALIDATION CHECKS: Use IDbContextFactory for thread-safe, parallel database queries. - // Each task gets its own DbContext instance. - var projectTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == dto.ProjectId); - }); - var expenseTypeTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId); - }); - var paymentModeTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId); - }); - var statusTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMaster.AsNoTracking().FirstOrDefaultAsync(es => es.Id == Draft); - }); - - - // Await all prerequisite checks at once. - await Task.WhenAll( - hasUploadPermissionTask, hasProjectPermissionTask, - projectTask, expenseTypeTask, paymentModeTask, statusTask - ); - - // Await all prerequisite checks at once. - await Task.WhenAll( - hasUploadPermissionTask, hasProjectPermissionTask, - projectTask, expenseTypeTask, paymentModeTask, statusTask - ); - - // 2. Aggregate and Check Results - if (!await hasUploadPermissionTask || !await hasProjectPermissionTask) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); - return StatusCode(403, ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403)); - } - - var validationErrors = new List(); - var project = await projectTask; - var expenseType = await expenseTypeTask; - var paymentMode = await paymentModeTask; - var status = await statusTask; - - if (project == null) validationErrors.Add("Project not found."); - if (expenseType == null) validationErrors.Add("Expense Type not found."); - if (paymentMode == null) validationErrors.Add("Payment Mode not found."); - if (status == null) validationErrors.Add("Default status 'Draft' not found."); - - if (validationErrors.Any()) - { - await transaction.RollbackAsync(); - var errorMessage = string.Join(" ", validationErrors); - _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); - return BadRequest(ApiResponse.ErrorResponse("Invalid input data.", errorMessage, 400)); - } - - // 3. Entity Creation - var expense = _mapper.Map(dto); - expense.CreatedById = loggedInEmployee.Id; - expense.CreatedAt = DateTime.UtcNow; - expense.TenantId = tenantId; - expense.IsActive = true; - expense.StatusId = Draft; - - _context.Expenses.Add(expense); - - // 4. Process Attachments - if (dto.BillAttachments?.Any() ?? false) - { - await ProcessAndUploadAttachmentsAsync(dto.BillAttachments, expense, loggedInEmployee.Id, tenantId); - } - - // 5. Database Commit - await _context.SaveChangesAsync(); - - // 6. Transaction Commit - await transaction.CommitAsync(); - - var response = _mapper.Map(expense); - response.Project = _mapper.Map(project); - response.Status = _mapper.Map(status); - response.PaymentMode = _mapper.Map(paymentMode); - response.ExpensesType = _mapper.Map(expenseType); - - _logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId); - return StatusCode(201, ApiResponse.SuccessResponse(response, "Expense created successfully.", 201)); - } - catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation - { - await transaction.RollbackAsync(); - _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); - return BadRequest(ApiResponse.ErrorResponse("Invalid Request Data.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - innerexcption = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 400)); - } - catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) - { - await transaction.RollbackAsync(); - _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); - return StatusCode(500, ApiResponse.ErrorResponse("An internal server error occurred.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - innerexcption = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500)); - } + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.CreateExpenseAsync(model, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); } [HttpPost("action")] public async Task ChangeStatus([FromBody] ExpenseRecordDto model) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var exsitingExpenses = await _context.Expenses - .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.TenantId == tenantId); - - if (exsitingExpenses == null) + var response = await _expensesService.ChangeStatusAsync(model, loggedInEmployee, tenantId); + if (response.Success) { - return NotFound(ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404)); + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Expanse", Response = response.Data }; + await _signalR.SendNotificationAsync(notification); } - - exsitingExpenses.StatusId = model.StatusId; - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException dbEx) - { - // --- Step 3: Handle Concurrency Conflicts --- - // This happens if another user modified the project after we fetched it. - _logger.LogError(dbEx, "Error occured while update status of expanse."); - return StatusCode(500, ApiResponse.ErrorResponse("Error occured while update status of expanse.", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - innerexcption = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500)); - } - var response = _mapper.Map(exsitingExpenses); - return Ok(ApiResponse.SuccessResponse(response)); + return StatusCode(response.StatusCode, response); } [HttpPut("edit/{id}")] public async Task UpdateExpanse(Guid id, [FromBody] UpdateExpensesDto model) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var exsitingExpense = await _context.Expenses.FirstOrDefaultAsync(e => e.Id == model.Id && e.TenantId == tenantId); - - - if (exsitingExpense == null) - { - return NotFound(ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404)); - } - _mapper.Map(model, exsitingExpense); - _context.Entry(exsitingExpense).State = EntityState.Modified; - - try - { - await _context.SaveChangesAsync(); - _logger.LogInfo("Successfully updated project {ProjectId} by user {UserId}.", id, loggedInEmployee.Id); - } - catch (DbUpdateConcurrencyException ex) - { - // --- Step 3: Handle Concurrency Conflicts --- - // This happens if another user modified the project after we fetched it. - _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); - return StatusCode(409, ApiResponse.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409)); - } - var response = _mapper.Map(exsitingExpense); - return Ok(ApiResponse.SuccessResponse(response)); + var response = await _expensesService.UpdateExpanseAsync(id, model, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); } [HttpDelete("delete/{id}")] public void Delete(int id) { } - #region =================================================================== Helper Functions =================================================================== - /// - /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). - /// - /// The JSON filter string from the request. - /// An object or null if deserialization fails. - private ExpensesFilter? TryDeserializeFilter(string? filter) - { - if (string.IsNullOrWhiteSpace(filter)) - { - return null; - } - - var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - ExpensesFilter? expenseFilter = null; - - try - { - // First, try to deserialize directly. This is the expected case (e.g., from a web client). - expenseFilter = JsonSerializer.Deserialize(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(filter, options) ?? ""; - if (!string.IsNullOrWhiteSpace(unescapedJsonString)) - { - expenseFilter = JsonSerializer.Deserialize(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 expenseFilter; - } - - /// - /// Processes and uploads attachments concurrently, then adds the resulting entities to the main DbContext. - /// - private async Task ProcessAndUploadAttachmentsAsync(IEnumerable attachments, Expenses expense, Guid employeeId, Guid tenantId) - { - // Pre-validate all attachments to fail fast before any uploads. - foreach (var attachment in attachments) - { - if (string.IsNullOrWhiteSpace(attachment.Base64Data) || !_s3Service.IsBase64String(attachment.Base64Data)) - { - throw new ArgumentException($"Invalid or missing Base64 data for attachment: {attachment.FileName ?? "N/A"}"); - } - } - - var batchId = Guid.NewGuid(); - - // Create a list of tasks to be executed concurrently. - var processingTasks = attachments.Select(attachment => - ProcessSingleAttachmentAsync(attachment, expense, employeeId, tenantId, batchId) - ).ToList(); - - var results = await Task.WhenAll(processingTasks); - - // This part is thread-safe as it runs after all concurrent tasks are complete. - foreach (var (document, billAttachment) in results) - { - _context.Documents.Add(document); - _context.BillAttachments.Add(billAttachment); - } - _logger.LogInfo("{AttachmentCount} attachments processed and staged for saving.", results.Length); - } - - /// - /// Handles the logic for a single attachment: upload to S3 and create corresponding entities. - /// - private async Task<(Document document, BillAttachments billAttachment)> ProcessSingleAttachmentAsync( - FileUploadModel attachment, Expenses expense, Guid employeeId, Guid tenantId, Guid batchId) - { - var base64Data = attachment.Base64Data!.Contains(',') ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] : attachment.Base64Data; - var fileType = _s3Service.GetContentTypeFromBase64(base64Data); - var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); - var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; - - // Await the I/O-bound upload operation directly. - await _s3Service.UploadFileAsync(base64Data, fileType, objectKey); - _logger.LogInfo("Uploaded file to S3 with key: {ObjectKey}", objectKey); - - return CreateAttachmentEntities(batchId, expense.Id, employeeId, tenantId, objectKey, attachment); - } - - - /// - /// A private static helper method to create Document and BillAttachment entities. - /// This remains unchanged as it's a pure data-shaping method. - /// - private static (Document document, BillAttachments billAttachment) CreateAttachmentEntities( - Guid batchId, Guid expenseId, Guid uploadedById, Guid tenantId, string s3Key, FileUploadModel attachmentDto) - { - var document = new Document - { - BatchId = batchId, - UploadedById = uploadedById, - FileName = attachmentDto.FileName ?? "", - ContentType = attachmentDto.ContentType ?? "", - S3Key = s3Key, - FileSize = attachmentDto.FileSize, - UploadedAt = DateTime.UtcNow, - TenantId = tenantId - }; - var billAttachment = new BillAttachments { Document = document, ExpensesId = expenseId, TenantId = tenantId }; - return (document, billAttachment); - } - - #endregion } } diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index a43af8b..6b6bfa5 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -172,6 +172,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); #endregion diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs new file mode 100644 index 0000000..71dfe33 --- /dev/null +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -0,0 +1,895 @@ +using AutoMapper; +using Marco.Pms.CacheHelper; +using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.DocumentManager; +using Marco.Pms.Model.Dtos.Expenses; +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Expenses; +using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.ViewModels.Expanses; +using Marco.Pms.Model.ViewModels.Master; +using Marco.Pms.Model.ViewModels.Projects; +using Marco.Pms.Services.Service.ServiceInterfaces; +using MarcoBMS.Services.Service; +using Microsoft.EntityFrameworkCore; +using System.Text.Json; + +namespace Marco.Pms.Services.Service +{ + public class ExpensesService : IExpensesService + { + private readonly IDbContextFactory _dbContextFactory; + private readonly ApplicationDbContext _context; + private readonly ILoggingService _logger; + private readonly S3UploadService _s3Service; + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly UpdateLogHelper _updateLogHelper; + private readonly IMapper _mapper; + private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); + private static readonly string Collection = "ExpensesModificationLog"; + public ExpensesService( + IDbContextFactory dbContextFactory, + ApplicationDbContext context, + IServiceScopeFactory serviceScopeFactory, + UpdateLogHelper updateLogHelper, + ILoggingService logger, + S3UploadService s3Service, + IMapper mapper) + { + _dbContextFactory = dbContextFactory; + _context = context; + _logger = logger; + _serviceScopeFactory = serviceScopeFactory; + _updateLogHelper = updateLogHelper; + _s3Service = s3Service; + _mapper = mapper; + } + + + /// + /// Retrieves a paginated list of expenses based on user permissions and optional filters. + /// + /// A URL-encoded JSON string containing filter criteria. See . + /// The number of records to return per page. + /// The page number to retrieve. + /// A paginated list of expenses. + public async Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber) + { + try + { + _logger.LogInfo( + "Attempting to fetch expenses list for PageNumber: {PageNumber}, PageSize: {PageSize} with Filter: {Filter}", + pageNumber, pageSize, filter ?? ""); + + // 1. --- Get User Permissions --- + if (loggedInEmployee == null) + { + // This is an authentication/authorization issue. The user should be logged in. + _logger.LogWarning("Could not find an employee for the current logged-in user."); + return ApiResponse.ErrorResponse("User not found or not authenticated.", 403); + } + Guid loggedInEmployeeId = loggedInEmployee.Id; + + var hasViewSelfPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId); + }); + + var hasViewAllPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId); + }); + + await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask); + + // 2. --- Build Base Query and Apply Permissions --- + // Start with a base IQueryable. Filters will be chained onto this. + var expensesQuery = _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. + + // Apply permission-based filtering BEFORE any other filters or pagination. + if (hasViewAllPermissionTask.Result) + { + // User has 'View All' permission, no initial restriction on who created the expense. + _logger.LogInfo("User {EmployeeId} has 'View All' permission.", loggedInEmployeeId); + } + else if (hasViewSelfPermissionTask.Result) + { + // User only has 'View Self' permission, so restrict the query to their own expenses. + _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); + expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); + } + else + { + // User has neither required permission. Deny access. + _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId); + return ApiResponse.SuccessResponse(new List(), "You do not have permission to view any expenses.", 200); + } + + // 3. --- Deserialize Filter and Apply --- + ExpensesFilter? expenseFilter = TryDeserializeFilter(filter); + + if (expenseFilter != null) + { + // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + { + expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + } + + if (expenseFilter.ProjectIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.ProjectIds.Contains(e.ProjectId)); + } + + if (expenseFilter.StatusIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.StatusIds.Contains(e.StatusId)); + } + + if (expenseFilter.PaidById?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById)); + } + + // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. + if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermissionTask.Result) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); + } + } + + // 4. --- Apply Ordering and Pagination --- + // This should be the last step before executing the query. + var paginatedQuery = expensesQuery + .OrderByDescending(e => e.CreatedAt) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + // 5. --- Execute Query and Map Results --- + var expensesList = await paginatedQuery.ToListAsync(); + + if (!expensesList.Any()) + { + _logger.LogInfo("No expenses found matching the criteria for employee {EmployeeId}.", loggedInEmployeeId); + return ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200); + } + + var response = _mapper.Map>(expensesList); + + // 6. --- Efficiently Fetch and Append 'Next Status' Information --- + var statusIds = expensesList.Select(e => e.StatusId).Distinct().ToList(); + + var statusMappings = await _context.ExpensesStatusMapping + .Include(sm => sm.NextStatus) + .Where(sm => statusIds.Contains(sm.StatusId)) + .ToListAsync(); + + // Use a Lookup for efficient O(1) mapping. This is much better than repeated `.Where()` in a loop. + var statusMapLookup = statusMappings.ToLookup(sm => sm.StatusId); + + foreach (var expense in response) + { + if (expense.Status?.Id != null && statusMapLookup.Contains(expense.Status.Id)) + { + expense.NextStatus = statusMapLookup[expense.Status.Id] + .Select(sm => _mapper.Map(sm.NextStatus)) + .ToList(); + } + else + { + expense.NextStatus = new List(); // Ensure it's never null + } + } + + // 7. --- Return Final Success Response --- + var message = $"{response.Count} expense records fetched successfully."; + _logger.LogInfo(message); + return ApiResponse.SuccessResponse(response, message, 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while fetching list expenses"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching list expenses"); + return ApiResponse.ErrorResponse("Error Occured", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } + } + + public string Get(int id) + { + return "value"; + } + + /// + /// Creates a new expense entry along with its bill attachments. + /// This operation is transactional and performs validations and file uploads concurrently for optimal performance + /// by leveraging async/await without unnecessary thread-pool switching via Task.Run. + /// + /// The data transfer object containing expense details and attachments. + /// An IActionResult indicating the result of the creation operation. + public async Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId) + { + _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); + // The entire operation is wrapped in a transaction to ensure data consistency. + await using var transaction = await _context.Database.BeginTransactionAsync(); + + try + { + // 1. Authorization & Validation: Run all I/O-bound checks concurrently using factories for safety. + + // PERMISSION CHECKS: Use IServiceScopeFactory for thread-safe access to scoped services. + var hasUploadPermissionTask = Task.Run(async () => // Task.Run is acceptable here to create a new scope, but let's do it cleaner. + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); + }); + + var hasProjectPermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasProjectPermission(loggedInEmployee, dto.ProjectId); + }); + + // VALIDATION CHECKS: Use IDbContextFactory for thread-safe, parallel database queries. + // Each task gets its own DbContext instance. + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == dto.ProjectId); + }); + var paidByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == dto.PaidById); + }); + var expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .FirstOrDefaultAsync(es => es.StatusId == Draft && es.Status != null); + }); + + + // Await all prerequisite checks at once. + await Task.WhenAll( + hasUploadPermissionTask, hasProjectPermissionTask, + projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask + ); + + // 2. Aggregate and Check Results + if (!await hasUploadPermissionTask || !await hasProjectPermissionTask) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403); + } + + var validationErrors = new List(); + var project = await projectTask; + var expenseType = await expenseTypeTask; + var paymentMode = await paymentModeTask; + var statusMapping = await statusMappingTask; + var paidBy = await paidByTask; + + if (project == null) validationErrors.Add("Project not found."); + if (paidBy == null) validationErrors.Add("Paid by employee not found"); + if (expenseType == null) validationErrors.Add("Expense Type not found."); + if (paymentMode == null) validationErrors.Add("Payment Mode not found."); + if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found."); + + if (validationErrors.Any()) + { + await transaction.RollbackAsync(); + var errorMessage = string.Join(" ", validationErrors); + _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); + return ApiResponse.ErrorResponse("Invalid input data.", errorMessage, 400); + } + + // 3. Entity Creation + var expense = _mapper.Map(dto); + expense.CreatedById = loggedInEmployee.Id; + expense.CreatedAt = DateTime.UtcNow; + expense.TenantId = tenantId; + expense.IsActive = true; + expense.StatusId = Draft; + + _context.Expenses.Add(expense); + + // 4. Process Attachments + if (dto.BillAttachments?.Any() ?? false) + { + await ProcessAndUploadAttachmentsAsync(dto.BillAttachments, expense, loggedInEmployee.Id, tenantId); + } + + // 5. Database Commit + await _context.SaveChangesAsync(); + + // 6. Transaction Commit + await transaction.CommitAsync(); + + var response = _mapper.Map(expense); + response.PaidBy = _mapper.Map(paidBy); + response.Project = _mapper.Map(project); + response.Status = _mapper.Map(statusMapping!.Status); + response.NextStatus = _mapper.Map>(statusMapping!.NextStatus); + response.PaymentMode = _mapper.Map(paymentMode); + response.ExpensesType = _mapper.Map(expenseType); + + _logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId); + return ApiResponse.SuccessResponse(response, "Expense created successfully.", 201); + } + catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation + { + await transaction.RollbackAsync(); + _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); + return ApiResponse.ErrorResponse("Invalid Request Data.", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 400); + } + catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) + { + await transaction.RollbackAsync(); + _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); + return ApiResponse.ErrorResponse("An internal server error occurred.", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } + } + + public async Task> ChangeStatus(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId) + { + + var existingExpense = await _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.StatusId != model.StatusId && e.TenantId == tenantId); + + if (existingExpense == null) + { + return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); + } + + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.NextStatus) + .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.NextStatusId == model.StatusId && s.TenantId == tenantId); + }); + var statusPermissionMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping.Where(sp => sp.StatusId == model.StatusId).ToListAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(statusMappingTask, statusPermissionMappingTask); + + var statusMapping = await statusMappingTask; + var statusPermissions = await statusPermissionMappingTask; + if (statusMapping == null) + { + return ApiResponse.ErrorResponse("There is no follow-up status for currect status"); + } + if (statusPermissions.Any()) + { + foreach (var sp in statusPermissions) + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + + if (!await permissionService.HasPermission(sp.PermissionId, loggedInEmployee.Id)) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to change status of expense from status {StatusId} to {NextStatusId}", + loggedInEmployee.Id, statusMapping.StatusId, statusMapping.NextStatusId); + return ApiResponse.ErrorResponse("You do not have permission", "Access Denied", 403); + } + } + } + else if (existingExpense.CreatedById != loggedInEmployee.Id) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to change status of expense from status {StatusId} to {NextStatusId}", + loggedInEmployee.Id, statusMapping.StatusId, statusMapping.NextStatusId); + return ApiResponse.ErrorResponse("You do not have permission", "Access Denied", 403); + } + var existingEntity = _updateLogHelper.EntityToBsonDocument(existingExpense); + + existingExpense.StatusId = statusMapping.NextStatusId; + existingExpense.Status = statusMapping.NextStatus; + + _context.ExpenseLogs.Add(new ExpenseLog + { + ExpenseId = existingExpense.Id, + Action = statusMapping.NextStatus!.Name, + UpdatedById = loggedInEmployee.Id, + Comment = model.Comment + }); + + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException dbEx) + { + _logger.LogError(dbEx, "Error occured while update status of expanse."); + return ApiResponse.ErrorResponse("Error occured while update status of expanse.", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + try + { + var updateLog = new UpdateLogsObject + { + EntityId = existingExpense.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntity, + UpdatedAt = DateTime.UtcNow + }; + var mongoDBTask = Task.Run(async () => + { + await _updateLogHelper.PushToUpdateLogsAsync(updateLog, Collection); + }); + + var getNextStatusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.NextStatus) + .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId); + }); + + await Task.WhenAll(mongoDBTask, getNextStatusTask); + + var getNextStatus = await getNextStatusTask; + + var response = _mapper.Map(existingExpense); + if (getNextStatus != null) + { + response.NextStatus = _mapper.Map>(getNextStatus.NextStatus); + } + + return ApiResponse.SuccessResponse(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while Saving old entity in mongoDb"); + return ApiResponse.ErrorResponse("Error occured while update status of expanse.", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + innerexcption = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } + } + /// + /// Changes the status of an expense record, performing validation, permission checks, and logging. + /// + /// The DTO containing the expense ID and the target status ID. + /// The employee performing the action. + /// The ID of the tenant owning the expense. + /// An ApiResponse containing the updated expense details or an error. + public async Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId) + { + // --- 1. Fetch Existing Expense --- + // We include all related entities needed for the final response mapping to avoid multiple database trips. + // The query also ensures we don't process a request if the status is already the one requested. + var existingExpense = await _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.StatusId != model.StatusId && e.TenantId == tenantId); + + if (existingExpense == null) + { + // Use structured logging for better searchability. + _logger.LogWarning("Attempted to change status for a non-existent or already-updated expense. ExpenseId: {ExpenseId}, TenantId: {TenantId}", model.ExpenseId, tenantId); + return ApiResponse.ErrorResponse("Expense not found or status is already set.", "Expense not found", 404); + } + + _logger.LogInfo("Initiating status change for ExpenseId: {ExpenseId} from StatusId: {OldStatusId} to {NewStatusId}", + existingExpense.Id, existingExpense.StatusId, model.StatusId); + + // --- 2. Concurrently Check Prerequisites --- + // We run status validation and permission fetching in parallel for efficiency. + // Using Task.Run with an async lambda is the standard way to start a concurrent, + // CPU- or I/O-bound operation on a background thread. + + // Task to validate if the requested status change is a valid transition. + var statusMappingTask = Task.Run(async () => + { + // 'await using' ensures the DbContext created by the factory is properly disposed + // within the scope of this background task. + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.NextStatus) + .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatusId == model.StatusId && s.TenantId == tenantId); + }); + + // Task to fetch all permissions required for the *target* status. + var statusPermissionMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping + .Where(sp => sp.StatusId == model.StatusId && sp.TenantId == tenantId) + .ToListAsync(); + }); + + // Await both tasks to complete concurrently. + await Task.WhenAll(statusMappingTask, statusPermissionMappingTask); + + // Now you can safely get the results. + var statusMapping = await statusMappingTask; + var statusPermissions = await statusPermissionMappingTask; + + // --- 3. Validate Status Transition and Permissions --- + if (statusMapping == null) + { + _logger.LogWarning("Invalid status transition attempted for ExpenseId: {ExpenseId}. From StatusId: {FromStatusId} to {ToStatusId}", + existingExpense.Id, existingExpense.StatusId, model.StatusId); + return ApiResponse.ErrorResponse("This status change is not allowed.", "Invalid Transition", 400); + } + + // Check permissions. The logic is: + // 1. If the target status has specific permissions defined, the user must have at least one of them. + // 2. If no permissions are defined for the target status, only the original creator of the expense can change it. + bool hasPermission = false; + if (statusPermissions.Any()) + { + // Using a scope to resolve scoped services like PermissionServices. + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + foreach (var sp in statusPermissions) + { + if (await permissionService.HasPermission(sp.PermissionId, loggedInEmployee.Id)) + { + hasPermission = true; + break; // User has one of the required permissions, no need to check further. + } + } + } + else if (existingExpense.CreatedById == loggedInEmployee.Id) + { + // Fallback: If no permissions are required for the status, allow the creator to make the change. + hasPermission = true; + } + + if (!hasPermission) + { + _logger.LogWarning("Access DENIED for EmployeeId: {EmployeeId} attempting to change status of ExpenseId: {ExpenseId} to StatusId: {NewStatusId}", + loggedInEmployee.Id, existingExpense.Id, model.StatusId); + return ApiResponse.ErrorResponse("You do not have the required permissions to perform this action.", "Access Denied", 403); + } + + // --- 4. Update Expense and Add Log (in a transaction) --- + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes. + + existingExpense.StatusId = statusMapping.NextStatusId; + existingExpense.Status = statusMapping.NextStatus; // Assigning the included entity for the response mapping. + + _context.ExpenseLogs.Add(new ExpenseLog + { + ExpenseId = existingExpense.Id, + Action = $"Status changed to '{statusMapping.NextStatus!.Name}'", + UpdatedById = loggedInEmployee.Id, + Comment = model.Comment, + TenantId = tenantId + }); + + try + { + await _context.SaveChangesAsync(); + _logger.LogInfo("Successfully updated status for ExpenseId: {ExpenseId} to StatusId: {NewStatusId}", existingExpense.Id, existingExpense.StatusId); + } + catch (DbUpdateConcurrencyException dbEx) + { + // This error occurs if the record was modified by someone else after we fetched it. + _logger.LogError(dbEx, "Concurrency conflict while updating status for ExpenseId: {ExpenseId}. The record may have been modified by another user.", existingExpense.Id); + return ApiResponse.ErrorResponse("The expense was modified by another user. Please refresh and try again.", "Concurrency Error", 409); // 409 Conflict is appropriate + } + + // --- 5. Perform Post-Save Actions (Audit Log and Fetching Next State for UI) --- + try + { + // Task to save the detailed audit log to a separate system (e.g., MongoDB). + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = existingExpense.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, Collection); + + // Task to get all possible next statuses from the *new* current state to help the UI. + // NOTE: This now fetches a list of all possible next states, which is more useful for a UI. + var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t => + { + var dbContext = t.Result; + return dbContext.ExpensesStatusMapping + .Include(s => s.NextStatus) + .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId) + .Select(s => s.NextStatus) // Select only the status object + .ToListAsync() + .ContinueWith(res => + { + dbContext.Dispose(); // Ensure the context is disposed + return res.Result; + }); + }).Unwrap(); + + await Task.WhenAll(mongoDBTask, getNextStatusesTask); + + var nextPossibleStatuses = await getNextStatusesTask; + + var response = _mapper.Map(existingExpense); + if (nextPossibleStatuses != null) + { + // The response DTO should have a property like: public List NextAvailableStatuses { get; set; } + response.NextStatus = _mapper.Map>(nextPossibleStatuses); + } + + return ApiResponse.SuccessResponse(response); + } + catch (Exception ex) + { + // This catch block handles errors from post-save operations like MongoDB logging. + // The primary update was successful, but we must log this failure. + _logger.LogError(ex, "Error occurred during post-save operations for ExpenseId: {ExpenseId} (e.g., audit logging). The primary status change was successful.", existingExpense.Id); + + // We can still return a success response because the main operation succeeded, + // but we should not block the user for a failed audit log. + // Alternatively, if audit logging is critical, you could return an error. + // Here, we choose to return success but log the ancillary failure. + var response = _mapper.Map(existingExpense); + return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); + } + } + public async Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId) + { + var exsitingExpense = await _context.Expenses.FirstOrDefaultAsync(e => e.Id == model.Id && e.TenantId == tenantId); + + + if (exsitingExpense == null) + { + return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); + } + _mapper.Map(model, exsitingExpense); + _context.Entry(exsitingExpense).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + _logger.LogInfo("Successfully updated project {ProjectId} by user {UserId}.", id, loggedInEmployee.Id); + } + catch (DbUpdateConcurrencyException ex) + { + // --- Step 3: Handle Concurrency Conflicts --- + // This happens if another user modified the project after we fetched it. + _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); + return ApiResponse.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409); + } + var response = _mapper.Map(exsitingExpense); + return ApiResponse.SuccessResponse(response); + } + + public void Delete(int id) + { + } + #region =================================================================== Helper Functions =================================================================== + + /// + /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). + /// + /// The JSON filter string from the request. + /// An object or null if deserialization fails. + private ExpensesFilter? TryDeserializeFilter(string? filter) + { + if (string.IsNullOrWhiteSpace(filter)) + { + return null; + } + + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + ExpensesFilter? expenseFilter = null; + + try + { + // First, try to deserialize directly. This is the expected case (e.g., from a web client). + expenseFilter = JsonSerializer.Deserialize(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(filter, options) ?? ""; + if (!string.IsNullOrWhiteSpace(unescapedJsonString)) + { + expenseFilter = JsonSerializer.Deserialize(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 expenseFilter; + } + + /// + /// Processes and uploads attachments concurrently, then adds the resulting entities to the main DbContext. + /// + private async Task ProcessAndUploadAttachmentsAsync(IEnumerable attachments, Expenses expense, Guid employeeId, Guid tenantId) + { + // Pre-validate all attachments to fail fast before any uploads. + foreach (var attachment in attachments) + { + if (string.IsNullOrWhiteSpace(attachment.Base64Data) || !_s3Service.IsBase64String(attachment.Base64Data)) + { + throw new ArgumentException($"Invalid or missing Base64 data for attachment: {attachment.FileName ?? "N/A"}"); + } + } + + var batchId = Guid.NewGuid(); + + // Create a list of tasks to be executed concurrently. + var processingTasks = attachments.Select(attachment => + ProcessSingleAttachmentAsync(attachment, expense, employeeId, tenantId, batchId) + ).ToList(); + + var results = await Task.WhenAll(processingTasks); + + // This part is thread-safe as it runs after all concurrent tasks are complete. + foreach (var (document, billAttachment) in results) + { + _context.Documents.Add(document); + _context.BillAttachments.Add(billAttachment); + } + _logger.LogInfo("{AttachmentCount} attachments processed and staged for saving.", results.Length); + } + + /// + /// Handles the logic for a single attachment: upload to S3 and create corresponding entities. + /// + private async Task<(Document document, BillAttachments billAttachment)> ProcessSingleAttachmentAsync( + FileUploadModel attachment, Expenses expense, Guid employeeId, Guid tenantId, Guid batchId) + { + var base64Data = attachment.Base64Data!.Contains(',') ? attachment.Base64Data[(attachment.Base64Data.IndexOf(",") + 1)..] : attachment.Base64Data; + var fileType = _s3Service.GetContentTypeFromBase64(base64Data); + var fileName = _s3Service.GenerateFileName(fileType, expense.Id, "Expense"); + var objectKey = $"tenant-{tenantId}/project-{expense.ProjectId}/Expenses/{fileName}"; + + // Await the I/O-bound upload operation directly. + await _s3Service.UploadFileAsync(base64Data, fileType, objectKey); + _logger.LogInfo("Uploaded file to S3 with key: {ObjectKey}", objectKey); + + return CreateAttachmentEntities(batchId, expense.Id, employeeId, tenantId, objectKey, attachment); + } + + + /// + /// A private static helper method to create Document and BillAttachment entities. + /// This remains unchanged as it's a pure data-shaping method. + /// + private static (Document document, BillAttachments billAttachment) CreateAttachmentEntities( + Guid batchId, Guid expenseId, Guid uploadedById, Guid tenantId, string s3Key, FileUploadModel attachmentDto) + { + var document = new Document + { + BatchId = batchId, + UploadedById = uploadedById, + FileName = attachmentDto.FileName ?? "", + ContentType = attachmentDto.ContentType ?? "", + S3Key = s3Key, + FileSize = attachmentDto.FileSize, + UploadedAt = DateTime.UtcNow, + TenantId = tenantId + }; + var billAttachment = new BillAttachments { Document = document, ExpensesId = expenseId, TenantId = tenantId }; + return (document, billAttachment); + } + + #endregion + } +} diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs new file mode 100644 index 0000000..2cf2721 --- /dev/null +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -0,0 +1,14 @@ +using Marco.Pms.Model.Dtos.Expenses; +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Utilities; + +namespace Marco.Pms.Services.Service.ServiceInterfaces +{ + public interface IExpensesService + { + Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber); + Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); + Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); + Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); + } +} diff --git a/Marco.Pms.Services/appsettings.Development.json b/Marco.Pms.Services/appsettings.Development.json index 030c450..579b059 100644 --- a/Marco.Pms.Services/appsettings.Development.json +++ b/Marco.Pms.Services/appsettings.Development.json @@ -46,8 +46,9 @@ "Region": "us-east-1", "BucketName": "testenv-marco-pms-documents" }, - "MongoDB": { - "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", - "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500" - } + "MongoDB": { + "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", + "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500", + "ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500" + } } From 1fffde6d7fbb737c914dc30a55b8dc59da8fa850 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 21 Jul 2025 18:39:34 +0530 Subject: [PATCH 18/81] Solved the database transcation error --- Marco.Pms.Services/Service/ExpensesService.cs | 18 ++-- .../appsettings.Production.json | 89 ++++++++++--------- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 71dfe33..9411443 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -250,8 +250,6 @@ namespace Marco.Pms.Services.Service public async Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId) { _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); - // The entire operation is wrapped in a transaction to ensure data consistency. - await using var transaction = await _context.Database.BeginTransactionAsync(); try { @@ -301,7 +299,7 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .FirstOrDefaultAsync(es => es.StatusId == Draft && es.Status != null); + .Where(es => es.StatusId == Draft && es.Status != null).ToListAsync(); }); @@ -329,11 +327,10 @@ namespace Marco.Pms.Services.Service if (paidBy == null) validationErrors.Add("Paid by employee not found"); if (expenseType == null) validationErrors.Add("Expense Type not found."); if (paymentMode == null) validationErrors.Add("Payment Mode not found."); - if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found."); + if (!statusMapping.Any()) validationErrors.Add("Default status 'Draft' not found."); if (validationErrors.Any()) { - await transaction.RollbackAsync(); var errorMessage = string.Join(" ", validationErrors); _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); return ApiResponse.ErrorResponse("Invalid input data.", errorMessage, 400); @@ -358,14 +355,13 @@ namespace Marco.Pms.Services.Service // 5. Database Commit await _context.SaveChangesAsync(); - // 6. Transaction Commit - await transaction.CommitAsync(); - + var status = statusMapping.Select(sm => sm.Status).FirstOrDefault(); + var nextStatus = statusMapping.Select(sm => sm.NextStatus).ToList(); var response = _mapper.Map(expense); response.PaidBy = _mapper.Map(paidBy); response.Project = _mapper.Map(project); - response.Status = _mapper.Map(statusMapping!.Status); - response.NextStatus = _mapper.Map>(statusMapping!.NextStatus); + response.Status = _mapper.Map(status); + response.NextStatus = _mapper.Map>(nextStatus); response.PaymentMode = _mapper.Map(paymentMode); response.ExpensesType = _mapper.Map(expenseType); @@ -374,7 +370,6 @@ namespace Marco.Pms.Services.Service } catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation { - await transaction.RollbackAsync(); _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("Invalid Request Data.", new { @@ -391,7 +386,6 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) { - await transaction.RollbackAsync(); _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("An internal server error occurred.", new { diff --git a/Marco.Pms.Services/appsettings.Production.json b/Marco.Pms.Services/appsettings.Production.json index 0abe3f1..f164fdf 100644 --- a/Marco.Pms.Services/appsettings.Production.json +++ b/Marco.Pms.Services/appsettings.Production.json @@ -1,46 +1,47 @@ { - "Cors": { - "AllowedOrigins": "https://app.marcoaiot.com", - "AllowedMethods": "*", - "AllowedHeaders": "*" - }, - "Environment": { - "Name": "Production", - "Title": "" - }, - "ConnectionStrings": { - "DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1" - }, - "SmtpSettings": { - "SmtpServer": "smtp.gmail.com", - "Port": 587, - "SenderName": "MarcoAIOT", - "SenderEmail": "marcoioitsoft@gmail.com", - "Password": "qrtq wfuj hwpp fhqr" - }, - "AppSettings": { - "WebFrontendUrl": "https://app.marcoaiot.com", - "ImagesBaseUrl": "https://app.marcoaiot.com" - }, - "Jwt": { - "Issuer": "https://app.marcoaiot.com", - "Audience": "https://app.marcoaiot.com", - "Key": "sworffishhkjfa9dnfdndfu33infnajfj", - "ExpiresInMinutes": 60, - "RefreshTokenExpiresInDays": 7 - }, - "MailingList": { - "RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com", - "ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com" - }, - "AWS": { - "AccessKey": "AKIARZDBH3VDMSUUY2FX", - "SecretKey": "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", - "Region": "us-east-1", - "BucketName": "testenv-marco-pms-documents" - }, - "MongoDB": { - "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", - "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches" - } + "Cors": { + "AllowedOrigins": "https://app.marcoaiot.com", + "AllowedMethods": "*", + "AllowedHeaders": "*" + }, + "Environment": { + "Name": "Production", + "Title": "" + }, + "ConnectionStrings": { + "DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMS1" + }, + "SmtpSettings": { + "SmtpServer": "smtp.gmail.com", + "Port": 587, + "SenderName": "MarcoAIOT", + "SenderEmail": "marcoioitsoft@gmail.com", + "Password": "qrtq wfuj hwpp fhqr" + }, + "AppSettings": { + "WebFrontendUrl": "https://app.marcoaiot.com", + "ImagesBaseUrl": "https://app.marcoaiot.com" + }, + "Jwt": { + "Issuer": "https://app.marcoaiot.com", + "Audience": "https://app.marcoaiot.com", + "Key": "sworffishhkjfa9dnfdndfu33infnajfj", + "ExpiresInMinutes": 60, + "RefreshTokenExpiresInDays": 7 + }, + "MailingList": { + "RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com", + "ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com" + }, + "AWS": { + "AccessKey": "AKIARZDBH3VDMSUUY2FX", + "SecretKey": "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", + "Region": "us-east-1", + "BucketName": "testenv-marco-pms-documents" + }, + "MongoDB": { + "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", + "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches", + "ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?authSource=admin&socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500" + } } \ No newline at end of file From 2449d2a5182c334e0d0a73aee6fd97a9842d0d42 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 21 Jul 2025 18:50:08 +0530 Subject: [PATCH 19/81] FIxed the database transaction error --- Marco.Pms.Services/Service/ExpensesService.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 9411443..9ea150f 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -250,6 +250,8 @@ namespace Marco.Pms.Services.Service public async Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId) { _logger.LogDebug("Starting CreateExpense for Project {ProjectId}", dto.ProjectId); + // The entire operation is wrapped in a transaction to ensure data consistency. + await using var transaction = await _context.Database.BeginTransactionAsync(); try { @@ -299,7 +301,14 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => es.StatusId == Draft && es.Status != null).ToListAsync(); + .Where(es => es.StatusId == Draft && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }) + .FirstOrDefaultAsync(); }); @@ -327,10 +336,11 @@ namespace Marco.Pms.Services.Service if (paidBy == null) validationErrors.Add("Paid by employee not found"); if (expenseType == null) validationErrors.Add("Expense Type not found."); if (paymentMode == null) validationErrors.Add("Payment Mode not found."); - if (!statusMapping.Any()) validationErrors.Add("Default status 'Draft' not found."); + if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found."); if (validationErrors.Any()) { + await transaction.RollbackAsync(); var errorMessage = string.Join(" ", validationErrors); _logger.LogWarning("Expense creation failed due to validation errors: {ValidationErrors}", errorMessage); return ApiResponse.ErrorResponse("Invalid input data.", errorMessage, 400); @@ -355,13 +365,14 @@ namespace Marco.Pms.Services.Service // 5. Database Commit await _context.SaveChangesAsync(); - var status = statusMapping.Select(sm => sm.Status).FirstOrDefault(); - var nextStatus = statusMapping.Select(sm => sm.NextStatus).ToList(); + // 6. Transaction Commit + await transaction.CommitAsync(); + var response = _mapper.Map(expense); response.PaidBy = _mapper.Map(paidBy); response.Project = _mapper.Map(project); - response.Status = _mapper.Map(status); - response.NextStatus = _mapper.Map>(nextStatus); + response.Status = _mapper.Map(statusMapping!.Status); + response.NextStatus = _mapper.Map>(statusMapping.NextStatus); response.PaymentMode = _mapper.Map(paymentMode); response.ExpensesType = _mapper.Map(expenseType); @@ -370,6 +381,7 @@ namespace Marco.Pms.Services.Service } catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation { + await transaction.RollbackAsync(); _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("Invalid Request Data.", new { @@ -386,6 +398,7 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) { + await transaction.RollbackAsync(); _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("An internal server error occurred.", new { From 5be154a9f14974354f859053cfd3659aeb55d789 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 22 Jul 2025 09:58:13 +0530 Subject: [PATCH 20/81] Added totalPages , totalEntites and Currect page in response of get expenses list --- .../Data/ApplicationDbContext.cs | 2 +- ...8_Added_Expense_Related_Tables.Designer.cs | 2 +- ...0721124928_Added_Expense_Related_Tables.cs | 5 +- .../ApplicationDbContextModelSnapshot.cs | 2 +- Marco.Pms.Services/Service/ExpensesService.cs | 164 ++---------------- 5 files changed, 20 insertions(+), 155 deletions(-) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 85ea792..82e1e68 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -395,7 +395,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Draft", DisplayName = "Draft", Description = "Expense has been created but not yet submitted.", - Color = "#212529", + Color = "#6c757d", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index ad83f62..27368b8 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1934,7 +1934,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Color = "#212529", + Color = "#6c757d", Description = "Expense has been created but not yet submitted.", DisplayName = "Draft", IsActive = true, diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index 1d1e2f9..22a0444 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; #nullable disable @@ -373,7 +372,7 @@ namespace Marco.Pms.DataAccess.Migrations columns: new[] { "Id", "Color", "Description", "DisplayName", "IsActive", "IsSystem", "Name", "TenantId" }, values: new object[,] { - { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#212529", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#6c757d", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#0dcaf0", "Review is completed, waiting for action of approver.", "Approve", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#198754", "Expense has been settled.", "Paid", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#0d6efd", "Reviewer is currently reviewing the expense.", "Review", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index c15054f..242e512 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1931,7 +1931,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Color = "#212529", + Color = "#6c757d", Description = "Expense has been created but not yet submitted.", DisplayName = "Draft", IsActive = true, diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 9ea150f..8d1c974 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -155,6 +155,9 @@ namespace Marco.Pms.Services.Service // 4. --- Apply Ordering and Pagination --- // This should be the last step before executing the query. + + var totalEntites = await expensesQuery.CountAsync(); + var paginatedQuery = expensesQuery .OrderByDescending(e => e.CreatedAt) .Skip((pageNumber - 1) * pageSize) @@ -169,7 +172,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200); } - var response = _mapper.Map>(expensesList); + var expenseVM = _mapper.Map>(expensesList); // 6. --- Efficiently Fetch and Append 'Next Status' Information --- var statusIds = expensesList.Select(e => e.StatusId).Distinct().ToList(); @@ -182,7 +185,7 @@ namespace Marco.Pms.Services.Service // Use a Lookup for efficient O(1) mapping. This is much better than repeated `.Where()` in a loop. var statusMapLookup = statusMappings.ToLookup(sm => sm.StatusId); - foreach (var expense in response) + foreach (var expense in expenseVM) { if (expense.Status?.Id != null && statusMapLookup.Contains(expense.Status.Id)) { @@ -197,8 +200,17 @@ namespace Marco.Pms.Services.Service } // 7. --- Return Final Success Response --- - var message = $"{response.Count} expense records fetched successfully."; + var message = $"{expenseVM.Count} expense records fetched successfully."; _logger.LogInfo(message); + var totalPages = (int)Math.Ceiling((double)totalEntites / pageSize); + var response = new + { + CurrentPage = pageNumber, + TotalPages = totalPages, + TotalEntites = totalEntites, + Data = expenseVM, + }; + return ApiResponse.SuccessResponse(response, message, 200); } catch (DbUpdateException dbEx) @@ -415,152 +427,6 @@ namespace Marco.Pms.Services.Service } } - public async Task> ChangeStatus(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId) - { - - var existingExpense = await _context.Expenses - .Include(e => e.ExpensesType) - .Include(e => e.Project) - .Include(e => e.PaidBy) - .ThenInclude(e => e!.JobRole) - .Include(e => e.PaymentMode) - .Include(e => e.Status) - .Include(e => e.CreatedBy) - .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.StatusId != model.StatusId && e.TenantId == tenantId); - - if (existingExpense == null) - { - return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); - } - - var statusMappingTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMapping - .Include(s => s.NextStatus) - .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.NextStatusId == model.StatusId && s.TenantId == tenantId); - }); - var statusPermissionMappingTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.StatusPermissionMapping.Where(sp => sp.StatusId == model.StatusId).ToListAsync(); - }); - - // Await all prerequisite checks at once. - await Task.WhenAll(statusMappingTask, statusPermissionMappingTask); - - var statusMapping = await statusMappingTask; - var statusPermissions = await statusPermissionMappingTask; - if (statusMapping == null) - { - return ApiResponse.ErrorResponse("There is no follow-up status for currect status"); - } - if (statusPermissions.Any()) - { - foreach (var sp in statusPermissions) - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - - if (!await permissionService.HasPermission(sp.PermissionId, loggedInEmployee.Id)) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to change status of expense from status {StatusId} to {NextStatusId}", - loggedInEmployee.Id, statusMapping.StatusId, statusMapping.NextStatusId); - return ApiResponse.ErrorResponse("You do not have permission", "Access Denied", 403); - } - } - } - else if (existingExpense.CreatedById != loggedInEmployee.Id) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to change status of expense from status {StatusId} to {NextStatusId}", - loggedInEmployee.Id, statusMapping.StatusId, statusMapping.NextStatusId); - return ApiResponse.ErrorResponse("You do not have permission", "Access Denied", 403); - } - var existingEntity = _updateLogHelper.EntityToBsonDocument(existingExpense); - - existingExpense.StatusId = statusMapping.NextStatusId; - existingExpense.Status = statusMapping.NextStatus; - - _context.ExpenseLogs.Add(new ExpenseLog - { - ExpenseId = existingExpense.Id, - Action = statusMapping.NextStatus!.Name, - UpdatedById = loggedInEmployee.Id, - Comment = model.Comment - }); - - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException dbEx) - { - _logger.LogError(dbEx, "Error occured while update status of expanse."); - return ApiResponse.ErrorResponse("Error occured while update status of expanse.", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - innerexcption = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); - } - try - { - var updateLog = new UpdateLogsObject - { - EntityId = existingExpense.Id.ToString(), - UpdatedById = loggedInEmployee.Id.ToString(), - OldObject = existingEntity, - UpdatedAt = DateTime.UtcNow - }; - var mongoDBTask = Task.Run(async () => - { - await _updateLogHelper.PushToUpdateLogsAsync(updateLog, Collection); - }); - - var getNextStatusTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMapping - .Include(s => s.NextStatus) - .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId); - }); - - await Task.WhenAll(mongoDBTask, getNextStatusTask); - - var getNextStatus = await getNextStatusTask; - - var response = _mapper.Map(existingExpense); - if (getNextStatus != null) - { - response.NextStatus = _mapper.Map>(getNextStatus.NextStatus); - } - - return ApiResponse.SuccessResponse(response); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occured while Saving old entity in mongoDb"); - return ApiResponse.ErrorResponse("Error occured while update status of expanse.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - innerexcption = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); - } - } /// /// Changes the status of an expense record, performing validation, permission checks, and logging. /// From cfbfbf2e2b01e60bb5bdaf66d511c0a888968d50 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 22 Jul 2025 10:53:55 +0530 Subject: [PATCH 21/81] Renamed the CacheHelper To Helpers --- .../CacheHelper}/EmployeeCache.cs | 4 +- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 24 +++++ .../CacheHelper}/ProjectCache.cs | 5 +- .../CacheHelper}/ReportCache.cs | 4 +- .../Marco.Pms.Helpers.csproj | 0 .../UpdateLogHelper.cs | 4 +- Marco.Pms.Model/Marco.Pms.Model.csproj | 28 ++--- .../EmployeePermissionMongoDB.cs | 2 +- .../Expenses/ExpenseDetailsMongoDB.cs | 6 ++ .../{ => Masters}/StatusMasterMongoDB.cs | 2 +- .../WorkCategoryMasterMongoDB.cs | 2 +- .../{ => Project}/ActivityMasterMongoDB.cs | 2 +- .../{ => Project}/BuildingMongoDB.cs | 2 +- .../{ => Project}/FloorMongoDB.cs | 2 +- .../{ => Project}/ProjectMongoDB.cs | 4 +- .../{ => Project}/WorkAreaInfoMongoDB.cs | 2 +- .../{ => Project}/WorkAreaMongoDB.cs | 2 +- .../{ => Project}/WorkItemMongoDB.cs | 4 +- .../ProjectReportEmailMongoDB.cs | 2 +- .../{ => Utility}/UpdateLogsObject.cs | 2 +- Marco.Pms.Services/Dockerfile | 2 +- .../Helpers/CacheUpdateHelper.cs | 7 +- Marco.Pms.Services/Helpers/GeneralHelper.cs | 1 + Marco.Pms.Services/Helpers/ReportHelper.cs | 2 +- .../MappingProfiles/MappingProfile.cs | 3 +- Marco.Pms.Services/Marco.Pms.Services.csproj | 90 ++++++++-------- Marco.Pms.Services/Program.cs | 3 +- Marco.Pms.Services/Service/ExpensesService.cs | 102 ++++++++++++++++-- Marco.Pms.Services/Service/ProjectServices.cs | 2 +- marco.pms.api.sln | 2 +- 30 files changed, 220 insertions(+), 97 deletions(-) rename {Marco.Pms.CacheHelper => Marco.Pms.Helpers/CacheHelper}/EmployeeCache.cs (98%) create mode 100644 Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs rename {Marco.Pms.CacheHelper => Marco.Pms.Helpers/CacheHelper}/ProjectCache.cs (99%) rename {Marco.Pms.CacheHelper => Marco.Pms.Helpers/CacheHelper}/ReportCache.cs (95%) rename Marco.Pms.CacheHelper/Marco.Pms.CacheHelper.csproj => Marco.Pms.Helpers/Marco.Pms.Helpers.csproj (100%) rename {Marco.Pms.CacheHelper => Marco.Pms.Helpers}/UpdateLogHelper.cs (97%) rename Marco.Pms.Model/MongoDBModels/{ => Employees}/EmployeePermissionMongoDB.cs (91%) create mode 100644 Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs rename Marco.Pms.Model/MongoDBModels/{ => Masters}/StatusMasterMongoDB.cs (74%) rename Marco.Pms.Model/MongoDBModels/{ => Masters}/WorkCategoryMasterMongoDB.cs (82%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/ActivityMasterMongoDB.cs (80%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/BuildingMongoDB.cs (94%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/FloorMongoDB.cs (93%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/ProjectMongoDB.cs (88%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/WorkAreaInfoMongoDB.cs (89%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/WorkAreaMongoDB.cs (89%) rename Marco.Pms.Model/MongoDBModels/{ => Project}/WorkItemMongoDB.cs (87%) rename Marco.Pms.Model/MongoDBModels/{ => Utility}/ProjectReportEmailMongoDB.cs (91%) rename Marco.Pms.Model/MongoDBModels/{ => Utility}/UpdateLogsObject.cs (90%) diff --git a/Marco.Pms.CacheHelper/EmployeeCache.cs b/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs similarity index 98% rename from Marco.Pms.CacheHelper/EmployeeCache.cs rename to Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs index 7c7f4b4..560748c 100644 --- a/Marco.Pms.CacheHelper/EmployeeCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs @@ -1,9 +1,9 @@ -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Employees; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MongoDB.Driver; -namespace Marco.Pms.CacheHelper +namespace Marco.Pms.Helpers.CacheHelper { public class EmployeeCache { diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs new file mode 100644 index 0000000..8036c5f --- /dev/null +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -0,0 +1,24 @@ +using Marco.Pms.Model.MongoDBModels.Employees; +using Microsoft.Extensions.Configuration; +using MongoDB.Driver; + +namespace Marco.Pms.Helpers.CacheHelper +{ + public class ExpenseCache + { + private readonly IMongoCollection _collection; + public ExpenseCache(IConfiguration configuration) + { + + var connectionString = configuration["MongoDB:ConnectionString"]; + var mongoUrl = new MongoUrl(connectionString); + var client = new MongoClient(mongoUrl); // Your MongoDB connection string + var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name + _collection = mongoDB.GetCollection("Expenses"); + } + public async Task AddExpenseToCacheAsync() + { + + } + } +} diff --git a/Marco.Pms.CacheHelper/ProjectCache.cs b/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs similarity index 99% rename from Marco.Pms.CacheHelper/ProjectCache.cs rename to Marco.Pms.Helpers/CacheHelper/ProjectCache.cs index 10eb623..f5721aa 100644 --- a/Marco.Pms.CacheHelper/ProjectCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs @@ -1,13 +1,14 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Master; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Masters; +using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Projects; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MongoDB.Bson; using MongoDB.Driver; -namespace Marco.Pms.CacheHelper +namespace Marco.Pms.Helpers { public class ProjectCache { diff --git a/Marco.Pms.CacheHelper/ReportCache.cs b/Marco.Pms.Helpers/CacheHelper/ReportCache.cs similarity index 95% rename from Marco.Pms.CacheHelper/ReportCache.cs rename to Marco.Pms.Helpers/CacheHelper/ReportCache.cs index 66611a8..009bdf2 100644 --- a/Marco.Pms.CacheHelper/ReportCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ReportCache.cs @@ -1,8 +1,8 @@ -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Utility; using Microsoft.Extensions.Configuration; using MongoDB.Driver; -namespace Marco.Pms.CacheHelper +namespace Marco.Pms.Helpers.CacheHelper { public class ReportCache { diff --git a/Marco.Pms.CacheHelper/Marco.Pms.CacheHelper.csproj b/Marco.Pms.Helpers/Marco.Pms.Helpers.csproj similarity index 100% rename from Marco.Pms.CacheHelper/Marco.Pms.CacheHelper.csproj rename to Marco.Pms.Helpers/Marco.Pms.Helpers.csproj diff --git a/Marco.Pms.CacheHelper/UpdateLogHelper.cs b/Marco.Pms.Helpers/UpdateLogHelper.cs similarity index 97% rename from Marco.Pms.CacheHelper/UpdateLogHelper.cs rename to Marco.Pms.Helpers/UpdateLogHelper.cs index ddea104..5c7595f 100644 --- a/Marco.Pms.CacheHelper/UpdateLogHelper.cs +++ b/Marco.Pms.Helpers/UpdateLogHelper.cs @@ -1,10 +1,10 @@ -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Utility; using Microsoft.Extensions.Configuration; using MongoDB.Bson; using MongoDB.Driver; using System.Collections; -namespace Marco.Pms.CacheHelper +namespace Marco.Pms.Helpers { public class UpdateLogHelper { diff --git a/Marco.Pms.Model/Marco.Pms.Model.csproj b/Marco.Pms.Model/Marco.Pms.Model.csproj index a1a21a5..332759a 100644 --- a/Marco.Pms.Model/Marco.Pms.Model.csproj +++ b/Marco.Pms.Model/Marco.Pms.Model.csproj @@ -1,20 +1,20 @@ - + - - net7.0 - enable - enable - + + net7.0 + enable + enable + - + - - - - + + + + - - - + + + diff --git a/Marco.Pms.Model/MongoDBModels/EmployeePermissionMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Employees/EmployeePermissionMongoDB.cs similarity index 91% rename from Marco.Pms.Model/MongoDBModels/EmployeePermissionMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Employees/EmployeePermissionMongoDB.cs index fab2b84..07da2ef 100644 --- a/Marco.Pms.Model/MongoDBModels/EmployeePermissionMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Employees/EmployeePermissionMongoDB.cs @@ -1,6 +1,6 @@ using MongoDB.Bson.Serialization.Attributes; -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Employees { [BsonIgnoreExtraElements] public class EmployeePermissionMongoDB diff --git a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs new file mode 100644 index 0000000..e4a1c5c --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs @@ -0,0 +1,6 @@ +namespace Marco.Pms.Model.MongoDBModels.Expenses +{ + public class ExpenseDetailsMongoDB + { + } +} diff --git a/Marco.Pms.Model/MongoDBModels/StatusMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/StatusMasterMongoDB.cs similarity index 74% rename from Marco.Pms.Model/MongoDBModels/StatusMasterMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Masters/StatusMasterMongoDB.cs index 77e8eb5..96a56a6 100644 --- a/Marco.Pms.Model/MongoDBModels/StatusMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Masters/StatusMasterMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Masters { public class StatusMasterMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/WorkCategoryMasterMongoDB.cs similarity index 82% rename from Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Masters/WorkCategoryMasterMongoDB.cs index 4ea4682..4270a25 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkCategoryMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Masters/WorkCategoryMasterMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Masters { public class WorkCategoryMasterMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/ActivityMasterMongoDB.cs similarity index 80% rename from Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/ActivityMasterMongoDB.cs index cc77d96..ecb88c1 100644 --- a/Marco.Pms.Model/MongoDBModels/ActivityMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/ActivityMasterMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Project { public class ActivityMasterMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/BuildingMongoDB.cs similarity index 94% rename from Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/BuildingMongoDB.cs index 786ceb5..640be18 100644 --- a/Marco.Pms.Model/MongoDBModels/BuildingMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/BuildingMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Project { public class BuildingMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/FloorMongoDB.cs similarity index 93% rename from Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/FloorMongoDB.cs index 15d3060..debb663 100644 --- a/Marco.Pms.Model/MongoDBModels/FloorMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/FloorMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Project { public class FloorMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/ProjectMongoDB.cs similarity index 88% rename from Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/ProjectMongoDB.cs index aac0e2c..c2600bd 100644 --- a/Marco.Pms.Model/MongoDBModels/ProjectMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/ProjectMongoDB.cs @@ -1,4 +1,6 @@ -namespace Marco.Pms.Model.MongoDBModels +using Marco.Pms.Model.MongoDBModels.Masters; + +namespace Marco.Pms.Model.MongoDBModels.Project { public class ProjectMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/WorkAreaInfoMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/WorkAreaInfoMongoDB.cs similarity index 89% rename from Marco.Pms.Model/MongoDBModels/WorkAreaInfoMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/WorkAreaInfoMongoDB.cs index da1001b..97da737 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkAreaInfoMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/WorkAreaInfoMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Project { public class WorkAreaInfoMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/WorkAreaMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/WorkAreaMongoDB.cs similarity index 89% rename from Marco.Pms.Model/MongoDBModels/WorkAreaMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/WorkAreaMongoDB.cs index 412c940..d768e3b 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkAreaMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/WorkAreaMongoDB.cs @@ -1,4 +1,4 @@ -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Project { public class WorkAreaMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/WorkItemMongoDB.cs similarity index 87% rename from Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Project/WorkItemMongoDB.cs index cf798f3..00aa168 100644 --- a/Marco.Pms.Model/MongoDBModels/WorkItemMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Project/WorkItemMongoDB.cs @@ -1,4 +1,6 @@ -namespace Marco.Pms.Model.MongoDBModels +using Marco.Pms.Model.MongoDBModels.Masters; + +namespace Marco.Pms.Model.MongoDBModels.Project { public class WorkItemMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/ProjectReportEmailMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Utility/ProjectReportEmailMongoDB.cs similarity index 91% rename from Marco.Pms.Model/MongoDBModels/ProjectReportEmailMongoDB.cs rename to Marco.Pms.Model/MongoDBModels/Utility/ProjectReportEmailMongoDB.cs index 519ea4f..928b814 100644 --- a/Marco.Pms.Model/MongoDBModels/ProjectReportEmailMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Utility/ProjectReportEmailMongoDB.cs @@ -1,7 +1,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Utility { public class ProjectReportEmailMongoDB { diff --git a/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs b/Marco.Pms.Model/MongoDBModels/Utility/UpdateLogsObject.cs similarity index 90% rename from Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs rename to Marco.Pms.Model/MongoDBModels/Utility/UpdateLogsObject.cs index 3153c78..30f87d6 100644 --- a/Marco.Pms.Model/MongoDBModels/UpdateLogsObject.cs +++ b/Marco.Pms.Model/MongoDBModels/Utility/UpdateLogsObject.cs @@ -1,7 +1,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; -namespace Marco.Pms.Model.MongoDBModels +namespace Marco.Pms.Model.MongoDBModels.Utility { public class UpdateLogsObject { diff --git a/Marco.Pms.Services/Dockerfile b/Marco.Pms.Services/Dockerfile index 2aa24ea..50b9865 100644 --- a/Marco.Pms.Services/Dockerfile +++ b/Marco.Pms.Services/Dockerfile @@ -19,7 +19,7 @@ COPY ["Marco.Pms.Services/Marco.Pms.Services.csproj", "Marco.Pms.Services/"] COPY ["Marco.Pms.DataAccess/Marco.Pms.DataAccess.csproj", "Marco.Pms.DataAccess/"] COPY ["Marco.Pms.Model/Marco.Pms.Model.csproj", "Marco.Pms.Model/"] COPY ["Marco.Pms.Utility/Marco.Pms.Utility.csproj", "Marco.Pms.Utility/"] -COPY ["Marco.Pms.CacheHelper/Marco.Pms.CacheHelper.csproj", "Marco.Pms.CacheHelper/"] +COPY ["Marco.Pms.Helpers/Marco.Pms.Helpers.csproj", "Marco.Pms.Helpers/"] RUN dotnet restore "./Marco.Pms.Services/Marco.Pms.Services.csproj" COPY . . WORKDIR "/src/Marco.Pms.Services" diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index d942ab1..1c4deb0 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -1,7 +1,10 @@ -using Marco.Pms.CacheHelper; +using Marco.Pms.Helpers; +using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Master; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Masters; +using Marco.Pms.Model.MongoDBModels.Project; +using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Projects; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; diff --git a/Marco.Pms.Services/Helpers/GeneralHelper.cs b/Marco.Pms.Services/Helpers/GeneralHelper.cs index c2f8fe4..b5bf7dc 100644 --- a/Marco.Pms.Services/Helpers/GeneralHelper.cs +++ b/Marco.Pms.Services/Helpers/GeneralHelper.cs @@ -1,5 +1,6 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Project; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; diff --git a/Marco.Pms.Services/Helpers/ReportHelper.cs b/Marco.Pms.Services/Helpers/ReportHelper.cs index 35dcf8b..5a174e6 100644 --- a/Marco.Pms.Services/Helpers/ReportHelper.cs +++ b/Marco.Pms.Services/Helpers/ReportHelper.cs @@ -2,7 +2,7 @@ using Marco.Pms.Model.Dtos.Attendance; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Mail; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Report; using MarcoBMS.Services.Service; diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index ea34613..33c64bb 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -5,7 +5,8 @@ using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Masters; +using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Projects; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Employee; diff --git a/Marco.Pms.Services/Marco.Pms.Services.csproj b/Marco.Pms.Services/Marco.Pms.Services.csproj index 2feafaf..5b30ba4 100644 --- a/Marco.Pms.Services/Marco.Pms.Services.csproj +++ b/Marco.Pms.Services/Marco.Pms.Services.csproj @@ -1,52 +1,52 @@ - - net8.0 - enable - enable - True - False - 55935cea-fc40-40f8-be42-da094f06b11f - Linux - + + net8.0 + enable + enable + True + False + 55935cea-fc40-40f8-be42-da094f06b11f + Linux + - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + - - - - - - + + + + + + PreserveNewest diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index 6b6bfa5..9e8e736 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -1,4 +1,5 @@ -using Marco.Pms.CacheHelper; +using Marco.Pms.Helpers; +using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Authentication; using Marco.Pms.Model.Entitlements; diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 8d1c974..26f3b21 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1,12 +1,12 @@ using AutoMapper; -using Marco.Pms.CacheHelper; +using Marco.Pms.Helpers; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.DocumentManager; using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Expanses; @@ -29,6 +29,7 @@ namespace Marco.Pms.Services.Service private readonly UpdateLogHelper _updateLogHelper; private readonly IMapper _mapper; private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); + private static readonly Guid Rejected = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); private static readonly string Collection = "ExpensesModificationLog"; public ExpensesService( IDbContextFactory dbContextFactory, @@ -391,9 +392,25 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId); return ApiResponse.SuccessResponse(response, "Expense created successfully.", 201); } - catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation + catch (DbUpdateException dbEx) { await transaction.RollbackAsync(); + _logger.LogError(dbEx, "Databsae Exception occured while adding expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + innerexcption = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation + { _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("Invalid Request Data.", new { @@ -410,7 +427,6 @@ namespace Marco.Pms.Services.Service } catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) { - await transaction.RollbackAsync(); _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); return ApiResponse.ErrorResponse("An internal server error occurred.", new { @@ -615,15 +631,29 @@ namespace Marco.Pms.Services.Service } public async Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId) { - var exsitingExpense = await _context.Expenses.FirstOrDefaultAsync(e => e.Id == model.Id && e.TenantId == tenantId); + var existingExpense = await _context.Expenses + .Include(e => e.ExpensesType) + .Include(e => e.Project) + .Include(e => e.PaidBy) + .ThenInclude(e => e!.JobRole) + .Include(e => e.PaymentMode) + .Include(e => e.Status) + .Include(e => e.CreatedBy) + .FirstOrDefaultAsync(e => + e.Id == model.Id && + e.CreatedById == loggedInEmployee.Id && + (e.StatusId == Draft || e.StatusId == Rejected) && + e.TenantId == tenantId); - if (exsitingExpense == null) + if (existingExpense == null) { return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); } - _mapper.Map(model, exsitingExpense); - _context.Entry(exsitingExpense).State = EntityState.Modified; + + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes + _mapper.Map(model, existingExpense); + _context.Entry(existingExpense).State = EntityState.Modified; try { @@ -637,8 +667,60 @@ namespace Marco.Pms.Services.Service _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); return ApiResponse.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409); } - var response = _mapper.Map(exsitingExpense); - return ApiResponse.SuccessResponse(response); + try + { + // Task to save the detailed audit log to a separate system (e.g., MongoDB). + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = existingExpense.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, Collection); + + // Task to get all possible next statuses from the *new* current state to help the UI. + // NOTE: This now fetches a list of all possible next states, which is more useful for a UI. + var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t => + { + var dbContext = t.Result; + return dbContext.ExpensesStatusMapping + .Include(s => s.NextStatus) + .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId) + .Select(s => s.NextStatus) // Select only the status object + .ToListAsync() + .ContinueWith(res => + { + dbContext.Dispose(); // Ensure the context is disposed + return res.Result; + }); + }).Unwrap(); + + await Task.WhenAll(mongoDBTask, getNextStatusesTask); + + var nextPossibleStatuses = await getNextStatusesTask; + + var response = _mapper.Map(existingExpense); + if (nextPossibleStatuses != null) + { + // The response DTO should have a property like: public List NextAvailableStatuses { get; set; } + response.NextStatus = _mapper.Map>(nextPossibleStatuses); + } + + return ApiResponse.SuccessResponse(response); + } + catch (Exception ex) + { + // This catch block handles errors from post-save operations like MongoDB logging. + // The primary update was successful, but we must log this failure. + _logger.LogError(ex, "Error occurred during post-save operations for ExpenseId: {ExpenseId} (e.g., audit logging). The primary status change was successful.", existingExpense.Id); + + // We can still return a success response because the main operation succeeded, + // but we should not block the user for a failed audit log. + // Alternatively, if audit logging is critical, you could return an error. + // Here, we choose to return success but log the ancillary failure. + var response = _mapper.Map(existingExpense); + return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); + } } public void Delete(int id) diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index 9406ec9..894ba81 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -5,7 +5,7 @@ using Marco.Pms.Model.Activities; using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Employee; diff --git a/marco.pms.api.sln b/marco.pms.api.sln index 424b709..cb6aefe 100644 --- a/marco.pms.api.sln +++ b/marco.pms.api.sln @@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marco.Pms.Utility", "Marco. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.Services", "Marco.Pms.Services\Marco.Pms.Services.csproj", "{27A83653-5B7F-4135-9886-01594D54AFAE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.CacheHelper", "Marco.Pms.CacheHelper\Marco.Pms.CacheHelper.csproj", "{1A105C22-4ED7-4F54-8834-6923DDD96852}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.Helpers", "Marco.Pms.Helpers\Marco.Pms.Helpers.csproj", "{1A105C22-4ED7-4F54-8834-6923DDD96852}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From d536b9c99c3ff09a0287dada19fbc676c2eefe27 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 22 Jul 2025 14:23:39 +0530 Subject: [PATCH 22/81] Added proper namespances and changed the getProjectdetails to getProjectDetailsOld --- Marco.Pms.Services/Controllers/ProjectController.cs | 2 +- Marco.Pms.Services/Controllers/ReportController.cs | 2 +- Marco.Pms.Services/Helpers/GeneralHelper.cs | 2 +- Marco.Pms.Services/Program.cs | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 796fd39..2c03d69 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -135,7 +135,7 @@ namespace MarcoBMS.Services.Controllers var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectDetailsAsync(id, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectDetailsOldAsync(id, tenantId, loggedInEmployee); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Controllers/ReportController.cs b/Marco.Pms.Services/Controllers/ReportController.cs index a46c391..e71061c 100644 --- a/Marco.Pms.Services/Controllers/ReportController.cs +++ b/Marco.Pms.Services/Controllers/ReportController.cs @@ -1,7 +1,7 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Mail; using Marco.Pms.Model.Mail; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Services.Helpers; using MarcoBMS.Services.Helpers; diff --git a/Marco.Pms.Services/Helpers/GeneralHelper.cs b/Marco.Pms.Services/Helpers/GeneralHelper.cs index b5bf7dc..8669811 100644 --- a/Marco.Pms.Services/Helpers/GeneralHelper.cs +++ b/Marco.Pms.Services/Helpers/GeneralHelper.cs @@ -1,5 +1,5 @@ using Marco.Pms.DataAccess.Data; -using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index 9e8e736..a89e16e 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -1,6 +1,6 @@ +using Marco.Pms.DataAccess.Data; using Marco.Pms.Helpers; using Marco.Pms.Helpers.CacheHelper; -using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Authentication; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Utilities; @@ -193,6 +193,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); #endregion // Singleton services (one instance for the app's lifetime) From 73cf85a1cc262d7fc5e556c775823b3b41f1ebfc Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 09:56:01 +0530 Subject: [PATCH 23/81] Added cache to expenses get list and create expense APIs --- .../CacheHelper/EmployeeCache.cs | 9 +- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 89 +++++- Marco.Pms.Helpers/CacheHelper/ProjectCache.cs | 15 +- .../Dtos/Projects/ProjectAllocationDot.cs | 2 - .../Employees/BasicEmployeeMongoDB.cs | 13 + .../Expenses/ExpenseDetailsMongoDB.cs | 22 ++ .../Masters/ExpensesStatusMasterMongoDB.cs | 13 + .../Masters/ExpensesTypeMasterMongoDB.cs | 11 + .../Masters/PaymentModeMatserMongoDB.cs | 10 + .../Project/ProjectBasicMongoDB.cs | 10 + .../Helpers/CacheUpdateHelper.cs | 188 ++++++++++++- .../MappingProfiles/MappingProfile.cs | 134 +++++++++ Marco.Pms.Services/Service/ExpensesService.cs | 256 +++++++++++------- 13 files changed, 642 insertions(+), 130 deletions(-) create mode 100644 Marco.Pms.Model/MongoDBModels/Employees/BasicEmployeeMongoDB.cs create mode 100644 Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs create mode 100644 Marco.Pms.Model/MongoDBModels/Masters/ExpensesTypeMasterMongoDB.cs create mode 100644 Marco.Pms.Model/MongoDBModels/Masters/PaymentModeMatserMongoDB.cs create mode 100644 Marco.Pms.Model/MongoDBModels/Project/ProjectBasicMongoDB.cs diff --git a/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs b/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs index 560748c..3e08484 100644 --- a/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/EmployeeCache.cs @@ -27,6 +27,7 @@ namespace Marco.Pms.Helpers.CacheHelper var update = Builders.Update .AddToSetEach(e => e.ApplicationRoleIds, newRoleIds) + .Set(r => r.ExpireAt, DateTime.UtcNow.Date.AddDays(1)) .AddToSetEach(e => e.PermissionIds, newPermissionIds); var options = new UpdateOptions { IsUpsert = true }; @@ -46,6 +47,7 @@ namespace Marco.Pms.Helpers.CacheHelper var filter = Builders.Filter.Eq(e => e.Id, employeeId.ToString()); var update = Builders.Update + .Set(r => r.ExpireAt, DateTime.UtcNow.Date.AddDays(1)) .AddToSetEach(e => e.ProjectIds, newprojectIds); var result = await _collection.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); @@ -187,17 +189,12 @@ namespace Marco.Pms.Helpers.CacheHelper // A private method to handle the one-time setup of the collection's indexes. private async Task InitializeCollectionAsync() { - // 1. Define the TTL (Time-To-Live) index on the 'ExpireAt' field. var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); var indexOptions = new CreateIndexOptions { - // This tells MongoDB to automatically delete documents when their 'ExpireAt' time is reached. - ExpireAfter = TimeSpan.FromSeconds(0) + ExpireAfter = TimeSpan.Zero // required for fixed expiration time }; var indexModel = new CreateIndexModel(indexKeys, indexOptions); - - // 2. Create the index. This is an idempotent operation if the index already exists. - // Use CreateOneAsync since we are only creating a single index. await _collection.Indexes.CreateOneAsync(indexModel); } } diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 8036c5f..5e63178 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -1,4 +1,5 @@ -using Marco.Pms.Model.MongoDBModels.Employees; +using Marco.Pms.Model.MongoDBModels.Expenses; +using Marco.Pms.Model.Utilities; using Microsoft.Extensions.Configuration; using MongoDB.Driver; @@ -6,7 +7,7 @@ namespace Marco.Pms.Helpers.CacheHelper { public class ExpenseCache { - private readonly IMongoCollection _collection; + private readonly IMongoCollection _collection; public ExpenseCache(IConfiguration configuration) { @@ -14,11 +15,91 @@ namespace Marco.Pms.Helpers.CacheHelper var mongoUrl = new MongoUrl(connectionString); var client = new MongoClient(mongoUrl); // Your MongoDB connection string var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name - _collection = mongoDB.GetCollection("Expenses"); + _collection = mongoDB.GetCollection("Expenses"); } - public async Task AddExpenseToCacheAsync() + public async Task AddExpenseToCacheAsync(ExpenseDetailsMongoDB expense) { + await _collection.InsertOneAsync(expense); + await InitializeCollectionAsync(); + } + public async Task AddExpensesListToCacheAsync(List expenses) + { + // 1. Add a guard clause to avoid an unnecessary database call for an empty list. + if (expenses == null || !expenses.Any()) + { + return; + } + + // 2. Perform the insert operation. This is the only responsibility of this method. + await _collection.InsertManyAsync(expenses); + await InitializeCollectionAsync(); + } + public async Task<(int totalPages, long totalCount, List expenseList)> GetExpenseListFromCacheAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll, + bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? expenseFilter) + { + var filterBuilder = Builders.Filter; + var filter = filterBuilder.Empty; + + // Permission-based filter + if (!viewAll && viewSelf) + { + filter &= filterBuilder.Eq(e => e.CreatedById, loggedInEmployeeId.ToString()); + } + + // Apply filters + if (expenseFilter != null) + { + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + { + filter &= filterBuilder.Gte(e => e.CreatedAt, expenseFilter.StartDate.Value.Date) + & filterBuilder.Lte(e => e.CreatedAt, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1)); + } + + if (expenseFilter.ProjectIds?.Any() == true) + { + filter &= filterBuilder.In(e => e.ProjectId, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList()); + } + + if (expenseFilter.StatusIds?.Any() == true) + { + filter &= filterBuilder.In(e => e.StatusId, expenseFilter.StatusIds.Select(p => p.ToString()).ToList()); + } + + if (expenseFilter.PaidById?.Any() == true) + { + filter &= filterBuilder.In(e => e.PaidById, expenseFilter.PaidById.Select(p => p.ToString()).ToList()); + } + + if (expenseFilter.CreatedByIds?.Any() == true && viewAll) + { + filter &= filterBuilder.In(e => e.CreatedById, expenseFilter.CreatedByIds.Select(p => p.ToString()).ToList()); + } + } + + // Total count + var totalCount = await _collection.CountDocumentsAsync(filter); + var totalPages = (int)Math.Ceiling((double)totalCount / pageSize); + + // Fetch paginated data + var expenses = await _collection + .Find(filter) + .Skip((pageNumber - 1) * pageSize) + .Limit(pageSize) + .SortByDescending(e => e.CreatedAt) + .ToListAsync(); + + return (totalPages, totalCount, expenses); + } + private async Task InitializeCollectionAsync() + { + var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); + var indexOptions = new CreateIndexOptions + { + ExpireAfter = TimeSpan.Zero // required for fixed expiration time + }; + var indexModel = new CreateIndexModel(indexKeys, indexOptions); + await _collection.Indexes.CreateOneAsync(indexModel); } } } diff --git a/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs b/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs index f5721aa..bee37af 100644 --- a/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ProjectCache.cs @@ -30,13 +30,7 @@ namespace Marco.Pms.Helpers { await _projectCollection.InsertOneAsync(projectDetails); - var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); - var indexOptions = new CreateIndexOptions - { - ExpireAfter = TimeSpan.Zero // required for fixed expiration time - }; - var indexModel = new CreateIndexModel(indexKeys, indexOptions); - await _projectCollection.Indexes.CreateOneAsync(indexModel); + await InitializeCollectionAsync(); } public async Task AddProjectDetailsListToCache(List projectDetailsList) @@ -53,17 +47,12 @@ namespace Marco.Pms.Helpers } private async Task InitializeCollectionAsync() { - // 1. Define the TTL (Time-To-Live) index on the 'ExpireAt' field. var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); var indexOptions = new CreateIndexOptions { - // This tells MongoDB to automatically delete documents when their 'ExpireAt' time is reached. - ExpireAfter = TimeSpan.FromSeconds(0) + ExpireAfter = TimeSpan.Zero // required for fixed expiration time }; var indexModel = new CreateIndexModel(indexKeys, indexOptions); - - // 2. Create the index. This is an idempotent operation if the index already exists. - // Use CreateOneAsync since we are only creating a single index. await _projectCollection.Indexes.CreateOneAsync(indexModel); } public async Task UpdateProjectDetailsOnlyToCache(Project project, StatusMaster projectStatus) diff --git a/Marco.Pms.Model/Dtos/Projects/ProjectAllocationDot.cs b/Marco.Pms.Model/Dtos/Projects/ProjectAllocationDot.cs index 7a1fd91..0805e62 100644 --- a/Marco.Pms.Model/Dtos/Projects/ProjectAllocationDot.cs +++ b/Marco.Pms.Model/Dtos/Projects/ProjectAllocationDot.cs @@ -5,7 +5,6 @@ public Guid EmpID { get; set; } public Guid JobRoleId { get; set; } public Guid ProjectId { get; set; } - public bool Status { get; set; } } @@ -14,7 +13,6 @@ { public Guid ProjectId { get; set; } public Guid JobRoleId { get; set; } - public bool Status { get; set; } } } diff --git a/Marco.Pms.Model/MongoDBModels/Employees/BasicEmployeeMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Employees/BasicEmployeeMongoDB.cs new file mode 100644 index 0000000..bff2e62 --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Employees/BasicEmployeeMongoDB.cs @@ -0,0 +1,13 @@ +namespace Marco.Pms.Model.MongoDBModels.Employees +{ + public class BasicEmployeeMongoDB + { + public string Id { get; set; } = string.Empty; + public string? FirstName { get; set; } + public string? LastName { get; set; } + public byte[]? Photo { get; set; } + public string? JobRoleId { get; set; } + public string? JobRoleName { get; set; } + public string TenantId { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs index e4a1c5c..c0ffdd9 100644 --- a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs @@ -2,5 +2,27 @@ { public class ExpenseDetailsMongoDB { + public string Id { get; set; } = string.Empty; + public string ProjectId { get; set; } = string.Empty; + public string ExpensesTypeId { get; set; } = string.Empty; + public string PaymentModeId { get; set; } = string.Empty; + public string PaidById { get; set; } = string.Empty; + public string CreatedById { get; set; } = string.Empty; + public DateTime TransactionDate { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime ExpireAt { get; set; } = DateTime.UtcNow.Date.AddDays(1); + public string SupplerName { get; set; } = string.Empty; + public double Amount { get; set; } + public string StatusId { get; set; } = string.Empty; + public bool PreApproved { get; set; } = false; + public string? TransactionId { get; set; } + public string Description { get; set; } = string.Empty; + public string? Location { get; set; } + public List S3Key { get; set; } = new List(); + public List? ThumbS3Key { get; set; } + public string? GSTNumber { get; set; } + public int? NoOfPersons { get; set; } + public bool IsActive { get; set; } = true; + public string TenantId { get; set; } = string.Empty; } } diff --git a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs new file mode 100644 index 0000000..8fe3910 --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs @@ -0,0 +1,13 @@ +namespace Marco.Pms.Model.MongoDBModels.Masters +{ + public class ExpensesStatusMasterMongoDB + { + public string Id { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string? Color { get; set; } + public bool IsSystem { get; set; } = false; + public string TenantId { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesTypeMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesTypeMasterMongoDB.cs new file mode 100644 index 0000000..d4b80ad --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesTypeMasterMongoDB.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.MongoDBModels.Masters +{ + public class ExpensesTypeMasterMongoDB + { + public string Id { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public bool NoOfPersonsRequired { get; set; } + public string Description { get; set; } = string.Empty; + public string TenantId { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/MongoDBModels/Masters/PaymentModeMatserMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/PaymentModeMatserMongoDB.cs new file mode 100644 index 0000000..0d7a74b --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Masters/PaymentModeMatserMongoDB.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.MongoDBModels.Masters +{ + public class PaymentModeMatserMongoDB + { + public string Id { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string TenantId { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/MongoDBModels/Project/ProjectBasicMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Project/ProjectBasicMongoDB.cs new file mode 100644 index 0000000..4d2bd6b --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Project/ProjectBasicMongoDB.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.MongoDBModels.Project +{ + public class ProjectBasicMongoDB + { + public string Id { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string ShortName { get; set; } = string.Empty; + public string TenantId { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 1c4deb0..bbec308 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -1,40 +1,58 @@ -using Marco.Pms.Helpers; -using Marco.Pms.Helpers.CacheHelper; +using AutoMapper; using Marco.Pms.DataAccess.Data; +using Marco.Pms.Helpers; +using Marco.Pms.Helpers.CacheHelper; +using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; +using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Projects; +using Marco.Pms.Model.Utilities; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; +using MongoDB.Driver; using Project = Marco.Pms.Model.Projects.Project; namespace Marco.Pms.Services.Helpers { public class CacheUpdateHelper { + private readonly IDbContextFactory _dbContextFactory; + private readonly ApplicationDbContext _context; + private readonly IMapper _mapper; private readonly ProjectCache _projectCache; private readonly EmployeeCache _employeeCache; private readonly ReportCache _reportCache; + private readonly ExpenseCache _expenseCache; private readonly ILoggingService _logger; - private readonly IDbContextFactory _dbContextFactory; - private readonly ApplicationDbContext _context; private readonly GeneralHelper _generalHelper; + private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); + private static readonly Guid Rejected = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); - public CacheUpdateHelper(ProjectCache projectCache, EmployeeCache employeeCache, ReportCache reportCache, ILoggingService logger, - IDbContextFactory dbContextFactory, ApplicationDbContext context, GeneralHelper generalHelper) + public CacheUpdateHelper( + IMapper mapper, + ProjectCache projectCache, + EmployeeCache employeeCache, + ReportCache reportCache, + ExpenseCache expenseCache, + ILoggingService logger, + IDbContextFactory dbContextFactory, + ApplicationDbContext context, + GeneralHelper generalHelper) { + _mapper = mapper; _projectCache = projectCache; _employeeCache = employeeCache; _reportCache = reportCache; + _expenseCache = expenseCache; _logger = logger; _dbContextFactory = dbContextFactory; _context = context; _generalHelper = generalHelper; } - - // ------------------------------------ Project Details Cache --------------------------------------- + #region ======================================================= Project Details Cache ======================================================= public async Task AddProjectDetails(Project project) { @@ -507,7 +525,9 @@ namespace Marco.Pms.Services.Helpers } } - // ------------------------------------ Project Infrastructure Cache --------------------------------------- + #endregion + + #region ======================================================= Project Infrastructure Cache ======================================================= public async Task AddBuildngInfra(Guid projectId, Building? building = null, Floor? floor = null, WorkArea? workArea = null, Guid? buildingId = null) { @@ -573,7 +593,9 @@ namespace Marco.Pms.Services.Helpers } } - // ------------------------------------------------------- WorkItem ------------------------------------------------------- + #endregion + + #region ======================================================= WorkItem Cache ======================================================= public async Task?> GetWorkItemsByWorkAreaIds(List workAreaIds) { @@ -680,8 +702,10 @@ namespace Marco.Pms.Services.Helpers } } + #endregion + + #region ======================================================= Employee Profile Cache ======================================================= - // ------------------------------------ Employee Profile Cache --------------------------------------- public async Task AddApplicationRole(Guid employeeId, List roleIds) { // 1. Guard Clause: Avoid unnecessary database work if there are no roles to add. @@ -839,8 +863,146 @@ namespace Marco.Pms.Services.Helpers } } + #endregion - // ------------------------------------ Report Cache --------------------------------------- + #region ======================================================= Expenses Cache ======================================================= + public async Task AddExpenseByObjectAsync(Expenses expense) + { + var expenseCache = _mapper.Map(expense); + + try + { + var billAttachments = await _context.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), + ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + }) + .FirstOrDefaultAsync(); ; + if (billAttachments != null) + { + expenseCache.S3Key = billAttachments.S3Keys; + expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); + } + try + { + await _expenseCache.AddExpenseToCacheAsync(expenseCache); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while storing expense related table in cahce"); + } + + } + public async Task AddExpenseByIdAsync(Guid Id, Guid tenantId) + { + var expense = await _context.Expenses.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Id && e.TenantId == tenantId); + var expenseCache = _mapper.Map(expense); + if (expense != null) + { + try + { + var billAttachments = await _context.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), + ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + }) + .FirstOrDefaultAsync(); + if (billAttachments != null) + { + expenseCache.S3Key = billAttachments.S3Keys; + expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); + } + } + try + { + await _expenseCache.AddExpenseToCacheAsync(expenseCache); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while storing expense related table in cahce"); + } + + } + public async Task AddExpensesListToCache(List expenses) + { + var expensesCache = _mapper.Map>(expenses); + var expenseIds = expenses.Select(e => e.Id).ToList(); + try + { + var billAttachments = await _context.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => expenseIds.Contains(ba.ExpensesId) && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + ExpensesId = g.Key, + S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), + ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + }) + .ToListAsync(); + foreach (var expenseCache in expensesCache) + { + expenseCache.S3Key = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.S3Keys).FirstOrDefault() ?? new List(); + expenseCache.ThumbS3Key = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.ThumbS3Keys).FirstOrDefault(); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); + } + + try + { + await _expenseCache.AddExpensesListToCacheAsync(expensesCache); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while saving the list of expenses to Cache"); + } + } + + public async Task<(int totalPages, long totalCount, List? expenseList)> GetExpenseListAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll, + bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? filter) + { + try + { + var (totalPages, totalCount, expenseList) = await _expenseCache.GetExpenseListFromCacheAsync(tenantId, loggedInEmployeeId, viewAll, viewSelf, pageNumber, pageSize, filter); + if (expenseList.Any()) + { + return (totalPages, totalCount, expenseList); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching the list of expenses to Cache"); + } + return (0, 0, null); + } + + #endregion + + #region ======================================================= Report Cache ======================================================= public async Task?> GetProjectReportMail(bool IsSend) { @@ -866,5 +1028,7 @@ namespace Marco.Pms.Services.Helpers _logger.LogError(ex, "Error occured while adding project report mail bodys"); } } + + #endregion } } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 33c64bb..6e4ca8e 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -5,6 +5,8 @@ using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; +using Marco.Pms.Model.MongoDBModels.Employees; +using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Projects; @@ -36,6 +38,23 @@ namespace Marco.Pms.Services.MappingProfiles opt => opt.MapFrom(src => new Guid(src.Id)) ); + CreateMap() + .ForMember( + dest => dest.Id, + // Explicitly and safely convert Guid Id to string Id + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => new Guid(src.Id))) + .ForMember( + dest => dest.ProjectStatusId, + opt => opt.MapFrom(src => Guid.Empty) + ); + CreateMap() .ForMember( dest => dest.Id, @@ -73,6 +92,27 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.JobRoleName, opt => opt.MapFrom(src => src.JobRole != null ? src.JobRole.Name : "")); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.JobRoleName, + opt => opt.MapFrom(src => src.JobRole != null ? src.JobRole.Name : "")) + .ForMember( + dest => dest.JobRoleId, + opt => opt.MapFrom(src => src.JobRoleId.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))) + .ForMember( + dest => dest.JobRoleId, + opt => opt.MapFrom(src => Guid.Parse(src.JobRoleId ?? ""))); #endregion #region ======================================================= Expenses ======================================================= @@ -80,6 +120,62 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.ProjectId, + opt => opt.MapFrom(src => src.ProjectId.ToString())) + .ForMember( + dest => dest.ExpensesTypeId, + opt => opt.MapFrom(src => src.ExpensesTypeId.ToString())) + .ForMember( + dest => dest.PaymentModeId, + opt => opt.MapFrom(src => src.PaymentModeId.ToString())) + .ForMember( + dest => dest.PaidById, + opt => opt.MapFrom(src => src.PaidById.ToString())) + .ForMember( + dest => dest.CreatedById, + opt => opt.MapFrom(src => src.CreatedById.ToString())) + .ForMember( + dest => dest.StatusId, + opt => opt.MapFrom(src => src.StatusId.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))) + .ForMember( + dest => dest.ProjectId, + opt => opt.MapFrom(src => Guid.Parse(src.ProjectId))) + .ForMember( + dest => dest.ExpensesTypeId, + opt => opt.MapFrom(src => Guid.Parse(src.ExpensesTypeId))) + .ForMember( + dest => dest.PaymentModeId, + opt => opt.MapFrom(src => Guid.Parse(src.PaymentModeId))) + .ForMember( + dest => dest.PaidById, + opt => opt.MapFrom(src => Guid.Parse(src.PaidById))) + .ForMember( + dest => dest.CreatedById, + opt => opt.MapFrom(src => Guid.Parse(src.CreatedById))) + .ForMember( + dest => dest.StatusId, + opt => opt.MapFrom(src => Guid.Parse(src.StatusId))) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => Guid.Parse(src.TenantId))); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))); #endregion @@ -93,6 +189,44 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))); + + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id.ToString())) + .ForMember( + dest => dest.TenantId, + opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))); + + #endregion } } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 26f3b21..d55b915 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1,7 +1,6 @@ using AutoMapper; -using Marco.Pms.Helpers; using Marco.Pms.DataAccess.Data; -using Marco.Pms.Model.DocumentManager; +using Marco.Pms.Helpers; using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; @@ -12,10 +11,13 @@ using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Expanses; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; +using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Service; +using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; using System.Text.Json; +using Document = Marco.Pms.Model.DocumentManager.Document; namespace Marco.Pms.Services.Service { @@ -27,6 +29,7 @@ namespace Marco.Pms.Services.Service private readonly S3UploadService _s3Service; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly UpdateLogHelper _updateLogHelper; + private readonly CacheUpdateHelper _cache; private readonly IMapper _mapper; private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); private static readonly Guid Rejected = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); @@ -36,6 +39,7 @@ namespace Marco.Pms.Services.Service ApplicationDbContext context, IServiceScopeFactory serviceScopeFactory, UpdateLogHelper updateLogHelper, + CacheUpdateHelper cache, ILoggingService logger, S3UploadService s3Service, IMapper mapper) @@ -43,6 +47,7 @@ namespace Marco.Pms.Services.Service _dbContextFactory = dbContextFactory; _context = context; _logger = logger; + _cache = cache; _serviceScopeFactory = serviceScopeFactory; _updateLogHelper = updateLogHelper; _s3Service = s3Service; @@ -73,7 +78,8 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("User not found or not authenticated.", 403); } Guid loggedInEmployeeId = loggedInEmployee.Id; - + List expenseVM = new List(); + var totalEntites = 0; var hasViewSelfPermissionTask = Task.Run(async () => { using var scope = _serviceScopeFactory.CreateScope(); @@ -90,120 +96,103 @@ namespace Marco.Pms.Services.Service await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask); - // 2. --- Build Base Query and Apply Permissions --- - // Start with a base IQueryable. Filters will be chained onto this. - var expensesQuery = _context.Expenses - .Include(e => e.ExpensesType) - .Include(e => e.Project) - .Include(e => e.PaidBy) - .ThenInclude(e => e!.JobRole) - .Include(e => e.PaymentMode) - .Include(e => e.Status) - .Include(e => e.CreatedBy) - .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. - - // Apply permission-based filtering BEFORE any other filters or pagination. - if (hasViewAllPermissionTask.Result) - { - // User has 'View All' permission, no initial restriction on who created the expense. - _logger.LogInfo("User {EmployeeId} has 'View All' permission.", loggedInEmployeeId); - } - else if (hasViewSelfPermissionTask.Result) - { - // User only has 'View Self' permission, so restrict the query to their own expenses. - _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); - expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); - } - else + if (!hasViewAllPermissionTask.Result && !hasViewSelfPermissionTask.Result) { // User has neither required permission. Deny access. _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId); return ApiResponse.SuccessResponse(new List(), "You do not have permission to view any expenses.", 200); } - // 3. --- Deserialize Filter and Apply --- + + // 2. --- Deserialize Filter and Apply --- ExpensesFilter? expenseFilter = TryDeserializeFilter(filter); - if (expenseFilter != null) + var (totalPages, totalCount, expenseList) = await _cache.GetExpenseListAsync(tenantId, loggedInEmployeeId, hasViewAllPermissionTask.Result, hasViewSelfPermissionTask.Result, + pageNumber, pageSize, expenseFilter); + + if (expenseList == null) { - // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. - if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + + // 3. --- Build Base Query and Apply Permissions --- + // Start with a base IQueryable. Filters will be chained onto this. + var expensesQuery = _context.Expenses + .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. + + await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync()); + + // Apply permission-based filtering BEFORE any other filters or pagination. + + if (!hasViewAllPermissionTask.Result && hasViewSelfPermissionTask.Result) { - expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + // User only has 'View Self' permission, so restrict the query to their own expenses. + _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); + expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); } - if (expenseFilter.ProjectIds?.Any() == true) + if (expenseFilter != null) { - expensesQuery = expensesQuery.Where(e => expenseFilter.ProjectIds.Contains(e.ProjectId)); + // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + { + expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + } + + if (expenseFilter.ProjectIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.ProjectIds.Contains(e.ProjectId)); + } + + if (expenseFilter.StatusIds?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.StatusIds.Contains(e.StatusId)); + } + + if (expenseFilter.PaidById?.Any() == true) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById)); + } + + // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. + if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermissionTask.Result) + { + expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); + } + + + } - if (expenseFilter.StatusIds?.Any() == true) + // 4. --- Apply Ordering and Pagination --- + // This should be the last step before executing the query. + + totalEntites = await expensesQuery.CountAsync(); + + var paginatedQuery = expensesQuery + .OrderByDescending(e => e.CreatedAt) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + // 5. --- Execute Query and Map Results --- + var expensesList = await paginatedQuery.ToListAsync(); + + if (!expensesList.Any()) { - expensesQuery = expensesQuery.Where(e => expenseFilter.StatusIds.Contains(e.StatusId)); + _logger.LogInfo("No expenses found matching the criteria for employee {EmployeeId}.", loggedInEmployeeId); + return ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200); } - if (expenseFilter.PaidById?.Any() == true) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById)); - } + expenseVM = await GetAllExpnesRelatedTables(expensesList); + - // Only allow filtering by 'CreatedBy' if the user has 'View All' permission. - if (expenseFilter.CreatedByIds?.Any() == true && hasViewAllPermissionTask.Result) - { - expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); - } } - - // 4. --- Apply Ordering and Pagination --- - // This should be the last step before executing the query. - - var totalEntites = await expensesQuery.CountAsync(); - - var paginatedQuery = expensesQuery - .OrderByDescending(e => e.CreatedAt) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize); - - // 5. --- Execute Query and Map Results --- - var expensesList = await paginatedQuery.ToListAsync(); - - if (!expensesList.Any()) + else { - _logger.LogInfo("No expenses found matching the criteria for employee {EmployeeId}.", loggedInEmployeeId); - return ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200); + expenseVM = await GetAllExpnesRelatedTables(_mapper.Map>(expenseList)); + totalEntites = (int)totalCount; } - - var expenseVM = _mapper.Map>(expensesList); - - // 6. --- Efficiently Fetch and Append 'Next Status' Information --- - var statusIds = expensesList.Select(e => e.StatusId).Distinct().ToList(); - - var statusMappings = await _context.ExpensesStatusMapping - .Include(sm => sm.NextStatus) - .Where(sm => statusIds.Contains(sm.StatusId)) - .ToListAsync(); - - // Use a Lookup for efficient O(1) mapping. This is much better than repeated `.Where()` in a loop. - var statusMapLookup = statusMappings.ToLookup(sm => sm.StatusId); - - foreach (var expense in expenseVM) - { - if (expense.Status?.Id != null && statusMapLookup.Contains(expense.Status.Id)) - { - expense.NextStatus = statusMapLookup[expense.Status.Id] - .Select(sm => _mapper.Map(sm.NextStatus)) - .ToList(); - } - else - { - expense.NextStatus = new List(); // Ensure it's never null - } - } - // 7. --- Return Final Success Response --- var message = $"{expenseVM.Count} expense records fetched successfully."; _logger.LogInfo(message); - var totalPages = (int)Math.Ceiling((double)totalEntites / pageSize); var response = new { CurrentPage = pageNumber, @@ -211,7 +200,6 @@ namespace Marco.Pms.Services.Service TotalEntites = totalEntites, Data = expenseVM, }; - return ApiResponse.SuccessResponse(response, message, 200); } catch (DbUpdateException dbEx) @@ -381,6 +369,8 @@ namespace Marco.Pms.Services.Service // 6. Transaction Commit await transaction.CommitAsync(); + await _cache.AddExpenseByObjectAsync(expense); + var response = _mapper.Map(expense); response.PaidBy = _mapper.Map(paidBy); response.Project = _mapper.Map(project); @@ -728,6 +718,86 @@ namespace Marco.Pms.Services.Service } #region =================================================================== Helper Functions =================================================================== + private async Task> GetAllExpnesRelatedTables(List model) + { + List expenseList = new List(); + var projectIds = model.Select(m => m.ProjectId).ToList(); + var statusIds = model.Select(m => m.StatusId).ToList(); + var expensesTypeIds = model.Select(m => m.ExpensesTypeId).ToList(); + var paymentModeIds = model.Select(m => m.PaymentModeId).ToList(); + var createdByIds = model.Select(m => m.CreatedById).ToList(); + var paidByIds = model.Select(m => m.PaidById).ToList(); + + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id)).ToListAsync(); + }); + var paidByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Employees.AsNoTracking().Where(e => paidByIds.Contains(e.Id)).ToListAsync(); + }); + var createdByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id)).ToListAsync(); + }); + var expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id)).ToListAsync(); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync(); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + StatusId = g.Key, + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }).ToListAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask); + + var projects = await projectTask; + var expenseTypes = await expenseTypeTask; + var paymentModes = await paymentModeTask; + var statusMappings = await statusMappingTask; + var paidBys = await paidByTask; + var createdBys = await createdByTask; + + expenseList = model.Select(m => + { + var response = _mapper.Map(m); + + response.Project = projects.Where(p => p.Id == m.ProjectId).Select(p => _mapper.Map(p)).FirstOrDefault(); + response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map(p)).FirstOrDefault(); + response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault(); + response.Status = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map(s.Status)).FirstOrDefault(); + response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault(); + response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map(pm)).FirstOrDefault(); + response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map(et)).FirstOrDefault(); + + return response; + }).ToList(); + + return expenseList; + } + /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). /// From 3083083148e434a6894b6edc481343aa16808dbf Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 10:51:58 +0530 Subject: [PATCH 24/81] Created the get Expense details API --- .../Data/ApplicationDbContext.cs | 14 +- .../20250501162003_Initmigration.Designer.cs | 2 +- .../20250501162003_Initmigration.cs | 2 +- ...0_Changed_DataType_ApproverdBY.Designer.cs | 2 +- ...0508055854_Added_IsSystem_Flag.Designer.cs | 2 +- ...dded_WorkCategory_Master_Table.Designer.cs | 2 +- ...y_For_WorkCategery_To_WorkItem.Designer.cs | 2 +- ...13_Changed_Freture_Permissions.Designer.cs | 2 +- ...Added_Directory_Related_Tables.Designer.cs | 2 +- ...ed_ContactProjectMapping_Table.Designer.cs | 2 +- ...53019_Fixed_Typo_Of_ColumnName.Designer.cs | 2 +- ...d_Feature_Directory_Management.Designer.cs | 2 +- ...5939_Added_Mail_Related_Tables.Designer.cs | 2 +- ..._Attendance_Feature_Permission.Designer.cs | 2 +- ...02139_Added_OTP_And_MPIN_Table.Designer.cs | 2 +- ...t_And_Removed_From_MailDetails.Designer.cs | 2 +- ...sUsed_FLag_In_OTPDetails_Table.Designer.cs | 2 +- ..._Name_Column_In_Projects_Table.Designer.cs | 2 +- ...43_Added_TaskAttachments_Table.Designer.cs | 2 +- ...ved_By_In_TaskAllocation_Table.Designer.cs | 2 +- ...orkItemForParentId_Description.Designer.cs | 2 +- ..._New_Status_Master_In_Progress.Designer.cs | 2 +- ...ontacts_And_ContactNotes_Table.Designer.cs | 2 +- ...e_Permissiom_View_All_Employee.Designer.cs | 2 +- ..._Permission_To_ViewTeamMembers.Designer.cs | 2 +- ..._ForeginKey_In_Decuments_Table.Designer.cs | 2 +- ...8_Added_Expense_Related_Tables.Designer.cs | 14 +- ...0721124928_Added_Expense_Related_Tables.cs | 12 +- .../ApplicationDbContextModelSnapshot.cs | 16 +-- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 11 ++ .../ViewModels/Expenses/ExpenseDetailsVM.cs | 31 +++++ .../Controllers/ExpenseController.cs | 6 +- .../Helpers/CacheUpdateHelper.cs | 62 +++++---- .../MappingProfiles/MappingProfile.cs | 6 + Marco.Pms.Services/Service/ExpensesService.cs | 122 +++++++++++++++++- .../ServiceInterfaces/IExpensesService.cs | 1 + 36 files changed, 261 insertions(+), 84 deletions(-) create mode 100644 Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 82e1e68..c01668f 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -215,7 +215,7 @@ namespace Marco.Pms.DataAccess.Data Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), Name = "In Review", Description = "These issues are currently under review", - ColorCode = "#6c757d", + ColorCode = "#8592a3", IsDefault = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") }, @@ -395,7 +395,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Draft", DisplayName = "Draft", Description = "Expense has been created but not yet submitted.", - Color = "#6c757d", + Color = "#8592a3", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -406,7 +406,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Review Pending", DisplayName = "Review", Description = "Reviewer is currently reviewing the expense.", - Color = "#0d6efd", + Color = "#696cff", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -417,7 +417,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Approval Pending", DisplayName = "Approve", Description = "Review is completed, waiting for action of approver.", - Color = "#0dcaf0", + Color = "#03c3ec", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -428,7 +428,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Rejected", DisplayName = "Reject", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", - Color = "#dc3545", + Color = "#ff3e1d", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -439,7 +439,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Process Pending", DisplayName = "Process", Description = "Approved expense is awaiting final payment.", - Color = "#ffc107", + Color = "#ffab00", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") @@ -450,7 +450,7 @@ namespace Marco.Pms.DataAccess.Data Name = "Processed", DisplayName = "Paid", Description = "Expense has been settled.", - Color = "#198754", + Color = "#71dd37", IsSystem = true, IsActive = true, TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") diff --git a/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.Designer.cs index fcb6e0b..331a01e 100644 --- a/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.Designer.cs @@ -1274,7 +1274,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.cs b/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.cs index eb6b5d3..63c4e45 100644 --- a/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.cs +++ b/Marco.Pms.DataAccess/Migrations/20250501162003_Initmigration.cs @@ -1295,7 +1295,7 @@ namespace Marco.Pms.DataAccess.Migrations columns: new[] { "Id", "ColorCode", "Description", "IsDefault", "Name", "TenantId" }, values: new object[,] { - { new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), "#6c757d", "These issues are currently under review", true, "In Review", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), "#8592a3", "These issues are currently under review", true, "In Review", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), "#FFCC99", "This is a newly created issue.", true, "New", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), "#E6FF99", "Assigned to employee or team of employees", true, "Assigned", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), "#99E6FF", "These issues are currently in progress", true, "In Progress", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, diff --git a/Marco.Pms.DataAccess/Migrations/20250505121140_Changed_DataType_ApproverdBY.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250505121140_Changed_DataType_ApproverdBY.Designer.cs index 4ce716b..4f4da8c 100644 --- a/Marco.Pms.DataAccess/Migrations/20250505121140_Changed_DataType_ApproverdBY.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250505121140_Changed_DataType_ApproverdBY.Designer.cs @@ -1216,7 +1216,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250508055854_Added_IsSystem_Flag.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250508055854_Added_IsSystem_Flag.Designer.cs index a43da65..ca6478a 100644 --- a/Marco.Pms.DataAccess/Migrations/20250508055854_Added_IsSystem_Flag.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250508055854_Added_IsSystem_Flag.Designer.cs @@ -1222,7 +1222,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250510074238_Added_WorkCategory_Master_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250510074238_Added_WorkCategory_Master_Table.Designer.cs index 5a16b4c..69834c6 100644 --- a/Marco.Pms.DataAccess/Migrations/20250510074238_Added_WorkCategory_Master_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250510074238_Added_WorkCategory_Master_Table.Designer.cs @@ -1299,7 +1299,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250511170748_Added_Foreign_key_For_WorkCategery_To_WorkItem.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250511170748_Added_Foreign_key_For_WorkCategery_To_WorkItem.Designer.cs index 748eb32..0348ebc 100644 --- a/Marco.Pms.DataAccess/Migrations/20250511170748_Added_Foreign_key_For_WorkCategery_To_WorkItem.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250511170748_Added_Foreign_key_For_WorkCategery_To_WorkItem.Designer.cs @@ -1299,7 +1299,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250513125713_Changed_Freture_Permissions.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250513125713_Changed_Freture_Permissions.Designer.cs index baf9d7f..8db96d1 100644 --- a/Marco.Pms.DataAccess/Migrations/20250513125713_Changed_Freture_Permissions.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250513125713_Changed_Freture_Permissions.Designer.cs @@ -1267,7 +1267,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250514103249_Added_Directory_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250514103249_Added_Directory_Related_Tables.Designer.cs index aad7361..b873cd3 100644 --- a/Marco.Pms.DataAccess/Migrations/20250514103249_Added_Directory_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250514103249_Added_Directory_Related_Tables.Designer.cs @@ -1602,7 +1602,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250517063809_Added_ContactProjectMapping_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250517063809_Added_ContactProjectMapping_Table.Designer.cs index 492cf00..0040f43 100644 --- a/Marco.Pms.DataAccess/Migrations/20250517063809_Added_ContactProjectMapping_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250517063809_Added_ContactProjectMapping_Table.Designer.cs @@ -1626,7 +1626,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250519053019_Fixed_Typo_Of_ColumnName.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250519053019_Fixed_Typo_Of_ColumnName.Designer.cs index 39fe4c3..96a4717 100644 --- a/Marco.Pms.DataAccess/Migrations/20250519053019_Fixed_Typo_Of_ColumnName.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250519053019_Fixed_Typo_Of_ColumnName.Designer.cs @@ -1593,7 +1593,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250524074333_Added_Feature_Directory_Management.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250524074333_Added_Feature_Directory_Management.Designer.cs index 6e2f931..39f365c 100644 --- a/Marco.Pms.DataAccess/Migrations/20250524074333_Added_Feature_Directory_Management.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250524074333_Added_Feature_Directory_Management.Designer.cs @@ -1633,7 +1633,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs index 09c4047..64dfc97 100644 --- a/Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs @@ -1358,7 +1358,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250604094759_Added_Self_Attendance_Feature_Permission.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250604094759_Added_Self_Attendance_Feature_Permission.Designer.cs index c80bbc1..fb39591 100644 --- a/Marco.Pms.DataAccess/Migrations/20250604094759_Added_Self_Attendance_Feature_Permission.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250604094759_Added_Self_Attendance_Feature_Permission.Designer.cs @@ -1366,7 +1366,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250605102139_Added_OTP_And_MPIN_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250605102139_Added_OTP_And_MPIN_Table.Designer.cs index 242339f..1269342 100644 --- a/Marco.Pms.DataAccess/Migrations/20250605102139_Added_OTP_And_MPIN_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250605102139_Added_OTP_And_MPIN_Table.Designer.cs @@ -1425,7 +1425,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250606095355_Added_Subject_In_MailingList_And_Removed_From_MailDetails.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250606095355_Added_Subject_In_MailingList_And_Removed_From_MailDetails.Designer.cs index bdf0ba4..53e758a 100644 --- a/Marco.Pms.DataAccess/Migrations/20250606095355_Added_Subject_In_MailingList_And_Removed_From_MailDetails.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250606095355_Added_Subject_In_MailingList_And_Removed_From_MailDetails.Designer.cs @@ -1425,7 +1425,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250607061133_Added_IsUsed_FLag_In_OTPDetails_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250607061133_Added_IsUsed_FLag_In_OTPDetails_Table.Designer.cs index fe82feb..7b5acc1 100644 --- a/Marco.Pms.DataAccess/Migrations/20250607061133_Added_IsUsed_FLag_In_OTPDetails_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250607061133_Added_IsUsed_FLag_In_OTPDetails_Table.Designer.cs @@ -1428,7 +1428,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250610051758_Added_Short_Name_Column_In_Projects_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250610051758_Added_Short_Name_Column_In_Projects_Table.Designer.cs index c50d6d8..63cdcab 100644 --- a/Marco.Pms.DataAccess/Migrations/20250610051758_Added_Short_Name_Column_In_Projects_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250610051758_Added_Short_Name_Column_In_Projects_Table.Designer.cs @@ -1428,7 +1428,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250612094243_Added_TaskAttachments_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250612094243_Added_TaskAttachments_Table.Designer.cs index 1407de2..f601434 100644 --- a/Marco.Pms.DataAccess/Migrations/20250612094243_Added_TaskAttachments_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250612094243_Added_TaskAttachments_Table.Designer.cs @@ -1811,7 +1811,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250616064217_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250616064217_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs index a00f9f1..cee5400 100644 --- a/Marco.Pms.DataAccess/Migrations/20250616064217_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250616064217_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs @@ -1835,7 +1835,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250618112021_EnhancedWorkItemForParentId_Description.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250618112021_EnhancedWorkItemForParentId_Description.Designer.cs index 4d39cf1..2ce46f8 100644 --- a/Marco.Pms.DataAccess/Migrations/20250618112021_EnhancedWorkItemForParentId_Description.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250618112021_EnhancedWorkItemForParentId_Description.Designer.cs @@ -1835,7 +1835,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250619060620_Added_New_Status_Master_In_Progress.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250619060620_Added_New_Status_Master_In_Progress.Designer.cs index 08ee943..0ea341d 100644 --- a/Marco.Pms.DataAccess/Migrations/20250619060620_Added_New_Status_Master_In_Progress.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250619060620_Added_New_Status_Master_In_Progress.Designer.cs @@ -1817,7 +1817,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250630071352_Added_UpdatedBy_In_Contacts_And_ContactNotes_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250630071352_Added_UpdatedBy_In_Contacts_And_ContactNotes_Table.Designer.cs index 7bc5be3..0a4cef2 100644 --- a/Marco.Pms.DataAccess/Migrations/20250630071352_Added_UpdatedBy_In_Contacts_And_ContactNotes_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250630071352_Added_UpdatedBy_In_Contacts_And_ContactNotes_Table.Designer.cs @@ -1857,7 +1857,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250630073319_Added_New_Feature_Permissiom_View_All_Employee.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250630073319_Added_New_Feature_Permissiom_View_All_Employee.Designer.cs index cfa4dea..43bbdbe 100644 --- a/Marco.Pms.DataAccess/Migrations/20250630073319_Added_New_Feature_Permissiom_View_All_Employee.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250630073319_Added_New_Feature_Permissiom_View_All_Employee.Designer.cs @@ -1857,7 +1857,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250630111659_Changed_Name_Of_Feature_Permission_To_ViewTeamMembers.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250630111659_Changed_Name_Of_Feature_Permission_To_ViewTeamMembers.Designer.cs index 4ddc1f7..a882d1f 100644 --- a/Marco.Pms.DataAccess/Migrations/20250630111659_Changed_Name_Of_Feature_Permission_To_ViewTeamMembers.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250630111659_Changed_Name_Of_Feature_Permission_To_ViewTeamMembers.Designer.cs @@ -1857,7 +1857,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs index c0c77b8..f18d9be 100644 --- a/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs @@ -1862,7 +1862,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index 27368b8..40fe611 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1934,7 +1934,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Color = "#6c757d", + Color = "#8592a3", Description = "Expense has been created but not yet submitted.", DisplayName = "Draft", IsActive = true, @@ -1945,7 +1945,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - Color = "#0d6efd", + Color = "#696cff", Description = "Reviewer is currently reviewing the expense.", DisplayName = "Review", IsActive = true, @@ -1956,7 +1956,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - Color = "#0dcaf0", + Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", DisplayName = "Approve", IsActive = true, @@ -1967,7 +1967,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Color = "#dc3545", + Color = "#ff3e1d", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", DisplayName = "Reject", IsActive = true, @@ -1978,7 +1978,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Color = "#ffc107", + Color = "#ffab00", Description = "Approved expense is awaiting final payment.", DisplayName = "Process", IsActive = true, @@ -1989,7 +1989,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - Color = "#198754", + Color = "#71dd37", Description = "Expense has been settled.", DisplayName = "Paid", IsActive = true, @@ -2535,7 +2535,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index 22a0444..ffc5400 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -372,12 +372,12 @@ namespace Marco.Pms.DataAccess.Migrations columns: new[] { "Id", "Color", "Description", "DisplayName", "IsActive", "IsSystem", "Name", "TenantId" }, values: new object[,] { - { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#6c757d", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#0dcaf0", "Review is completed, waiting for action of approver.", "Approve", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#198754", "Expense has been settled.", "Paid", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#0d6efd", "Reviewer is currently reviewing the expense.", "Review", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#dc3545", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffc107", "Approved expense is awaiting final payment.", "Process", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#8592a3", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Approve", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Paid", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Review", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#ff3e1d", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Process", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); migrationBuilder.InsertData( diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 242e512..3406e12 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -20,7 +20,7 @@ namespace Marco.Pms.DataAccess.Migrations .HasAnnotation("ProductVersion", "8.0.12") .HasAnnotation("Relational:MaxIdentifierLength", 64); - //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => { @@ -1931,7 +1931,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - Color = "#6c757d", + Color = "#8592a3", Description = "Expense has been created but not yet submitted.", DisplayName = "Draft", IsActive = true, @@ -1942,7 +1942,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - Color = "#0d6efd", + Color = "#696cff", Description = "Reviewer is currently reviewing the expense.", DisplayName = "Review", IsActive = true, @@ -1953,7 +1953,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - Color = "#0dcaf0", + Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", DisplayName = "Approve", IsActive = true, @@ -1964,7 +1964,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Color = "#dc3545", + Color = "#ff3e1d", Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", DisplayName = "Reject", IsActive = true, @@ -1975,7 +1975,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Color = "#ffc107", + Color = "#ffab00", Description = "Approved expense is awaiting final payment.", DisplayName = "Process", IsActive = true, @@ -1986,7 +1986,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - Color = "#198754", + Color = "#71dd37", Description = "Expense has been settled.", DisplayName = "Paid", IsActive = true, @@ -2532,7 +2532,7 @@ namespace Marco.Pms.DataAccess.Migrations new { Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), - ColorCode = "#6c757d", + ColorCode = "#8592a3", Description = "These issues are currently under review", IsDefault = true, Name = "In Review", diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 5e63178..02263e2 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -91,6 +91,17 @@ namespace Marco.Pms.Helpers.CacheHelper return (totalPages, totalCount, expenses); } + + public async Task GetExpenseDetailsByIdAsync(Guid id, Guid tenantId) + { + var filter = Builders.Filter.And( + Builders.Filter.Eq(e => e.Id, id.ToString()), + Builders.Filter.Eq(e => e.TenantId, tenantId.ToString()) + ); + var expense = await _collection.Find(filter).FirstOrDefaultAsync(); + + return expense; + } private async Task InitializeCollectionAsync() { var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs new file mode 100644 index 0000000..e44347a --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -0,0 +1,31 @@ +using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.ViewModels.Master; +using Marco.Pms.Model.ViewModels.Projects; + +namespace Marco.Pms.Model.ViewModels.Expenses +{ + public class ExpenseDetailsVM + { + public Guid Id { get; set; } + public ProjectInfoVM? Project { get; set; } + public ExpensesTypeMasterVM? ExpensesType { get; set; } + public PaymentModeMatserVM? PaymentMode { get; set; } + public BasicEmployeeVM? PaidBy { get; set; } + public BasicEmployeeVM? CreatedBy { get; set; } + public DateTime TransactionDate { get; set; } + public DateTime CreatedAt { get; set; } + public string SupplerName { get; set; } = string.Empty; + public double Amount { get; set; } + public ExpensesStatusMasterVM? Status { get; set; } + public List? NextStatus { get; set; } + public bool PreApproved { get; set; } = false; + public string? TransactionId { get; set; } + public string Description { get; set; } = string.Empty; + public string? Location { get; set; } + public List S3Key { get; set; } = new List(); + public List? ThumbS3Key { get; set; } + public string? GSTNumber { get; set; } + public int? NoOfPersons { get; set; } + public bool IsActive { get; set; } = true; + } +} diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 8f3351d..5a17d3d 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -47,9 +47,11 @@ namespace Marco.Pms.Services.Controllers } [HttpGet("details/{id}")] - public string Get(int id) + public async Task GetExpenseDetails(Guid id) { - return "value"; + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetExpenseDetailsAsync(id, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); } /// diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index bbec308..13de18a 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -900,39 +900,43 @@ namespace Marco.Pms.Services.Helpers catch (Exception ex) { _logger.LogError(ex, "Error occurd while storing expense related table in cahce"); + return; } + return; } - public async Task AddExpenseByIdAsync(Guid Id, Guid tenantId) + public async Task AddExpenseByIdAsync(Guid Id, Guid tenantId) { var expense = await _context.Expenses.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Id && e.TenantId == tenantId); var expenseCache = _mapper.Map(expense); - if (expense != null) + if (expense == null) { - try + return null; + } + try + { + var billAttachments = await _context.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new { - var billAttachments = await _context.BillAttachments - .Include(ba => ba.Document) - .AsNoTracking() - .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) - .GroupBy(ba => ba.ExpensesId) - .Select(g => new - { - S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), - ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() - }) - .FirstOrDefaultAsync(); - if (billAttachments != null) - { - expenseCache.S3Key = billAttachments.S3Keys; - expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; - } - } - catch (Exception ex) + S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), + ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + }) + .FirstOrDefaultAsync(); + if (billAttachments != null) { - _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); + expenseCache.S3Key = billAttachments.S3Keys; + expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; } } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); + return null; + } try { await _expenseCache.AddExpenseToCacheAsync(expenseCache); @@ -940,8 +944,12 @@ namespace Marco.Pms.Services.Helpers catch (Exception ex) { _logger.LogError(ex, "Error occurd while storing expense related table in cahce"); + return null; } + return expenseCache; + + } public async Task AddExpensesListToCache(List expenses) { @@ -1000,6 +1008,16 @@ namespace Marco.Pms.Services.Helpers return (0, 0, null); } + public async Task GetExpenseDetailsById(Guid id, Guid tenantId) + { + var response = await _expenseCache.GetExpenseDetailsByIdAsync(id, tenantId); + if (response == null || response.Id == string.Empty) + { + return null; + } + return response; + } + #endregion #region ======================================================= Report Cache ======================================================= diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 6e4ca8e..c21b93d 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -13,6 +13,7 @@ using Marco.Pms.Model.Projects; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Model.ViewModels.Expanses; +using Marco.Pms.Model.ViewModels.Expenses; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; @@ -177,6 +178,11 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.Id, opt => opt.MapFrom(src => Guid.Parse(src.Id))); + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => Guid.Parse(src.Id))); + #endregion #region ======================================================= Master ======================================================= diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index d55b915..a8ea7b8 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -5,10 +5,12 @@ using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; +using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Expanses; +using Marco.Pms.Model.ViewModels.Expenses; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; using Marco.Pms.Services.Helpers; @@ -210,7 +212,7 @@ namespace Marco.Pms.Services.Service Message = dbEx.Message, StackTrace = dbEx.StackTrace, Source = dbEx.Source, - innerexcption = new + InnerException = new { Message = dbEx.InnerException?.Message, StackTrace = dbEx.InnerException?.StackTrace, @@ -226,7 +228,7 @@ namespace Marco.Pms.Services.Service Message = ex.Message, StackTrace = ex.StackTrace, Source = ex.Source, - innerexcption = new + InnerException = new { Message = ex.InnerException?.Message, StackTrace = ex.InnerException?.StackTrace, @@ -236,9 +238,35 @@ namespace Marco.Pms.Services.Service } } - public string Get(int id) + public async Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { - return "value"; + try + { + var expenseDetails = await _cache.GetExpenseDetailsById(id, tenantId); + if (expenseDetails == null) + { + expenseDetails = await _cache.AddExpenseByIdAsync(id, tenantId); + } + var vm = GetAllExpnesRelatedTablesFromMongoDB([expenseDetails]); + return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); + + } + catch (Exception ex) + { + _logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId}.", id); + return ApiResponse.ErrorResponse("An internal server error occurred.", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + InnerException = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } } /// @@ -391,7 +419,7 @@ namespace Marco.Pms.Services.Service Message = dbEx.Message, StackTrace = dbEx.StackTrace, Source = dbEx.Source, - innerexcption = new + InnerException = new { Message = dbEx.InnerException?.Message, StackTrace = dbEx.InnerException?.StackTrace, @@ -407,7 +435,7 @@ namespace Marco.Pms.Services.Service Message = ex.Message, StackTrace = ex.StackTrace, Source = ex.Source, - innerexcption = new + InnerException = new { Message = ex.InnerException?.Message, StackTrace = ex.InnerException?.StackTrace, @@ -423,7 +451,7 @@ namespace Marco.Pms.Services.Service Message = ex.Message, StackTrace = ex.StackTrace, Source = ex.Source, - innerexcption = new + InnerException = new { Message = ex.InnerException?.Message, StackTrace = ex.InnerException?.StackTrace, @@ -716,6 +744,7 @@ namespace Marco.Pms.Services.Service public void Delete(int id) { } + #region =================================================================== Helper Functions =================================================================== private async Task> GetAllExpnesRelatedTables(List model) @@ -797,6 +826,85 @@ namespace Marco.Pms.Services.Service return expenseList; } + private async Task> GetAllExpnesRelatedTablesFromMongoDB(List model) + { + List expenseList = new List(); + var projectIds = model.Select(m => Guid.Parse(m.ProjectId)).ToList(); + var statusIds = model.Select(m => Guid.Parse(m.StatusId)).ToList(); + var expensesTypeIds = model.Select(m => Guid.Parse(m.ExpensesTypeId)).ToList(); + var paymentModeIds = model.Select(m => Guid.Parse(m.PaymentModeId)).ToList(); + var createdByIds = model.Select(m => Guid.Parse(m.CreatedById)).ToList(); + var paidByIds = model.Select(m => Guid.Parse(m.PaidById)).ToList(); + + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id)).ToListAsync(); + }); + var paidByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Employees.AsNoTracking().Where(e => paidByIds.Contains(e.Id)).ToListAsync(); + }); + var createdByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id)).ToListAsync(); + }); + var expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id)).ToListAsync(); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync(); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + StatusId = g.Key, + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }).ToListAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask); + + var projects = await projectTask; + var expenseTypes = await expenseTypeTask; + var paymentModes = await paymentModeTask; + var statusMappings = await statusMappingTask; + var paidBys = await paidByTask; + var createdBys = await createdByTask; + + expenseList = model.Select(m => + { + var response = _mapper.Map(m); + + response.Project = projects.Where(p => p.Id == Guid.Parse(m.ProjectId)).Select(p => _mapper.Map(p)).FirstOrDefault(); + response.PaidBy = paidBys.Where(p => p.Id == Guid.Parse(m.PaidById)).Select(p => _mapper.Map(p)).FirstOrDefault(); + response.CreatedBy = createdBys.Where(e => e.Id == Guid.Parse(m.CreatedById)).Select(e => _mapper.Map(e)).FirstOrDefault(); + response.Status = statusMappings.Where(s => s.StatusId == Guid.Parse(m.StatusId)).Select(s => _mapper.Map(s.Status)).FirstOrDefault(); + response.NextStatus = statusMappings.Where(s => s.StatusId == Guid.Parse(m.StatusId)).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault(); + response.PaymentMode = paymentModes.Where(pm => pm.Id == Guid.Parse(m.PaymentModeId)).Select(pm => _mapper.Map(pm)).FirstOrDefault(); + response.ExpensesType = expenseTypes.Where(et => et.Id == Guid.Parse(m.ExpensesTypeId)).Select(et => _mapper.Map(et)).FirstOrDefault(); + + return response; + }).ToList(); + + return expenseList; + } /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index 2cf2721..75d937a 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -7,6 +7,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces public interface IExpensesService { Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber); + Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId); Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); From 4a762e4983615f424cd4f49ef880feb71a40bf10 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 10:58:16 +0530 Subject: [PATCH 25/81] commented un wanted code --- .../Migrations/ApplicationDbContextModelSnapshot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 3406e12..ed3710f 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -20,7 +20,7 @@ namespace Marco.Pms.DataAccess.Migrations .HasAnnotation("ProductVersion", "8.0.12") .HasAnnotation("Relational:MaxIdentifierLength", 64); - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => { From 0095cd54f650f474ad3c4a90facec6e554dc23fa Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 12:50:42 +0530 Subject: [PATCH 26/81] Added persigned Urls in Expesne Details API --- .../MongoDBModels/DocumentMongoDB.cs | 11 +++ .../Expenses/ExpenseDetailsMongoDB.cs | 3 +- .../ViewModels/DocumentManager/DocumentVM.cs | 8 ++ .../ViewModels/Expenses/ExpenseDetailsVM.cs | 4 +- .../Controllers/AttendanceController.cs | 4 +- .../Controllers/ForumController.cs | 16 ++-- .../Controllers/ImageController.cs | 12 +-- .../Controllers/TaskController.cs | 8 +- .../Controllers/WeatherForecastController.cs | 2 +- .../Helpers/CacheUpdateHelper.cs | 44 +++++++---- .../MappingProfiles/MappingProfile.cs | 11 +++ Marco.Pms.Services/Service/ExpensesService.cs | 77 ++++++++++--------- Marco.Pms.Services/Service/S3UploadService.cs | 3 +- 13 files changed, 126 insertions(+), 77 deletions(-) create mode 100644 Marco.Pms.Model/MongoDBModels/DocumentMongoDB.cs diff --git a/Marco.Pms.Model/MongoDBModels/DocumentMongoDB.cs b/Marco.Pms.Model/MongoDBModels/DocumentMongoDB.cs new file mode 100644 index 0000000..d65af2a --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/DocumentMongoDB.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.MongoDBModels +{ + public class DocumentMongoDB + { + public string DocumentId { get; set; } = string.Empty; + public string FileName { get; set; } = string.Empty; + public string ContentType { get; set; } = string.Empty; + public string S3Key { get; set; } = string.Empty; + public string ThumbS3Key { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs index c0ffdd9..c58a22c 100644 --- a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs @@ -18,8 +18,7 @@ public string? TransactionId { get; set; } public string Description { get; set; } = string.Empty; public string? Location { get; set; } - public List S3Key { get; set; } = new List(); - public List? ThumbS3Key { get; set; } + public List Documents { get; set; } = new List(); public string? GSTNumber { get; set; } public int? NoOfPersons { get; set; } public bool IsActive { get; set; } = true; diff --git a/Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs b/Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs index 4940600..d971ea4 100644 --- a/Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs +++ b/Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs @@ -11,4 +11,12 @@ public string ContentType { get; set; } = string.Empty; public DateTime UploadedAt { get; set; } } + public class BasicDocumentVM + { + public Guid DocumentId { get; set; } + public string FileName { get; set; } = string.Empty; + public string ContentType { get; set; } = string.Empty; + public string? PreSignedUrl { get; set; } + public string? ThumbPreSignedUrl { get; set; } + } } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs index e44347a..34ecc24 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -1,4 +1,5 @@ using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.ViewModels.DocumentManager; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; @@ -22,8 +23,7 @@ namespace Marco.Pms.Model.ViewModels.Expenses public string? TransactionId { get; set; } public string Description { get; set; } = string.Empty; public string? Location { get; set; } - public List S3Key { get; set; } = new List(); - public List? ThumbS3Key { get; set; } + public List Documents { get; set; } = new List(); public string? GSTNumber { get; set; } public int? NoOfPersons { get; set; } public bool IsActive { get; set; } = true; diff --git a/Marco.Pms.Services/Controllers/AttendanceController.cs b/Marco.Pms.Services/Controllers/AttendanceController.cs index 7339966..5af6c67 100644 --- a/Marco.Pms.Services/Controllers/AttendanceController.cs +++ b/Marco.Pms.Services/Controllers/AttendanceController.cs @@ -74,7 +74,7 @@ namespace MarcoBMS.Services.Controllers foreach (var attendanceLog in lstAttendance) { string objectKey = attendanceLog.Document != null ? attendanceLog.Document.S3Key : string.Empty; - string preSignedUrl = string.IsNullOrEmpty(objectKey) ? string.Empty : _s3Service.GeneratePreSignedUrlAsync(objectKey); + string preSignedUrl = string.IsNullOrEmpty(objectKey) ? string.Empty : _s3Service.GeneratePreSignedUrl(objectKey); attendanceLogVMs.Add(attendanceLog.ToAttendanceLogVMFromAttendanceLog(preSignedUrl, preSignedUrl)); } _logger.LogInfo("{count} Attendance records fetched successfully", lstAttendance.Count); @@ -708,7 +708,7 @@ namespace MarcoBMS.Services.Controllers var objectKey = $"tenant-{tenantId}/Employee/{recordAttendanceDot.EmployeeID}/Attendance/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(objectKey); + preSignedUrl = _s3Service.GeneratePreSignedUrl(objectKey); document = new Document { diff --git a/Marco.Pms.Services/Controllers/ForumController.cs b/Marco.Pms.Services/Controllers/ForumController.cs index fb6d0e7..4e3b948 100644 --- a/Marco.Pms.Services/Controllers/ForumController.cs +++ b/Marco.Pms.Services/Controllers/ForumController.cs @@ -129,7 +129,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl)); } @@ -301,7 +301,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } if (attachment.CommentId == null) { @@ -418,7 +418,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl)); } @@ -532,7 +532,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl)); } @@ -606,7 +606,7 @@ namespace Marco.Pms.Services.Controllers _context.TicketAttachments.Add(attachment); await _context.SaveChangesAsync(); - string preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + string preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); TicketAttachmentVM attachmentVM = attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl); ticketAttachmentVMs.Add(attachmentVM); @@ -671,7 +671,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } if (attachment.CommentId == null) { @@ -749,7 +749,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } if (attachment.CommentId == null) { @@ -851,7 +851,7 @@ namespace Marco.Pms.Services.Controllers string preSignedUrl = string.Empty; if (document != null) { - preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(document.S3Key); + preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); } if (attachment.CommentId == null) { diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 9014171..cf046a8 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -220,8 +220,8 @@ namespace Marco.Pms.Services.Controllers Documents = d.Documents?.Select(x => new { Id = x.Id, - thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null), - Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null, + thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrl(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrl(x.S3Key) : null), + Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrl(x.S3Key) : null, UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), UploadedAt = x.UploadedAt, }).ToList(), @@ -334,8 +334,8 @@ namespace Marco.Pms.Services.Controllers Documents = documents?.Select(x => new { Id = x.Id, - thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null), - Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null, + thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrl(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrl(x.S3Key) : null), + Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrl(x.S3Key) : null, UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), UploadedAt = x.UploadedAt, }).ToList(), @@ -382,11 +382,11 @@ namespace Marco.Pms.Services.Controllers // Step 4: Generate pre-signed URLs for thumbnail and full image (if keys exist) string? thumbnailUrl = document.ThumbS3Key != null - ? _s3Service.GeneratePreSignedUrlAsync(document.ThumbS3Key) + ? _s3Service.GeneratePreSignedUrl(document.ThumbS3Key) : null; string? imageUrl = document.S3Key != null - ? _s3Service.GeneratePreSignedUrlAsync(document.S3Key) + ? _s3Service.GeneratePreSignedUrl(document.S3Key) : null; // Step 5: Prepare the response object diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index 6a1921b..9f648ac 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -499,7 +499,7 @@ namespace MarcoBMS.Services.Controllers .ToList(); response.ReportedPreSignedUrls = taskDocs - .Select(d => _s3Service.GeneratePreSignedUrlAsync(d.S3Key)) + .Select(d => _s3Service.GeneratePreSignedUrl(d.S3Key)) .ToList(); // Add team members @@ -532,7 +532,7 @@ namespace MarcoBMS.Services.Controllers var commentVm = comment.ToCommentVMFromTaskComment(); commentVm.PreSignedUrls = commentDocs - .Select(d => _s3Service.GeneratePreSignedUrlAsync(d.S3Key)) + .Select(d => _s3Service.GeneratePreSignedUrl(d.S3Key)) .ToList(); commentVMs.Add(commentVm); @@ -649,7 +649,7 @@ namespace MarcoBMS.Services.Controllers .ToList(); taskVM.PreSignedUrls = taskDocuments - .Select(d => _s3Service.GeneratePreSignedUrlAsync(d.S3Key)) + .Select(d => _s3Service.GeneratePreSignedUrl(d.S3Key)) .ToList(); // Construct CommentVM list with document URLs @@ -667,7 +667,7 @@ namespace MarcoBMS.Services.Controllers var commentVM = comment.ToCommentVMFromTaskComment(); commentVM.PreSignedUrls = commentDocs - .Select(d => _s3Service.GeneratePreSignedUrlAsync(d.S3Key)) + .Select(d => _s3Service.GeneratePreSignedUrl(d.S3Key)) .ToList(); return commentVM; diff --git a/Marco.Pms.Services/Controllers/WeatherForecastController.cs b/Marco.Pms.Services/Controllers/WeatherForecastController.cs index fae8c73..2ffd222 100644 --- a/Marco.Pms.Services/Controllers/WeatherForecastController.cs +++ b/Marco.Pms.Services/Controllers/WeatherForecastController.cs @@ -39,7 +39,7 @@ namespace MarcoBMS.Services.Controllers // return BadRequest("Base64 data is missing"); // var objectKey = await _s3Service.UploadFileAsync(Image.Base64Data, 1, "Forum"); // //var objectKey = await _s3Service.UploadFileAsync(Image.FileName, Image.ContentType); - // var preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(objectKey); + // var preSignedUrl = _s3Service.GeneratePreSignedUrl(objectKey); // return Ok(new // { diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 13de18a..d7466c6 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -4,6 +4,7 @@ using Marco.Pms.Helpers; using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; +using Marco.Pms.Model.MongoDBModels; using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; @@ -872,21 +873,26 @@ namespace Marco.Pms.Services.Helpers try { - var billAttachments = await _context.BillAttachments + var billAttachment = await _context.BillAttachments .Include(ba => ba.Document) .AsNoTracking() .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) .GroupBy(ba => ba.ExpensesId) .Select(g => new { - S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), - ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() }) .FirstOrDefaultAsync(); ; - if (billAttachments != null) + if (billAttachment != null) { - expenseCache.S3Key = billAttachments.S3Keys; - expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; + expenseCache.Documents = billAttachment.Documents; } } catch (Exception ex) @@ -922,14 +928,19 @@ namespace Marco.Pms.Services.Helpers .GroupBy(ba => ba.ExpensesId) .Select(g => new { - S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), - ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() }) .FirstOrDefaultAsync(); if (billAttachments != null) { - expenseCache.S3Key = billAttachments.S3Keys; - expenseCache.ThumbS3Key = billAttachments.ThumbS3Keys; + expenseCache.Documents = billAttachments.Documents; } } catch (Exception ex) @@ -965,14 +976,19 @@ namespace Marco.Pms.Services.Helpers .Select(g => new { ExpensesId = g.Key, - S3Keys = g.Select(ba => ba.Document!.S3Key).ToList(), - ThumbS3Keys = g.Select(ba => ba.Document!.ThumbS3Key ?? ba.Document.S3Key).ToList() + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() }) .ToListAsync(); foreach (var expenseCache in expensesCache) { - expenseCache.S3Key = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.S3Keys).FirstOrDefault() ?? new List(); - expenseCache.ThumbS3Key = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.ThumbS3Keys).FirstOrDefault(); + expenseCache.Documents = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.Documents).FirstOrDefault() ?? new List(); } } catch (Exception ex) diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index c21b93d..5db13c1 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -5,12 +5,14 @@ using Marco.Pms.Model.Dtos.Project; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; +using Marco.Pms.Model.MongoDBModels; using Marco.Pms.Model.MongoDBModels.Employees; using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.Projects; using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.ViewModels.DocumentManager; using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Model.ViewModels.Expanses; using Marco.Pms.Model.ViewModels.Expenses; @@ -234,6 +236,15 @@ namespace Marco.Pms.Services.MappingProfiles #endregion + + #region ======================================================= Document ======================================================= + + CreateMap() + .ForMember( + dest => dest.DocumentId, + opt => opt.MapFrom(src => Guid.Parse(src.DocumentId))); + + #endregion } } } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index a8ea7b8..4da381d 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -184,7 +184,7 @@ namespace Marco.Pms.Services.Service } expenseVM = await GetAllExpnesRelatedTables(expensesList); - + totalPages = (int)Math.Ceiling((double)totalEntites / pageSize); } else @@ -246,8 +246,13 @@ namespace Marco.Pms.Services.Service if (expenseDetails == null) { expenseDetails = await _cache.AddExpenseByIdAsync(id, tenantId); + if (expenseDetails == null) + { + return ApiResponse.ErrorResponse("Expense Not Found", "Expense Not Found", 404); + } } - var vm = GetAllExpnesRelatedTablesFromMongoDB([expenseDetails]); + var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails); + return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); } @@ -826,40 +831,32 @@ namespace Marco.Pms.Services.Service return expenseList; } - private async Task> GetAllExpnesRelatedTablesFromMongoDB(List model) + private async Task GetAllExpnesRelatedTablesFromMongoDB(ExpenseDetailsMongoDB model) { - List expenseList = new List(); - var projectIds = model.Select(m => Guid.Parse(m.ProjectId)).ToList(); - var statusIds = model.Select(m => Guid.Parse(m.StatusId)).ToList(); - var expensesTypeIds = model.Select(m => Guid.Parse(m.ExpensesTypeId)).ToList(); - var paymentModeIds = model.Select(m => Guid.Parse(m.PaymentModeId)).ToList(); - var createdByIds = model.Select(m => Guid.Parse(m.CreatedById)).ToList(); - var paidByIds = model.Select(m => Guid.Parse(m.PaidById)).ToList(); - var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id)).ToListAsync(); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == Guid.Parse(model.ProjectId)); }); var paidByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().Where(e => paidByIds.Contains(e.Id)).ToListAsync(); + return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.PaidById)); }); var createdByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id)).ToListAsync(); + return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.CreatedById)); }); var expenseTypeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id)).ToListAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == Guid.Parse(model.ExpensesTypeId)); }); var paymentModeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id)).ToListAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == Guid.Parse(model.PaymentModeId)); }); var statusMappingTask = Task.Run(async () => { @@ -868,44 +865,50 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) + .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null) .GroupBy(s => s.StatusId) .Select(g => new { - StatusId = g.Key, Status = g.Select(s => s.Status).FirstOrDefault(), NextStatus = g.Select(s => s.NextStatus).ToList() - }).ToListAsync(); + }).FirstOrDefaultAsync(); }); // Await all prerequisite checks at once. await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask); - var projects = await projectTask; - var expenseTypes = await expenseTypeTask; - var paymentModes = await paymentModeTask; - var statusMappings = await statusMappingTask; - var paidBys = await paidByTask; - var createdBys = await createdByTask; + var project = await projectTask; + var expenseType = await expenseTypeTask; + var paymentMode = await paymentModeTask; + var statusMapping = await statusMappingTask; + var paidBy = await paidByTask; + var createdBy = await createdByTask; - expenseList = model.Select(m => + var response = _mapper.Map(model); + + response.Project = _mapper.Map(project); + response.PaidBy = _mapper.Map(paidBy); + response.CreatedBy = _mapper.Map(createdBy); + response.PaymentMode = _mapper.Map(paymentMode); + response.ExpensesType = _mapper.Map(expenseType); + if (statusMapping != null) { - var response = _mapper.Map(m); + response.Status = _mapper.Map(statusMapping.Status); + response.NextStatus = _mapper.Map>(statusMapping.NextStatus); + } - response.Project = projects.Where(p => p.Id == Guid.Parse(m.ProjectId)).Select(p => _mapper.Map(p)).FirstOrDefault(); - response.PaidBy = paidBys.Where(p => p.Id == Guid.Parse(m.PaidById)).Select(p => _mapper.Map(p)).FirstOrDefault(); - response.CreatedBy = createdBys.Where(e => e.Id == Guid.Parse(m.CreatedById)).Select(e => _mapper.Map(e)).FirstOrDefault(); - response.Status = statusMappings.Where(s => s.StatusId == Guid.Parse(m.StatusId)).Select(s => _mapper.Map(s.Status)).FirstOrDefault(); - response.NextStatus = statusMappings.Where(s => s.StatusId == Guid.Parse(m.StatusId)).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault(); - response.PaymentMode = paymentModes.Where(pm => pm.Id == Guid.Parse(m.PaymentModeId)).Select(pm => _mapper.Map(pm)).FirstOrDefault(); - response.ExpensesType = expenseTypes.Where(et => et.Id == Guid.Parse(m.ExpensesTypeId)).Select(et => _mapper.Map(et)).FirstOrDefault(); + foreach (var document in model.Documents) + { + var vm = response.Documents.FirstOrDefault(d => d.DocumentId == Guid.Parse(document.DocumentId)); - return response; - }).ToList(); + vm!.PreSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); + vm!.ThumbPreSignedUrl = _s3Service.GeneratePreSignedUrl(document.ThumbS3Key); + } - return expenseList; + return response; } + /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). /// diff --git a/Marco.Pms.Services/Service/S3UploadService.cs b/Marco.Pms.Services/Service/S3UploadService.cs index b07093c..57a46fa 100644 --- a/Marco.Pms.Services/Service/S3UploadService.cs +++ b/Marco.Pms.Services/Service/S3UploadService.cs @@ -71,8 +71,9 @@ namespace Marco.Pms.Services.Service } - public string GeneratePreSignedUrlAsync(string objectKey) + public string GeneratePreSignedUrl(string objectKey) { + int expiresInMinutes = 10; var request = new GetPreSignedUrlRequest { From 4370d5a350753d2e9852412195a9c30eab6dc0fc Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 16:24:59 +0530 Subject: [PATCH 27/81] Adsing file to delete from S3 in mongoDB while update expenes --- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 10 +++ .../UtilityMongoDBHelper.cs} | 43 +++++++++++- .../MongoDBModels/Utility/S3DeletionObject.cs | 15 ++++ Marco.Pms.Model/Utilities/FileUploadModel.cs | 2 + .../Helpers/CacheUpdateHelper.cs | 45 ++++++++++-- Marco.Pms.Services/Program.cs | 3 +- Marco.Pms.Services/Service/ExpensesService.cs | 69 +++++++++++++++++-- Marco.Pms.Services/Service/S3UploadService.cs | 3 +- 8 files changed, 176 insertions(+), 14 deletions(-) rename Marco.Pms.Helpers/{UpdateLogHelper.cs => Utility/UtilityMongoDBHelper.cs} (63%) create mode 100644 Marco.Pms.Model/MongoDBModels/Utility/S3DeletionObject.cs diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 02263e2..5d29088 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -102,6 +102,16 @@ namespace Marco.Pms.Helpers.CacheHelper return expense; } + + public async Task DeleteExpenseFromCacheAsync(Guid id, Guid tenantId) + { + var filter = Builders.Filter.And( + Builders.Filter.Eq(e => e.Id, id.ToString()), + Builders.Filter.Eq(e => e.TenantId, tenantId.ToString()) + ); + var result = await _collection.DeleteOneAsync(filter); + return result.DeletedCount > 0; + } private async Task InitializeCollectionAsync() { var indexKeys = Builders.IndexKeys.Ascending(x => x.ExpireAt); diff --git a/Marco.Pms.Helpers/UpdateLogHelper.cs b/Marco.Pms.Helpers/Utility/UtilityMongoDBHelper.cs similarity index 63% rename from Marco.Pms.Helpers/UpdateLogHelper.cs rename to Marco.Pms.Helpers/Utility/UtilityMongoDBHelper.cs index 5c7595f..7159850 100644 --- a/Marco.Pms.Helpers/UpdateLogHelper.cs +++ b/Marco.Pms.Helpers/Utility/UtilityMongoDBHelper.cs @@ -1,21 +1,28 @@ using Marco.Pms.Model.MongoDBModels.Utility; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; using System.Collections; -namespace Marco.Pms.Helpers +namespace Marco.Pms.Helpers.Utility { - public class UpdateLogHelper + public class UtilityMongoDBHelper { private readonly IMongoDatabase _mongoDatabase; - public UpdateLogHelper(IConfiguration configuration) + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + public UtilityMongoDBHelper(IConfiguration configuration, ILogger logger) { + _configuration = configuration; + _logger = logger; var connectionString = configuration["MongoDB:ModificationConnectionString"]; var mongoUrl = new MongoUrl(connectionString); var client = new MongoClient(mongoUrl); // Your MongoDB connection string _mongoDatabase = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name } + + #region =================================================================== Update Log Helper Functions =================================================================== public async Task PushToUpdateLogsAsync(UpdateLogsObject oldObject, string collectionName) { var collection = _mongoDatabase.GetCollection(collectionName); @@ -87,5 +94,35 @@ namespace Marco.Pms.Helpers return bson; } + #endregion + + #region =================================================================== S3 deletion Helper Functions =================================================================== + + public async Task PushToS3DeletionAsync(List deletionObject) + { + var bucketName = _configuration["AWS:BucketName"]; + if (bucketName != null) + { + deletionObject = deletionObject.Select(d => new S3DeletionObject + { + BucketName = bucketName, + Key = d.Key, + Deleted = false + }).ToList(); + } + _logger.LogInformation("Delection object for bucket {BucketName} added to mongoDB", bucketName); + try + { + var collection = _mongoDatabase.GetCollection("S3Delection"); + await collection.InsertManyAsync(deletionObject); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while saving delection object for S3 to MogoDB"); + } + _logger.LogInformation("Delection Objects added to MongoDB Successfully"); + } + + #endregion } } diff --git a/Marco.Pms.Model/MongoDBModels/Utility/S3DeletionObject.cs b/Marco.Pms.Model/MongoDBModels/Utility/S3DeletionObject.cs new file mode 100644 index 0000000..bb957de --- /dev/null +++ b/Marco.Pms.Model/MongoDBModels/Utility/S3DeletionObject.cs @@ -0,0 +1,15 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.MongoDBModels.Utility +{ + public class S3DeletionObject + { + [BsonId] + [BsonRepresentation(BsonType.String)] + public Guid Id { get; set; } = Guid.NewGuid(); + public string BucketName { get; set; } = string.Empty; + public string Key { get; set; } = string.Empty; + public bool Deleted { get; set; } = false; + } +} diff --git a/Marco.Pms.Model/Utilities/FileUploadModel.cs b/Marco.Pms.Model/Utilities/FileUploadModel.cs index 93ecb2c..98a6a26 100644 --- a/Marco.Pms.Model/Utilities/FileUploadModel.cs +++ b/Marco.Pms.Model/Utilities/FileUploadModel.cs @@ -2,10 +2,12 @@ { public class FileUploadModel { + public Guid? DocumentId { get; set; } public string? FileName { get; set; } // Name of the file (e.g., "image1.png") public string? Base64Data { get; set; } // Base64-encoded string of the file public string? ContentType { get; set; } // MIME type (e.g., "image/png", "application/pdf") public long FileSize { get; set; } // File size in bytes public string? Description { get; set; } // Optional: Description or purpose of the file + public bool IsActive { get; set; } = true; } } diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index d7466c6..9acf08f 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -1026,12 +1026,49 @@ namespace Marco.Pms.Services.Helpers public async Task GetExpenseDetailsById(Guid id, Guid tenantId) { - var response = await _expenseCache.GetExpenseDetailsByIdAsync(id, tenantId); - if (response == null || response.Id == string.Empty) + try { - return null; + var response = await _expenseCache.GetExpenseDetailsByIdAsync(id, tenantId); + if (response != null && response.Id != string.Empty) + { + return response; + } } - return response; + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching expense details from cache"); + } + return null; + } + + public async Task ReplaceExpenseAsync(Expenses expense) + { + bool response = false; + try + { + response = await _expenseCache.DeleteExpenseFromCacheAsync(expense.Id, expense.TenantId); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while deleting expense from cache"); + } + if (response) + { + await AddExpenseByObjectAsync(expense); + } + + } + public async Task DeleteExpenseAsync(Guid id, Guid tenantId) + { + try + { + var response = await _expenseCache.DeleteExpenseFromCacheAsync(id, tenantId); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while deleting expense from cache"); + } + } #endregion diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index a89e16e..2f8bbac 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -1,6 +1,7 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Helpers; using Marco.Pms.Helpers.CacheHelper; +using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Authentication; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Utilities; @@ -186,7 +187,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); #endregion #region Cache Services diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 4da381d..d37142f 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1,6 +1,6 @@ using AutoMapper; using Marco.Pms.DataAccess.Data; -using Marco.Pms.Helpers; +using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; @@ -30,7 +30,7 @@ namespace Marco.Pms.Services.Service private readonly ILoggingService _logger; private readonly S3UploadService _s3Service; private readonly IServiceScopeFactory _serviceScopeFactory; - private readonly UpdateLogHelper _updateLogHelper; + private readonly UtilityMongoDBHelper _updateLogHelper; private readonly CacheUpdateHelper _cache; private readonly IMapper _mapper; private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); @@ -40,7 +40,7 @@ namespace Marco.Pms.Services.Service IDbContextFactory dbContextFactory, ApplicationDbContext context, IServiceScopeFactory serviceScopeFactory, - UpdateLogHelper updateLogHelper, + UtilityMongoDBHelper updateLogHelper, CacheUpdateHelper cache, ILoggingService logger, S3UploadService s3Service, @@ -690,6 +690,63 @@ namespace Marco.Pms.Services.Service _logger.LogError(ex, "Concurrency conflict while updating project {ProjectId} ", id); return ApiResponse.ErrorResponse("Conflict occurred.", "This project has been modified by someone else. Please refresh and try again.", 409); } + + if (model.BillAttachments?.Any() ?? false) + { + var newBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId == null && ba.IsActive).ToList(); + if (newBillAttachments.Any()) + { + await ProcessAndUploadAttachmentsAsync(newBillAttachments, existingExpense, loggedInEmployee.Id, tenantId); + await _context.SaveChangesAsync(); + } + var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList(); + if (deleteBillAttachments.Any()) + { + var documentIds = deleteBillAttachments.Select(d => d.DocumentId).ToList(); + + var attachmentTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync(); + + dbContext.BillAttachments.RemoveRange(attachments); + await dbContext.SaveChangesAsync(); + }); + var documentsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync(); + + if (documents.Any()) + { + dbContext.Documents.RemoveRange(documents); + await dbContext.SaveChangesAsync(); + + List deletionObject = new List(); + foreach (var document in documents) + { + deletionObject.Add(new S3DeletionObject + { + Key = document.S3Key + }); + if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key) + { + deletionObject.Add(new S3DeletionObject + { + Key = document.ThumbS3Key + }); + } + } + await _updateLogHelper.PushToS3DeletionAsync(deletionObject); + } + }); + + await Task.WhenAll(attachmentTask, documentsTask); + + } + } + + try { // Task to save the detailed audit log to a separate system (e.g., MongoDB). @@ -718,9 +775,11 @@ namespace Marco.Pms.Services.Service }); }).Unwrap(); - await Task.WhenAll(mongoDBTask, getNextStatusesTask); + var cacheUpdateTask = _cache.ReplaceExpenseAsync(existingExpense); - var nextPossibleStatuses = await getNextStatusesTask; + await Task.WhenAll(mongoDBTask, getNextStatusesTask, cacheUpdateTask); + + var nextPossibleStatuses = getNextStatusesTask.Result; var response = _mapper.Map(existingExpense); if (nextPossibleStatuses != null) diff --git a/Marco.Pms.Services/Service/S3UploadService.cs b/Marco.Pms.Services/Service/S3UploadService.cs index 57a46fa..79c5fa7 100644 --- a/Marco.Pms.Services/Service/S3UploadService.cs +++ b/Marco.Pms.Services/Service/S3UploadService.cs @@ -42,7 +42,8 @@ namespace Marco.Pms.Services.Service if (allowedFilesType == null || !allowedFilesType.Contains(fileType)) { _logger.LogWarning("Unsupported file type. {FileType}", fileType); - throw new InvalidOperationException("Unsupported file type."); + //throw new InvalidOperationException("Unsupported file type."); + return; } fileBytes = Convert.FromBase64String(base64); From b6dfb30f92f8cd3dc3a25dcaff31b2359547a93d Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 17:22:19 +0530 Subject: [PATCH 28/81] Create API base for delete expense API --- .../Controllers/ExpenseController.cs | 13 +- Marco.Pms.Services/Service/ExpensesService.cs | 153 +++++++++++++----- .../ServiceInterfaces/IExpensesService.cs | 1 + 3 files changed, 117 insertions(+), 50 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 5a17d3d..a895125 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -54,14 +54,6 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } - /// - /// Creates a new expense entry along with its bill attachments. - /// This operation is transactional and performs validations and file uploads concurrently for optimal performance - /// by leveraging async/await without unnecessary thread-pool switching via Task.Run. - /// - /// The data transfer object containing expense details and attachments. - /// An IActionResult indicating the result of the creation operation. - [HttpPost("create")] public async Task CreateExpense([FromBody] CreateExpensesDto model) { @@ -92,8 +84,11 @@ namespace Marco.Pms.Services.Controllers } [HttpDelete("delete/{id}")] - public void Delete(int id) + public async Task DeleteExpanse(Guid id) { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.DeleteExpanseAsync(id, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); } } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index d37142f..94f0cd7 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -702,47 +702,9 @@ namespace Marco.Pms.Services.Service var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList(); if (deleteBillAttachments.Any()) { - var documentIds = deleteBillAttachments.Select(d => d.DocumentId).ToList(); - - var attachmentTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync(); - - dbContext.BillAttachments.RemoveRange(attachments); - await dbContext.SaveChangesAsync(); - }); - var documentsTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync(); - - if (documents.Any()) - { - dbContext.Documents.RemoveRange(documents); - await dbContext.SaveChangesAsync(); - - List deletionObject = new List(); - foreach (var document in documents) - { - deletionObject.Add(new S3DeletionObject - { - Key = document.S3Key - }); - if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key) - { - deletionObject.Add(new S3DeletionObject - { - Key = document.ThumbS3Key - }); - } - } - await _updateLogHelper.PushToS3DeletionAsync(deletionObject); - } - }); - - await Task.WhenAll(attachmentTask, documentsTask); + var documentIds = deleteBillAttachments.Select(d => d.DocumentId!.Value).ToList(); + await DeleteAttachemnts(documentIds); } } @@ -805,8 +767,75 @@ namespace Marco.Pms.Services.Service } } - public void Delete(int id) + public async Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { + var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id && e.TenantId == tenantId); + + var hasAprrovePermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id); + }); + + var hasAprrovePermission = await hasAprrovePermissionTask; + if (!hasAprrovePermission) + { + expenseQuery = expenseQuery.Where(e => e.CreatedById == loggedInEmployee.Id); + } + + var existingExpense = await expenseQuery.FirstOrDefaultAsync(); + if (existingExpense == null) + { + return ApiResponse.ErrorResponse("Expense cannot be deleted", "Expense cannot be deleted", 400); + } + var documentIds = await _context.BillAttachments + .Where(ba => ba.ExpensesId == existingExpense.Id) + .Select(ba => ba.DocumentId) + .ToListAsync(); + + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); + + _context.Expenses.Remove(existingExpense); + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while adding expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + InnerException = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + var attachmentDeletionTask = Task.Run(async () => + { + await DeleteAttachemnts(documentIds); + }); + + var cacheTask = Task.Run(async () => + { + await _cache.DeleteExpenseAsync(id, tenantId); + }); + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = existingExpense.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, Collection); + + await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask); + return ApiResponse.SuccessResponse("Success", "Expense Deleted Successfully", 200); } #region =================================================================== Helper Functions =================================================================== @@ -1085,6 +1114,48 @@ namespace Marco.Pms.Services.Service return (document, billAttachment); } + private async Task DeleteAttachemnts(List documentIds) + { + var attachmentTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync(); + + dbContext.BillAttachments.RemoveRange(attachments); + await dbContext.SaveChangesAsync(); + }); + var documentsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync(); + + if (documents.Any()) + { + dbContext.Documents.RemoveRange(documents); + await dbContext.SaveChangesAsync(); + + List deletionObject = new List(); + foreach (var document in documents) + { + deletionObject.Add(new S3DeletionObject + { + Key = document.S3Key + }); + if (!string.IsNullOrWhiteSpace(document.ThumbS3Key) && document.ThumbS3Key != document.S3Key) + { + deletionObject.Add(new S3DeletionObject + { + Key = document.ThumbS3Key + }); + } + } + await _updateLogHelper.PushToS3DeletionAsync(deletionObject); + } + }); + + await Task.WhenAll(attachmentTask, documentsTask); + } + #endregion } } diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index 75d937a..5d2f7e4 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -11,5 +11,6 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); + Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId); } } From ae1222bb962508859f09050b615ea8f7df1367c6 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 17:31:15 +0530 Subject: [PATCH 29/81] Added the API to featch list of suppler names from expenses --- .../Controllers/ExpenseController.cs | 8 ++++++ Marco.Pms.Services/Service/ExpensesService.cs | 28 +++++++++++++++++-- .../ServiceInterfaces/IExpensesService.cs | 1 + 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index a895125..ee3c36a 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -54,6 +54,14 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpGet("suppler-name")] + public async Task GetSupplerNameList() + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetSupplerNameListAsync(loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + [HttpPost("create")] public async Task CreateExpense([FromBody] CreateExpensesDto model) { diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 94f0cd7..6276df8 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -237,7 +237,6 @@ namespace Marco.Pms.Services.Service }, 500); } } - public async Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { try @@ -274,6 +273,32 @@ namespace Marco.Pms.Services.Service } } + public async Task> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId) + { + try + { + var supplerNameList = await _context.Expenses.Where(e => e.TenantId == tenantId).Select(e => e.SupplerName).Distinct().ToListAsync(); + _logger.LogInfo("Employee {EmployeeId} fetched list of organizations in a tenant {TenantId}", loggedInEmployee.Id, tenantId); + return ApiResponse.SuccessResponse(supplerNameList, $"{supplerNameList.Count} records of suppler names fetched from expense", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while fetching suppler name list from expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + InnerException = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + } + /// /// Creates a new expense entry along with its bill attachments. /// This operation is transactional and performs validations and file uploads concurrently for optimal performance @@ -766,7 +791,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); } } - public async Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id && e.TenantId == tenantId); diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index 5d2f7e4..673c26c 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -8,6 +8,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces { Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber); Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); From 8b5b0aed4c61b32ea011942c261353608d748152 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 23 Jul 2025 18:02:12 +0530 Subject: [PATCH 30/81] Added proper logs to all Expesne APIs --- Marco.Pms.Services/Service/ExpensesService.cs | 174 +++++++++++++++--- 1 file changed, 148 insertions(+), 26 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 6276df8..b7d8370 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -56,6 +56,7 @@ namespace Marco.Pms.Services.Service _mapper = mapper; } + #region =================================================================== Get Functions =================================================================== /// /// Retrieves a paginated list of expenses based on user permissions and optional filters. @@ -159,9 +160,6 @@ namespace Marco.Pms.Services.Service { expensesQuery = expensesQuery.Where(e => expenseFilter.CreatedByIds.Contains(e.CreatedById)); } - - - } // 4. --- Apply Ordering and Pagination --- @@ -247,11 +245,13 @@ namespace Marco.Pms.Services.Service expenseDetails = await _cache.AddExpenseByIdAsync(id, tenantId); if (expenseDetails == null) { + _logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id); return ApiResponse.ErrorResponse("Expense Not Found", "Expense Not Found", 404); } } var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails); + _logger.LogInfo("Employee {EmployeeId} successfully fetched expense details with ID {ExpenseId}", loggedInEmployee.Id, vm.Id); return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); } @@ -272,13 +272,12 @@ namespace Marco.Pms.Services.Service }, 500); } } - public async Task> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId) { try { var supplerNameList = await _context.Expenses.Where(e => e.TenantId == tenantId).Select(e => e.SupplerName).Distinct().ToListAsync(); - _logger.LogInfo("Employee {EmployeeId} fetched list of organizations in a tenant {TenantId}", loggedInEmployee.Id, tenantId); + _logger.LogInfo("Employee {EmployeeId} fetched list of suppler names from expenses in a tenant {TenantId}", loggedInEmployee.Id, tenantId); return ApiResponse.SuccessResponse(supplerNameList, $"{supplerNameList.Count} records of suppler names fetched from expense", 200); } catch (DbUpdateException dbEx) @@ -299,6 +298,10 @@ namespace Marco.Pms.Services.Service } } + #endregion + + #region =================================================================== Post Functions =================================================================== + /// /// Creates a new expense entry along with its bill attachments. /// This operation is transactional and performs validations and file uploads concurrently for optimal performance @@ -633,6 +636,8 @@ namespace Marco.Pms.Services.Service UpdatedAt = DateTime.UtcNow }, Collection); + var cacheUpdateTask = _cache.ReplaceExpenseAsync(existingExpense); + // Task to get all possible next statuses from the *new* current state to help the UI. // NOTE: This now fetches a list of all possible next states, which is more useful for a UI. var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t => @@ -650,7 +655,7 @@ namespace Marco.Pms.Services.Service }); }).Unwrap(); - await Task.WhenAll(mongoDBTask, getNextStatusesTask); + await Task.WhenAll(mongoDBTask, getNextStatusesTask, cacheUpdateTask); var nextPossibleStatuses = await getNextStatusesTask; @@ -677,6 +682,11 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); } } + + #endregion + + #region =================================================================== Put Functions =================================================================== + public async Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId) { var existingExpense = await _context.Expenses @@ -696,6 +706,7 @@ namespace Marco.Pms.Services.Service if (existingExpense == null) { + _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but not found in database", id); return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); } @@ -722,14 +733,73 @@ namespace Marco.Pms.Services.Service if (newBillAttachments.Any()) { await ProcessAndUploadAttachmentsAsync(newBillAttachments, existingExpense, loggedInEmployee.Id, tenantId); - await _context.SaveChangesAsync(); + try + { + await _context.SaveChangesAsync(); + _logger.LogInfo("{Count} New attachments added while updating expense {ExpenseId} by employee {EmployeeId}", + newBillAttachments.Count, existingExpense.Id, loggedInEmployee.Id); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while adding new attachments during updating expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + InnerException = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + + } } + var deleteBillAttachments = model.BillAttachments.Where(ba => ba.DocumentId != null && !ba.IsActive).ToList(); if (deleteBillAttachments.Any()) { var documentIds = deleteBillAttachments.Select(d => d.DocumentId!.Value).ToList(); - - await DeleteAttachemnts(documentIds); + try + { + await DeleteAttachemnts(documentIds); + _logger.LogInfo("{Count} Attachments deleted while updating expense {ExpenseId} by employee {EmployeeId}", + deleteBillAttachments.Count, existingExpense.Id, loggedInEmployee.Id); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + InnerException = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while deleting attachments during updating expense"); + return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + InnerException = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } } } @@ -791,6 +861,11 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); } } + + #endregion + + #region =================================================================== Delete Functions =================================================================== + public async Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id && e.TenantId == tenantId); @@ -811,7 +886,16 @@ namespace Marco.Pms.Services.Service var existingExpense = await expenseQuery.FirstOrDefaultAsync(); if (existingExpense == null) { - return ApiResponse.ErrorResponse("Expense cannot be deleted", "Expense cannot be deleted", 400); + var message = hasAprrovePermission ? "Expenses not found" : "Expense cannot be deleted"; + if (hasAprrovePermission) + { + _logger.LogWarning("Employee {EmployeeId} attempted to delete expense {ExpenseId}, but not found in database", loggedInEmployee.Id, id); + } + else + { + _logger.LogWarning("Employee {EmployeeId} attempted to delete expense {ExpenseId}, Which is created by another employee", loggedInEmployee.Id, id); + } + return ApiResponse.ErrorResponse(message, message, 400); } var documentIds = await _context.BillAttachments .Where(ba => ba.ExpensesId == existingExpense.Id) @@ -824,10 +908,11 @@ namespace Marco.Pms.Services.Service try { await _context.SaveChangesAsync(); + _logger.LogInfo("Employeee {EmployeeId} successfully deleted the expense {EmpenseId}", loggedInEmployee.Id, id); } catch (DbUpdateException dbEx) { - _logger.LogError(dbEx, "Databsae Exception occured while adding expense"); + _logger.LogError(dbEx, "Databsae Exception occured while deleting expense"); return ApiResponse.ErrorResponse("Databsae Exception", new { Message = dbEx.Message, @@ -841,27 +926,64 @@ namespace Marco.Pms.Services.Service } }, 500); } - var attachmentDeletionTask = Task.Run(async () => + try { - await DeleteAttachemnts(documentIds); - }); + var attachmentDeletionTask = Task.Run(async () => + { + await DeleteAttachemnts(documentIds); + }); - var cacheTask = Task.Run(async () => - { - await _cache.DeleteExpenseAsync(id, tenantId); - }); - var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject - { - EntityId = existingExpense.Id.ToString(), - UpdatedById = loggedInEmployee.Id.ToString(), - OldObject = existingEntityBson, - UpdatedAt = DateTime.UtcNow - }, Collection); + var cacheTask = Task.Run(async () => + { + await _cache.DeleteExpenseAsync(id, tenantId); + }); + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = existingExpense.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, Collection); - await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask); + await Task.WhenAll(attachmentDeletionTask, cacheTask, mongoDBTask); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense"); + return ApiResponse.ErrorResponse("Databsae Exception", new + { + Message = dbEx.Message, + StackTrace = dbEx.StackTrace, + Source = dbEx.Source, + InnerException = new + { + Message = dbEx.InnerException?.Message, + StackTrace = dbEx.InnerException?.StackTrace, + Source = dbEx.InnerException?.Source, + } + }, 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while deleting attachments during updating expense"); + return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + InnerException = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }, 500); + } return ApiResponse.SuccessResponse("Success", "Expense Deleted Successfully", 200); } + #endregion + #region =================================================================== Helper Functions =================================================================== private async Task> GetAllExpnesRelatedTables(List model) From a1db851eddc9b504163b6bc356ff728b13f18d70 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 24 Jul 2025 10:15:33 +0530 Subject: [PATCH 31/81] Added peoper return messages and validations in update expesnse API --- Marco.Pms.Services/Service/ExpensesService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index b7d8370..951e961 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -689,6 +689,11 @@ namespace Marco.Pms.Services.Service public async Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId) { + if (id != model.Id) + { + _logger.LogWarning("Id provided by path parameter and Id from body not matches for employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Parameters", "Invalid Parameters", 400); + } var existingExpense = await _context.Expenses .Include(e => e.ExpensesType) .Include(e => e.Project) @@ -845,7 +850,7 @@ namespace Marco.Pms.Services.Service response.NextStatus = _mapper.Map>(nextPossibleStatuses); } - return ApiResponse.SuccessResponse(response); + return ApiResponse.SuccessResponse(response, "Expense Updated Successfully", 200); } catch (Exception ex) { From 57d7b4c07b16c53e2824e0ebcd081fcc9da66aca Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 24 Jul 2025 10:38:31 +0530 Subject: [PATCH 32/81] Solved the issue of not showing final status in list and details API of expesne model --- Marco.Pms.Services/Service/ExpensesService.cs | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 951e961..ce77f08 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1042,16 +1042,24 @@ namespace Marco.Pms.Services.Service NextStatus = g.Select(s => s.NextStatus).ToList() }).ToListAsync(); }); + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster + .AsNoTracking() + .Where(es => statusIds.Contains(es.Id)) + .ToListAsync(); + }); // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask); - var projects = await projectTask; - var expenseTypes = await expenseTypeTask; - var paymentModes = await paymentModeTask; - var statusMappings = await statusMappingTask; - var paidBys = await paidByTask; - var createdBys = await createdByTask; + var projects = projectTask.Result; + var expenseTypes = expenseTypeTask.Result; + var paymentModes = paymentModeTask.Result; + var statusMappings = statusMappingTask.Result; + var paidBys = paidByTask.Result; + var createdBys = createdByTask.Result; expenseList = model.Select(m => { @@ -1061,6 +1069,11 @@ namespace Marco.Pms.Services.Service response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map(p)).FirstOrDefault(); response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault(); response.Status = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map(s.Status)).FirstOrDefault(); + if (response.Status == null) + { + var status = statusTask.Result; + response.Status = status.Where(s => s.Id == m.StatusId).Select(s => _mapper.Map(s)).FirstOrDefault(); + } response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault(); response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map(pm)).FirstOrDefault(); response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map(et)).FirstOrDefault(); @@ -1112,16 +1125,22 @@ namespace Marco.Pms.Services.Service NextStatus = g.Select(s => s.NextStatus).ToList() }).FirstOrDefaultAsync(); }); - + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster + .AsNoTracking() + .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId)); + }); // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask); - var project = await projectTask; - var expenseType = await expenseTypeTask; - var paymentMode = await paymentModeTask; - var statusMapping = await statusMappingTask; - var paidBy = await paidByTask; - var createdBy = await createdByTask; + var project = projectTask.Result; + var expenseType = expenseTypeTask.Result; + var paymentMode = paymentModeTask.Result; + var statusMapping = statusMappingTask.Result; + var paidBy = paidByTask.Result; + var createdBy = createdByTask.Result; var response = _mapper.Map(model); @@ -1133,6 +1152,11 @@ namespace Marco.Pms.Services.Service if (statusMapping != null) { response.Status = _mapper.Map(statusMapping.Status); + if (response.Status == null) + { + var status = statusTask.Result; + response.Status = _mapper.Map(status); + } response.NextStatus = _mapper.Map>(statusMapping.NextStatus); } From 809d64e29656875b009e75df84f97d6dda802f34 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 24 Jul 2025 16:03:23 +0530 Subject: [PATCH 33/81] Added permission IDs in expesne status master View model --- .../Master/ExpensesStatusMasterVM.cs | 1 + Marco.Pms.Services/Service/ExpensesService.cs | 88 ++++++++++++++----- 2 files changed, 68 insertions(+), 21 deletions(-) diff --git a/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs index 73a6487..8f6f02a 100644 --- a/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs +++ b/Marco.Pms.Model/ViewModels/Master/ExpensesStatusMasterVM.cs @@ -6,6 +6,7 @@ public string Name { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; + public List? PermissionIds { get; set; } public string? Color { get; set; } public bool IsSystem { get; set; } = false; } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index ce77f08..416ecc3 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -181,13 +181,13 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(new List(), "No expenses found for the given criteria.", 200); } - expenseVM = await GetAllExpnesRelatedTables(expensesList); + expenseVM = await GetAllExpnesRelatedTables(expensesList, tenantId); totalPages = (int)Math.Ceiling((double)totalEntites / pageSize); } else { - expenseVM = await GetAllExpnesRelatedTables(_mapper.Map>(expenseList)); + expenseVM = await GetAllExpnesRelatedTables(_mapper.Map>(expenseList), tenantId); totalEntites = (int)totalCount; } // 7. --- Return Final Success Response --- @@ -249,7 +249,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Expense Not Found", "Expense Not Found", 404); } } - var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails); + var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails, tenantId); _logger.LogInfo("Employee {EmployeeId} successfully fetched expense details with ID {ExpenseId}", loggedInEmployee.Id, vm.Id); return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); @@ -991,7 +991,7 @@ namespace Marco.Pms.Services.Service #region =================================================================== Helper Functions =================================================================== - private async Task> GetAllExpnesRelatedTables(List model) + private async Task> GetAllExpnesRelatedTables(List model, Guid tenantId) { List expenseList = new List(); var projectIds = model.Select(m => m.ProjectId).ToList(); @@ -1004,27 +1004,27 @@ namespace Marco.Pms.Services.Service var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id)).ToListAsync(); + return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync(); }); var paidByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().Where(e => paidByIds.Contains(e.Id)).ToListAsync(); + return await dbContext.Employees.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.AsNoTracking().Where(e => createdByIds.Contains(e.Id)).ToListAsync(); + return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync(); }); var expenseTypeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id)).ToListAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id) && et.TenantId == tenantId).ToListAsync(); }); var paymentModeTask = Task.Run(async () => { 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) && pm.TenantId == tenantId).ToListAsync(); }); var statusMappingTask = Task.Run(async () => { @@ -1033,7 +1033,7 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) + .Where(es => statusIds.Contains(es.StatusId) && es.Status != null && es.TenantId == tenantId) .GroupBy(s => s.StatusId) .Select(g => new { @@ -1047,17 +1047,30 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMaster .AsNoTracking() - .Where(es => statusIds.Contains(es.Id)) + .Where(es => statusIds.Contains(es.Id) && es.TenantId == tenantId) .ToListAsync(); }); + var permissionStatusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping + .Where(ps => ps.TenantId == tenantId) + .GroupBy(ps => ps.StatusId) + .Select(g => new + { + StatusId = g.Key, + PermissionIds = g.Select(ps => ps.PermissionId).ToList() + }).ToListAsync(); + }); // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask); var projects = projectTask.Result; var expenseTypes = expenseTypeTask.Result; var paymentModes = paymentModeTask.Result; var statusMappings = statusMappingTask.Result; + var permissionStatusMappings = permissionStatusMappingTask.Result; var paidBys = paidByTask.Result; var createdBys = createdByTask.Result; @@ -1074,7 +1087,18 @@ namespace Marco.Pms.Services.Service var status = statusTask.Result; response.Status = status.Where(s => s.Id == m.StatusId).Select(s => _mapper.Map(s)).FirstOrDefault(); } + if (response.Status != null) + { + response.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == m.StatusId).Select(ps => ps.PermissionIds).FirstOrDefault(); + } response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault(); + if (response.NextStatus != null) + { + foreach (var status in response.NextStatus) + { + status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + } + } response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map(pm)).FirstOrDefault(); response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map(et)).FirstOrDefault(); @@ -1083,32 +1107,32 @@ namespace Marco.Pms.Services.Service return expenseList; } - private async Task GetAllExpnesRelatedTablesFromMongoDB(ExpenseDetailsMongoDB model) + private async Task GetAllExpnesRelatedTablesFromMongoDB(ExpenseDetailsMongoDB model, Guid tenantId) { var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == Guid.Parse(model.ProjectId)); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == Guid.Parse(model.ProjectId) && p.TenantId == tenantId); }); var paidByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.PaidById)); + return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.PaidById) && e.TenantId == tenantId); }); var createdByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.CreatedById)); + return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.CreatedById) && e.TenantId == tenantId); }); var expenseTypeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == Guid.Parse(model.ExpensesTypeId)); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == Guid.Parse(model.ExpensesTypeId) && et.TenantId == tenantId); }); var paymentModeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == Guid.Parse(model.PaymentModeId)); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == Guid.Parse(model.PaymentModeId) && pm.TenantId == tenantId); }); var statusMappingTask = Task.Run(async () => { @@ -1117,7 +1141,7 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null) + .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null && es.TenantId == tenantId) .GroupBy(s => s.StatusId) .Select(g => new { @@ -1130,15 +1154,29 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMaster .AsNoTracking() - .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId)); + .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId) && es.TenantId == tenantId); }); + var permissionStatusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping + .Where(ps => ps.TenantId == tenantId) + .GroupBy(ps => ps.StatusId) + .Select(g => new + { + StatusId = g.Key, + PermissionIds = g.Select(ps => ps.PermissionId).ToList() + }).ToListAsync(); + }); + // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask); var project = projectTask.Result; var expenseType = expenseTypeTask.Result; var paymentMode = paymentModeTask.Result; var statusMapping = statusMappingTask.Result; + var permissionStatusMappings = permissionStatusMappingTask.Result; var paidBy = paidByTask.Result; var createdBy = createdByTask.Result; @@ -1157,7 +1195,15 @@ namespace Marco.Pms.Services.Service var status = statusTask.Result; response.Status = _mapper.Map(status); } + response.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == Guid.Parse(model.StatusId)).Select(ps => ps.PermissionIds).FirstOrDefault(); response.NextStatus = _mapper.Map>(statusMapping.NextStatus); + if (response.NextStatus != null) + { + foreach (var status in response.NextStatus) + { + status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + } + } } foreach (var document in model.Documents) From c881964ab1359d89437a4134c9da0ecc1f2aa431 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 24 Jul 2025 16:07:39 +0530 Subject: [PATCH 34/81] Added proper validation and logs in get expesne status, expenses type and payment mode APIs --- .../Controllers/MasterController.cs | 64 ++++++--- Marco.Pms.Services/Service/MasterService.cs | 130 +++++++++++++++--- .../ServiceInterfaces/IMasterService.cs | 9 +- 3 files changed, 161 insertions(+), 42 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 608caed..6b059b1 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -29,6 +29,7 @@ namespace Marco.Pms.Services.Controllers private readonly ILoggingService _logger; private readonly MasterHelper _masterHelper; private readonly IMasterService _masterService; + private readonly Guid tenantId; public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, MasterHelper masterHelper, IMasterService masterService) { _context = context; @@ -36,9 +37,11 @@ namespace Marco.Pms.Services.Controllers _logger = logger; _masterHelper = masterHelper; _masterService = masterService; + tenantId = userHelper.GetTenantId(); } - // -------------------------------- Activity -------------------------------- + #region =================================================================== Activity APIs =================================================================== + [HttpGet] [Route("activities")] public async Task GetActivitiesMaster() @@ -189,7 +192,9 @@ namespace Marco.Pms.Services.Controllers return Ok(ApiResponse.SuccessResponse(new { }, "Activity Deleted Successfully", 200)); } - // -------------------------------- Industry -------------------------------- + #endregion + + #region =================================================================== Industry APIs =================================================================== [HttpGet] [Route("industries")] @@ -202,7 +207,9 @@ namespace Marco.Pms.Services.Controllers return Ok(ApiResponse.SuccessResponse(industries, System.String.Format("{0} industry records fetched successfully", industries.Count), 200)); } - // -------------------------------- Ticket Status -------------------------------- + #endregion + + #region =================================================================== Ticket Status APIs =================================================================== [HttpGet("ticket-status")] public async Task GetTicketStatusMaster() @@ -289,7 +296,9 @@ namespace Marco.Pms.Services.Controllers } } - // -------------------------------- Ticket Type -------------------------------- + #endregion + + #region =================================================================== Ticket Type APIs =================================================================== [HttpGet("ticket-types")] public async Task GetTicketTypeMaster() @@ -377,7 +386,9 @@ namespace Marco.Pms.Services.Controllers } } - // -------------------------------- Ticket Priority -------------------------------- + #endregion + + #region =================================================================== Ticket Priority APIs =================================================================== [HttpGet("ticket-priorities")] public async Task GetTicketPriorityMaster() @@ -465,7 +476,9 @@ namespace Marco.Pms.Services.Controllers } } - // -------------------------------- Ticket Tag -------------------------------- + #endregion + + #region =================================================================== Ticket Tag APIs =================================================================== [HttpGet("ticket-tags")] public async Task GetTicketTagMaster() @@ -553,7 +566,9 @@ namespace Marco.Pms.Services.Controllers } } - // -------------------------------- Work Category -------------------------------- + #endregion + + #region =================================================================== Work Category APIs =================================================================== [HttpGet("work-categories")] public async Task GetWorkCategoryMasterList() @@ -674,7 +689,9 @@ namespace Marco.Pms.Services.Controllers } } - // -------------------------------- Work Status -------------------------------- + #endregion + + #region =================================================================== Work Status APIs =================================================================== [HttpGet("work-status")] public async Task GetWorkStatusMasterList() @@ -713,7 +730,9 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } - // -------------------------------- Contact Category -------------------------------- + #endregion + + #region =================================================================== Contact Category APIs =================================================================== [HttpGet("contact-categories")] public async Task GetContactCategoryMasterList() @@ -782,7 +801,9 @@ namespace Marco.Pms.Services.Controllers return Ok(response); } - // -------------------------------- Contact Tag -------------------------------- + #endregion + + #region =================================================================== Contact Tag APIs =================================================================== [HttpGet("contact-tags")] public async Task GetContactTagMasterList() @@ -791,12 +812,6 @@ namespace Marco.Pms.Services.Controllers return Ok(response); } - //[HttpGet("contact-tag/{id}")] - //public async Task GetContactTagMaster(Guid id) - //{ - // return Ok(); - //} - [HttpPost("contact-tag")] public async Task CreateContactTagMaster([FromBody] CreateContactTagDto contactTagDto) { @@ -849,27 +864,34 @@ namespace Marco.Pms.Services.Controllers var response = await _masterHelper.DeleteContactTag(id); return Ok(response); } + #endregion + #region =================================================================== Expenses Type APIs =================================================================== + [HttpGet("expenses-types")] public async Task GetExpenseTypeList() { - var response = await _masterService.GetExpenseTypeListAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("expenses-type")] public async Task CreateExpenseType(ExpensesTypeMasterDto dto) { - var response = await _masterService.GetExpenseTypeListAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Expenses Status APIs =================================================================== + [HttpGet("expenses-status")] public async Task GetExpenseStatusList() { - var response = await _masterService.GetExpenseStatusListAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetExpenseStatusListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } @@ -877,10 +899,12 @@ namespace Marco.Pms.Services.Controllers #endregion #region =================================================================== Payment mode APIs =================================================================== + [HttpGet("payment-modes")] public async Task GetPaymentModeList() { - var response = await _masterService.GetPaymentModeListAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetPaymentModeListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index bd74bce..2705e43 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -1,11 +1,12 @@ using AutoMapper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Master; +using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Master; using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Services.Service.ServiceInterfaces; -using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; @@ -15,36 +16,50 @@ namespace Marco.Pms.Services.Service { private readonly ApplicationDbContext _context; private readonly ILoggingService _logger; - private readonly UserHelper _userHelper; private readonly PermissionServices _permission; private readonly IMapper _mapper; - private readonly Guid tenantId; public MasterService( ApplicationDbContext context, ILoggingService logger, - UserHelper userHelper, PermissionServices permission, IMapper mapper) { _context = context; _logger = logger; - _userHelper = userHelper; _permission = permission; _mapper = mapper; - tenantId = userHelper.GetTenantId(); } #region =================================================================== Expenses Type APIs =================================================================== - public async Task> GetExpenseTypeListAsync() + public async Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId) { - var typeList = await _context.ExpensesTypeMaster.Where(et => et.TenantId == tenantId).ToListAsync(); - return ApiResponse.SuccessResponse(typeList); + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to fetch the list of expense type from different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Featching the list of Expenses Type. + var typeList = await _context.ExpensesTypeMaster.Where(et => et.TenantId == tenantId).ToListAsync(); + var response = _mapper.Map>(typeList); + + _logger.LogInfo("{Count} records of expense type have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id); + return ApiResponse.SuccessResponse(response, $"{response.Count} records of expense type have been fetched successfully.", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching list of expense type list by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } - public async Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto dto) + public async Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto dto, Employee loggedInEmployee, Guid tenantId) { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); if (!hasManagePermission) { @@ -52,26 +67,105 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); } var expensesType = _mapper.Map(dto); - return ApiResponse.SuccessResponse(expensesType); + _context.ExpensesTypeMaster.Add(expensesType); + await _context.SaveChangesAsync(); + _logger.LogInfo("New Expense Type {ExpensesTypeId} was added by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); + + var response = _mapper.Map(expensesType); + return ApiResponse.SuccessResponse(response, "Expense type craeted Successfully", 201); } #endregion #region =================================================================== Expenses Status APIs =================================================================== - public async Task> GetExpenseStatusListAsync() + public async Task> GetExpenseStatusListAsync(Employee loggedInEmployee, Guid tenantId) { - var typeList = await _context.ExpensesStatusMaster.Where(et => et.TenantId == tenantId).ToListAsync(); - return ApiResponse.SuccessResponse(typeList); + + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to fetch the list of expense status from different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Featching the list of Expenses Status. + var statusList = await _context.ExpensesStatusMaster.Where(es => es.TenantId == tenantId).ToListAsync(); + var response = _mapper.Map>(statusList); + + var statusIds = statusList.Select(s => s.Id).ToList(); + var permissionStatusMapping = await _context.StatusPermissionMapping + .Where(ps => statusIds.Contains(ps.StatusId)) + .GroupBy(ps => ps.StatusId) + .Select(g => new + { + StatusId = g.Key, + PermissionIds = g.Select(ps => ps.PermissionId).ToList() + }).ToListAsync(); + + foreach (var status in response) + { + status.PermissionIds = permissionStatusMapping.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + } + + _logger.LogInfo("{Count} records of expense status have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id); + return ApiResponse.SuccessResponse(response, $"{response.Count} records of expense status have been fetched successfully.", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while fetching list of expense sattus list by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } } #endregion #region =================================================================== Payment mode APIs =================================================================== - public async Task> GetPaymentModeListAsync() + public async Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId) { - var typeList = await _context.PaymentModeMatser.Where(et => et.TenantId == tenantId).ToListAsync(); - return ApiResponse.SuccessResponse(typeList); + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to fetch the list of payment modes from different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Featching the list of Payment Modes. + var paymentModes = await _context.PaymentModeMatser.Where(pm => pm.TenantId == tenantId).ToListAsync(); + var response = _mapper.Map>(paymentModes); + + _logger.LogInfo("{Count} records of payment modes have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id); + return ApiResponse.SuccessResponse(response, $"{response.Count} records of payment modes have been fetched successfully.", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occured while featching list of payment modes list by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured while featching list of payment modes list", ExceptionMapper(ex), 500); + } + } + + + #endregion + + #region =================================================================== Helper Function =================================================================== + private static object ExceptionMapper(Exception ex) + { + return new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + InnerException = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }; } diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 1b970ca..e427fc4 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -1,11 +1,12 @@ -using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Utilities; namespace Marco.Pms.Services.Service.ServiceInterfaces { public interface IMasterService { - Task> GetExpenseTypeListAsync(); - Task> GetExpenseStatusListAsync(); - Task> GetPaymentModeListAsync(); + Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetExpenseStatusListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); } } From c2fe726f0c92f742377de20362bf5bfbd49d2f17 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 24 Jul 2025 16:16:30 +0530 Subject: [PATCH 35/81] Added signalR in update expesne API --- Marco.Pms.Services/Controllers/ExpenseController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index ee3c36a..5bbcf2c 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -88,6 +88,11 @@ namespace Marco.Pms.Services.Controllers { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _expensesService.UpdateExpanseAsync(id, model, loggedInEmployee, tenantId); + if (response.Success) + { + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Expanse", Response = response.Data }; + await _signalR.SendNotificationAsync(notification); + } return StatusCode(response.StatusCode, response); } From e1102c297808c47c3ac0ea46c554c7438abc611f Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 10:26:29 +0530 Subject: [PATCH 36/81] Added an API to add new Expense type to master table for that tenant --- .../Controllers/MasterController.cs | 2 +- Marco.Pms.Services/Service/MasterService.cs | 47 ++++++++++++++----- .../ServiceInterfaces/IMasterService.cs | 13 ++++- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 6b059b1..0a5a7a8 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -879,7 +879,7 @@ namespace Marco.Pms.Services.Controllers public async Task CreateExpenseType(ExpensesTypeMasterDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId); + var response = await _masterService.CreateExpenseTypeAsync(dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 2705e43..5e816aa 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -58,21 +58,43 @@ namespace Marco.Pms.Services.Service } } - public async Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto dto, Employee loggedInEmployee, Guid tenantId) + public async Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId) { - var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); - if (!hasManagePermission) + try { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); - } - var expensesType = _mapper.Map(dto); - _context.ExpensesTypeMaster.Add(expensesType); - await _context.SaveChangesAsync(); - _logger.LogInfo("New Expense Type {ExpensesTypeId} was added by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to add new expense type in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + } + var expensesType = _mapper.Map(model); + expensesType.TenantId = tenantId; - var response = _mapper.Map(expensesType); - return ApiResponse.SuccessResponse(response, "Expense type craeted Successfully", 201); + _context.ExpensesTypeMaster.Add(expensesType); + await _context.SaveChangesAsync(); + + _logger.LogInfo("New Expense Type {ExpensesTypeId} was added by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); + + var response = _mapper.Map(expensesType); + return ApiResponse.SuccessResponse(response, "Expense type craeted Successfully", 201); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while adding new expense type by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while adding new expense type by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } } #endregion @@ -148,7 +170,6 @@ namespace Marco.Pms.Services.Service } } - #endregion #region =================================================================== Helper Function =================================================================== diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index e427fc4..13bdcbb 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -1,12 +1,23 @@ -using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Dtos.Master; +using Marco.Pms.Model.Employees; using Marco.Pms.Model.Utilities; namespace Marco.Pms.Services.Service.ServiceInterfaces { public interface IMasterService { + #region =================================================================== Expenses Type APIs =================================================================== Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId); + Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); + + #endregion + #region =================================================================== Expenses Status APIs =================================================================== Task> GetExpenseStatusListAsync(Employee loggedInEmployee, Guid tenantId); + + #endregion + #region =================================================================== Payment mode APIs =================================================================== Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); + + #endregion } } From 1834c103f05b7b931c93fb1b21ed426fddcccdce Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 10:36:57 +0530 Subject: [PATCH 37/81] Added an API to add new payment mode to master table for that tenant --- .../Dtos/Master/PaymentModeMatserDto.cs | 9 ++++ .../Controllers/MasterController.cs | 7 ++++ .../MappingProfiles/MappingProfile.cs | 25 ++++++++++- Marco.Pms.Services/Service/MasterService.cs | 41 +++++++++++++++++++ .../ServiceInterfaces/IMasterService.cs | 1 + 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/Master/PaymentModeMatserDto.cs diff --git a/Marco.Pms.Model/Dtos/Master/PaymentModeMatserDto.cs b/Marco.Pms.Model/Dtos/Master/PaymentModeMatserDto.cs new file mode 100644 index 0000000..fb89b64 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Master/PaymentModeMatserDto.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.Dtos.Master +{ + public class PaymentModeMatserDto + { + public Guid? Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 0a5a7a8..d959046 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -908,6 +908,13 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpPost("payment-mode")] + public async Task CreatePaymentMode(PaymentModeMatserDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.CreatePaymentModeAsync(dto, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 5db13c1..6453bcd 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -188,6 +188,9 @@ namespace Marco.Pms.Services.MappingProfiles #endregion #region ======================================================= Master ======================================================= + + #region ======================================================= Expenses Type Master ======================================================= + CreateMap() .ForMember( dest => dest.Id, @@ -195,8 +198,6 @@ namespace Marco.Pms.Services.MappingProfiles opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) ); CreateMap(); - CreateMap(); - CreateMap(); CreateMap() .ForMember( @@ -205,10 +206,16 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.TenantId, opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() .ForMember( dest => dest.Id, opt => opt.MapFrom(src => Guid.Parse(src.Id))); + #endregion + + #region ======================================================= Expenses Status Master ======================================================= + + CreateMap(); CreateMap() .ForMember( @@ -217,10 +224,22 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.TenantId, opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() .ForMember( dest => dest.Id, opt => opt.MapFrom(src => Guid.Parse(src.Id))); + #endregion + + #region ======================================================= Payment Mode Matser ======================================================= + + CreateMap() + .ForMember( + dest => dest.Id, + // Explicitly and safely convert nullable Guid to non-nullable Guid + opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) + ); + CreateMap(); CreateMap() .ForMember( @@ -229,11 +248,13 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.TenantId, opt => opt.MapFrom(src => src.TenantId.ToString())); + CreateMap() .ForMember( dest => dest.Id, opt => opt.MapFrom(src => Guid.Parse(src.Id))); + #endregion #endregion diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 5e816aa..12ca747 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -169,6 +169,47 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured while featching list of payment modes list", ExceptionMapper(ex), 500); } } + public async Task> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId) + { + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to add new payment mode in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing PAYMENT MODE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + + } + // Mapping the DTO to PaymentModeMatser Model + var paymentMode = _mapper.Map(model); + paymentMode.TenantId = tenantId; + + _context.PaymentModeMatser.Add(paymentMode); + await _context.SaveChangesAsync(); + + _logger.LogInfo("New Payment Mode {PaymentModeId} was added by employee {EmployeeId}", paymentMode.Id, loggedInEmployee.Id); + + // Mapping the PaymentModeMatser Model to View Model + var response = _mapper.Map(paymentMode); + return ApiResponse.SuccessResponse(response, "Payment Mode craeted Successfully", 201); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while adding new payment mode by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while adding new payment mode by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 13bdcbb..fb2e86c 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -17,6 +17,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #endregion #region =================================================================== Payment mode APIs =================================================================== Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); + Task> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); #endregion } From 9cd9bac975e869f33ed1cef339d9b52b52f1acf9 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 10:55:25 +0530 Subject: [PATCH 38/81] Added an API to add new Expense status to master table for that tenant --- .../Dtos/Master/ExpensesStatusMasterDto.cs | 12 ++++ .../Controllers/MasterController.cs | 4 +- .../MappingProfiles/MappingProfile.cs | 11 +++- Marco.Pms.Services/Service/MasterService.cs | 56 ++++++++++++++++++- .../ServiceInterfaces/IMasterService.cs | 2 +- 5 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/Master/ExpensesStatusMasterDto.cs diff --git a/Marco.Pms.Model/Dtos/Master/ExpensesStatusMasterDto.cs b/Marco.Pms.Model/Dtos/Master/ExpensesStatusMasterDto.cs new file mode 100644 index 0000000..6bff02b --- /dev/null +++ b/Marco.Pms.Model/Dtos/Master/ExpensesStatusMasterDto.cs @@ -0,0 +1,12 @@ +namespace Marco.Pms.Model.Dtos.Master +{ + public class ExpensesStatusMasterDto + { + public Guid? Id { get; set; } + public required string Name { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public List? PermissionIds { get; set; } + public required string? Color { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index d959046..4ccd30b 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -888,10 +888,10 @@ namespace Marco.Pms.Services.Controllers #region =================================================================== Expenses Status APIs =================================================================== [HttpGet("expenses-status")] - public async Task GetExpenseStatusList() + public async Task GetExpensesStatusList() { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetExpenseStatusListAsync(loggedInEmployee, tenantId); + var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 6453bcd..2a99028 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -195,7 +195,7 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.Id, // Explicitly and safely convert nullable Guid to non-nullable Guid - opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) + opt => opt.MapFrom(src => src.Id ?? Guid.Empty) ); CreateMap(); @@ -215,6 +215,13 @@ namespace Marco.Pms.Services.MappingProfiles #region ======================================================= Expenses Status Master ======================================================= + CreateMap() + .ForMember( + dest => dest.Id, + opt => opt.MapFrom(src => src.Id ?? Guid.Empty)) + .ForMember( + dest => dest.DisplayName, + opt => opt.MapFrom(src => string.IsNullOrWhiteSpace(src.DisplayName) ? src.Name : src.DisplayName)); CreateMap(); CreateMap() @@ -237,7 +244,7 @@ namespace Marco.Pms.Services.MappingProfiles .ForMember( dest => dest.Id, // Explicitly and safely convert nullable Guid to non-nullable Guid - opt => opt.MapFrom(src => src.Id != null ? src.Id : Guid.Empty) + opt => opt.MapFrom(src => src.Id ?? Guid.Empty) ); CreateMap(); diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 12ca747..919ccdc 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -3,6 +3,7 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; +using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Master; @@ -100,7 +101,7 @@ namespace Marco.Pms.Services.Service #endregion #region =================================================================== Expenses Status APIs =================================================================== - public async Task> GetExpenseStatusListAsync(Employee loggedInEmployee, Guid tenantId) + public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId) { try @@ -141,6 +142,59 @@ namespace Marco.Pms.Services.Service } } + public async Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId) + { + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to add new Expense Status in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + + } + // Mapping the DTO to ExpensesStatusMaster Model + var expensesStatus = _mapper.Map(model); + expensesStatus.TenantId = tenantId; + + _context.ExpensesStatusMaster.Add(expensesStatus); + + if (model.PermissionIds?.Any() ?? false) + { + var permissionStatusMappings = model.PermissionIds.Select(p => new StatusPermissionMapping + { + PermissionId = p, + StatusId = expensesStatus.Id, + TenantId = tenantId + }).ToList(); + + _context.StatusPermissionMapping.AddRange(permissionStatusMappings); + } + await _context.SaveChangesAsync(); + + _logger.LogInfo("New Expense Status {ExpensesStatusId} was added by employee {EmployeeId}", expensesStatus.Id, loggedInEmployee.Id); + + // Mapping the ExpensesStatusMaster Model to View Model + var response = _mapper.Map(expensesStatus); + return ApiResponse.SuccessResponse(response, "Expense Status craeted Successfully", 201); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index fb2e86c..8c54850 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -12,7 +12,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #endregion #region =================================================================== Expenses Status APIs =================================================================== - Task> GetExpenseStatusListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Payment mode APIs =================================================================== From cad631ec7aa249bde5f94dc32c9299a8d8f73ce4 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 11:07:15 +0530 Subject: [PATCH 39/81] Added the end point for add expenses status API --- Marco.Pms.Services/Controllers/MasterController.cs | 8 +++++++- .../Service/ServiceInterfaces/IMasterService.cs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 4ccd30b..0f34a05 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -894,7 +894,13 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } - + [HttpPost("expenses-status")] + public async Task CreateExpensesStatus(ExpensesStatusMasterDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.CreateExpensesStatusAsync(dto, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 8c54850..7269ee0 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -13,6 +13,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #endregion #region =================================================================== Expenses Status APIs =================================================================== Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); + Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Payment mode APIs =================================================================== From 5b5aa9f77a910af4edaf37195af7681313bd7d49 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 11:52:47 +0530 Subject: [PATCH 40/81] Added an API to update Expense type to master table for that tenant --- .../Controllers/MasterController.cs | 7 ++ Marco.Pms.Services/Service/MasterService.cs | 82 ++++++++++++++++++- .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 0f34a05..3f00d2e 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -882,6 +882,13 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.CreateExpenseTypeAsync(dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPut("expenses-type/edit/{id}")] + public async Task UpdateExpenseType(Guid id, ExpensesTypeMasterDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdateExpenseTypeAsync(id, dto, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 919ccdc..a03c8ef 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -1,12 +1,15 @@ using AutoMapper; using Marco.Pms.DataAccess.Data; +using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; +using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Master; +using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; @@ -19,17 +22,23 @@ namespace Marco.Pms.Services.Service private readonly ILoggingService _logger; private readonly PermissionServices _permission; private readonly IMapper _mapper; + private readonly UtilityMongoDBHelper _updateLogHelper; + private readonly CacheUpdateHelper _cache; public MasterService( ApplicationDbContext context, ILoggingService logger, PermissionServices permission, - IMapper mapper) + IMapper mapper, + UtilityMongoDBHelper updateLogHelper, + CacheUpdateHelper cache) { _context = context; _logger = logger; _permission = permission; _mapper = mapper; + _updateLogHelper = updateLogHelper; + _cache = cache; } #region =================================================================== Expenses Type APIs =================================================================== @@ -97,6 +106,77 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } + public async Task> UpdateExpenseTypeAsync(Guid id, ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId) + { + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to update expense type in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + } + + // Validating the prvided data + if (model.Id != id) + { + _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); + } + + var expensesType = await _context.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId); + + // Checking if expense type exists + if (expensesType == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to update expense type, but not found in database", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Expense Type not found", "Expense Type not found", 404); + } + + // Mapping ExpensesTypeMaster to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesType); + + // Mapping ExpensesTypeMasterDto to ExpensesTypeMaster + _mapper.Map(model, expensesType); + + _context.ExpensesTypeMaster.Update(expensesType); + await _context.SaveChangesAsync(); + + _logger.LogInfo("New Expense Type {ExpensesTypeId} was updated by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); + + // Saving the old entity in mongoDB + + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = expensesType.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, "ExpensesTypeMasterModificationLog"); + + // Mapping ExpensesTypeMaster to ExpensesTypeMasterVM + var response = _mapper.Map(expensesType); + return ApiResponse.SuccessResponse(response, "Expense type updated Successfully", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while updating expense type by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while updating expense type by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 7269ee0..67217c4 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -9,6 +9,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #region =================================================================== Expenses Type APIs =================================================================== Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); + Task> UpdateExpenseTypeAsync(Guid id, ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Expenses Status APIs =================================================================== From a196906bf9efa97c8d83c33e98818e582c9fb677 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 12:07:16 +0530 Subject: [PATCH 41/81] Added an API to update payment mode to master table for that tenant --- .../Controllers/MasterController.cs | 8 ++ Marco.Pms.Services/Service/MasterService.cs | 82 +++++++++++++++++-- .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 3f00d2e..1571229 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -929,6 +929,14 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpPut("payment-mode/edit/{id}")] + public async Task UpdatePaymentMode(Guid id, PaymentModeMatserDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdatePaymentModeAsync(id, dto, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + #endregion } } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index a03c8ef..4334370 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -82,7 +82,7 @@ namespace Marco.Pms.Services.Service if (!hasManagePermission) { _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } var expensesType = _mapper.Map(model); expensesType.TenantId = tenantId; @@ -122,7 +122,7 @@ namespace Marco.Pms.Services.Service if (!hasManagePermission) { _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } // Validating the prvided data @@ -150,7 +150,7 @@ namespace Marco.Pms.Services.Service _context.ExpensesTypeMaster.Update(expensesType); await _context.SaveChangesAsync(); - _logger.LogInfo("New Expense Type {ExpensesTypeId} was updated by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); + _logger.LogInfo("Expense Type {ExpensesTypeId} was updated by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id); // Saving the old entity in mongoDB @@ -236,7 +236,7 @@ namespace Marco.Pms.Services.Service if (!hasManagePermission) { _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } // Mapping the DTO to ExpensesStatusMaster Model @@ -317,7 +317,7 @@ namespace Marco.Pms.Services.Service if (!hasManagePermission) { _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing PAYMENT MODE MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Upload expenses for this project", 403); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } // Mapping the DTO to PaymentModeMatser Model @@ -345,6 +345,78 @@ namespace Marco.Pms.Services.Service } } + public async Task> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId) + { + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to update Payment Mode in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing PAYMENT MODE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + // Validating the prvided data + if (model.Id != id) + { + _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); + } + + var paymentMode = await _context.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId); + + // Checking if Payment Mode exists + if (paymentMode == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to update Payment Mode, but not found in database", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404); + } + + // Mapping PaymentModeMatser to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(paymentMode); + + // Mapping PaymentModeMatserDto to PaymentModeMatser + _mapper.Map(model, paymentMode); + + _context.PaymentModeMatser.Update(paymentMode); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Payment Mode {PaymentModeId} was updated by employee {EmployeeId}", paymentMode.Id, loggedInEmployee.Id); + + // Saving the old entity in mongoDB + + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = paymentMode.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, "PaymentModeMasterModificationLog"); + + // Mapping PaymentModeMatser to PaymentModeMatserVM + var response = _mapper.Map(paymentMode); + return ApiResponse.SuccessResponse(response, "Payment Mode updated Successfully", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while updating Payment Mode by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while updating Payment Mode by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } + #endregion #region =================================================================== Helper Function =================================================================== diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 67217c4..e5e869c 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -20,6 +20,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #region =================================================================== Payment mode APIs =================================================================== Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); + Task> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); #endregion } From 2ad0638d4f3356f9c8a54e1bb07d6467a08b0f09 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 12:26:34 +0530 Subject: [PATCH 42/81] Added applied filters in response --- Marco.Pms.Services/Service/ExpensesService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 416ecc3..6ee264b 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -195,6 +195,7 @@ namespace Marco.Pms.Services.Service _logger.LogInfo(message); var response = new { + Filter = expenseFilter, CurrentPage = pageNumber, TotalPages = totalPages, TotalEntites = totalEntites, From e31e19ed74ab1c87295f261ba5025a852215d9ac Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 12:28:06 +0530 Subject: [PATCH 43/81] Added an API to update expenses status to master table for that tenant --- .../Controllers/MasterController.cs | 7 ++ Marco.Pms.Services/Service/MasterService.cs | 99 +++++++++++++++++++ .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 107 insertions(+) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 1571229..013c890 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -908,6 +908,13 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.CreateExpensesStatusAsync(dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPut("expenses-status/edit/{id}")] + public async Task UpdateExpensesStatus(Guid id, ExpensesStatusMasterDto dto) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdateExpensesStatusAsync(id, dto, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 4334370..294b13c 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -12,12 +12,14 @@ using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Service; +using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; namespace Marco.Pms.Services.Service { public class MasterService : IMasterService { + private readonly IDbContextFactory _dbContextFactory; private readonly ApplicationDbContext _context; private readonly ILoggingService _logger; private readonly PermissionServices _permission; @@ -26,6 +28,7 @@ namespace Marco.Pms.Services.Service private readonly CacheUpdateHelper _cache; public MasterService( + IDbContextFactory dbContextFactory, ApplicationDbContext context, ILoggingService logger, PermissionServices permission, @@ -33,6 +36,7 @@ namespace Marco.Pms.Services.Service UtilityMongoDBHelper updateLogHelper, CacheUpdateHelper cache) { + _dbContextFactory = dbContextFactory; _context = context; _logger = logger; _permission = permission; @@ -275,6 +279,101 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } + public async Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId) + { + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to add new Expense Status in different tenant", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + + } + // Validating the prvided data + if (model.Id != id) + { + _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); + } + // featching expenses status and permissions parallelly + var expensesStatusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster.AsNoTracking() + .FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId); + }); + + var permissionStatusMappingsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping + .AsNoTracking() + .Where(ps => ps.StatusId == model.Id.Value && ps.TenantId == tenantId) + .ToListAsync(); + }); + + await Task.WhenAll(expensesStatusTask, permissionStatusMappingsTask); + var expensesStatus = expensesStatusTask.Result; + + // Checking if Expense Status exists + if (expensesStatus == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to update Expense Status, but not found in database", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Expense Status not found", "Expense Status not found", 404); + } + + // Mapping ExpensesStatusMaster to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesStatus); + + // Mapping ExpensesStatusMasterDto to ExpensesStatusMaster + _mapper.Map(model, expensesStatus); + + _context.ExpensesStatusMaster.Update(expensesStatus); + + var permissionStatusMappings = permissionStatusMappingsTask.Result; + var permissionIds = permissionStatusMappings.Select(ps => ps.PermissionId).ToList(); + if (model.PermissionIds != null) + { + var newPermissionStatusMappings = model.PermissionIds.Where(p => !permissionIds.Contains(p)).Select(p => new StatusPermissionMapping + { + PermissionId = p, + StatusId = expensesStatus.Id, + TenantId = tenantId + }).ToList(); + var deletedPermissionStatusMappings = permissionStatusMappings.Where(ps => !model.PermissionIds.Contains(ps.PermissionId)).ToList(); + + _context.StatusPermissionMapping.AddRange(newPermissionStatusMappings); + _context.StatusPermissionMapping.RemoveRange(deletedPermissionStatusMappings); + + } + await _context.SaveChangesAsync(); + + _logger.LogInfo("New Expense Status {ExpensesStatusId} was added by employee {EmployeeId}", expensesStatus.Id, loggedInEmployee.Id); + + // Mapping the ExpensesStatusMaster Model to View Model + var response = _mapper.Map(expensesStatus); + return ApiResponse.SuccessResponse(response, "Expense Status craeted Successfully", 201); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index e5e869c..24a26bf 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -15,6 +15,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #region =================================================================== Expenses Status APIs =================================================================== Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); + Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Payment mode APIs =================================================================== From b4931aafd6b9be2c74be8ee13de51935345dff58 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 12:54:49 +0530 Subject: [PATCH 44/81] Added an API to modify isActive parameter in Expense type master table for that tenant --- .../Controllers/MasterController.cs | 24 +++++-- Marco.Pms.Services/Service/MasterService.cs | 62 +++++++++++++++++++ .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 013c890..411a413 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -875,21 +875,31 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPost("expenses-type")] - public async Task CreateExpenseType(ExpensesTypeMasterDto dto) + public async Task CreateExpenseType([FromBody] ExpensesTypeMasterDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.CreateExpenseTypeAsync(dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPut("expenses-type/edit/{id}")] - public async Task UpdateExpenseType(Guid id, ExpensesTypeMasterDto dto) + public async Task UpdateExpenseType(Guid id, [FromBody] ExpensesTypeMasterDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.UpdateExpenseTypeAsync(id, dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpDelete("expenses-type/delete/{id}")] + public async Task DeleteExpenseType(Guid id, [FromQuery] bool isActive = false) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeleteExpenseTypeAsync(id, isActive, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + #endregion #region =================================================================== Expenses Status APIs =================================================================== @@ -901,15 +911,17 @@ namespace Marco.Pms.Services.Controllers var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPost("expenses-status")] - public async Task CreateExpensesStatus(ExpensesStatusMasterDto dto) + public async Task CreateExpensesStatus([FromBody] ExpensesStatusMasterDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.CreateExpensesStatusAsync(dto, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + [HttpPut("expenses-status/edit/{id}")] - public async Task UpdateExpensesStatus(Guid id, ExpensesStatusMasterDto dto) + public async Task UpdateExpensesStatus(Guid id, [FromBody] ExpensesStatusMasterDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.UpdateExpensesStatusAsync(id, dto, loggedInEmployee, tenantId); @@ -929,7 +941,7 @@ namespace Marco.Pms.Services.Controllers } [HttpPost("payment-mode")] - public async Task CreatePaymentMode(PaymentModeMatserDto dto) + public async Task CreatePaymentMode([FromBody] PaymentModeMatserDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.CreatePaymentModeAsync(dto, loggedInEmployee, tenantId); @@ -937,7 +949,7 @@ namespace Marco.Pms.Services.Controllers } [HttpPut("payment-mode/edit/{id}")] - public async Task UpdatePaymentMode(Guid id, PaymentModeMatserDto dto) + public async Task UpdatePaymentMode(Guid id, [FromBody] PaymentModeMatserDto dto) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _masterService.UpdatePaymentModeAsync(id, dto, loggedInEmployee, tenantId); diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 294b13c..a23a597 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -181,6 +181,68 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } + public async Task> DeleteExpenseTypeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) + { + string action = isActive ? "delete" : "restore"; + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to {Action} expense type in different tenant", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPANSES TYPE MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + var expensesType = await _context.ExpensesTypeMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); + + // Checking if expense type exists + if (expensesType == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to {Action} expense type, but not found in database", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Expense Type not found", "Expense Type not found", 404); + } + + // Mapping ExpensesTypeMaster to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesType); + + expensesType.IsActive = isActive; + await _context.SaveChangesAsync(); + + _logger.LogInfo("Expense Type {ExpensesTypeId} was {Action}d by employee {EmployeeId}", expensesType.Id, action, loggedInEmployee.Id); + + // Saving the old entity in mongoDB + + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = expensesType.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, "ExpensesTypeMasterModificationLog"); + + // Mapping ExpensesTypeMaster to ExpensesTypeMasterVM + var response = _mapper.Map(expensesType); + return ApiResponse.SuccessResponse(response, $"Expense type {action}d Successfully", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while {Action}ing expense type by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while {Action}ing expense type by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 24a26bf..774ac4a 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -10,6 +10,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpenseTypeAsync(Guid id, ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); + Task> DeleteExpenseTypeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Expenses Status APIs =================================================================== From f1e9a8655a9f0aeaffec931ae4efa202b64096bf Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 13:02:13 +0530 Subject: [PATCH 45/81] Added an API to modify isActive parameter in Expense status master table for that tenant --- .../Controllers/MasterController.cs | 8 +++ Marco.Pms.Services/Service/MasterService.cs | 63 ++++++++++++++++++- .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 411a413..a7b441e 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -928,6 +928,14 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpDelete("expenses-status/delete/{id}")] + public async Task DeleteExpensesStatus(Guid id, [FromQuery] bool isActive = false) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeleteExpensesStatusAsync(id, isActive, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + #endregion #region =================================================================== Payment mode APIs =================================================================== diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index a23a597..d264d11 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -287,7 +287,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } - public async Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId) { try @@ -436,6 +435,68 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } + public async Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) + { + string action = isActive ? "delete" : "restore"; + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to {Action} Expense Status in different tenant", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); + + // Checking if Expense Status exists + if (expensesStatus == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to {Action} Expense Status, but not found in database", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Expense Status not found", "Expense Status not found", 404); + } + + // Mapping ExpensesStatusMaster to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesStatus); + + expensesStatus.IsActive = isActive; + await _context.SaveChangesAsync(); + + _logger.LogInfo("Expense Status {ExpensesStatusId} was {Action}d by employee {EmployeeId}", expensesStatus.Id, action, loggedInEmployee.Id); + + // Saving the old entity in mongoDB + + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = expensesStatus.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, "ExpensesStatusMasterModificationLog"); + + // Mapping ExpensesStatusMaster to ExpensesStatusMasterVM + var response = _mapper.Map(expensesStatus); + return ApiResponse.SuccessResponse(response, $"Expense Status {action}d Successfully", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while {Action}ing Expense Status by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while {Action}ing Expense Status by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 774ac4a..039f5bf 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -17,6 +17,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); + Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); #endregion #region =================================================================== Payment mode APIs =================================================================== From aa47bfe59c10bea07a1e043fb951e994eab0b725 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 25 Jul 2025 13:06:28 +0530 Subject: [PATCH 46/81] Added an API to modify isActive parameter in Payment mode master table for that tenant --- .../Controllers/MasterController.cs | 8 +++ Marco.Pms.Services/Service/MasterService.cs | 63 ++++++++++++++++++- .../ServiceInterfaces/IMasterService.cs | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index a7b441e..2cfc1fe 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -964,6 +964,14 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpDelete("payment-mode/delete/{id}")] + public async Task DeletePaymentMode(Guid id, [FromQuery] bool isActive = false) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeletePaymentModeAsync(id, isActive, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + #endregion } } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index d264d11..e33fc59 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -566,7 +566,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } - public async Task> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId) { try @@ -638,6 +637,68 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } + public async Task> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) + { + string action = isActive ? "delete" : "restore"; + try + { + // Validation if employee is taking action in same tenant + if (tenantId != loggedInEmployee.TenantId) + { + _logger.LogWarning("Employee {EmployeeId} attempted to {Action} Payment Mode in different tenant", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); + } + + // Checking permssion for managing masters + var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); + if (!hasManagePermission) + { + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + var paymentMode = await _context.PaymentModeMatser.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); + + // Checking if Payment Mode exists + if (paymentMode == null) + { + _logger.LogWarning("Employee {EmployeeId} tries to {Action} Payment Mode, but not found in database", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse("Payment Mode not found", "Payment Mode not found", 404); + } + + // Mapping PaymentModeMatser to BsonDocument + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(paymentMode); + + paymentMode.IsActive = isActive; + await _context.SaveChangesAsync(); + + _logger.LogInfo("Payment Mode {PaymentModeId} was {Action}d by employee {EmployeeId}", paymentMode.Id, action, loggedInEmployee.Id); + + // Saving the old entity in mongoDB + + var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + { + EntityId = paymentMode.Id.ToString(), + UpdatedById = loggedInEmployee.Id.ToString(), + OldObject = existingEntityBson, + UpdatedAt = DateTime.UtcNow + }, "PaymentModeMatserModificationLog"); + + // Mapping PaymentModeMatser to PaymentModeMatserVM + var response = _mapper.Map(paymentMode); + return ApiResponse.SuccessResponse(response, $"Payment Mode {action}d Successfully", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Database Exception occured while {Action}ing Payment Mode by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while {Action}ing Payment Mode by employee {EmployeeId}", action, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 039f5bf..41154a9 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -24,6 +24,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); Task> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); + Task> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); #endregion } From 57d2b03c02c4990ab02fa69d7f3e55069bc9c417 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 26 Jul 2025 09:11:04 +0530 Subject: [PATCH 47/81] Change the id else logic to show proper message upon deletion or resotation of master entity in expenses module --- Marco.Pms.Services/Service/MasterService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index e33fc59..daa4191 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -183,7 +183,7 @@ namespace Marco.Pms.Services.Service } public async Task> DeleteExpenseTypeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) { - string action = isActive ? "delete" : "restore"; + string action = isActive ? "restore" : "delete"; try { // Validation if employee is taking action in same tenant @@ -437,7 +437,7 @@ namespace Marco.Pms.Services.Service } public async Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) { - string action = isActive ? "delete" : "restore"; + string action = isActive ? "restore" : "delete"; try { // Validation if employee is taking action in same tenant @@ -639,7 +639,7 @@ namespace Marco.Pms.Services.Service } public async Task> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) { - string action = isActive ? "delete" : "restore"; + string action = isActive ? "restore" : "delete"; try { // Validation if employee is taking action in same tenant From 7619ce9820ae15a430f344008616495903266bb7 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 26 Jul 2025 09:17:26 +0530 Subject: [PATCH 48/81] FIltering the master list by active and inactive --- Marco.Pms.Services/Controllers/MasterController.cs | 12 ++++++------ Marco.Pms.Services/Service/MasterService.cs | 14 +++++++------- .../Service/ServiceInterfaces/IMasterService.cs | 8 +++++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 2cfc1fe..61d9a2e 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -869,10 +869,10 @@ namespace Marco.Pms.Services.Controllers #region =================================================================== Expenses Type APIs =================================================================== [HttpGet("expenses-types")] - public async Task GetExpenseTypeList() + public async Task GetExpenseTypeList([FromQuery] bool isActive = true) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId); + var response = await _masterService.GetExpenseTypeListAsync(loggedInEmployee, tenantId, isActive); return StatusCode(response.StatusCode, response); } @@ -905,10 +905,10 @@ namespace Marco.Pms.Services.Controllers #region =================================================================== Expenses Status APIs =================================================================== [HttpGet("expenses-status")] - public async Task GetExpensesStatusList() + public async Task GetExpensesStatusList([FromQuery] bool isActive = true) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId); + var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId, isActive); return StatusCode(response.StatusCode, response); } @@ -941,10 +941,10 @@ namespace Marco.Pms.Services.Controllers #region =================================================================== Payment mode APIs =================================================================== [HttpGet("payment-modes")] - public async Task GetPaymentModeList() + public async Task GetPaymentModeList([FromQuery] bool isActive = true) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetPaymentModeListAsync(loggedInEmployee, tenantId); + var response = await _masterService.GetPaymentModeListAsync(loggedInEmployee, tenantId, isActive); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index daa4191..16d98b2 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -47,7 +47,7 @@ namespace Marco.Pms.Services.Service #region =================================================================== Expenses Type APIs =================================================================== - public async Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId) + public async Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive) { try { @@ -59,7 +59,7 @@ namespace Marco.Pms.Services.Service } // Featching the list of Expenses Type. - var typeList = await _context.ExpensesTypeMaster.Where(et => et.TenantId == tenantId).ToListAsync(); + var typeList = await _context.ExpensesTypeMaster.Where(et => et.TenantId == tenantId && et.IsActive == isActive).ToListAsync(); var response = _mapper.Map>(typeList); _logger.LogInfo("{Count} records of expense type have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id); @@ -247,7 +247,7 @@ namespace Marco.Pms.Services.Service #endregion #region =================================================================== Expenses Status APIs =================================================================== - public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId) + public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive) { try @@ -260,7 +260,7 @@ namespace Marco.Pms.Services.Service } // Featching the list of Expenses Status. - var statusList = await _context.ExpensesStatusMaster.Where(es => es.TenantId == tenantId).ToListAsync(); + var statusList = await _context.ExpensesStatusMaster.Where(es => es.TenantId == tenantId && es.IsActive == isActive).ToListAsync(); var response = _mapper.Map>(statusList); var statusIds = statusList.Select(s => s.Id).ToList(); @@ -455,7 +455,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } - var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); + var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId && !et.IsSystem); // Checking if Expense Status exists if (expensesStatus == null) @@ -501,7 +501,7 @@ namespace Marco.Pms.Services.Service #endregion #region =================================================================== Payment mode APIs =================================================================== - public async Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId) + public async Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive) { try { @@ -513,7 +513,7 @@ namespace Marco.Pms.Services.Service } // Featching the list of Payment Modes. - var paymentModes = await _context.PaymentModeMatser.Where(pm => pm.TenantId == tenantId).ToListAsync(); + var paymentModes = await _context.PaymentModeMatser.Where(pm => pm.TenantId == tenantId && pm.IsActive == isActive).ToListAsync(); var response = _mapper.Map>(paymentModes); _logger.LogInfo("{Count} records of payment modes have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id); diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 41154a9..7a64b3a 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -7,21 +7,23 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces public interface IMasterService { #region =================================================================== Expenses Type APIs =================================================================== - Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive); Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpenseTypeAsync(Guid id, ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> DeleteExpenseTypeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); #endregion + #region =================================================================== Expenses Status APIs =================================================================== - Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive); Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); #endregion + #region =================================================================== Payment mode APIs =================================================================== - Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive); Task> CreatePaymentModeAsync(PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdatePaymentModeAsync(Guid id, PaymentModeMatserDto model, Employee loggedInEmployee, Guid tenantId); Task> DeletePaymentModeAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); From 61741331e084176ba50cd4dfcffcc2de0bd4a2bc Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 28 Jul 2025 10:37:18 +0530 Subject: [PATCH 49/81] Corrected the feaching logic for expense delete API --- Marco.Pms.Services/Service/ExpensesService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 6ee264b..eadea99 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -874,7 +874,7 @@ namespace Marco.Pms.Services.Service public async Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { - var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.CreatedById == loggedInEmployee.Id && e.TenantId == tenantId); + var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId); var hasAprrovePermissionTask = Task.Run(async () => { From 5b091a8d6f1eb39d61cca378d77331710b451a3a Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 28 Jul 2025 11:18:26 +0530 Subject: [PATCH 50/81] Rewrite the uf condiotn in get expense details API --- Marco.Pms.Services/Service/ExpensesService.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index eadea99..c838aab 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1191,12 +1191,7 @@ namespace Marco.Pms.Services.Service if (statusMapping != null) { response.Status = _mapper.Map(statusMapping.Status); - if (response.Status == null) - { - var status = statusTask.Result; - response.Status = _mapper.Map(status); - } - response.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == Guid.Parse(model.StatusId)).Select(ps => ps.PermissionIds).FirstOrDefault(); + response.NextStatus = _mapper.Map>(statusMapping.NextStatus); if (response.NextStatus != null) { @@ -1206,6 +1201,12 @@ namespace Marco.Pms.Services.Service } } } + if (response.Status == null) + { + var status = statusTask.Result; + response.Status = _mapper.Map(status); + } + response.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == Guid.Parse(model.StatusId)).Select(ps => ps.PermissionIds).FirstOrDefault(); foreach (var document in model.Documents) { From 0b2883af0fd74319baf56d5e5ddc7165917089c6 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 28 Jul 2025 18:00:37 +0530 Subject: [PATCH 51/81] Added proper reponse message in expense APIs --- Marco.Pms.Services/Service/ExpensesService.cs | 227 +++++------------- Marco.Pms.Services/Service/MasterService.cs | 8 +- 2 files changed, 68 insertions(+), 167 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index c838aab..7d30672 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -206,34 +206,12 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while fetching list expenses"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } catch (Exception ex) { _logger.LogError(ex, "Error occured while fetching list expenses"); - return ApiResponse.ErrorResponse("Error Occured", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Error Occured", ExceptionMapper(ex), 500); } } public async Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId) @@ -259,18 +237,7 @@ namespace Marco.Pms.Services.Service catch (Exception ex) { _logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId}.", id); - return ApiResponse.ErrorResponse("An internal server error occurred.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("An internal server error occurred.", ExceptionMapper(ex), 500); } } public async Task> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId) @@ -284,18 +251,7 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while fetching suppler name list from expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } } @@ -448,50 +404,17 @@ namespace Marco.Pms.Services.Service { await transaction.RollbackAsync(); _logger.LogError(dbEx, "Databsae Exception occured while adding expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } catch (ArgumentException ex) // Catches bad Base64 from attachment pre-validation { _logger.LogError(ex, "Invalid argument during expense creation for project {ProjectId}.", dto.ProjectId); - return ApiResponse.ErrorResponse("Invalid Request Data.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 400); + return ApiResponse.ErrorResponse("Invalid Request Data.", ExceptionMapper(ex), 400); } catch (Exception ex) // General-purpose catch for unexpected errors (e.g., S3 or DB connection failure) { _logger.LogError(ex, "An unhandled exception occurred while creating an expense for project {ProjectId}.", dto.ProjectId); - return ApiResponse.ErrorResponse("An internal server error occurred.", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("An internal server error occurred.", ExceptionMapper(ex), 500); } } @@ -705,8 +628,6 @@ namespace Marco.Pms.Services.Service .Include(e => e.CreatedBy) .FirstOrDefaultAsync(e => e.Id == model.Id && - e.CreatedById == loggedInEmployee.Id && - (e.StatusId == Draft || e.StatusId == Rejected) && e.TenantId == tenantId); @@ -716,6 +637,17 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); } + if (existingExpense.StatusId != Draft && existingExpense.StatusId != Rejected) + { + _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Expense connot be updated", "Expense connot be updated", 400); + } + if (existingExpense.CreatedById != loggedInEmployee.Id) + { + _logger.LogWarning("User attempted to update expense with ID {ExpenseId} which not created by them", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("You donot have access to update this expense", "You donot have access to update this expense", 400); + } + var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes _mapper.Map(model, existingExpense); _context.Entry(existingExpense).State = EntityState.Modified; @@ -748,18 +680,7 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while adding new attachments during updating expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } } @@ -777,34 +698,12 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while deleting attachments during updating expense"); - return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", ExceptionMapper(ex), 500); } } } @@ -874,7 +773,11 @@ namespace Marco.Pms.Services.Service public async Task> DeleteExpanseAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { - var expenseQuery = _context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId); + var expenseTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync(); + }); var hasAprrovePermissionTask = Task.Run(async () => { @@ -883,13 +786,11 @@ namespace Marco.Pms.Services.Service return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id); }); - var hasAprrovePermission = await hasAprrovePermissionTask; - if (!hasAprrovePermission) - { - expenseQuery = expenseQuery.Where(e => e.CreatedById == loggedInEmployee.Id); - } + await Task.WhenAll(expenseTask, hasAprrovePermissionTask); + + var hasAprrovePermission = hasAprrovePermissionTask.Result; + var existingExpense = expenseTask.Result; - var existingExpense = await expenseQuery.FirstOrDefaultAsync(); if (existingExpense == null) { var message = hasAprrovePermission ? "Expenses not found" : "Expense cannot be deleted"; @@ -903,6 +804,19 @@ namespace Marco.Pms.Services.Service } return ApiResponse.ErrorResponse(message, message, 400); } + if (existingExpense.StatusId != Draft) + { + _logger.LogWarning("User attempted to delete expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Expense connot be deleted", "Expense connot be deleted", 400); + } + + if (!hasAprrovePermission && existingExpense.CreatedById != loggedInEmployee.Id) + { + _logger.LogWarning("User attempted to delete expense with ID {ExpenseId} which not created by them", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("You donot have access to delete this expense", "You donot have access to delete this expense", 400); + + } + var documentIds = await _context.BillAttachments .Where(ba => ba.ExpensesId == existingExpense.Id) .Select(ba => ba.DocumentId) @@ -919,18 +833,7 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while deleting expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } try { @@ -956,34 +859,12 @@ namespace Marco.Pms.Services.Service catch (DbUpdateException dbEx) { _logger.LogError(dbEx, "Databsae Exception occured while deleting attachments during updating expense"); - return ApiResponse.ErrorResponse("Databsae Exception", new - { - Message = dbEx.Message, - StackTrace = dbEx.StackTrace, - Source = dbEx.Source, - InnerException = new - { - Message = dbEx.InnerException?.Message, - StackTrace = dbEx.InnerException?.StackTrace, - Source = dbEx.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while deleting attachments during updating expense"); - return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", new - { - Message = ex.Message, - StackTrace = ex.StackTrace, - Source = ex.Source, - InnerException = new - { - Message = ex.InnerException?.Message, - StackTrace = ex.InnerException?.StackTrace, - Source = ex.InnerException?.Source, - } - }, 500); + return ApiResponse.ErrorResponse("Exception occured while deleting attachments during updating expense ", ExceptionMapper(ex), 500); } return ApiResponse.SuccessResponse("Success", "Expense Deleted Successfully", 200); } @@ -991,7 +872,21 @@ namespace Marco.Pms.Services.Service #endregion #region =================================================================== Helper Functions =================================================================== - + private static object ExceptionMapper(Exception ex) + { + return new + { + Message = ex.Message, + StackTrace = ex.StackTrace, + Source = ex.Source, + InnerException = new + { + Message = ex.InnerException?.Message, + StackTrace = ex.InnerException?.StackTrace, + Source = ex.InnerException?.Source, + } + }; + } private async Task> GetAllExpnesRelatedTables(List model, Guid tenantId) { List expenseList = new List(); diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 16d98b2..6d789bb 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -455,7 +455,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } - var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId && !et.IsSystem); + var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); // Checking if Expense Status exists if (expensesStatus == null) @@ -464,6 +464,12 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Expense Status not found", "Expense Status not found", 404); } + if (expensesStatus.IsSystem) + { + _logger.LogWarning("Employee {Employee} attempts to {Action} Expense status, but status is system defined", loggedInEmployee.Id, action); + return ApiResponse.ErrorResponse($"Expense Status is system defined cannot able to {action}", $"Expense Status is system defined cannot able to {action}", 400); + } + // Mapping ExpensesStatusMaster to BsonDocument var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesStatus); From 6c32a48095a65b28c56efeda7f49bc2c1686fd68 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 29 Jul 2025 15:47:49 +0530 Subject: [PATCH 52/81] Changed the display names of expense status --- Marco.Pms.DataAccess/Data/ApplicationDbContext.cs | 6 +++--- .../20250721124928_Added_Expense_Related_Tables.Designer.cs | 6 +++--- .../20250721124928_Added_Expense_Related_Tables.cs | 6 +++--- .../Migrations/ApplicationDbContextModelSnapshot.cs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index c01668f..cc01da9 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -404,7 +404,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), Name = "Review Pending", - DisplayName = "Review", + DisplayName = "Submit", Description = "Reviewer is currently reviewing the expense.", Color = "#696cff", IsSystem = true, @@ -415,7 +415,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Name = "Approval Pending", - DisplayName = "Approve", + DisplayName = "Reviewed", Description = "Review is completed, waiting for action of approver.", Color = "#03c3ec", IsSystem = true, @@ -447,7 +447,7 @@ namespace Marco.Pms.DataAccess.Data new ExpensesStatusMaster { Id = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), - Name = "Processed", + Name = "Paid", DisplayName = "Paid", Description = "Expense has been settled.", Color = "#71dd37", diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index 40fe611..f359fee 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1947,7 +1947,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), Color = "#696cff", Description = "Reviewer is currently reviewing the expense.", - DisplayName = "Review", + DisplayName = "Submit", IsActive = true, IsSystem = true, Name = "Review Pending", @@ -1958,7 +1958,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", - DisplayName = "Approve", + DisplayName = "Reviewed", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1994,7 +1994,7 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Paid", IsActive = true, IsSystem = true, - Name = "Processed", + Name = "Paid", TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }); }); diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index ffc5400..30ad9ce 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -373,9 +373,9 @@ namespace Marco.Pms.DataAccess.Migrations values: new object[,] { { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#8592a3", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Approve", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Paid", true, true, "Processed", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Review", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Reviewed", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Paid", true, true, "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Submit", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#ff3e1d", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Process", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index ed3710f..83218db 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1944,7 +1944,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), Color = "#696cff", Description = "Reviewer is currently reviewing the expense.", - DisplayName = "Review", + DisplayName = "Submit", IsActive = true, IsSystem = true, Name = "Review Pending", @@ -1955,7 +1955,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", - DisplayName = "Approve", + DisplayName = "Reviewed", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1991,7 +1991,7 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Paid", IsActive = true, IsSystem = true, - Name = "Processed", + Name = "Paid", TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }); }); From ce4e52e69d2a008b5ad5f6bd92510fd8f7f21ef2 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 29 Jul 2025 15:59:12 +0530 Subject: [PATCH 53/81] Chnage the name of Prosecc Pending to payment Payment pending --- Marco.Pms.DataAccess/Data/ApplicationDbContext.cs | 4 ++-- .../20250721124928_Added_Expense_Related_Tables.Designer.cs | 4 ++-- .../Migrations/20250721124928_Added_Expense_Related_Tables.cs | 2 +- .../Migrations/ApplicationDbContextModelSnapshot.cs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index cc01da9..8e7ed83 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -436,8 +436,8 @@ namespace Marco.Pms.DataAccess.Data new ExpensesStatusMaster { Id = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - Name = "Process Pending", - DisplayName = "Process", + Name = "Payment Pending", + DisplayName = "Approved", Description = "Approved expense is awaiting final payment.", Color = "#ffab00", IsSystem = true, diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index f359fee..931ec5b 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1980,10 +1980,10 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Color = "#ffab00", Description = "Approved expense is awaiting final payment.", - DisplayName = "Process", + DisplayName = "Approved", IsActive = true, IsSystem = true, - Name = "Process Pending", + Name = "Payment Pending", TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, new diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index 30ad9ce..f7f74ef 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -377,7 +377,7 @@ namespace Marco.Pms.DataAccess.Migrations { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Paid", true, true, "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Submit", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#ff3e1d", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Process", true, true, "Process Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Approved", true, true, "Payment Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); migrationBuilder.InsertData( diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 83218db..8765c37 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1977,10 +1977,10 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Color = "#ffab00", Description = "Approved expense is awaiting final payment.", - DisplayName = "Process", + DisplayName = "Approved", IsActive = true, IsSystem = true, - Name = "Process Pending", + Name = "Payment Pending", TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, new From f4368ae4e3a1374a1b35bcf1008d643d09d3fdde Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 29 Jul 2025 17:17:57 +0530 Subject: [PATCH 54/81] change display name fo expense status from Paid to Mark as Paid --- Marco.Pms.DataAccess/Data/ApplicationDbContext.cs | 2 +- .../20250721124928_Added_Expense_Related_Tables.Designer.cs | 2 +- .../Migrations/20250721124928_Added_Expense_Related_Tables.cs | 2 +- .../Migrations/ApplicationDbContextModelSnapshot.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 8e7ed83..92a0251 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -448,7 +448,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), Name = "Paid", - DisplayName = "Paid", + DisplayName = "Mark as Paid", Description = "Expense has been settled.", Color = "#71dd37", IsSystem = true, diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index 931ec5b..b370dc4 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1991,7 +1991,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), Color = "#71dd37", Description = "Expense has been settled.", - DisplayName = "Paid", + DisplayName = "Mark as Paid", IsActive = true, IsSystem = true, Name = "Paid", diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index f7f74ef..d4259fa 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -374,7 +374,7 @@ namespace Marco.Pms.DataAccess.Migrations { { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#8592a3", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Reviewed", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Paid", true, true, "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Mark as Paid", true, true, "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Submit", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#ff3e1d", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Approved", true, true, "Payment Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 8765c37..592e88d 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1988,7 +1988,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), Color = "#71dd37", Description = "Expense has been settled.", - DisplayName = "Paid", + DisplayName = "Mark as Paid", IsActive = true, IsSystem = true, Name = "Paid", From 0c1cb98f5b81b74a2223c95bded5500468f2ac2a Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 29 Jul 2025 18:11:33 +0530 Subject: [PATCH 55/81] Added the code to save reimbursement in database --- .../Dtos/Expenses/ExpenseRecordDto.cs | 3 ++ .../ViewModels/Expenses/ExpenseDetailsVM.cs | 1 + .../Expenses/ExpensesReimburseVM.cs | 13 ++++++ .../MappingProfiles/MappingProfile.cs | 2 + Marco.Pms.Services/Service/ExpensesService.cs | 41 ++++++++++++++++++- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 Marco.Pms.Model/ViewModels/Expenses/ExpensesReimburseVM.cs diff --git a/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs index 3731f3b..d59c90e 100644 --- a/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs +++ b/Marco.Pms.Model/Dtos/Expenses/ExpenseRecordDto.cs @@ -5,5 +5,8 @@ public Guid ExpenseId { get; set; } public Guid StatusId { get; set; } public string? Comment { get; set; } + public string? ReimburseTransactionId { get; set; } + public DateTime? ReimburseDate { get; set; } + public Guid? ReimburseById { get; set; } } } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs index 34ecc24..b59bd59 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -27,5 +27,6 @@ namespace Marco.Pms.Model.ViewModels.Expenses public string? GSTNumber { get; set; } public int? NoOfPersons { get; set; } public bool IsActive { get; set; } = true; + public List ExpensesReimburse { get; set; } = new List(); } } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpensesReimburseVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpensesReimburseVM.cs new file mode 100644 index 0000000..75e04ba --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpensesReimburseVM.cs @@ -0,0 +1,13 @@ +using Marco.Pms.Model.ViewModels.Activities; + +namespace Marco.Pms.Model.ViewModels.Expenses +{ + public class ExpensesReimburseVM + { + public Guid Id { get; set; } + public string ReimburseTransactionId { get; set; } = string.Empty; + public DateTime ReimburseDate { get; set; } + public BasicEmployeeVM? ReimburseBy { get; set; } + public string ReimburseNote { get; set; } = string.Empty; + } +} diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 2a99028..793e94a 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -123,6 +123,8 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + + CreateMap(); CreateMap() .ForMember( dest => dest.Id, diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 7d30672..2ae8c20 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -35,6 +35,7 @@ namespace Marco.Pms.Services.Service private readonly IMapper _mapper; private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); private static readonly Guid Rejected = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); + private static readonly Guid PaidStatus = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"); private static readonly string Collection = "ExpensesModificationLog"; public ExpensesService( IDbContextFactory dbContextFactory, @@ -490,6 +491,17 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("This status change is not allowed.", "Invalid Transition", 400); } + if (statusMapping.NextStatusId == PaidStatus && + (string.IsNullOrWhiteSpace(model.ReimburseTransactionId) || + !model.ReimburseDate.HasValue || + model.ReimburseById == null || + model.ReimburseById == Guid.Empty)) + { + _logger.LogWarning("Invalid status transition attempted for ExpenseId: {ExpenseId}. From StatusId: {FromStatusId} to {ToStatusId}", + existingExpense.Id, existingExpense.StatusId, model.StatusId); + return ApiResponse.ErrorResponse("This status change is not allowed.", "Invalid Transition", 400); + } + // Check permissions. The logic is: // 1. If the target status has specific permissions defined, the user must have at least one of them. // 2. If no permissions are defined for the target status, only the original creator of the expense can change it. @@ -527,6 +539,23 @@ namespace Marco.Pms.Services.Service existingExpense.StatusId = statusMapping.NextStatusId; existingExpense.Status = statusMapping.NextStatus; // Assigning the included entity for the response mapping. + var expensesRemburse = new ExpensesReimburse + { + ReimburseTransactionId = model.ReimburseTransactionId!, + ReimburseDate = model.ReimburseDate!.Value, + ReimburseById = model.ReimburseById!.Value, + ReimburseNote = model.Comment ?? string.Empty, + TenantId = tenantId + }; + _context.ExpensesReimburse.Add(expensesRemburse); + + _context.ExpensesReimburseMapping.Add(new ExpensesReimburseMapping + { + ExpensesId = existingExpense.Id, + ExpensesReimburseId = expensesRemburse.Id, + TenantId = tenantId + }); + _context.ExpenseLogs.Add(new ExpenseLog { ExpenseId = existingExpense.Id, @@ -1064,9 +1093,17 @@ namespace Marco.Pms.Services.Service PermissionIds = g.Select(ps => ps.PermissionId).ToList() }).ToListAsync(); }); + var expenseReimburseTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesReimburseMapping + .Include(er => er.ExpensesReimburse) + .Where(er => er.TenantId == tenantId && er.ExpensesId == Guid.Parse(model.Id)) + .Select(er => er.ExpensesReimburse).ToListAsync(); + }); // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask, expenseReimburseTask); var project = projectTask.Result; var expenseType = expenseTypeTask.Result; @@ -1075,6 +1112,7 @@ namespace Marco.Pms.Services.Service var permissionStatusMappings = permissionStatusMappingTask.Result; var paidBy = paidByTask.Result; var createdBy = createdByTask.Result; + var expensesReimburse = expenseReimburseTask.Result; var response = _mapper.Map(model); @@ -1083,6 +1121,7 @@ namespace Marco.Pms.Services.Service response.CreatedBy = _mapper.Map(createdBy); response.PaymentMode = _mapper.Map(paymentMode); response.ExpensesType = _mapper.Map(expenseType); + response.ExpensesReimburse = _mapper.Map>(expensesReimburse); if (statusMapping != null) { response.Status = _mapper.Map(statusMapping.Status); From 4325dffc065a42c5f5917e4e5b20591fee4df716 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 30 Jul 2025 09:34:16 +0530 Subject: [PATCH 56/81] change ExpensesReimburse from list to single entity in expense details view model --- Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs | 2 +- Marco.Pms.Services/Service/ExpensesService.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs index b59bd59..becf685 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -27,6 +27,6 @@ namespace Marco.Pms.Model.ViewModels.Expenses public string? GSTNumber { get; set; } public int? NoOfPersons { get; set; } public bool IsActive { get; set; } = true; - public List ExpensesReimburse { get; set; } = new List(); + public ExpensesReimburseVM ExpensesReimburse { get; set; } = new ExpensesReimburseVM(); } } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 2ae8c20..0be0872 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1099,7 +1099,7 @@ namespace Marco.Pms.Services.Service return await dbContext.ExpensesReimburseMapping .Include(er => er.ExpensesReimburse) .Where(er => er.TenantId == tenantId && er.ExpensesId == Guid.Parse(model.Id)) - .Select(er => er.ExpensesReimburse).ToListAsync(); + .Select(er => er.ExpensesReimburse).FirstOrDefaultAsync(); }); // Await all prerequisite checks at once. @@ -1121,7 +1121,7 @@ namespace Marco.Pms.Services.Service response.CreatedBy = _mapper.Map(createdBy); response.PaymentMode = _mapper.Map(paymentMode); response.ExpensesType = _mapper.Map(expenseType); - response.ExpensesReimburse = _mapper.Map>(expensesReimburse); + response.ExpensesReimburse = _mapper.Map(expensesReimburse); if (statusMapping != null) { response.Status = _mapper.Map(statusMapping.Status); From 388979ef823a9753dca4ea9e8ee18737519a3554 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 30 Jul 2025 10:08:26 +0530 Subject: [PATCH 57/81] Chnage Reviewed to Mark as Reviewed in expenses status --- Marco.Pms.DataAccess/Data/ApplicationDbContext.cs | 4 ++-- .../20250721124928_Added_Expense_Related_Tables.Designer.cs | 4 ++-- .../Migrations/20250721124928_Added_Expense_Related_Tables.cs | 4 ++-- .../Migrations/ApplicationDbContextModelSnapshot.cs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 92a0251..d9894f3 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -415,7 +415,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Name = "Approval Pending", - DisplayName = "Reviewed", + DisplayName = "Mark as Reviewed", Description = "Review is completed, waiting for action of approver.", Color = "#03c3ec", IsSystem = true, @@ -437,7 +437,7 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Name = "Payment Pending", - DisplayName = "Approved", + DisplayName = "Mark as Approved", Description = "Approved expense is awaiting final payment.", Color = "#ffab00", IsSystem = true, diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs index b370dc4..495a2a8 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.Designer.cs @@ -1958,7 +1958,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", - DisplayName = "Reviewed", + DisplayName = "Mark as Reviewed", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1980,7 +1980,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Color = "#ffab00", Description = "Approved expense is awaiting final payment.", - DisplayName = "Approved", + DisplayName = "Mark as Approved", IsActive = true, IsSystem = true, Name = "Payment Pending", diff --git a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs index d4259fa..11136ab 100644 --- a/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs +++ b/Marco.Pms.DataAccess/Migrations/20250721124928_Added_Expense_Related_Tables.cs @@ -373,11 +373,11 @@ namespace Marco.Pms.DataAccess.Migrations values: new object[,] { { new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), "#8592a3", "Expense has been created but not yet submitted.", "Draft", true, true, "Draft", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Reviewed", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), "#03c3ec", "Review is completed, waiting for action of approver.", "Mark as Reviewed", true, true, "Approval Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), "#71dd37", "Expense has been settled.", "Mark as Paid", true, true, "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), "#696cff", "Reviewer is currently reviewing the expense.", "Submit", true, true, "Review Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, { new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), "#ff3e1d", "Expense was declined, often with a reason(either review rejected or approval rejected.", "Reject", true, true, "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, - { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Approved", true, true, "Payment Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + { new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), "#ffab00", "Approved expense is awaiting final payment.", "Mark as Approved", true, true, "Payment Pending", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } }); migrationBuilder.InsertData( diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 592e88d..b2fd07b 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1955,7 +1955,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), Color = "#03c3ec", Description = "Review is completed, waiting for action of approver.", - DisplayName = "Reviewed", + DisplayName = "Mark as Reviewed", IsActive = true, IsSystem = true, Name = "Approval Pending", @@ -1977,7 +1977,7 @@ namespace Marco.Pms.DataAccess.Migrations Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), Color = "#ffab00", Description = "Approved expense is awaiting final payment.", - DisplayName = "Approved", + DisplayName = "Mark as Approved", IsActive = true, IsSystem = true, Name = "Payment Pending", From d28f37714fa682bcca117647fb5fce1f1e3ae5b7 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 30 Jul 2025 12:24:19 +0530 Subject: [PATCH 58/81] Added new status and change expesne status from tenant scop to system scope --- .../Data/ApplicationDbContext.cs | 123 +- ...penseStatus_To_Be_System_Scope.Designer.cs | 4346 +++++++++++++++++ ...Change_ExpenseStatus_To_Be_System_Scope.cs | 437 ++ .../ApplicationDbContextModelSnapshot.cs | 173 +- Marco.Pms.Model/Expenses/Expenses.cs | 15 + .../Expenses/ExpensesStatusMapping.cs | 3 +- .../Expenses/StatusPermissionMapping.cs | 3 +- Marco.Pms.Model/Master/CurrencyMaster.cs | 11 + .../Master/ExpensesStatusMaster.cs | 6 +- .../Expenses/ExpenseDetailsMongoDB.cs | 3 + .../Masters/ExpensesStatusMasterMongoDB.cs | 1 - Marco.Pms.Model/Utilities/ExpensesFilter.cs | 1 + .../ViewModels/Expenses/ExpenseDetailsVM.cs | 3 + .../ViewModels/Expenses/ExpenseList.cs | 3 + .../Controllers/MasterController.cs | 26 +- .../MappingProfiles/MappingProfile.cs | 23 +- Marco.Pms.Services/Service/ExpensesService.cs | 29 +- Marco.Pms.Services/Service/MasterService.cs | 223 +- .../ServiceInterfaces/IMasterService.cs | 5 +- 19 files changed, 5018 insertions(+), 416 deletions(-) create mode 100644 Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.cs create mode 100644 Marco.Pms.Model/Master/CurrencyMaster.cs diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index d9894f3..87f5e84 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -397,8 +397,7 @@ namespace Marco.Pms.DataAccess.Data Description = "Expense has been created but not yet submitted.", Color = "#8592a3", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true }, new ExpensesStatusMaster { @@ -408,8 +407,17 @@ namespace Marco.Pms.DataAccess.Data Description = "Reviewer is currently reviewing the expense.", Color = "#696cff", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true + }, + new ExpensesStatusMaster + { + Id = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b"), + Name = "Rejected by Reviewer", + DisplayName = "Reject", + Description = "Expense was declined, often with a reason(review rejected).", + Color = "#ff3e1d", + IsSystem = true, + IsActive = true }, new ExpensesStatusMaster { @@ -419,19 +427,17 @@ namespace Marco.Pms.DataAccess.Data Description = "Review is completed, waiting for action of approver.", Color = "#03c3ec", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true }, new ExpensesStatusMaster { Id = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - Name = "Rejected", + Name = "Rejected by Approver", DisplayName = "Reject", - Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + Description = "Expense was declined, often with a reason(approval rejected).", Color = "#ff3e1d", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true }, new ExpensesStatusMaster { @@ -441,19 +447,17 @@ namespace Marco.Pms.DataAccess.Data Description = "Approved expense is awaiting final payment.", Color = "#ffab00", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true }, new ExpensesStatusMaster { Id = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), - Name = "Paid", - DisplayName = "Mark as Paid", + Name = "Processed", + DisplayName = "Mark as Processed", Description = "Expense has been settled.", Color = "#71dd37", IsSystem = true, - IsActive = true, - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + IsActive = true } ); @@ -463,99 +467,108 @@ namespace Marco.Pms.DataAccess.Data { Id = Guid.Parse("5cf7f1df-9d1f-4289-add0-1775ad614f25"), StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - NextStatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95") }, - // Approve to Rejected + // Rejected by Approver to Review + new ExpensesStatusMapping + { + Id = Guid.Parse("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), + StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), + NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + // Approve to Rejected by Approver new ExpensesStatusMapping { Id = Guid.Parse("36c00548-241c-43ec-bc95-cacebedb925c"), StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - NextStatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729") }, // Approve to Process new ExpensesStatusMapping { Id = Guid.Parse("1fca1700-1266-477d-bba4-9ac3753aa33c"), StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27") }, - // Rejected to Review + // Rejected by Reviewer to Review new ExpensesStatusMapping { - Id = Guid.Parse("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), - StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + Id = Guid.Parse("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + StatusId = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b"), + NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7") }, - // Review to Rejected + // Review to Rejected by Reviewer new ExpensesStatusMapping { - Id = Guid.Parse("fddaaf20-4ccc-4f4e-a724-dd310272b356"), + Id = Guid.Parse("6b867bec-66e6-42a7-9611-f4595af9b9ce"), StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - NextStatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b") }, // Review to Aprrove new ExpensesStatusMapping { Id = Guid.Parse("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - NextStatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, // Draft to Review new ExpensesStatusMapping { Id = Guid.Parse("af1e4492-98ee-4451-8ab7-fd8323f29c32"), StatusId = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"), - NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + NextStatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7") } ); modelBuilder.Entity().HasData( - + // Draft Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), + PermissionId = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8") + }, + // Review Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), + PermissionId = Guid.Parse("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + // Rejected by Reviewer Permission Mapping + new StatusPermissionMapping + { + Id = Guid.Parse("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + PermissionId = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b") + }, // Approval Pending Permission Mapping new StatusPermissionMapping { - Id = Guid.Parse("ed893799-1a5f-4311-a077-de93c86ca8fd"), + Id = Guid.Parse("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), PermissionId = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"), - StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") - }, - // Rejected Permission Mapping - new StatusPermissionMapping - { - Id = Guid.Parse("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), - PermissionId = Guid.Parse("1f4bda08-1873-449a-bb66-3e8222bd871b"), - StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, + // Rejected by Approver Permission Mapping new StatusPermissionMapping { Id = Guid.Parse("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), PermissionId = Guid.Parse("eaafdd76-8aac-45f9-a530-315589c6deca"), - StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729") }, - // Process Pending Permission Mapping + // Payment Pending Permission Mapping new StatusPermissionMapping { Id = Guid.Parse("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), PermissionId = Guid.Parse("eaafdd76-8aac-45f9-a530-315589c6deca"), - StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27") }, // Processed Permission Mapping new StatusPermissionMapping { Id = Guid.Parse("214354e5-daad-4569-ad69-eb5bf4e87fbc"), PermissionId = Guid.Parse("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), - StatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"), - TenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95") }); modelBuilder.Entity().HasData( diff --git a/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.Designer.cs new file mode 100644 index 0000000..7f8875d --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.Designer.cs @@ -0,0 +1,4346 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250730063711_Change_ExpenseStatus_To_Be_System_Scope")] + partial class Change_ExpenseStatus_To_Be_System_Scope + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProcessedById") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReviewedById") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProcessedById"); + + b.HasIndex("ProjectId"); + + b.HasIndex("ReviewedById"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("StatusId"); + + b.ToTable("ExpensesStatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce"), + NextStatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + + b.HasData( + new + { + Id = new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }, + new + { + Id = new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Color") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Color = "#8592a3", + Description = "Expense has been created but not yet submitted.", + DisplayName = "Draft", + IsActive = true, + IsSystem = true, + Name = "Draft" + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Color = "#696cff", + Description = "Reviewer is currently reviewing the expense.", + DisplayName = "Submit", + IsActive = true, + IsSystem = true, + Name = "Review Pending" + }, + new + { + Id = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(review rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Reviewer" + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Color = "#03c3ec", + Description = "Review is completed, waiting for action of approver.", + DisplayName = "Mark as Reviewed", + IsActive = true, + IsSystem = true, + Name = "Approval Pending" + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(approval rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Approver" + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Color = "#ffab00", + Description = "Approved expense is awaiting final payment.", + DisplayName = "Mark as Approved", + IsActive = true, + IsSystem = true, + Name = "Payment Pending" + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Color = "#71dd37", + Description = "Expense has been settled.", + DisplayName = "Mark as Processed", + IsActive = true, + IsSystem = true, + Name = "Processed" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#8592a3", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ProcessedBy") + .WithMany() + .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") + .WithMany() + .HasForeignKey("ReviewedById"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApprovedBy"); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("ProcessedBy"); + + b.Navigation("Project"); + + b.Navigation("ReviewedBy"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.cs b/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.cs new file mode 100644 index 0000000..e8a09c7 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250730063711_Change_ExpenseStatus_To_Be_System_Scope.cs @@ -0,0 +1,437 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Change_ExpenseStatus_To_Be_System_Scope : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ExpensesStatusMapping_Tenants_TenantId", + table: "ExpensesStatusMapping"); + + migrationBuilder.DropForeignKey( + name: "FK_ExpensesStatusMaster_Tenants_TenantId", + table: "ExpensesStatusMaster"); + + migrationBuilder.DropForeignKey( + name: "FK_StatusPermissionMapping_Tenants_TenantId", + table: "StatusPermissionMapping"); + + migrationBuilder.DropIndex( + name: "IX_StatusPermissionMapping_TenantId", + table: "StatusPermissionMapping"); + + migrationBuilder.DropIndex( + name: "IX_ExpensesStatusMaster_TenantId", + table: "ExpensesStatusMaster"); + + migrationBuilder.DropIndex( + name: "IX_ExpensesStatusMapping_TenantId", + table: "ExpensesStatusMapping"); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e")); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd")); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "StatusPermissionMapping"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "ExpensesStatusMaster"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "ExpensesStatusMapping"); + + migrationBuilder.AddColumn( + name: "ApprovedById", + table: "Expenses", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "ProcessedById", + table: "Expenses", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "ReviewedById", + table: "Expenses", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.InsertData( + table: "ExpensesStatusMapping", + columns: new[] { "Id", "NextStatusId", "StatusId" }, + values: new object[] { new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") }); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + columns: new[] { "DisplayName", "Name" }, + values: new object[] { "Mark as Processed", "Processed" }); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + columns: new[] { "Description", "Name" }, + values: new object[] { "Expense was declined, often with a reason(approval rejected).", "Rejected by Approver" }); + + migrationBuilder.InsertData( + table: "ExpensesStatusMaster", + columns: new[] { "Id", "Color", "Description", "DisplayName", "IsActive", "IsSystem", "Name" }, + values: new object[] { new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), "#ff3e1d", "Expense was declined, often with a reason(review rejected).", "Reject", true, true, "Rejected by Reviewer" }); + + migrationBuilder.InsertData( + table: "StatusPermissionMapping", + columns: new[] { "Id", "PermissionId", "StatusId" }, + values: new object[,] + { + { new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, + { new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") }, + { new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") } + }); + + migrationBuilder.InsertData( + table: "ExpensesStatusMapping", + columns: new[] { "Id", "NextStatusId", "StatusId" }, + values: new object[,] + { + { new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce"), new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") }, + { new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") } + }); + + migrationBuilder.InsertData( + table: "StatusPermissionMapping", + columns: new[] { "Id", "PermissionId", "StatusId" }, + values: new object[] { new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") }); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_ApprovedById", + table: "Expenses", + column: "ApprovedById"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_ProcessedById", + table: "Expenses", + column: "ProcessedById"); + + migrationBuilder.CreateIndex( + name: "IX_Expenses_ReviewedById", + table: "Expenses", + column: "ReviewedById"); + + migrationBuilder.AddForeignKey( + name: "FK_Expenses_Employees_ApprovedById", + table: "Expenses", + column: "ApprovedById", + principalTable: "Employees", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Expenses_Employees_ProcessedById", + table: "Expenses", + column: "ProcessedById", + principalTable: "Employees", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Expenses_Employees_ReviewedById", + table: "Expenses", + column: "ReviewedById", + principalTable: "Employees", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Expenses_Employees_ApprovedById", + table: "Expenses"); + + migrationBuilder.DropForeignKey( + name: "FK_Expenses_Employees_ProcessedById", + table: "Expenses"); + + migrationBuilder.DropForeignKey( + name: "FK_Expenses_Employees_ReviewedById", + table: "Expenses"); + + migrationBuilder.DropIndex( + name: "IX_Expenses_ApprovedById", + table: "Expenses"); + + migrationBuilder.DropIndex( + name: "IX_Expenses_ProcessedById", + table: "Expenses"); + + migrationBuilder.DropIndex( + name: "IX_Expenses_ReviewedById", + table: "Expenses"); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54")); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce")); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d")); + + migrationBuilder.DeleteData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e")); + + migrationBuilder.DeleteData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("965eda62-7907-4963-b4a1-657fb0b2724b")); + + migrationBuilder.DropColumn( + name: "ApprovedById", + table: "Expenses"); + + migrationBuilder.DropColumn( + name: "ProcessedById", + table: "Expenses"); + + migrationBuilder.DropColumn( + name: "ReviewedById", + table: "Expenses"); + + migrationBuilder.AddColumn( + name: "TenantId", + table: "StatusPermissionMapping", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "TenantId", + table: "ExpensesStatusMaster", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "TenantId", + table: "ExpensesStatusMapping", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci"); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMapping", + keyColumn: "Id", + keyValue: new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.InsertData( + table: "ExpensesStatusMapping", + columns: new[] { "Id", "NextStatusId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + columns: new[] { "DisplayName", "Name", "TenantId" }, + values: new object[] { "Mark as Paid", "Paid", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + columns: new[] { "Description", "Name", "TenantId" }, + values: new object[] { "Expense was declined, often with a reason(either review rejected or approval rejected.", "Rejected", new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }); + + migrationBuilder.UpdateData( + table: "ExpensesStatusMaster", + keyColumn: "Id", + keyValue: new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.UpdateData( + table: "StatusPermissionMapping", + keyColumn: "Id", + keyValue: new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + column: "TenantId", + value: new Guid("b3466e83-7e11-464c-b93a-daf047838b26")); + + migrationBuilder.InsertData( + table: "StatusPermissionMapping", + columns: new[] { "Id", "PermissionId", "StatusId", "TenantId" }, + values: new object[,] + { + { new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") }, + { new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd"), new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), new Guid("b3466e83-7e11-464c-b93a-daf047838b26") } + }); + + migrationBuilder.CreateIndex( + name: "IX_StatusPermissionMapping_TenantId", + table: "StatusPermissionMapping", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMaster_TenantId", + table: "ExpensesStatusMaster", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ExpensesStatusMapping_TenantId", + table: "ExpensesStatusMapping", + column: "TenantId"); + + migrationBuilder.AddForeignKey( + name: "FK_ExpensesStatusMapping_Tenants_TenantId", + table: "ExpensesStatusMapping", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ExpensesStatusMaster_Tenants_TenantId", + table: "ExpensesStatusMaster", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_StatusPermissionMapping_Tenants_TenantId", + table: "StatusPermissionMapping", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index b2fd07b..528e15d 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1330,6 +1330,9 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("Amount") .HasColumnType("double"); + b.Property("ApprovedById") + .HasColumnType("char(36)"); + b.Property("CreatedAt") .HasColumnType("datetime(6)"); @@ -1364,9 +1367,15 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("PreApproved") .HasColumnType("tinyint(1)"); + b.Property("ProcessedById") + .HasColumnType("char(36)"); + b.Property("ProjectId") .HasColumnType("char(36)"); + b.Property("ReviewedById") + .HasColumnType("char(36)"); + b.Property("StatusId") .HasColumnType("char(36)"); @@ -1385,6 +1394,8 @@ namespace Marco.Pms.DataAccess.Migrations b.HasKey("Id"); + b.HasIndex("ApprovedById"); + b.HasIndex("CreatedById"); b.HasIndex("ExpensesTypeId"); @@ -1393,8 +1404,12 @@ namespace Marco.Pms.DataAccess.Migrations b.HasIndex("PaymentModeId"); + b.HasIndex("ProcessedById"); + b.HasIndex("ProjectId"); + b.HasIndex("ReviewedById"); + b.HasIndex("StatusId"); b.HasIndex("TenantId"); @@ -1472,17 +1487,12 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("StatusId") .HasColumnType("char(36)"); - b.Property("TenantId") - .HasColumnType("char(36)"); - b.HasKey("Id"); b.HasIndex("NextStatusId"); b.HasIndex("StatusId"); - b.HasIndex("TenantId"); - b.ToTable("ExpensesStatusMapping"); b.HasData( @@ -1490,50 +1500,49 @@ namespace Marco.Pms.DataAccess.Migrations { Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") }, new { Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, new { Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, new { - Id = new Guid("75bbda6a-6a53-47d1-ad71-5f5f9446a11e"), + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") }, new { - Id = new Guid("fddaaf20-4ccc-4f4e-a724-dd310272b356"), - NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Id = new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce"), + NextStatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") }, new { Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") }, new { Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), - StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") }); }); @@ -1549,54 +1558,56 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("StatusId") .HasColumnType("char(36)"); - b.Property("TenantId") - .HasColumnType("char(36)"); - b.HasKey("Id"); b.HasIndex("PermissionId"); b.HasIndex("StatusId"); - b.HasIndex("TenantId"); - b.ToTable("StatusPermissionMapping"); b.HasData( new { - Id = new Guid("ed893799-1a5f-4311-a077-de93c86ca8fd"), - PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), - StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Id = new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") }, new { - Id = new Guid("4652d73f-fc71-4fe1-9f2f-1e48b342d741"), + Id = new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), - StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") }, new { Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), - StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") }, new { Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), - StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") }, new { Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), - StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95") }); }); @@ -1918,13 +1929,8 @@ namespace Marco.Pms.DataAccess.Migrations .IsRequired() .HasColumnType("longtext"); - b.Property("TenantId") - .HasColumnType("char(36)"); - b.HasKey("Id"); - b.HasIndex("TenantId"); - b.ToTable("ExpensesStatusMaster"); b.HasData( @@ -1936,8 +1942,7 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Draft", IsActive = true, IsSystem = true, - Name = "Draft", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Draft" }, new { @@ -1947,8 +1952,17 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Submit", IsActive = true, IsSystem = true, - Name = "Review Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Review Pending" + }, + new + { + Id = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(review rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Reviewer" }, new { @@ -1958,19 +1972,17 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Mark as Reviewed", IsActive = true, IsSystem = true, - Name = "Approval Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Approval Pending" }, new { Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), Color = "#ff3e1d", - Description = "Expense was declined, often with a reason(either review rejected or approval rejected.", + Description = "Expense was declined, often with a reason(approval rejected).", DisplayName = "Reject", IsActive = true, IsSystem = true, - Name = "Rejected", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Rejected by Approver" }, new { @@ -1980,19 +1992,17 @@ namespace Marco.Pms.DataAccess.Migrations DisplayName = "Mark as Approved", IsActive = true, IsSystem = true, - Name = "Payment Pending", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Payment Pending" }, new { Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), Color = "#71dd37", Description = "Expense has been settled.", - DisplayName = "Mark as Paid", + DisplayName = "Mark as Processed", IsActive = true, IsSystem = true, - Name = "Paid", - TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + Name = "Processed" }); }); @@ -3790,6 +3800,10 @@ namespace Marco.Pms.DataAccess.Migrations modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") .WithMany() .HasForeignKey("CreatedById") @@ -3814,12 +3828,20 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Employees.Employee", "ProcessedBy") + .WithMany() + .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") + .WithMany() + .HasForeignKey("ReviewedById"); + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") .WithMany() .HasForeignKey("StatusId") @@ -3832,6 +3854,8 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.Navigation("ApprovedBy"); + b.Navigation("CreatedBy"); b.Navigation("ExpensesType"); @@ -3840,8 +3864,12 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("PaymentMode"); + b.Navigation("ProcessedBy"); + b.Navigation("Project"); + b.Navigation("ReviewedBy"); + b.Navigation("Status"); b.Navigation("Tenant"); @@ -3907,17 +3935,9 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.Navigation("NextStatus"); b.Navigation("Status"); - - b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => @@ -3934,17 +3954,9 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.Navigation("Permission"); b.Navigation("Status"); - - b.Navigation("Tenant"); }); modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => @@ -4051,17 +4063,6 @@ namespace Marco.Pms.DataAccess.Migrations b.Navigation("Tenant"); }); - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => - { - b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") - .WithMany() - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tenant"); - }); - modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => { b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") diff --git a/Marco.Pms.Model/Expenses/Expenses.cs b/Marco.Pms.Model/Expenses/Expenses.cs index a396715..35e8836 100644 --- a/Marco.Pms.Model/Expenses/Expenses.cs +++ b/Marco.Pms.Model/Expenses/Expenses.cs @@ -35,6 +35,21 @@ namespace Marco.Pms.Model.Expenses [ValidateNever] [ForeignKey("CreatedById")] public Employee? CreatedBy { get; set; } + public Guid? ReviewedById { get; set; } + + [ValidateNever] + [ForeignKey("ReviewedById")] + public Employee? ReviewedBy { get; set; } + public Guid? ApprovedById { get; set; } + + [ValidateNever] + [ForeignKey("ApprovedById")] + public Employee? ApprovedBy { get; set; } + public Guid? ProcessedById { get; set; } + + [ValidateNever] + [ForeignKey("ProcessedById")] + public Employee? ProcessedBy { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public string? TransactionId { get; set; } diff --git a/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs index 1eb7470..902927d 100644 --- a/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs +++ b/Marco.Pms.Model/Expenses/ExpensesStatusMapping.cs @@ -1,11 +1,10 @@ using Marco.Pms.Model.Master; -using Marco.Pms.Model.Utilities; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using System.ComponentModel.DataAnnotations.Schema; namespace Marco.Pms.Model.Expenses { - public class ExpensesStatusMapping : TenantRelation + public class ExpensesStatusMapping { public Guid Id { get; set; } public Guid StatusId { get; set; } diff --git a/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs index 9333412..2fe9334 100644 --- a/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs +++ b/Marco.Pms.Model/Expenses/StatusPermissionMapping.cs @@ -1,12 +1,11 @@ using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Master; -using Marco.Pms.Model.Utilities; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using System.ComponentModel.DataAnnotations.Schema; namespace Marco.Pms.Model.Expenses { - public class StatusPermissionMapping : TenantRelation + public class StatusPermissionMapping { public Guid Id { get; set; } public Guid StatusId { get; set; } diff --git a/Marco.Pms.Model/Master/CurrencyMaster.cs b/Marco.Pms.Model/Master/CurrencyMaster.cs new file mode 100644 index 0000000..62f73d3 --- /dev/null +++ b/Marco.Pms.Model/Master/CurrencyMaster.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.Master +{ + public class CurrencyMaster + { + public Guid Id { get; set; } + public string CurrencyCode { get; set; } = string.Empty; + public string CurrencyName { get; set; } = string.Empty; + public string Symbol { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + } +} diff --git a/Marco.Pms.Model/Master/ExpensesStatusMaster.cs b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs index dc393cd..35358c3 100644 --- a/Marco.Pms.Model/Master/ExpensesStatusMaster.cs +++ b/Marco.Pms.Model/Master/ExpensesStatusMaster.cs @@ -1,8 +1,6 @@ -using Marco.Pms.Model.Utilities; - -namespace Marco.Pms.Model.Master +namespace Marco.Pms.Model.Master { - public class ExpensesStatusMaster : TenantRelation + public class ExpensesStatusMaster { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; diff --git a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs index c58a22c..9dad1ce 100644 --- a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs @@ -8,6 +8,9 @@ public string PaymentModeId { get; set; } = string.Empty; public string PaidById { get; set; } = string.Empty; public string CreatedById { get; set; } = string.Empty; + public string? ReviewedById { get; set; } + public string? ApprovedById { get; set; } + public string? ProcessedById { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public DateTime ExpireAt { get; set; } = DateTime.UtcNow.Date.AddDays(1); diff --git a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs index 8fe3910..3e4a52a 100644 --- a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs @@ -8,6 +8,5 @@ public string Description { get; set; } = string.Empty; public string? Color { get; set; } public bool IsSystem { get; set; } = false; - public string TenantId { get; set; } = string.Empty; } } diff --git a/Marco.Pms.Model/Utilities/ExpensesFilter.cs b/Marco.Pms.Model/Utilities/ExpensesFilter.cs index 7a0c397..bd24ab8 100644 --- a/Marco.Pms.Model/Utilities/ExpensesFilter.cs +++ b/Marco.Pms.Model/Utilities/ExpensesFilter.cs @@ -6,6 +6,7 @@ public List? StatusIds { get; set; } public List? CreatedByIds { get; set; } public List? PaidById { get; set; } + public bool IsTransactionDate { get; set; } = false; public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs index becf685..b777d13 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -13,6 +13,9 @@ namespace Marco.Pms.Model.ViewModels.Expenses public PaymentModeMatserVM? PaymentMode { get; set; } public BasicEmployeeVM? PaidBy { get; set; } public BasicEmployeeVM? CreatedBy { get; set; } + public BasicEmployeeVM? ReviewedBy { get; set; } + public BasicEmployeeVM? ApprovedBy { get; set; } + public BasicEmployeeVM? ProcessedBy { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public string SupplerName { get; set; } = string.Empty; diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs index 198102d..f6ba5ea 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs @@ -12,6 +12,9 @@ namespace Marco.Pms.Model.ViewModels.Expanses public PaymentModeMatserVM? PaymentMode { get; set; } public BasicEmployeeVM? PaidBy { get; set; } public BasicEmployeeVM? CreatedBy { get; set; } + public BasicEmployeeVM? ReviewedBy { get; set; } + public BasicEmployeeVM? ApprovedBy { get; set; } + public BasicEmployeeVM? ProcessedBy { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public string SupplerName { get; set; } = string.Empty; diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 61d9a2e..bcc4264 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -908,31 +908,7 @@ namespace Marco.Pms.Services.Controllers public async Task GetExpensesStatusList([FromQuery] bool isActive = true) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId, isActive); - return StatusCode(response.StatusCode, response); - } - - [HttpPost("expenses-status")] - public async Task CreateExpensesStatus([FromBody] ExpensesStatusMasterDto dto) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.CreateExpensesStatusAsync(dto, loggedInEmployee, tenantId); - return StatusCode(response.StatusCode, response); - } - - [HttpPut("expenses-status/edit/{id}")] - public async Task UpdateExpensesStatus(Guid id, [FromBody] ExpensesStatusMasterDto dto) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.UpdateExpensesStatusAsync(id, dto, loggedInEmployee, tenantId); - return StatusCode(response.StatusCode, response); - } - - [HttpDelete("expenses-status/delete/{id}")] - public async Task DeleteExpensesStatus(Guid id, [FromQuery] bool isActive = false) - { - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _masterService.DeleteExpensesStatusAsync(id, isActive, loggedInEmployee, tenantId); + var response = await _masterService.GetExpensesStatusListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 793e94a..504e3d2 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -145,6 +145,15 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.CreatedById, opt => opt.MapFrom(src => src.CreatedById.ToString())) .ForMember( + dest => dest.ReviewedById, + opt => opt.MapFrom(src => src.ReviewedById.ToString())) + .ForMember( + dest => dest.ApprovedById, + opt => opt.MapFrom(src => src.ApprovedById.ToString())) + .ForMember( + dest => dest.ProcessedById, + opt => opt.MapFrom(src => src.ProcessedById.ToString())) + .ForMember( dest => dest.StatusId, opt => opt.MapFrom(src => src.StatusId.ToString())) .ForMember( @@ -171,6 +180,15 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.CreatedById, opt => opt.MapFrom(src => Guid.Parse(src.CreatedById))) .ForMember( + dest => dest.ReviewedById, + opt => opt.MapFrom(src => Guid.Parse(src.ReviewedById ?? ""))) + .ForMember( + dest => dest.ApprovedById, + opt => opt.MapFrom(src => Guid.Parse(src.ApprovedById ?? ""))) + .ForMember( + dest => dest.ProcessedById, + opt => opt.MapFrom(src => Guid.Parse(src.ProcessedById ?? ""))) + .ForMember( dest => dest.StatusId, opt => opt.MapFrom(src => Guid.Parse(src.StatusId))) .ForMember( @@ -229,10 +247,7 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap() .ForMember( dest => dest.Id, - opt => opt.MapFrom(src => src.Id.ToString())) - .ForMember( - dest => dest.TenantId, - opt => opt.MapFrom(src => src.TenantId.ToString())); + opt => opt.MapFrom(src => src.Id.ToString())); CreateMap() .ForMember( diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 0be0872..c8c3c1b 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -135,10 +135,17 @@ namespace Marco.Pms.Services.Service if (expenseFilter != null) { - // CRITICAL FIX: Apply filters cumulatively using multiple `if` statements, not `if-else if`. if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) { - expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + if (expenseFilter.IsTransactionDate) + { + expensesQuery = expensesQuery.Where(e => e.TransactionDate.Date >= expenseFilter.StartDate.Value.Date && e.TransactionDate.Date <= expenseFilter.EndDate.Value.Date); + } + else + { + expensesQuery = expensesQuery.Where(e => e.CreatedAt.Date >= expenseFilter.StartDate.Value.Date && e.CreatedAt.Date <= expenseFilter.EndDate.Value.Date); + } + } if (expenseFilter.ProjectIds?.Any() == true) @@ -464,7 +471,7 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMapping .Include(s => s.NextStatus) - .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatusId == model.StatusId && s.TenantId == tenantId); + .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatusId == model.StatusId); }); // Task to fetch all permissions required for the *target* status. @@ -472,7 +479,7 @@ namespace Marco.Pms.Services.Service { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.StatusPermissionMapping - .Where(sp => sp.StatusId == model.StatusId && sp.TenantId == tenantId) + .Where(sp => sp.StatusId == model.StatusId) .ToListAsync(); }); @@ -598,7 +605,7 @@ namespace Marco.Pms.Services.Service var dbContext = t.Result; return dbContext.ExpensesStatusMapping .Include(s => s.NextStatus) - .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId) + .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null) .Select(s => s.NextStatus) // Select only the status object .ToListAsync() .ContinueWith(res => @@ -756,7 +763,7 @@ namespace Marco.Pms.Services.Service var dbContext = t.Result; return dbContext.ExpensesStatusMapping .Include(s => s.NextStatus) - .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null && s.TenantId == tenantId) + .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null) .Select(s => s.NextStatus) // Select only the status object .ToListAsync() .ContinueWith(res => @@ -958,7 +965,7 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => statusIds.Contains(es.StatusId) && es.Status != null && es.TenantId == tenantId) + .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) .GroupBy(s => s.StatusId) .Select(g => new { @@ -972,14 +979,13 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMaster .AsNoTracking() - .Where(es => statusIds.Contains(es.Id) && es.TenantId == tenantId) + .Where(es => statusIds.Contains(es.Id)) .ToListAsync(); }); var permissionStatusMappingTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.StatusPermissionMapping - .Where(ps => ps.TenantId == tenantId) .GroupBy(ps => ps.StatusId) .Select(g => new { @@ -1066,7 +1072,7 @@ namespace Marco.Pms.Services.Service .Include(s => s.Status) .Include(s => s.NextStatus) .AsNoTracking() - .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null && es.TenantId == tenantId) + .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null) .GroupBy(s => s.StatusId) .Select(g => new { @@ -1079,13 +1085,12 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMaster .AsNoTracking() - .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId) && es.TenantId == tenantId); + .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId)); }); var permissionStatusMappingTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.StatusPermissionMapping - .Where(ps => ps.TenantId == tenantId) .GroupBy(ps => ps.StatusId) .Select(g => new { diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 6d789bb..88467d1 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -4,7 +4,6 @@ using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Dtos.Master; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; -using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; @@ -247,9 +246,8 @@ namespace Marco.Pms.Services.Service #endregion #region =================================================================== Expenses Status APIs =================================================================== - public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive) + public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId) { - try { // Validation if employee is taking action in same tenant @@ -260,7 +258,7 @@ namespace Marco.Pms.Services.Service } // Featching the list of Expenses Status. - var statusList = await _context.ExpensesStatusMaster.Where(es => es.TenantId == tenantId && es.IsActive == isActive).ToListAsync(); + var statusList = await _context.ExpensesStatusMaster.ToListAsync(); var response = _mapper.Map>(statusList); var statusIds = statusList.Select(s => s.Id).ToList(); @@ -287,223 +285,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); } } - public async Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId) - { - try - { - // Validation if employee is taking action in same tenant - if (tenantId != loggedInEmployee.TenantId) - { - _logger.LogWarning("Employee {EmployeeId} attempted to add new Expense Status in different tenant", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); - } - var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); - if (!hasManagePermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); - - } - // Mapping the DTO to ExpensesStatusMaster Model - var expensesStatus = _mapper.Map(model); - expensesStatus.TenantId = tenantId; - - _context.ExpensesStatusMaster.Add(expensesStatus); - - if (model.PermissionIds?.Any() ?? false) - { - var permissionStatusMappings = model.PermissionIds.Select(p => new StatusPermissionMapping - { - PermissionId = p, - StatusId = expensesStatus.Id, - TenantId = tenantId - }).ToList(); - - _context.StatusPermissionMapping.AddRange(permissionStatusMappings); - } - await _context.SaveChangesAsync(); - - _logger.LogInfo("New Expense Status {ExpensesStatusId} was added by employee {EmployeeId}", expensesStatus.Id, loggedInEmployee.Id); - - // Mapping the ExpensesStatusMaster Model to View Model - var response = _mapper.Map(expensesStatus); - return ApiResponse.SuccessResponse(response, "Expense Status craeted Successfully", 201); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Database Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); - } - } - public async Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId) - { - try - { - // Validation if employee is taking action in same tenant - if (tenantId != loggedInEmployee.TenantId) - { - _logger.LogWarning("Employee {EmployeeId} attempted to add new Expense Status in different tenant", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); - } - - // Checking permssion for managing masters - var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); - if (!hasManagePermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); - - } - // Validating the prvided data - if (model.Id != id) - { - _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); - } - // featching expenses status and permissions parallelly - var expensesStatusTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMaster.AsNoTracking() - .FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId); - }); - - var permissionStatusMappingsTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.StatusPermissionMapping - .AsNoTracking() - .Where(ps => ps.StatusId == model.Id.Value && ps.TenantId == tenantId) - .ToListAsync(); - }); - - await Task.WhenAll(expensesStatusTask, permissionStatusMappingsTask); - var expensesStatus = expensesStatusTask.Result; - - // Checking if Expense Status exists - if (expensesStatus == null) - { - _logger.LogWarning("Employee {EmployeeId} tries to update Expense Status, but not found in database", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Expense Status not found", "Expense Status not found", 404); - } - - // Mapping ExpensesStatusMaster to BsonDocument - var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesStatus); - - // Mapping ExpensesStatusMasterDto to ExpensesStatusMaster - _mapper.Map(model, expensesStatus); - - _context.ExpensesStatusMaster.Update(expensesStatus); - - var permissionStatusMappings = permissionStatusMappingsTask.Result; - var permissionIds = permissionStatusMappings.Select(ps => ps.PermissionId).ToList(); - if (model.PermissionIds != null) - { - var newPermissionStatusMappings = model.PermissionIds.Where(p => !permissionIds.Contains(p)).Select(p => new StatusPermissionMapping - { - PermissionId = p, - StatusId = expensesStatus.Id, - TenantId = tenantId - }).ToList(); - var deletedPermissionStatusMappings = permissionStatusMappings.Where(ps => !model.PermissionIds.Contains(ps.PermissionId)).ToList(); - - _context.StatusPermissionMapping.AddRange(newPermissionStatusMappings); - _context.StatusPermissionMapping.RemoveRange(deletedPermissionStatusMappings); - - } - await _context.SaveChangesAsync(); - - _logger.LogInfo("New Expense Status {ExpensesStatusId} was added by employee {EmployeeId}", expensesStatus.Id, loggedInEmployee.Id); - - // Mapping the ExpensesStatusMaster Model to View Model - var response = _mapper.Map(expensesStatus); - return ApiResponse.SuccessResponse(response, "Expense Status craeted Successfully", 201); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Database Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception occured while adding new Expense Status by employee {EmployeeId}", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); - } - } - public async Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId) - { - string action = isActive ? "restore" : "delete"; - try - { - // Validation if employee is taking action in same tenant - if (tenantId != loggedInEmployee.TenantId) - { - _logger.LogWarning("Employee {EmployeeId} attempted to {Action} Expense Status in different tenant", loggedInEmployee.Id, action); - return ApiResponse.ErrorResponse("Access Denied", "User do not have access for this information", 403); - } - - // Checking permssion for managing masters - var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); - if (!hasManagePermission) - { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); - } - - var expensesStatus = await _context.ExpensesStatusMaster.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId); - - // Checking if Expense Status exists - if (expensesStatus == null) - { - _logger.LogWarning("Employee {EmployeeId} tries to {Action} Expense Status, but not found in database", loggedInEmployee.Id, action); - return ApiResponse.ErrorResponse("Expense Status not found", "Expense Status not found", 404); - } - - if (expensesStatus.IsSystem) - { - _logger.LogWarning("Employee {Employee} attempts to {Action} Expense status, but status is system defined", loggedInEmployee.Id, action); - return ApiResponse.ErrorResponse($"Expense Status is system defined cannot able to {action}", $"Expense Status is system defined cannot able to {action}", 400); - } - - // Mapping ExpensesStatusMaster to BsonDocument - var existingEntityBson = _updateLogHelper.EntityToBsonDocument(expensesStatus); - - expensesStatus.IsActive = isActive; - await _context.SaveChangesAsync(); - - _logger.LogInfo("Expense Status {ExpensesStatusId} was {Action}d by employee {EmployeeId}", expensesStatus.Id, action, loggedInEmployee.Id); - - // Saving the old entity in mongoDB - - var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject - { - EntityId = expensesStatus.Id.ToString(), - UpdatedById = loggedInEmployee.Id.ToString(), - OldObject = existingEntityBson, - UpdatedAt = DateTime.UtcNow - }, "ExpensesStatusMasterModificationLog"); - - // Mapping ExpensesStatusMaster to ExpensesStatusMasterVM - var response = _mapper.Map(expensesStatus); - return ApiResponse.SuccessResponse(response, $"Expense Status {action}d Successfully", 200); - } - catch (DbUpdateException dbEx) - { - _logger.LogError(dbEx, "Database Exception occured while {Action}ing Expense Status by employee {EmployeeId}", action, loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500); - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception occured while {Action}ing Expense Status by employee {EmployeeId}", action, loggedInEmployee.Id); - return ApiResponse.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); - } - } - #endregion #region =================================================================== Payment mode APIs =================================================================== diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index 7a64b3a..2cde277 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -15,10 +15,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #endregion #region =================================================================== Expenses Status APIs =================================================================== - Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive); - Task> CreateExpensesStatusAsync(ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); - Task> UpdateExpensesStatusAsync(Guid id, ExpensesStatusMasterDto model, Employee loggedInEmployee, Guid tenantId); - Task> DeleteExpensesStatusAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId); + Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId); #endregion From 1a0641162c118472f0d1c751a315bf720eeaca8f Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 30 Jul 2025 15:44:19 +0530 Subject: [PATCH 59/81] Added the currency master table --- .../Data/ApplicationDbContext.cs | 60 + ...549_Added_CurrencyMaster_Table.Designer.cs | 4430 +++++++++++++++++ ...250730070549_Added_CurrencyMaster_Table.cs | 57 + .../ApplicationDbContextModelSnapshot.cs | 84 + .../ViewModels/Expenses/ExpenseList.cs | 6 +- .../MappingProfiles/MappingProfile.cs | 6 +- Marco.Pms.Services/Service/ExpensesService.cs | 347 +- 7 files changed, 4856 insertions(+), 134 deletions(-) create mode 100644 Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.cs diff --git a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs index 87f5e84..d9a5653 100644 --- a/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs +++ b/Marco.Pms.DataAccess/Data/ApplicationDbContext.cs @@ -53,6 +53,7 @@ namespace Marco.Pms.DataAccess.Data public DbSet Modules { get; set; } public DbSet Features { get; set; } public DbSet FeaturePermissions { get; set; } + public DbSet CurrencyMaster { get; set; } public DbSet ApplicationRoles { get; set; } public DbSet JobRoles { get; set; } public DbSet RolePermissionMappings { get; set; } @@ -760,6 +761,65 @@ namespace Marco.Pms.DataAccess.Data new FeaturePermission { Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Manage", Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules." } ); + + modelBuilder.Entity().HasData( + new CurrencyMaster + { + Id = Guid.Parse("78e96e4a-7ce0-4164-ae3a-c833ad45ec2c"), + CurrencyCode = "INR", + CurrencyName = "Indian Rupee", + Symbol = "₹", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("2f672568-a67b-4961-acb2-a8c7834e1762"), + CurrencyCode = "USD", + CurrencyName = "US Dollar", + Symbol = "$", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("4d1155bb-1448-4d97-a732-96c92eb99c45"), + CurrencyCode = "EUR", + CurrencyName = "Euro", + Symbol = "€", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("3e456237-ef06-4ea1-a261-188c9b0c6df6"), + CurrencyCode = "GBP", + CurrencyName = "Pound Sterling", + Symbol = "£", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("297e237a-56d3-48f6-b39d-ec3991dea8bf"), + CurrencyCode = "JPY", + CurrencyName = "Japanese Yen", + Symbol = "¥", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("efe9b4f6-64d6-446e-a42d-1c7aaf6dd70d"), + CurrencyCode = "RUB", + CurrencyName = "Russian Ruble", + Symbol = "₽", + IsActive = true + }, + new CurrencyMaster + { + Id = Guid.Parse("b960166a-f7e9-49e3-bb4b-28511f126c08"), + CurrencyCode = "CNY", + CurrencyName = "Chinese Yuan (Renminbi)", + Symbol = "¥", + IsActive = true + } + ); } } } diff --git a/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.Designer.cs new file mode 100644 index 0000000..fd265dd --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.Designer.cs @@ -0,0 +1,4430 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250730070549_Added_CurrencyMaster_Table")] + partial class Added_CurrencyMaster_Table + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProcessedById") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReviewedById") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProcessedById"); + + b.HasIndex("ProjectId"); + + b.HasIndex("ReviewedById"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("StatusId"); + + b.ToTable("ExpensesStatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce"), + NextStatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + + b.HasData( + new + { + Id = new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }, + new + { + Id = new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.CurrencyMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CurrencyCode") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CurrencyName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CurrencyMaster"); + + b.HasData( + new + { + Id = new Guid("78e96e4a-7ce0-4164-ae3a-c833ad45ec2c"), + CurrencyCode = "INR", + CurrencyName = "Indian Rupee", + IsActive = true, + Symbol = "₹" + }, + new + { + Id = new Guid("2f672568-a67b-4961-acb2-a8c7834e1762"), + CurrencyCode = "USD", + CurrencyName = "US Dollar", + IsActive = true, + Symbol = "$" + }, + new + { + Id = new Guid("4d1155bb-1448-4d97-a732-96c92eb99c45"), + CurrencyCode = "EUR", + CurrencyName = "Euro", + IsActive = true, + Symbol = "€" + }, + new + { + Id = new Guid("3e456237-ef06-4ea1-a261-188c9b0c6df6"), + CurrencyCode = "GBP", + CurrencyName = "Pound Sterling", + IsActive = true, + Symbol = "£" + }, + new + { + Id = new Guid("297e237a-56d3-48f6-b39d-ec3991dea8bf"), + CurrencyCode = "JPY", + CurrencyName = "Japanese Yen", + IsActive = true, + Symbol = "¥" + }, + new + { + Id = new Guid("efe9b4f6-64d6-446e-a42d-1c7aaf6dd70d"), + CurrencyCode = "RUB", + CurrencyName = "Russian Ruble", + IsActive = true, + Symbol = "₽" + }, + new + { + Id = new Guid("b960166a-f7e9-49e3-bb4b-28511f126c08"), + CurrencyCode = "CNY", + CurrencyName = "Chinese Yuan (Renminbi)", + IsActive = true, + Symbol = "¥" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Color") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Color = "#8592a3", + Description = "Expense has been created but not yet submitted.", + DisplayName = "Draft", + IsActive = true, + IsSystem = true, + Name = "Draft" + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Color = "#696cff", + Description = "Reviewer is currently reviewing the expense.", + DisplayName = "Submit", + IsActive = true, + IsSystem = true, + Name = "Review Pending" + }, + new + { + Id = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(review rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Reviewer" + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Color = "#03c3ec", + Description = "Review is completed, waiting for action of approver.", + DisplayName = "Mark as Reviewed", + IsActive = true, + IsSystem = true, + Name = "Approval Pending" + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(approval rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Approver" + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Color = "#ffab00", + Description = "Approved expense is awaiting final payment.", + DisplayName = "Mark as Approved", + IsActive = true, + IsSystem = true, + Name = "Payment Pending" + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Color = "#71dd37", + Description = "Expense has been settled.", + DisplayName = "Mark as Processed", + IsActive = true, + IsSystem = true, + Name = "Processed" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#8592a3", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ProcessedBy") + .WithMany() + .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") + .WithMany() + .HasForeignKey("ReviewedById"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApprovedBy"); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("ProcessedBy"); + + b.Navigation("Project"); + + b.Navigation("ReviewedBy"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.cs b/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.cs new file mode 100644 index 0000000..d525786 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250730070549_Added_CurrencyMaster_Table.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_CurrencyMaster_Table : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CurrencyMaster", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + CurrencyCode = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + CurrencyName = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Symbol = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + IsActive = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CurrencyMaster", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "CurrencyMaster", + columns: new[] { "Id", "CurrencyCode", "CurrencyName", "IsActive", "Symbol" }, + values: new object[,] + { + { new Guid("297e237a-56d3-48f6-b39d-ec3991dea8bf"), "JPY", "Japanese Yen", true, "¥" }, + { new Guid("2f672568-a67b-4961-acb2-a8c7834e1762"), "USD", "US Dollar", true, "$" }, + { new Guid("3e456237-ef06-4ea1-a261-188c9b0c6df6"), "GBP", "Pound Sterling", true, "£" }, + { new Guid("4d1155bb-1448-4d97-a732-96c92eb99c45"), "EUR", "Euro", true, "€" }, + { new Guid("78e96e4a-7ce0-4164-ae3a-c833ad45ec2c"), "INR", "Indian Rupee", true, "₹" }, + { new Guid("b960166a-f7e9-49e3-bb4b-28511f126c08"), "CNY", "Chinese Yuan (Renminbi)", true, "¥" }, + { new Guid("efe9b4f6-64d6-446e-a42d-1c7aaf6dd70d"), "RUB", "Russian Ruble", true, "₽" } + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CurrencyMaster"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 528e15d..4a93185 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1901,6 +1901,90 @@ namespace Marco.Pms.DataAccess.Migrations b.ToTable("ActivityMasters"); }); + modelBuilder.Entity("Marco.Pms.Model.Master.CurrencyMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CurrencyCode") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CurrencyName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CurrencyMaster"); + + b.HasData( + new + { + Id = new Guid("78e96e4a-7ce0-4164-ae3a-c833ad45ec2c"), + CurrencyCode = "INR", + CurrencyName = "Indian Rupee", + IsActive = true, + Symbol = "₹" + }, + new + { + Id = new Guid("2f672568-a67b-4961-acb2-a8c7834e1762"), + CurrencyCode = "USD", + CurrencyName = "US Dollar", + IsActive = true, + Symbol = "$" + }, + new + { + Id = new Guid("4d1155bb-1448-4d97-a732-96c92eb99c45"), + CurrencyCode = "EUR", + CurrencyName = "Euro", + IsActive = true, + Symbol = "€" + }, + new + { + Id = new Guid("3e456237-ef06-4ea1-a261-188c9b0c6df6"), + CurrencyCode = "GBP", + CurrencyName = "Pound Sterling", + IsActive = true, + Symbol = "£" + }, + new + { + Id = new Guid("297e237a-56d3-48f6-b39d-ec3991dea8bf"), + CurrencyCode = "JPY", + CurrencyName = "Japanese Yen", + IsActive = true, + Symbol = "¥" + }, + new + { + Id = new Guid("efe9b4f6-64d6-446e-a42d-1c7aaf6dd70d"), + CurrencyCode = "RUB", + CurrencyName = "Russian Ruble", + IsActive = true, + Symbol = "₽" + }, + new + { + Id = new Guid("b960166a-f7e9-49e3-bb4b-28511f126c08"), + CurrencyCode = "CNY", + CurrencyName = "Chinese Yuan (Renminbi)", + IsActive = true, + Symbol = "¥" + }); + }); + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => { b.Property("Id") diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs index f6ba5ea..9bc3b08 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs @@ -12,9 +12,9 @@ namespace Marco.Pms.Model.ViewModels.Expanses public PaymentModeMatserVM? PaymentMode { get; set; } public BasicEmployeeVM? PaidBy { get; set; } public BasicEmployeeVM? CreatedBy { get; set; } - public BasicEmployeeVM? ReviewedBy { get; set; } - public BasicEmployeeVM? ApprovedBy { get; set; } - public BasicEmployeeVM? ProcessedBy { get; set; } + //public BasicEmployeeVM? ReviewedBy { get; set; } + //public BasicEmployeeVM? ApprovedBy { get; set; } + //public BasicEmployeeVM? ProcessedBy { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public string SupplerName { get; set; } = string.Empty; diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 504e3d2..7be54f2 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -181,13 +181,13 @@ namespace Marco.Pms.Services.MappingProfiles opt => opt.MapFrom(src => Guid.Parse(src.CreatedById))) .ForMember( dest => dest.ReviewedById, - opt => opt.MapFrom(src => Guid.Parse(src.ReviewedById ?? ""))) + opt => opt.MapFrom(src => src.ReviewedById != null ? Guid.Parse(src.ReviewedById) : Guid.Empty)) .ForMember( dest => dest.ApprovedById, - opt => opt.MapFrom(src => Guid.Parse(src.ApprovedById ?? ""))) + opt => opt.MapFrom(src => src.ApprovedById != null ? Guid.Parse(src.ApprovedById) : Guid.Empty)) .ForMember( dest => dest.ProcessedById, - opt => opt.MapFrom(src => Guid.Parse(src.ProcessedById ?? ""))) + opt => opt.MapFrom(src => src.ProcessedById != null ? Guid.Parse(src.ProcessedById) : Guid.Empty)) .ForMember( dest => dest.StatusId, opt => opt.MapFrom(src => Guid.Parse(src.StatusId))) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index c8c3c1b..5458486 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -34,8 +34,12 @@ namespace Marco.Pms.Services.Service private readonly CacheUpdateHelper _cache; private readonly IMapper _mapper; private static readonly Guid Draft = Guid.Parse("297e0d8f-f668-41b5-bfea-e03b354251c8"); - private static readonly Guid Rejected = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); - private static readonly Guid PaidStatus = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"); + 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 Approve = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"); + private static readonly Guid RejectedByApprover = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); + private static readonly Guid ProcessPending = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"); + private static readonly Guid Processed = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"); private static readonly string Collection = "ExpensesModificationLog"; public ExpensesService( IDbContextFactory dbContextFactory, @@ -201,12 +205,14 @@ namespace Marco.Pms.Services.Service // 7. --- Return Final Success Response --- var message = $"{expenseVM.Count} expense records fetched successfully."; _logger.LogInfo(message); + var defaultFilter = await GetObjectForfilter(tenantId); var response = new { - Filter = expenseFilter, + CurrentFilter = expenseFilter, CurrentPage = pageNumber, TotalPages = totalPages, TotalEntites = totalEntites, + DefaultFilter = defaultFilter, Data = expenseVM, }; return ApiResponse.SuccessResponse(response, message, 200); @@ -435,211 +441,202 @@ namespace Marco.Pms.Services.Service /// An ApiResponse containing the updated expense details or an error. public async Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId) { - // --- 1. Fetch Existing Expense --- - // We include all related entities needed for the final response mapping to avoid multiple database trips. - // The query also ensures we don't process a request if the status is already the one requested. - var existingExpense = await _context.Expenses + // 1. Fetch Existing Expense with Related Entities (Single Query) + var expense = await _context.Expenses .Include(e => e.ExpensesType) .Include(e => e.Project) - .Include(e => e.PaidBy) - .ThenInclude(e => e!.JobRole) + .Include(e => e.PaidBy).ThenInclude(e => e!.JobRole) .Include(e => e.PaymentMode) .Include(e => e.Status) .Include(e => e.CreatedBy) - .FirstOrDefaultAsync(e => e.Id == model.ExpenseId && e.StatusId != model.StatusId && e.TenantId == tenantId); + .Include(e => e.ReviewedBy) + .Include(e => e.ApprovedBy) + .Include(e => e.ProcessedBy) + .FirstOrDefaultAsync(e => + e.Id == model.ExpenseId && + e.StatusId != model.StatusId && + e.TenantId == tenantId + ); - if (existingExpense == null) + if (expense == null) { - // Use structured logging for better searchability. - _logger.LogWarning("Attempted to change status for a non-existent or already-updated expense. ExpenseId: {ExpenseId}, TenantId: {TenantId}", model.ExpenseId, tenantId); + _logger.LogWarning("ChangeStatus: Expense not found or already at target status. ExpenseId={ExpenseId}, TenantId={TenantId}", model.ExpenseId, tenantId); return ApiResponse.ErrorResponse("Expense not found or status is already set.", "Expense not found", 404); } - _logger.LogInfo("Initiating status change for ExpenseId: {ExpenseId} from StatusId: {OldStatusId} to {NewStatusId}", - existingExpense.Id, existingExpense.StatusId, model.StatusId); + _logger.LogInfo("ChangeStatus: Requested status change. ExpenseId={ExpenseId} FromStatus={FromStatusId} ToStatus={ToStatusId}", + expense.Id, expense.StatusId, model.StatusId); - // --- 2. Concurrently Check Prerequisites --- - // We run status validation and permission fetching in parallel for efficiency. - // Using Task.Run with an async lambda is the standard way to start a concurrent, - // CPU- or I/O-bound operation on a background thread. - - // Task to validate if the requested status change is a valid transition. - var statusMappingTask = Task.Run(async () => + // 2. Run Prerequisite Checks in Parallel (Status transition + Permissions) + var statusTransitionTask = Task.Run(async () => { - // 'await using' ensures the DbContext created by the factory is properly disposed - // within the scope of this background task. await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesStatusMapping - .Include(s => s.NextStatus) - .FirstOrDefaultAsync(s => s.StatusId == existingExpense.StatusId && s.NextStatusId == model.StatusId); + .Include(m => m.NextStatus) + .FirstOrDefaultAsync(m => m.StatusId == expense.StatusId && m.NextStatusId == model.StatusId); }); - // Task to fetch all permissions required for the *target* status. - var statusPermissionMappingTask = Task.Run(async () => + var targetStatusPermissionsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.StatusPermissionMapping - .Where(sp => sp.StatusId == model.StatusId) + .Where(spm => spm.StatusId == model.StatusId) .ToListAsync(); }); - // Await both tasks to complete concurrently. - await Task.WhenAll(statusMappingTask, statusPermissionMappingTask); + await Task.WhenAll(statusTransitionTask, targetStatusPermissionsTask); + var statusTransition = await statusTransitionTask; + var requiredPermissions = await targetStatusPermissionsTask; - // Now you can safely get the results. - var statusMapping = await statusMappingTask; - var statusPermissions = await statusPermissionMappingTask; - - // --- 3. Validate Status Transition and Permissions --- - if (statusMapping == null) + // 3. Validate Transition and Required Fields + if (statusTransition == null) { - _logger.LogWarning("Invalid status transition attempted for ExpenseId: {ExpenseId}. From StatusId: {FromStatusId} to {ToStatusId}", - existingExpense.Id, existingExpense.StatusId, model.StatusId); - return ApiResponse.ErrorResponse("This status change is not allowed.", "Invalid Transition", 400); + _logger.LogWarning("ChangeStatus: Invalid status transition. ExpenseId={ExpenseId}, FromStatus={FromStatus}, ToStatus={ToStatus}", + expense.Id, expense.StatusId, model.StatusId); + return ApiResponse.ErrorResponse("Status change is not permitted.", "Invalid Transition", 400); } - if (statusMapping.NextStatusId == PaidStatus && + // Validate special logic for "Processed" + if (statusTransition.NextStatusId == Processed && (string.IsNullOrWhiteSpace(model.ReimburseTransactionId) || - !model.ReimburseDate.HasValue || + !model.ReimburseDate.HasValue || model.ReimburseById == null || model.ReimburseById == Guid.Empty)) { - _logger.LogWarning("Invalid status transition attempted for ExpenseId: {ExpenseId}. From StatusId: {FromStatusId} to {ToStatusId}", - existingExpense.Id, existingExpense.StatusId, model.StatusId); - return ApiResponse.ErrorResponse("This status change is not allowed.", "Invalid Transition", 400); + _logger.LogWarning("ChangeStatus: Missing reimbursement fields for 'Processed'. ExpenseId={ExpenseId}", expense.Id); + return ApiResponse.ErrorResponse("Reimbursement details are missing or invalid.", "Invalid Reimbursement", 400); } - // Check permissions. The logic is: - // 1. If the target status has specific permissions defined, the user must have at least one of them. - // 2. If no permissions are defined for the target status, only the original creator of the expense can change it. + // 4. Permission Check (CreatedBy -> Reviewer bypass, else required permissions) bool hasPermission = false; - if (statusPermissions.Any()) + if (model.StatusId == Review && expense.CreatedById == loggedInEmployee.Id) + { + hasPermission = true; + } + else if (requiredPermissions.Any()) { - // Using a scope to resolve scoped services like PermissionServices. using var scope = _serviceScopeFactory.CreateScope(); var permissionService = scope.ServiceProvider.GetRequiredService(); - foreach (var sp in statusPermissions) + foreach (var permission in requiredPermissions) { - if (await permissionService.HasPermission(sp.PermissionId, loggedInEmployee.Id)) + if (await permissionService.HasPermission(permission.PermissionId, loggedInEmployee.Id)) { hasPermission = true; - break; // User has one of the required permissions, no need to check further. + break; } } } - else if (existingExpense.CreatedById == loggedInEmployee.Id) - { - // Fallback: If no permissions are required for the status, allow the creator to make the change. - hasPermission = true; - } if (!hasPermission) { - _logger.LogWarning("Access DENIED for EmployeeId: {EmployeeId} attempting to change status of ExpenseId: {ExpenseId} to StatusId: {NewStatusId}", - loggedInEmployee.Id, existingExpense.Id, model.StatusId); - return ApiResponse.ErrorResponse("You do not have the required permissions to perform this action.", "Access Denied", 403); + _logger.LogWarning("ChangeStatus: Permission denied. EmployeeId={EmployeeId} ExpenseId={ExpenseId} ToStatus={ToStatusId}", + loggedInEmployee.Id, expense.Id, model.StatusId); + return ApiResponse.ErrorResponse("You do not have permission for this action.", "Access Denied", 403); } - // --- 4. Update Expense and Add Log (in a transaction) --- - var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes. + // 5. Prepare for update (Audit snapshot) + var expenseStateBeforeChange = _updateLogHelper.EntityToBsonDocument(expense); - existingExpense.StatusId = statusMapping.NextStatusId; - existingExpense.Status = statusMapping.NextStatus; // Assigning the included entity for the response mapping. + // 6. Apply Status Transition + expense.StatusId = statusTransition.NextStatusId; + expense.Status = statusTransition.NextStatus; - var expensesRemburse = new ExpensesReimburse + // Handle reviewer/approver/processor fields based on target StatusId (Guid) + if (model.StatusId == Approve || model.StatusId == RejectedByReviewer) { - ReimburseTransactionId = model.ReimburseTransactionId!, - ReimburseDate = model.ReimburseDate!.Value, - ReimburseById = model.ReimburseById!.Value, - ReimburseNote = model.Comment ?? string.Empty, - TenantId = tenantId - }; - _context.ExpensesReimburse.Add(expensesRemburse); - - _context.ExpensesReimburseMapping.Add(new ExpensesReimburseMapping + expense.ReviewedById = loggedInEmployee.Id; + } + else if (model.StatusId == ProcessPending || model.StatusId == RejectedByApprover) { - ExpensesId = existingExpense.Id, - ExpensesReimburseId = expensesRemburse.Id, - TenantId = tenantId - }); + expense.ApprovedById = loggedInEmployee.Id; + } + else if (model.StatusId == Processed) + { + expense.ProcessedById = loggedInEmployee.Id; + } + // 7. Add Reimbursement if applicable + if (model.StatusId == Processed) + { + var reimbursement = new ExpensesReimburse + { + ReimburseTransactionId = model.ReimburseTransactionId!, + ReimburseDate = model.ReimburseDate!.Value, + ReimburseById = model.ReimburseById!.Value, + ReimburseNote = model.Comment ?? string.Empty, + TenantId = tenantId + }; + _context.ExpensesReimburse.Add(reimbursement); + _context.ExpensesReimburseMapping.Add(new ExpensesReimburseMapping + { + ExpensesId = expense.Id, + ExpensesReimburseId = reimbursement.Id, + TenantId = tenantId + }); + } + + // 8. Add Expense Log Entry _context.ExpenseLogs.Add(new ExpenseLog { - ExpenseId = existingExpense.Id, - Action = $"Status changed to '{statusMapping.NextStatus!.Name}'", + ExpenseId = expense.Id, + Action = $"Status changed to '{statusTransition.NextStatus?.Name}'", UpdatedById = loggedInEmployee.Id, Comment = model.Comment, TenantId = tenantId }); + // 9. Commit database transaction try { await _context.SaveChangesAsync(); - _logger.LogInfo("Successfully updated status for ExpenseId: {ExpenseId} to StatusId: {NewStatusId}", existingExpense.Id, existingExpense.StatusId); + _logger.LogInfo("ChangeStatus: Status updated successfully. ExpenseId={ExpenseId} NewStatus={NewStatusId}", expense.Id, expense.StatusId); } - catch (DbUpdateConcurrencyException dbEx) + catch (DbUpdateConcurrencyException ex) { - // This error occurs if the record was modified by someone else after we fetched it. - _logger.LogError(dbEx, "Concurrency conflict while updating status for ExpenseId: {ExpenseId}. The record may have been modified by another user.", existingExpense.Id); - return ApiResponse.ErrorResponse("The expense was modified by another user. Please refresh and try again.", "Concurrency Error", 409); // 409 Conflict is appropriate + _logger.LogError(ex, "ChangeStatus: Concurrency error. ExpenseId={ExpenseId}", expense.Id); + return ApiResponse.ErrorResponse("Expense was modified by another user. Please refresh and try again.", "Concurrency Error", 409); } - // --- 5. Perform Post-Save Actions (Audit Log and Fetching Next State for UI) --- + // 10. Post-processing (audit log, cache, fetch next states) try { - // Task to save the detailed audit log to a separate system (e.g., MongoDB). - var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject + var auditLogTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject { - EntityId = existingExpense.Id.ToString(), + EntityId = expense.Id.ToString(), UpdatedById = loggedInEmployee.Id.ToString(), - OldObject = existingEntityBson, + OldObject = expenseStateBeforeChange, UpdatedAt = DateTime.UtcNow }, Collection); - var cacheUpdateTask = _cache.ReplaceExpenseAsync(existingExpense); + var cacheUpdateTask = _cache.ReplaceExpenseAsync(expense); - // Task to get all possible next statuses from the *new* current state to help the UI. - // NOTE: This now fetches a list of all possible next states, which is more useful for a UI. - var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t => + var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(async t => { var dbContext = t.Result; - return dbContext.ExpensesStatusMapping - .Include(s => s.NextStatus) - .Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null) - .Select(s => s.NextStatus) // Select only the status object - .ToListAsync() - .ContinueWith(res => - { - dbContext.Dispose(); // Ensure the context is disposed - return res.Result; - }); + var nextStatuses = await dbContext.ExpensesStatusMapping + .Include(m => m.NextStatus) + .Where(m => m.StatusId == expense.StatusId && m.NextStatus != null) + .Select(m => m.NextStatus) + .ToListAsync(); + await dbContext.DisposeAsync(); + return nextStatuses; }).Unwrap(); - await Task.WhenAll(mongoDBTask, getNextStatusesTask, cacheUpdateTask); + await Task.WhenAll(auditLogTask, getNextStatusesTask, cacheUpdateTask); + // Prepare response with possible next states var nextPossibleStatuses = await getNextStatusesTask; + var responseDto = _mapper.Map(expense); + if (nextPossibleStatuses is { Count: > 0 }) + responseDto.NextStatus = _mapper.Map>(nextPossibleStatuses); - var response = _mapper.Map(existingExpense); - if (nextPossibleStatuses != null) - { - // The response DTO should have a property like: public List NextAvailableStatuses { get; set; } - response.NextStatus = _mapper.Map>(nextPossibleStatuses); - } - - return ApiResponse.SuccessResponse(response); + return ApiResponse.SuccessResponse(responseDto); } catch (Exception ex) { - // This catch block handles errors from post-save operations like MongoDB logging. - // The primary update was successful, but we must log this failure. - _logger.LogError(ex, "Error occurred during post-save operations for ExpenseId: {ExpenseId} (e.g., audit logging). The primary status change was successful.", existingExpense.Id); - - // We can still return a success response because the main operation succeeded, - // but we should not block the user for a failed audit log. - // Alternatively, if audit logging is critical, you could return an error. - // Here, we choose to return success but log the ancillary failure. - var response = _mapper.Map(existingExpense); - return ApiResponse.SuccessResponse(response, "Status updated, but a post-processing error occurred."); + _logger.LogError(ex, "ChangeStatus: Post-operation error (e.g. audit logging). ExpenseId={ExpenseId}", expense.Id); + var responseDto = _mapper.Map(expense); + return ApiResponse.SuccessResponse(responseDto, "Status updated, but audit logging or cache update failed."); } } @@ -662,6 +659,9 @@ namespace Marco.Pms.Services.Service .Include(e => e.PaymentMode) .Include(e => e.Status) .Include(e => e.CreatedBy) + .Include(e => e.ReviewedBy) + .Include(e => e.ApprovedBy) + .Include(e => e.ProcessedBy) .FirstOrDefaultAsync(e => e.Id == model.Id && e.TenantId == tenantId); @@ -673,7 +673,7 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Expense not found", "Expense not found", 404); } - if (existingExpense.StatusId != Draft && existingExpense.StatusId != Rejected) + if (existingExpense.StatusId != Draft && existingExpense.StatusId != RejectedByReviewer && existingExpense.StatusId != RejectedByApprover) { _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED", loggedInEmployee.Id); return ApiResponse.ErrorResponse("Expense connot be updated", "Expense connot be updated", 400); @@ -1040,6 +1040,10 @@ namespace Marco.Pms.Services.Service } private async Task GetAllExpnesRelatedTablesFromMongoDB(ExpenseDetailsMongoDB model, Guid tenantId) { + var reviewedById = model.ReviewedById != null ? Guid.Parse(model.ReviewedById) : Guid.Empty; + var approvedById = model.ApprovedById != null ? Guid.Parse(model.ApprovedById) : Guid.Empty; + var processedById = model.ProcessedById != null ? Guid.Parse(model.ProcessedById) : Guid.Empty; + var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); @@ -1048,12 +1052,27 @@ namespace Marco.Pms.Services.Service var paidByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.PaidById) && e.TenantId == tenantId); + return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.PaidById) && e.TenantId == tenantId); }); var createdByTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(model.CreatedById) && e.TenantId == tenantId); + return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == Guid.Parse(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 == 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 == 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 == processedById && e.TenantId == tenantId); }); var expenseTypeTask = Task.Run(async () => { @@ -1103,12 +1122,15 @@ namespace Marco.Pms.Services.Service await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ExpensesReimburseMapping .Include(er => er.ExpensesReimburse) + .ThenInclude(er => er!.ReimburseBy) + .ThenInclude(e => e!.JobRole) .Where(er => er.TenantId == tenantId && er.ExpensesId == Guid.Parse(model.Id)) .Select(er => er.ExpensesReimburse).FirstOrDefaultAsync(); }); // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask, expenseReimburseTask); + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, processedByTask, + statusTask, permissionStatusMappingTask, expenseReimburseTask); var project = projectTask.Result; var expenseType = expenseTypeTask.Result; @@ -1117,6 +1139,9 @@ namespace Marco.Pms.Services.Service var permissionStatusMappings = permissionStatusMappingTask.Result; var paidBy = paidByTask.Result; var createdBy = createdByTask.Result; + var reviewedBy = reviewedByTask.Result; + var approvedBy = approvedByTask.Result; + var processedBy = processedByTask.Result; var expensesReimburse = expenseReimburseTask.Result; var response = _mapper.Map(model); @@ -1124,6 +1149,9 @@ namespace Marco.Pms.Services.Service response.Project = _mapper.Map(project); response.PaidBy = _mapper.Map(paidBy); response.CreatedBy = _mapper.Map(createdBy); + if (reviewedBy != null) response.ReviewedBy = _mapper.Map(reviewedBy); + if (approvedBy != null) response.ApprovedBy = _mapper.Map(approvedBy); + if (processedBy != null) response.ProcessedBy = _mapper.Map(processedBy); response.PaymentMode = _mapper.Map(paymentMode); response.ExpensesType = _mapper.Map(expenseType); response.ExpensesReimburse = _mapper.Map(expensesReimburse); @@ -1158,6 +1186,69 @@ namespace Marco.Pms.Services.Service return response; } + private async Task GetObjectForfilter(Guid tenantId) + { + // Task 1: Get all distinct projects associated with the tenant's expenses. + var projectsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.Project != null) + .Select(e => e.Project!) + .Distinct() + .Select(p => new { p.Id, Name = $"{p.Name}" }) + .ToListAsync(); + }); + + // Task 2: Get all distinct users who paid for the tenant's expenses. + var paidByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.PaidBy != null) + .Select(e => e.PaidBy!) + .Distinct() + .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) + .ToListAsync(); + }); + + // Task 3: Get all distinct users who created the tenant's expenses. + var createdByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.CreatedBy != null) + .Select(e => e.CreatedBy!) + .Distinct() + .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) + .ToListAsync(); + }); + + // Task 4: Get all distinct statuses associated with the tenant's expenses. + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.Status != null) + .Select(e => e.Status!) + .Distinct() + .Select(s => new { s.Id, s.Name }) + .ToListAsync(); + }); + + // Execute all four queries concurrently. The total wait time will be determined + // by the longest-running query, not the sum of all four. + await Task.WhenAll(projectsTask, paidByTask, createdByTask, statusTask); + + // Construct the final object from the results of the completed tasks. + return new + { + Projects = await projectsTask, + PaidBy = await paidByTask, + CreatedBy = await createdByTask, + Status = await statusTask + }; + } /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). From 1c9008ca627b9f05eb0a3c6c82aad9af68532dbf Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 31 Jul 2025 10:28:45 +0530 Subject: [PATCH 60/81] Added the search funcationality abd chnaged the cache object --- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 51 ++- .../Expenses/ExpenseDetailsMongoDB.cs | 25 +- .../Masters/ExpensesStatusMasterMongoDB.cs | 1 + .../ViewModels/Expenses/ExpenseList.cs | 2 + .../Controllers/ExpenseController.cs | 22 +- .../Helpers/CacheUpdateHelper.cs | 381 +++++++++++++----- .../MappingProfiles/MappingProfile.cs | 54 --- Marco.Pms.Services/Service/ExpensesService.cs | 377 ++++++++--------- .../ServiceInterfaces/IExpensesService.cs | 3 +- 9 files changed, 530 insertions(+), 386 deletions(-) diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 5d29088..fc670d6 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -1,6 +1,7 @@ using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.Utilities; using Microsoft.Extensions.Configuration; +using MongoDB.Bson; using MongoDB.Driver; namespace Marco.Pms.Helpers.CacheHelper @@ -36,7 +37,7 @@ namespace Marco.Pms.Helpers.CacheHelper await InitializeCollectionAsync(); } public async Task<(int totalPages, long totalCount, List expenseList)> GetExpenseListFromCacheAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll, - bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? expenseFilter) + bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? expenseFilter, string? searchString) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Empty; @@ -44,10 +45,11 @@ namespace Marco.Pms.Helpers.CacheHelper // Permission-based filter if (!viewAll && viewSelf) { - filter &= filterBuilder.Eq(e => e.CreatedById, loggedInEmployeeId.ToString()); + filter &= filterBuilder.Eq(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()); } // Apply filters + if (expenseFilter != null) { if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) @@ -58,25 +60,62 @@ namespace Marco.Pms.Helpers.CacheHelper if (expenseFilter.ProjectIds?.Any() == true) { - filter &= filterBuilder.In(e => e.ProjectId, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList()); + filter &= filterBuilder.In(e => e.Project.Id, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList()); } if (expenseFilter.StatusIds?.Any() == true) { - filter &= filterBuilder.In(e => e.StatusId, expenseFilter.StatusIds.Select(p => p.ToString()).ToList()); + filter &= filterBuilder.In(e => e.Status.Id, expenseFilter.StatusIds.Select(p => p.ToString()).ToList()); } if (expenseFilter.PaidById?.Any() == true) { - filter &= filterBuilder.In(e => e.PaidById, expenseFilter.PaidById.Select(p => p.ToString()).ToList()); + filter &= filterBuilder.In(e => e.PaidBy.Id, expenseFilter.PaidById.Select(p => p.ToString()).ToList()); } if (expenseFilter.CreatedByIds?.Any() == true && viewAll) { - filter &= filterBuilder.In(e => e.CreatedById, expenseFilter.CreatedByIds.Select(p => p.ToString()).ToList()); + filter &= filterBuilder.In(e => e.CreatedBy.Id, expenseFilter.CreatedByIds.Select(p => p.ToString()).ToList()); } } + if (!string.IsNullOrWhiteSpace(searchString)) + { + var searchPattern = new BsonRegularExpression(searchString, "i"); + + // The base text searches remain the same + var searchClauses = new List> + { + filterBuilder.Regex(e => e.Description, searchPattern), + filterBuilder.Regex(e => e.TransactionId, searchPattern) + }; + + // Build the complex filter for PaidBy.FullName + var paidByFilter = new BsonDocument("$expr", + new BsonDocument("$regexMatch", new BsonDocument + { + { "input", new BsonDocument("$concat", new BsonArray { "$PaidBy.FirstName", " ", "$PaidBy.LastName" }) }, + { "regex", searchString }, // BsonRegularExpression can't be used here, pass the string + { "options", "i" } // Case-insensitivity option + }) + ); + searchClauses.Add(paidByFilter); + + // Build the complex filter for CreatedBy.FullName + var createdByFilter = new BsonDocument("$expr", + new BsonDocument("$regexMatch", new BsonDocument + { + { "input", new BsonDocument("$concat", new BsonArray { "$CreatedBy.FirstName", " ", "$CreatedBy.LastName" }) }, + { "regex", searchString }, + { "options", "i" } + }) + ); + searchClauses.Add(createdByFilter); + + // Combine all clauses with an OR + filter &= filterBuilder.Or(searchClauses); + } + // Total count var totalCount = await _collection.CountDocumentsAsync(filter); var totalPages = (int)Math.Ceiling((double)totalCount / pageSize); diff --git a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs index 9dad1ce..c2618b9 100644 --- a/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Expenses/ExpenseDetailsMongoDB.cs @@ -1,22 +1,27 @@ -namespace Marco.Pms.Model.MongoDBModels.Expenses +using Marco.Pms.Model.MongoDBModels.Employees; +using Marco.Pms.Model.MongoDBModels.Masters; +using Marco.Pms.Model.MongoDBModels.Project; + +namespace Marco.Pms.Model.MongoDBModels.Expenses { public class ExpenseDetailsMongoDB { public string Id { get; set; } = string.Empty; - public string ProjectId { get; set; } = string.Empty; - public string ExpensesTypeId { get; set; } = string.Empty; - public string PaymentModeId { get; set; } = string.Empty; - public string PaidById { get; set; } = string.Empty; - public string CreatedById { get; set; } = string.Empty; - public string? ReviewedById { get; set; } - public string? ApprovedById { get; set; } - public string? ProcessedById { get; set; } + public ProjectBasicMongoDB Project { get; set; } = new ProjectBasicMongoDB(); + public ExpensesTypeMasterMongoDB ExpensesType { get; set; } = new ExpensesTypeMasterMongoDB(); + public PaymentModeMatserMongoDB PaymentMode { get; set; } = new PaymentModeMatserMongoDB(); + public BasicEmployeeMongoDB PaidBy { get; set; } = new BasicEmployeeMongoDB(); + public BasicEmployeeMongoDB CreatedBy { get; set; } = new BasicEmployeeMongoDB(); + public BasicEmployeeMongoDB? ReviewedBy { get; set; } + public BasicEmployeeMongoDB? ApprovedBy { get; set; } + public BasicEmployeeMongoDB? ProcessedBy { get; set; } public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public DateTime ExpireAt { get; set; } = DateTime.UtcNow.Date.AddDays(1); public string SupplerName { get; set; } = string.Empty; public double Amount { get; set; } - public string StatusId { get; set; } = string.Empty; + public ExpensesStatusMasterMongoDB Status { get; set; } = new ExpensesStatusMasterMongoDB(); + public List NextStatus { get; set; } = new List(); public bool PreApproved { get; set; } = false; public string? TransactionId { get; set; } public string Description { get; set; } = string.Empty; diff --git a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs index 3e4a52a..03e512d 100644 --- a/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs +++ b/Marco.Pms.Model/MongoDBModels/Masters/ExpensesStatusMasterMongoDB.cs @@ -6,6 +6,7 @@ public string Name { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; + //public List PermissionIds { get; set; } = new List(); public string? Color { get; set; } public bool IsSystem { get; set; } = false; } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs index 9bc3b08..c29b020 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseList.cs @@ -18,6 +18,8 @@ namespace Marco.Pms.Model.ViewModels.Expanses public DateTime TransactionDate { get; set; } public DateTime CreatedAt { get; set; } public string SupplerName { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string TransactionId { get; set; } = string.Empty; public double Amount { get; set; } public ExpensesStatusMasterVM? Status { get; set; } public List? NextStatus { get; set; } diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 5bbcf2c..36b0f74 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -39,10 +39,10 @@ namespace Marco.Pms.Services.Controllers /// A paginated list of expenses. [HttpGet("list")] - public async Task GetExpensesList(string? filter, int pageSize = 20, int pageNumber = 1) + public async Task GetExpensesList([FromQuery] string? searchString, [FromQuery] string? filter, [FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _expensesService.GetExpensesListAsync(loggedInEmployee, tenantId, filter, pageSize, pageNumber); + var response = await _expensesService.GetExpensesListAsync(loggedInEmployee, tenantId, searchString, filter, pageSize, pageNumber); return StatusCode(response.StatusCode, response); } @@ -62,11 +62,24 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpGet("filter")] + public async Task GetFilterObject() + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetFilterObjectAsync(loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + [HttpPost("create")] public async Task CreateExpense([FromBody] CreateExpensesDto model) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _expensesService.CreateExpenseAsync(model, loggedInEmployee, tenantId); + if (response.Success) + { + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Expanse", Response = response.Data }; + await _signalR.SendNotificationAsync(notification); + } return StatusCode(response.StatusCode, response); } @@ -101,6 +114,11 @@ namespace Marco.Pms.Services.Controllers { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _expensesService.DeleteExpanseAsync(id, loggedInEmployee, tenantId); + if (response.Success) + { + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Expanse", Response = response.Data }; + await _signalR.SendNotificationAsync(notification); + } return StatusCode(response.StatusCode, response); } diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 9acf08f..6aa5305 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -5,6 +5,7 @@ using Marco.Pms.Helpers.CacheHelper; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Master; using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Employees; using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Masters; using Marco.Pms.Model.MongoDBModels.Project; @@ -869,36 +870,8 @@ namespace Marco.Pms.Services.Helpers #region ======================================================= Expenses Cache ======================================================= public async Task AddExpenseByObjectAsync(Expenses expense) { - var expenseCache = _mapper.Map(expense); + var expenseCache = await GetAllExpnesRelatedTablesForSingle(expense, expense.TenantId); - try - { - var billAttachment = await _context.BillAttachments - .Include(ba => ba.Document) - .AsNoTracking() - .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) - .GroupBy(ba => ba.ExpensesId) - .Select(g => new - { - Documents = g.Select(ba => new DocumentMongoDB - { - DocumentId = ba.Document!.Id.ToString(), - FileName = ba.Document.FileName, - ContentType = ba.Document.ContentType, - S3Key = ba.Document.S3Key, - ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key - }).ToList() - }) - .FirstOrDefaultAsync(); ; - if (billAttachment != null) - { - expenseCache.Documents = billAttachment.Documents; - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); - } try { await _expenseCache.AddExpenseToCacheAsync(expenseCache); @@ -914,40 +887,13 @@ namespace Marco.Pms.Services.Helpers public async Task AddExpenseByIdAsync(Guid Id, Guid tenantId) { var expense = await _context.Expenses.AsNoTracking().FirstOrDefaultAsync(e => e.Id == Id && e.TenantId == tenantId); - var expenseCache = _mapper.Map(expense); + if (expense == null) { return null; } - try - { - var billAttachments = await _context.BillAttachments - .Include(ba => ba.Document) - .AsNoTracking() - .Where(ba => ba.ExpensesId == expense.Id && ba.Document != null) - .GroupBy(ba => ba.ExpensesId) - .Select(g => new - { - Documents = g.Select(ba => new DocumentMongoDB - { - DocumentId = ba.Document!.Id.ToString(), - FileName = ba.Document.FileName, - ContentType = ba.Document.ContentType, - S3Key = ba.Document.S3Key, - ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key - }).ToList() - }) - .FirstOrDefaultAsync(); - if (billAttachments != null) - { - expenseCache.Documents = billAttachments.Documents; - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); - return null; - } + var expenseCache = await GetAllExpnesRelatedTablesForSingle(expense, expense.TenantId); + try { await _expenseCache.AddExpenseToCacheAsync(expenseCache); @@ -962,39 +908,9 @@ namespace Marco.Pms.Services.Helpers } - public async Task AddExpensesListToCache(List expenses) + public async Task AddExpensesListToCache(List expenses, Guid tenantId) { - var expensesCache = _mapper.Map>(expenses); - var expenseIds = expenses.Select(e => e.Id).ToList(); - try - { - var billAttachments = await _context.BillAttachments - .Include(ba => ba.Document) - .AsNoTracking() - .Where(ba => expenseIds.Contains(ba.ExpensesId) && ba.Document != null) - .GroupBy(ba => ba.ExpensesId) - .Select(g => new - { - ExpensesId = g.Key, - Documents = g.Select(ba => new DocumentMongoDB - { - DocumentId = ba.Document!.Id.ToString(), - FileName = ba.Document.FileName, - ContentType = ba.Document.ContentType, - S3Key = ba.Document.S3Key, - ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key - }).ToList() - }) - .ToListAsync(); - foreach (var expenseCache in expensesCache) - { - expenseCache.Documents = billAttachments.Where(ba => ba.ExpensesId == Guid.Parse(expenseCache.Id)).Select(ba => ba.Documents).FirstOrDefault() ?? new List(); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurd while fetched expense related tables to save in cahce"); - } + var expensesCache = await GetAllExpnesRelatedTablesForList(expenses, tenantId); try { @@ -1007,15 +923,18 @@ namespace Marco.Pms.Services.Helpers } public async Task<(int totalPages, long totalCount, List? expenseList)> GetExpenseListAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll, - bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? filter) + bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? filter, string? searchString) { try { - var (totalPages, totalCount, expenseList) = await _expenseCache.GetExpenseListFromCacheAsync(tenantId, loggedInEmployeeId, viewAll, viewSelf, pageNumber, pageSize, filter); + var (totalPages, totalCount, expenseList) = await _expenseCache.GetExpenseListFromCacheAsync(tenantId, loggedInEmployeeId, viewAll, viewSelf, pageNumber, pageSize, filter, searchString); if (expenseList.Any()) { + + return (totalPages, totalCount, expenseList); } + } catch (Exception ex) { @@ -1101,5 +1020,281 @@ namespace Marco.Pms.Services.Helpers } #endregion + + + #region ======================================================= Helper Functions ======================================================= + private async Task> GetAllExpnesRelatedTablesForList(List model, Guid tenantId) + { + List expenseList = new List(); + var expenseIds = model.Select(m => m.Id).ToList(); + var projectIds = model.Select(m => m.ProjectId).ToList(); + var statusIds = model.Select(m => m.StatusId).ToList(); + var expensesTypeIds = model.Select(m => m.ExpensesTypeId).ToList(); + var paymentModeIds = model.Select(m => m.PaymentModeId).ToList(); + var createdByIds = model.Select(m => m.CreatedById).ToList(); + var reviewedByIds = model.Select(m => m.ReviewedById).ToList(); + var approvedByIds = model.Select(m => m.ApprovedById).ToList(); + var processedByIds = model.Select(m => m.ProcessedById).ToList(); + var paidByIds = model.Select(m => m.PaidById).ToList(); + + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).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(); + }); + 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 expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id) && et.TenantId == tenantId).ToListAsync(); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().Where(pm => paymentModeIds.Contains(pm.Id) && pm.TenantId == tenantId).ToListAsync(); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .Where(es => statusIds.Contains(es.StatusId) && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + StatusId = g.Key, + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }).ToListAsync(); + }); + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster + .AsNoTracking() + .Where(es => statusIds.Contains(es.Id)) + .ToListAsync(); + }); + var billAttachmentsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => expenseIds.Contains(ba.ExpensesId) && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + ExpensesId = g.Key, + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() + }) + .ToListAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, + processedByTask, statusTask, billAttachmentsTask); + + var projects = projectTask.Result; + var expenseTypes = expenseTypeTask.Result; + var paymentModes = paymentModeTask.Result; + 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; + + expenseList = model.Select(m => + { + var response = _mapper.Map(m); + + response.Project = projects.Where(p => p.Id == m.ProjectId).Select(p => _mapper.Map(p)).FirstOrDefault() ?? new ProjectBasicMongoDB(); + response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map(p)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.ReviewedBy = reviewedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.ApprovedBy = approvedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.ProcessedBy = processedBy.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.Status = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map(s.Status)).FirstOrDefault() ?? new ExpensesStatusMasterMongoDB(); + if (response.Status.Id == string.Empty) + { + var status = statusTask.Result; + response.Status = status.Where(s => s.Id == m.StatusId).Select(s => _mapper.Map(s)).FirstOrDefault() ?? new ExpensesStatusMasterMongoDB(); + } + + response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map>(s.NextStatus)).FirstOrDefault() ?? new List(); + response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map(pm)).FirstOrDefault() ?? new PaymentModeMatserMongoDB(); + response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map(et)).FirstOrDefault() ?? new ExpensesTypeMasterMongoDB(); + response.Documents = billAttachments.Where(ba => ba.ExpensesId == m.Id).Select(ba => ba.Documents).FirstOrDefault() ?? new List(); + return response; + }).ToList(); + + return expenseList; + } + private async Task GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId) + { + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId); + }); + 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); + }); + 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 expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.ExpensesTypeId && et.TenantId == tenantId); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId && pm.TenantId == tenantId); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .Where(es => es.StatusId == model.StatusId && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + StatusId = g.Key, + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }).FirstOrDefaultAsync(); + }); + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster + .AsNoTracking() + .FirstOrDefaultAsync(es => es.Id == model.StatusId); + }); + var billAttachmentsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => ba.ExpensesId == model.Id && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + ExpensesId = g.Key, + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() + }) + .FirstOrDefaultAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, + processedByTask, statusTask, billAttachmentsTask); + + var project = projectTask.Result; + var expenseType = expenseTypeTask.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 response = _mapper.Map(model); + + response.Project = _mapper.Map(project); + response.PaidBy = _mapper.Map(paidBy); + response.CreatedBy = _mapper.Map(createdBy); + response.ReviewedBy = _mapper.Map(reviewedBy); + response.ApprovedBy = _mapper.Map(approvedBy); + response.ProcessedBy = _mapper.Map(processedBy); + if (statusMapping != null) + { + response.Status = _mapper.Map(statusMapping.Status); + response.NextStatus = _mapper.Map>(statusMapping.NextStatus); + } + if (response.Status == null) + { + var status = statusTask.Result; + response.Status = _mapper.Map(status); + } + response.PaymentMode = _mapper.Map(paymentMode); + response.ExpensesType = _mapper.Map(expenseType); + if (billAttachment != null) response.Documents = billAttachment.Documents; + + return response; + + } + + #endregion } } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 7be54f2..a4c58b3 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -130,33 +130,6 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.Id, opt => opt.MapFrom(src => src.Id.ToString())) .ForMember( - dest => dest.ProjectId, - opt => opt.MapFrom(src => src.ProjectId.ToString())) - .ForMember( - dest => dest.ExpensesTypeId, - opt => opt.MapFrom(src => src.ExpensesTypeId.ToString())) - .ForMember( - dest => dest.PaymentModeId, - opt => opt.MapFrom(src => src.PaymentModeId.ToString())) - .ForMember( - dest => dest.PaidById, - opt => opt.MapFrom(src => src.PaidById.ToString())) - .ForMember( - dest => dest.CreatedById, - opt => opt.MapFrom(src => src.CreatedById.ToString())) - .ForMember( - dest => dest.ReviewedById, - opt => opt.MapFrom(src => src.ReviewedById.ToString())) - .ForMember( - dest => dest.ApprovedById, - opt => opt.MapFrom(src => src.ApprovedById.ToString())) - .ForMember( - dest => dest.ProcessedById, - opt => opt.MapFrom(src => src.ProcessedById.ToString())) - .ForMember( - dest => dest.StatusId, - opt => opt.MapFrom(src => src.StatusId.ToString())) - .ForMember( dest => dest.TenantId, opt => opt.MapFrom(src => src.TenantId.ToString())); @@ -165,33 +138,6 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.Id, opt => opt.MapFrom(src => Guid.Parse(src.Id))) .ForMember( - dest => dest.ProjectId, - opt => opt.MapFrom(src => Guid.Parse(src.ProjectId))) - .ForMember( - dest => dest.ExpensesTypeId, - opt => opt.MapFrom(src => Guid.Parse(src.ExpensesTypeId))) - .ForMember( - dest => dest.PaymentModeId, - opt => opt.MapFrom(src => Guid.Parse(src.PaymentModeId))) - .ForMember( - dest => dest.PaidById, - opt => opt.MapFrom(src => Guid.Parse(src.PaidById))) - .ForMember( - dest => dest.CreatedById, - opt => opt.MapFrom(src => Guid.Parse(src.CreatedById))) - .ForMember( - dest => dest.ReviewedById, - opt => opt.MapFrom(src => src.ReviewedById != null ? Guid.Parse(src.ReviewedById) : Guid.Empty)) - .ForMember( - dest => dest.ApprovedById, - opt => opt.MapFrom(src => src.ApprovedById != null ? Guid.Parse(src.ApprovedById) : Guid.Empty)) - .ForMember( - dest => dest.ProcessedById, - opt => opt.MapFrom(src => src.ProcessedById != null ? Guid.Parse(src.ProcessedById) : Guid.Empty)) - .ForMember( - dest => dest.StatusId, - opt => opt.MapFrom(src => Guid.Parse(src.StatusId))) - .ForMember( dest => dest.TenantId, opt => opt.MapFrom(src => Guid.Parse(src.TenantId))); diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 5458486..871059a 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -5,7 +5,6 @@ using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; -using Marco.Pms.Model.MongoDBModels.Expenses; using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; @@ -70,7 +69,7 @@ namespace Marco.Pms.Services.Service /// The number of records to return per page. /// The page number to retrieve. /// A paginated list of expenses. - public async Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber) + public async Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? searchString, string? filter, int pageSize, int pageNumber) { try { @@ -115,10 +114,10 @@ namespace Marco.Pms.Services.Service // 2. --- Deserialize Filter and Apply --- ExpensesFilter? expenseFilter = TryDeserializeFilter(filter); - var (totalPages, totalCount, expenseList) = await _cache.GetExpenseListAsync(tenantId, loggedInEmployeeId, hasViewAllPermissionTask.Result, hasViewSelfPermissionTask.Result, - pageNumber, pageSize, expenseFilter); + var (totalPages, totalCount, cacheList) = await _cache.GetExpenseListAsync(tenantId, loggedInEmployeeId, hasViewAllPermissionTask.Result, hasViewSelfPermissionTask.Result, + pageNumber, pageSize, expenseFilter, searchString); - if (expenseList == null) + if (cacheList == null) { // 3. --- Build Base Query and Apply Permissions --- @@ -126,7 +125,7 @@ namespace Marco.Pms.Services.Service var expensesQuery = _context.Expenses .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. - await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync()); + await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync(), tenantId); // Apply permission-based filtering BEFORE any other filters or pagination. @@ -174,6 +173,16 @@ namespace Marco.Pms.Services.Service } } + if (!string.IsNullOrWhiteSpace(searchString)) + { + var searchStringLower = searchString.ToLower(); + expensesQuery = expensesQuery.Include(e => e.PaidBy).Include(e => e.CreatedBy) + .Where(e => e.Description.ToLower().Contains(searchStringLower) || + (e.TransactionId != null && e.TransactionId.ToLower().Contains(searchStringLower)) || + (e.PaidBy != null && (e.PaidBy.FirstName + " " + e.PaidBy.LastName).ToLower().Contains(searchStringLower)) || + (e.CreatedBy != null && (e.CreatedBy.FirstName + " " + e.CreatedBy.LastName).ToLower().Contains(searchStringLower))); + } + // 4. --- Apply Ordering and Pagination --- // This should be the last step before executing the query. @@ -199,20 +208,40 @@ namespace Marco.Pms.Services.Service } else { - expenseVM = await GetAllExpnesRelatedTables(_mapper.Map>(expenseList), tenantId); + var permissionStatusMapping = await _context.StatusPermissionMapping + .GroupBy(ps => ps.StatusId) + .Select(g => new + { + StatusId = g.Key, + PermissionIds = g.Select(ps => ps.PermissionId).ToList() + }).ToListAsync(); + + expenseVM = cacheList.Select(m => + { + var response = _mapper.Map(m); + if (response.Status != null && (response.NextStatus?.Any() ?? false)) + { + response.Status.PermissionIds = permissionStatusMapping.Where(ps => ps.StatusId == Guid.Parse(m.Status.Id)).Select(ps => ps.PermissionIds).FirstOrDefault(); + foreach (var status in response.NextStatus) + { + status.PermissionIds = permissionStatusMapping.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + } + } + return response; + }).ToList(); totalEntites = (int)totalCount; } // 7. --- Return Final Success Response --- var message = $"{expenseVM.Count} expense records fetched successfully."; _logger.LogInfo(message); - var defaultFilter = await GetObjectForfilter(tenantId); + + var response = new { CurrentFilter = expenseFilter, CurrentPage = pageNumber, TotalPages = totalPages, TotalEntites = totalEntites, - DefaultFilter = defaultFilter, Data = expenseVM, }; return ApiResponse.SuccessResponse(response, message, 200); @@ -242,7 +271,50 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Expense Not Found", "Expense Not Found", 404); } } - var vm = await GetAllExpnesRelatedTablesFromMongoDB(expenseDetails, tenantId); + var vm = _mapper.Map(expenseDetails); + + var permissionStatusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.StatusPermissionMapping + .GroupBy(ps => ps.StatusId) + .Select(g => new + { + StatusId = g.Key, + PermissionIds = g.Select(ps => ps.PermissionId).ToList() + }).ToListAsync(); + }); + var expenseReimburseTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesReimburseMapping + .Include(er => er.ExpensesReimburse) + .ThenInclude(er => er!.ReimburseBy) + .ThenInclude(e => e!.JobRole) + .Where(er => er.TenantId == tenantId && er.ExpensesId == vm.Id) + .Select(er => er.ExpensesReimburse).FirstOrDefaultAsync(); + }); + var permissionStatusMappings = permissionStatusMappingTask.Result; + var expensesReimburse = expenseReimburseTask.Result; + + if (vm.Status != null && (vm.NextStatus?.Any() ?? false)) + { + vm.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == vm.Status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + foreach (var status in vm.NextStatus) + { + status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); + } + } + vm.ExpensesReimburse = _mapper.Map(expensesReimburse); + + foreach (var document in expenseDetails.Documents) + { + var response = vm.Documents.FirstOrDefault(d => d.DocumentId == Guid.Parse(document.DocumentId)); + + response!.PreSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); + response!.ThumbPreSignedUrl = _s3Service.GeneratePreSignedUrl(document.ThumbS3Key); + } + _logger.LogInfo("Employee {EmployeeId} successfully fetched expense details with ID {ExpenseId}", loggedInEmployee.Id, vm.Id); return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); @@ -268,6 +340,81 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); } } + public async Task> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId) + { + try + { + using var scope = _serviceScopeFactory.CreateScope(); + var projectHelper = scope.ServiceProvider.GetRequiredService(); + var projectIds = await projectHelper.GetMyProjectIdsAsync(tenantId, loggedInEmployee); + + // Task 1: Get all distinct projects associated with the tenant's expenses. + var projectsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.Project != null && projectIds.Contains(e.ProjectId)) + .Select(e => e.Project!) + .Distinct() + .Select(p => new { p.Id, Name = $"{p.Name}" }) + .ToListAsync(); + }); + + // Task 2: Get all distinct users who paid for the tenant's expenses. + var paidByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.PaidBy != null) + .Select(e => e.PaidBy!) + .Distinct() + .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) + .ToListAsync(); + }); + + // Task 3: Get all distinct users who created the tenant's expenses. + var createdByTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.CreatedBy != null) + .Select(e => e.CreatedBy!) + .Distinct() + .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) + .ToListAsync(); + }); + + // Task 4: Get all distinct statuses associated with the tenant's expenses. + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Expenses + .Where(e => e.TenantId == tenantId && e.Status != null) + .Select(e => e.Status!) + .Distinct() + .Select(s => new { s.Id, s.Name }) + .ToListAsync(); + }); + + // Execute all four queries concurrently. The total wait time will be determined + // by the longest-running query, not the sum of all four. + await Task.WhenAll(projectsTask, paidByTask, createdByTask, statusTask); + + // Construct the final object from the results of the completed tasks. + return ApiResponse.SuccessResponse(new + { + Projects = await projectsTask, + PaidBy = await paidByTask, + CreatedBy = await createdByTask, + Status = await statusTask + }, "Successfully fetched the filter list", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while fetching the list filters for expenses"); + return ApiResponse.ErrorResponse("Internal Exception Occured", ExceptionMapper(ex), 500); + } + } #endregion @@ -1038,217 +1185,7 @@ namespace Marco.Pms.Services.Service return expenseList; } - private async Task GetAllExpnesRelatedTablesFromMongoDB(ExpenseDetailsMongoDB model, Guid tenantId) - { - var reviewedById = model.ReviewedById != null ? Guid.Parse(model.ReviewedById) : Guid.Empty; - var approvedById = model.ApprovedById != null ? Guid.Parse(model.ApprovedById) : Guid.Empty; - var processedById = model.ProcessedById != null ? Guid.Parse(model.ProcessedById) : Guid.Empty; - var projectTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == Guid.Parse(model.ProjectId) && p.TenantId == tenantId); - }); - 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 == Guid.Parse(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 == Guid.Parse(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 == 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 == 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 == processedById && e.TenantId == tenantId); - }); - var expenseTypeTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == Guid.Parse(model.ExpensesTypeId) && et.TenantId == tenantId); - }); - var paymentModeTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == Guid.Parse(model.PaymentModeId) && pm.TenantId == tenantId); - }); - var statusMappingTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMapping - .Include(s => s.Status) - .Include(s => s.NextStatus) - .AsNoTracking() - .Where(es => es.StatusId == Guid.Parse(model.StatusId) && es.Status != null) - .GroupBy(s => s.StatusId) - .Select(g => new - { - Status = g.Select(s => s.Status).FirstOrDefault(), - NextStatus = g.Select(s => s.NextStatus).ToList() - }).FirstOrDefaultAsync(); - }); - var statusTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesStatusMaster - .AsNoTracking() - .FirstOrDefaultAsync(es => es.Id == Guid.Parse(model.StatusId)); - }); - var permissionStatusMappingTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.StatusPermissionMapping - .GroupBy(ps => ps.StatusId) - .Select(g => new - { - StatusId = g.Key, - PermissionIds = g.Select(ps => ps.PermissionId).ToList() - }).ToListAsync(); - }); - var expenseReimburseTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.ExpensesReimburseMapping - .Include(er => er.ExpensesReimburse) - .ThenInclude(er => er!.ReimburseBy) - .ThenInclude(e => e!.JobRole) - .Where(er => er.TenantId == tenantId && er.ExpensesId == Guid.Parse(model.Id)) - .Select(er => er.ExpensesReimburse).FirstOrDefaultAsync(); - }); - - // Await all prerequisite checks at once. - await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, processedByTask, - statusTask, permissionStatusMappingTask, expenseReimburseTask); - - var project = projectTask.Result; - var expenseType = expenseTypeTask.Result; - var paymentMode = paymentModeTask.Result; - var statusMapping = statusMappingTask.Result; - var permissionStatusMappings = permissionStatusMappingTask.Result; - var paidBy = paidByTask.Result; - var createdBy = createdByTask.Result; - var reviewedBy = reviewedByTask.Result; - var approvedBy = approvedByTask.Result; - var processedBy = processedByTask.Result; - var expensesReimburse = expenseReimburseTask.Result; - - var response = _mapper.Map(model); - - response.Project = _mapper.Map(project); - response.PaidBy = _mapper.Map(paidBy); - response.CreatedBy = _mapper.Map(createdBy); - if (reviewedBy != null) response.ReviewedBy = _mapper.Map(reviewedBy); - if (approvedBy != null) response.ApprovedBy = _mapper.Map(approvedBy); - if (processedBy != null) response.ProcessedBy = _mapper.Map(processedBy); - response.PaymentMode = _mapper.Map(paymentMode); - response.ExpensesType = _mapper.Map(expenseType); - response.ExpensesReimburse = _mapper.Map(expensesReimburse); - if (statusMapping != null) - { - response.Status = _mapper.Map(statusMapping.Status); - - response.NextStatus = _mapper.Map>(statusMapping.NextStatus); - if (response.NextStatus != null) - { - foreach (var status in response.NextStatus) - { - status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == status.Id).Select(ps => ps.PermissionIds).FirstOrDefault(); - } - } - } - if (response.Status == null) - { - var status = statusTask.Result; - response.Status = _mapper.Map(status); - } - response.Status.PermissionIds = permissionStatusMappings.Where(ps => ps.StatusId == Guid.Parse(model.StatusId)).Select(ps => ps.PermissionIds).FirstOrDefault(); - - foreach (var document in model.Documents) - { - var vm = response.Documents.FirstOrDefault(d => d.DocumentId == Guid.Parse(document.DocumentId)); - - vm!.PreSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key); - vm!.ThumbPreSignedUrl = _s3Service.GeneratePreSignedUrl(document.ThumbS3Key); - } - - return response; - } - - private async Task GetObjectForfilter(Guid tenantId) - { - // Task 1: Get all distinct projects associated with the tenant's expenses. - var projectsTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Expenses - .Where(e => e.TenantId == tenantId && e.Project != null) - .Select(e => e.Project!) - .Distinct() - .Select(p => new { p.Id, Name = $"{p.Name}" }) - .ToListAsync(); - }); - - // Task 2: Get all distinct users who paid for the tenant's expenses. - var paidByTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Expenses - .Where(e => e.TenantId == tenantId && e.PaidBy != null) - .Select(e => e.PaidBy!) - .Distinct() - .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) - .ToListAsync(); - }); - - // Task 3: Get all distinct users who created the tenant's expenses. - var createdByTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Expenses - .Where(e => e.TenantId == tenantId && e.CreatedBy != null) - .Select(e => e.CreatedBy!) - .Distinct() - .Select(u => new { u.Id, Name = $"{u.FirstName} {u.LastName}" }) - .ToListAsync(); - }); - - // Task 4: Get all distinct statuses associated with the tenant's expenses. - var statusTask = Task.Run(async () => - { - await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); - return await dbContext.Expenses - .Where(e => e.TenantId == tenantId && e.Status != null) - .Select(e => e.Status!) - .Distinct() - .Select(s => new { s.Id, s.Name }) - .ToListAsync(); - }); - - // Execute all four queries concurrently. The total wait time will be determined - // by the longest-running query, not the sum of all four. - await Task.WhenAll(projectsTask, paidByTask, createdByTask, statusTask); - - // Construct the final object from the results of the completed tasks. - return new - { - Projects = await projectsTask, - PaidBy = await paidByTask, - CreatedBy = await createdByTask, - Status = await statusTask - }; - } /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index 673c26c..5d84eab 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -6,9 +6,10 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces { public interface IExpensesService { - Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? filter, int pageSize, int pageNumber); + Task> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? searchString, string? filter, int pageSize, int pageNumber); Task> GetExpenseDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId); Task> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId); Task> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId); Task> ChangeStatusAsync(ExpenseRecordDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId); From 36db35d90eec0210d910c8daf218644e2c5defef Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 31 Jul 2025 11:15:37 +0530 Subject: [PATCH 61/81] Sending every project exists in expense table --- Marco.Pms.Services/Service/ExpensesService.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 871059a..03a22f6 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -344,16 +344,12 @@ namespace Marco.Pms.Services.Service { try { - using var scope = _serviceScopeFactory.CreateScope(); - var projectHelper = scope.ServiceProvider.GetRequiredService(); - var projectIds = await projectHelper.GetMyProjectIdsAsync(tenantId, loggedInEmployee); - // Task 1: Get all distinct projects associated with the tenant's expenses. var projectsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.Expenses - .Where(e => e.TenantId == tenantId && e.Project != null && projectIds.Contains(e.ProjectId)) + .Where(e => e.TenantId == tenantId && e.Project != null) .Select(e => e.Project!) .Distinct() .Select(p => new { p.Id, Name = $"{p.Name}" }) From 732182a67212f374f514aaa9b96b8facaea2ae78 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 31 Jul 2025 17:26:09 +0530 Subject: [PATCH 62/81] Added new API to fetch basic employee list --- .../Controllers/EmployeeController.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/EmployeeController.cs b/Marco.Pms.Services/Controllers/EmployeeController.cs index d5d7f3d..c558de4 100644 --- a/Marco.Pms.Services/Controllers/EmployeeController.cs +++ b/Marco.Pms.Services/Controllers/EmployeeController.cs @@ -1,4 +1,5 @@ -using Marco.Pms.DataAccess.Data; +using AutoMapper; +using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Attendance; using Marco.Pms.Model.Dtos.Employees; using Marco.Pms.Model.Employees; @@ -6,6 +7,7 @@ using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Employee; using Marco.Pms.Services.Hubs; using Marco.Pms.Services.Service; @@ -38,13 +40,14 @@ namespace MarcoBMS.Services.Controllers private readonly ILoggingService _logger; private readonly IHubContext _signalR; private readonly PermissionServices _permission; + private readonly IMapper _mapper; private readonly IProjectServices _projectServices; private readonly Guid tenantId; public EmployeeController(UserManager userManager, IEmailSender emailSender, ApplicationDbContext context, EmployeeHelper employeeHelper, UserHelper userHelper, IConfiguration configuration, ILoggingService logger, - IHubContext signalR, PermissionServices permission, IProjectServices projectServices) + IHubContext signalR, PermissionServices permission, IProjectServices projectServices, IMapper mapper) { _context = context; _userManager = userManager; @@ -56,6 +59,7 @@ namespace MarcoBMS.Services.Controllers _signalR = signalR; _permission = permission; _projectServices = projectServices; + _mapper = mapper; tenantId = _userHelper.GetTenantId(); } @@ -162,6 +166,30 @@ namespace MarcoBMS.Services.Controllers return Ok(ApiResponse.SuccessResponse(result, "Filter applied.", 200)); } + [HttpGet("basic")] + public async Task GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var employeeQuery = _context.Employees.Where(e => e.TenantId == tenantId); + if (projectId != null && projectId == Guid.Empty) + { + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value); + if (!hasProjectPermission) + { + _logger.LogWarning("User {EmployeeId} attempts to get employee for project {ProjectId}, but not have access to the project", loggedInEmployee.Id, projectId); + return StatusCode(403, ApiResponse.ErrorResponse("Access denied", "User do not have access to view the list for this project", 403)); + } + var employeeIds = await _context.ProjectAllocations.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.TenantId == tenantId).Select(p => p.EmployeeId).ToListAsync(); + employeeQuery = employeeQuery.Where(e => employeeIds.Contains(e.Id)); + } + if (!string.IsNullOrWhiteSpace(searchString)) + { + var searchStringLower = searchString.ToLower(); + employeeQuery = employeeQuery.Where(e => (e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower)); + } + var response = await employeeQuery.Select(e => _mapper.Map(e)).ToListAsync(); + return Ok(ApiResponse.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200)); + } [HttpGet] [Route("search/{name}/{projectid?}")] public async Task SearchEmployee(string name, Guid? projectid) From 59459acaee1f260beb1cbb312f4c4aed9da25bf0 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 31 Jul 2025 19:06:26 +0530 Subject: [PATCH 63/81] Only sending 10 employees if project Id is not provided --- Marco.Pms.Services/Controllers/EmployeeController.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/EmployeeController.cs b/Marco.Pms.Services/Controllers/EmployeeController.cs index c558de4..21de1bf 100644 --- a/Marco.Pms.Services/Controllers/EmployeeController.cs +++ b/Marco.Pms.Services/Controllers/EmployeeController.cs @@ -171,7 +171,7 @@ namespace MarcoBMS.Services.Controllers { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var employeeQuery = _context.Employees.Where(e => e.TenantId == tenantId); - if (projectId != null && projectId == Guid.Empty) + if (projectId != null && projectId != Guid.Empty) { var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value); if (!hasProjectPermission) @@ -187,6 +187,11 @@ namespace MarcoBMS.Services.Controllers var searchStringLower = searchString.ToLower(); employeeQuery = employeeQuery.Where(e => (e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower)); } + + if (string.IsNullOrWhiteSpace(searchString) && (projectId == null || projectId == Guid.Empty)) + { + employeeQuery = employeeQuery.Take(10); + } var response = await employeeQuery.Select(e => _mapper.Map(e)).ToListAsync(); return Ok(ApiResponse.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200)); } From 4808d6e77b0fc4adeda6c54bbbd567f9a1974d05 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 1 Aug 2025 09:03:12 +0530 Subject: [PATCH 64/81] COrrected the seppling mistake for projectDetails API --- Marco.Pms.Services/Controllers/ProjectController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 796fd39..2c03d69 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -135,7 +135,7 @@ namespace MarcoBMS.Services.Controllers var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _projectServices.GetProjectDetailsAsync(id, tenantId, loggedInEmployee); + var response = await _projectServices.GetProjectDetailsOldAsync(id, tenantId, loggedInEmployee); return StatusCode(response.StatusCode, response); } From 0be021448d516948c4daa8c0ba496144f61dfbe1 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 1 Aug 2025 11:34:23 +0530 Subject: [PATCH 65/81] Added the date filert in mongo get function also --- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index fc670d6..5bdc934 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -52,12 +52,18 @@ namespace Marco.Pms.Helpers.CacheHelper if (expenseFilter != null) { - if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue) + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue && expenseFilter.IsTransactionDate == false) { filter &= filterBuilder.Gte(e => e.CreatedAt, expenseFilter.StartDate.Value.Date) & filterBuilder.Lte(e => e.CreatedAt, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1)); } + if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue && expenseFilter.IsTransactionDate) + { + filter &= filterBuilder.Gte(e => e.TransactionDate, expenseFilter.StartDate.Value.Date) + & filterBuilder.Lte(e => e.TransactionDate, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1)); + } + if (expenseFilter.ProjectIds?.Any() == true) { filter &= filterBuilder.In(e => e.Project.Id, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList()); From 555bb8777928746fb13542e65a1b1297c37bcfe3 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 1 Aug 2025 12:15:24 +0530 Subject: [PATCH 66/81] Validating the null objects while saving the object in cache --- .../Helpers/CacheUpdateHelper.cs | 6 +- .../MappingProfiles/MappingProfile.cs | 2 +- Marco.Pms.Services/Service/ExpensesService.cs | 152 +++++++++++++++++- 3 files changed, 148 insertions(+), 12 deletions(-) diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 6aa5305..5db4d4c 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -1146,9 +1146,9 @@ namespace Marco.Pms.Services.Helpers response.Project = projects.Where(p => p.Id == m.ProjectId).Select(p => _mapper.Map(p)).FirstOrDefault() ?? new ProjectBasicMongoDB(); response.PaidBy = paidBys.Where(p => p.Id == m.PaidById).Select(p => _mapper.Map(p)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); response.CreatedBy = createdBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); - response.ReviewedBy = reviewedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); - response.ApprovedBy = approvedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); - response.ProcessedBy = processedBy.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault() ?? new BasicEmployeeMongoDB(); + response.ReviewedBy = reviewedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault(); + response.ApprovedBy = approvedBys.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault(); + response.ProcessedBy = processedBy.Where(e => e.Id == m.CreatedById).Select(e => _mapper.Map(e)).FirstOrDefault(); response.Status = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map(s.Status)).FirstOrDefault() ?? new ExpensesStatusMasterMongoDB(); if (response.Status.Id == string.Empty) { diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index a4c58b3..3d1b90d 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -112,7 +112,7 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap() .ForMember( dest => dest.Id, - opt => opt.MapFrom(src => Guid.Parse(src.Id))) + opt => opt.MapFrom(src => string.IsNullOrWhiteSpace(src.Id) ? Guid.Empty : Guid.Parse(src.Id))) .ForMember( dest => dest.JobRoleId, opt => opt.MapFrom(src => Guid.Parse(src.JobRoleId ?? ""))); diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 03a22f6..5b2420c 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -5,6 +5,11 @@ using Marco.Pms.Model.Dtos.Expenses; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; +using Marco.Pms.Model.MongoDBModels; +using Marco.Pms.Model.MongoDBModels.Employees; +using Marco.Pms.Model.MongoDBModels.Expenses; +using Marco.Pms.Model.MongoDBModels.Masters; +using Marco.Pms.Model.MongoDBModels.Project; using Marco.Pms.Model.MongoDBModels.Utility; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; @@ -117,14 +122,13 @@ namespace Marco.Pms.Services.Service var (totalPages, totalCount, cacheList) = await _cache.GetExpenseListAsync(tenantId, loggedInEmployeeId, hasViewAllPermissionTask.Result, hasViewSelfPermissionTask.Result, pageNumber, pageSize, expenseFilter, searchString); + // 3. --- Build Base Query and Apply Permissions --- + // Start with a base IQueryable. Filters will be chained onto this. + var expensesQuery = _context.Expenses + .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. + if (cacheList == null) { - - // 3. --- Build Base Query and Apply Permissions --- - // Start with a base IQueryable. Filters will be chained onto this. - var expensesQuery = _context.Expenses - .Where(e => e.TenantId == tenantId); // Always filter by TenantId first. - await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync(), tenantId); // Apply permission-based filtering BEFORE any other filters or pagination. @@ -264,12 +268,14 @@ namespace Marco.Pms.Services.Service var expenseDetails = await _cache.GetExpenseDetailsById(id, tenantId); if (expenseDetails == null) { - expenseDetails = await _cache.AddExpenseByIdAsync(id, tenantId); - if (expenseDetails == null) + var expense = await _context.Expenses.AsNoTracking().FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId); + + if (expense == null) { _logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id); return ApiResponse.ErrorResponse("Expense Not Found", "Expense Not Found", 404); } + expenseDetails = await GetAllExpnesRelatedTablesForSingle(expense, expense.TenantId); } var vm = _mapper.Map(expenseDetails); @@ -1182,6 +1188,136 @@ namespace Marco.Pms.Services.Service return expenseList; } + private async Task GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId) + { + var projectTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId); + }); + 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); + }); + 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 expenseTypeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.ExpensesTypeId && et.TenantId == tenantId); + }); + var paymentModeTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId && pm.TenantId == tenantId); + }); + var statusMappingTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMapping + .Include(s => s.Status) + .Include(s => s.NextStatus) + .AsNoTracking() + .Where(es => es.StatusId == model.StatusId && es.Status != null) + .GroupBy(s => s.StatusId) + .Select(g => new + { + StatusId = g.Key, + Status = g.Select(s => s.Status).FirstOrDefault(), + NextStatus = g.Select(s => s.NextStatus).ToList() + }).FirstOrDefaultAsync(); + }); + var statusTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.ExpensesStatusMaster + .AsNoTracking() + .FirstOrDefaultAsync(es => es.Id == model.StatusId); + }); + var billAttachmentsTask = Task.Run(async () => + { + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.BillAttachments + .Include(ba => ba.Document) + .AsNoTracking() + .Where(ba => ba.ExpensesId == model.Id && ba.Document != null) + .GroupBy(ba => ba.ExpensesId) + .Select(g => new + { + ExpensesId = g.Key, + Documents = g.Select(ba => new DocumentMongoDB + { + DocumentId = ba.Document!.Id.ToString(), + FileName = ba.Document.FileName, + ContentType = ba.Document.ContentType, + S3Key = ba.Document.S3Key, + ThumbS3Key = ba.Document.ThumbS3Key ?? ba.Document.S3Key + }).ToList() + }) + .FirstOrDefaultAsync(); + }); + + // Await all prerequisite checks at once. + await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, + processedByTask, statusTask, billAttachmentsTask); + + var project = projectTask.Result; + var expenseType = expenseTypeTask.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 response = _mapper.Map(model); + + response.Project = _mapper.Map(project); + response.PaidBy = _mapper.Map(paidBy); + response.CreatedBy = _mapper.Map(createdBy); + response.ReviewedBy = _mapper.Map(reviewedBy); + response.ApprovedBy = _mapper.Map(approvedBy); + response.ProcessedBy = _mapper.Map(processedBy); + if (statusMapping != null) + { + response.Status = _mapper.Map(statusMapping.Status); + response.NextStatus = _mapper.Map>(statusMapping.NextStatus); + } + if (response.Status == null) + { + var status = statusTask.Result; + response.Status = _mapper.Map(status); + } + response.PaymentMode = _mapper.Map(paymentMode); + response.ExpensesType = _mapper.Map(expenseType); + if (billAttachment != null) response.Documents = billAttachment.Documents; + + return response; + + } + /// /// Deserializes the filter string, handling multiple potential formats (e.g., direct JSON vs. escaped JSON string). From eaf6284a57db9566519550eb01491cf197c2239f Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 1 Aug 2025 16:18:17 +0530 Subject: [PATCH 67/81] Order nextStatus by it name --- Marco.Pms.Services/Helpers/CacheUpdateHelper.cs | 4 ++-- Marco.Pms.Services/Service/ExpensesService.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs index 5db4d4c..cbd7b6e 100644 --- a/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs +++ b/Marco.Pms.Services/Helpers/CacheUpdateHelper.cs @@ -1090,7 +1090,7 @@ namespace Marco.Pms.Services.Helpers { StatusId = g.Key, Status = g.Select(s => s.Status).FirstOrDefault(), - NextStatus = g.Select(s => s.NextStatus).ToList() + NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList() }).ToListAsync(); }); var statusTask = Task.Run(async () => @@ -1220,7 +1220,7 @@ namespace Marco.Pms.Services.Helpers { StatusId = g.Key, Status = g.Select(s => s.Status).FirstOrDefault(), - NextStatus = g.Select(s => s.NextStatus).ToList() + NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList() }).FirstOrDefaultAsync(); }); var statusTask = Task.Run(async () => diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 5b2420c..cf91fed 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1120,7 +1120,7 @@ namespace Marco.Pms.Services.Service { StatusId = g.Key, Status = g.Select(s => s.Status).FirstOrDefault(), - NextStatus = g.Select(s => s.NextStatus).ToList() + NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList() }).ToListAsync(); }); var statusTask = Task.Run(async () => @@ -1243,7 +1243,7 @@ namespace Marco.Pms.Services.Service { StatusId = g.Key, Status = g.Select(s => s.Status).FirstOrDefault(), - NextStatus = g.Select(s => s.NextStatus).ToList() + NextStatus = g.Select(s => s.NextStatus).OrderBy(s => s!.Name).ToList() }).FirstOrDefaultAsync(); }); var statusTask = Task.Run(async () => From a7392a515d1236eb0358b115ff2d4597bdd166fb Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 1 Aug 2025 17:50:59 +0530 Subject: [PATCH 68/81] Added new logs in expense update API --- Marco.Pms.Services/Service/ExpensesService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index cf91fed..5d82745 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -824,12 +824,12 @@ namespace Marco.Pms.Services.Service if (existingExpense.StatusId != Draft && existingExpense.StatusId != RejectedByReviewer && existingExpense.StatusId != RejectedByApprover) { - _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED", loggedInEmployee.Id); + _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED, but is {StatusId}", existingExpense.Id, existingExpense.StatusId); return ApiResponse.ErrorResponse("Expense connot be updated", "Expense connot be updated", 400); } if (existingExpense.CreatedById != loggedInEmployee.Id) { - _logger.LogWarning("User attempted to update expense with ID {ExpenseId} which not created by them", loggedInEmployee.Id); + _logger.LogWarning("User attempted to update expense with ID {ExpenseId} which not created by them", existingExpense.Id); return ApiResponse.ErrorResponse("You donot have access to update this expense", "You donot have access to update this expense", 400); } From 2ccae935f36240e5af1ae22f99b81841f90ea65d Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 2 Aug 2025 12:48:20 +0530 Subject: [PATCH 69/81] Sending the ExpenseLogs in Details API --- .../ViewModels/Expenses/ExpenseDetailsVM.cs | 1 + Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs | 12 ++++++++++++ Marco.Pms.Services/Controllers/EmployeeController.cs | 6 +----- Marco.Pms.Services/MappingProfiles/MappingProfile.cs | 1 + Marco.Pms.Services/Service/ExpensesService.cs | 3 +++ 5 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs index b777d13..174a53d 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseDetailsVM.cs @@ -27,6 +27,7 @@ namespace Marco.Pms.Model.ViewModels.Expenses public string Description { get; set; } = string.Empty; public string? Location { get; set; } public List Documents { get; set; } = new List(); + public List ExpenseLogs { get; set; } = new List(); public string? GSTNumber { get; set; } public int? NoOfPersons { get; set; } public bool IsActive { get; set; } = true; diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs new file mode 100644 index 0000000..6a05ff7 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs @@ -0,0 +1,12 @@ +using Marco.Pms.Model.ViewModels.Activities; + +namespace Marco.Pms.Model.ViewModels.Expenses +{ + public class ExpenseLogVM + { + public Guid Id { get; set; } + public BasicEmployeeVM? UpdatedBy { get; set; } + public string Action { get; set; } = string.Empty; + public string? Comment { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/EmployeeController.cs b/Marco.Pms.Services/Controllers/EmployeeController.cs index 21de1bf..cdc28ed 100644 --- a/Marco.Pms.Services/Controllers/EmployeeController.cs +++ b/Marco.Pms.Services/Controllers/EmployeeController.cs @@ -188,11 +188,7 @@ namespace MarcoBMS.Services.Controllers employeeQuery = employeeQuery.Where(e => (e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower)); } - if (string.IsNullOrWhiteSpace(searchString) && (projectId == null || projectId == Guid.Empty)) - { - employeeQuery = employeeQuery.Take(10); - } - var response = await employeeQuery.Select(e => _mapper.Map(e)).ToListAsync(); + var response = await employeeQuery.Take(10).Select(e => _mapper.Map(e)).ToListAsync(); return Ok(ApiResponse.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200)); } [HttpGet] diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 3d1b90d..a5fc445 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -123,6 +123,7 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); CreateMap() diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 5d82745..fb639bc 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -321,6 +321,9 @@ namespace Marco.Pms.Services.Service response!.ThumbPreSignedUrl = _s3Service.GeneratePreSignedUrl(document.ThumbS3Key); } + var expenselogs = await _context.ExpenseLogs.Include(el => el.UpdatedBy).Where(el => el.ExpenseId == vm.Id).Select(el => _mapper.Map(el)).ToListAsync(); + + vm.ExpenseLogs = expenselogs; _logger.LogInfo("Employee {EmployeeId} successfully fetched expense details with ID {ExpenseId}", loggedInEmployee.Id, vm.Id); return ApiResponse.SuccessResponse(vm, "Successfully fetched the details of expense", 200); From 2c94854f57a0573cfd1bf5b50cab0d75b2069de8 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 09:46:56 +0530 Subject: [PATCH 70/81] Showing the draft of self only --- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 7 +++++++ Marco.Pms.Services/Service/ExpensesService.cs | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 5bdc934..11e4554 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -47,6 +47,13 @@ namespace Marco.Pms.Helpers.CacheHelper { filter &= filterBuilder.Eq(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()); } + else + { + filter &= filterBuilder.Or( + filterBuilder.Ne(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()), + filterBuilder.Ne(e => e.Status.Id, "297e0d8f-f668-41b5-bfea-e03b354251c8") + ); + } // Apply filters diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index fb639bc..dd0bf95 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -139,6 +139,10 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); } + else + { + expensesQuery = expensesQuery.Where(e => e.CreatedById != loggedInEmployeeId || e.StatusId != Draft); + } if (expenseFilter != null) { From 30fa924d0f2a719e020783be408ca103c933a488 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 11:12:07 +0530 Subject: [PATCH 71/81] added the date in update logs --- ...Added_Updated_At_In_UpdateLogs.Designer.cs | 4437 +++++++++++++++++ ...04053705_Added_Updated_At_In_UpdateLogs.cs | 29 + .../ApplicationDbContextModelSnapshot.cs | 3 + Marco.Pms.Model/Expenses/ExpenseLog.cs | 1 + .../ViewModels/Expenses/ExpenseLogVM.cs | 1 + 5 files changed, 4471 insertions(+) create mode 100644 Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.cs diff --git a/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.Designer.cs new file mode 100644 index 0000000..5b67b33 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.Designer.cs @@ -0,0 +1,4437 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250804053705_Added_Updated_At_In_UpdateLogs")] + partial class Added_Updated_At_In_UpdateLogs + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Designation") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }, + new + { + Id = new Guid("385be49f-8fde-440e-bdbc-3dffeb8dd116"), + Description = "Allows a user to view only the expense records that they have personally submitted", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View Self" + }, + new + { + Id = new Guid("01e06444-9ca7-4df4-b900-8c3fa051b92f"), + Description = "Allows a user to view all expense records across the organization or project, regardless of who submitted or paid them", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "View All" + }, + new + { + Id = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + Description = "Allows a user to create and submit new expense records, including attaching relevant documents like receipts or invoices.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Upload" + }, + new + { + Id = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + Description = "Allows a user to examine submitted expenses for accuracy, completeness, and policy compliance before they are approved or rejected.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Review" + }, + new + { + Id = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + Description = "Allows a user to authorize or reject submitted expenses, making them officially accepted or declined within the system.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Approve" + }, + new + { + Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Process" + }, + new + { + Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), + Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules.", + FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + IsEnabled = true, + Name = "Manage" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("DocumentId"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("TenantId"); + + b.ToTable("BillAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("ExpenseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpenseId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ExpenseLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("double"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ExpensesTypeId") + .HasColumnType("char(36)"); + + b.Property("GSTNumber") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Location") + .HasColumnType("longtext"); + + b.Property("NoOfPersons") + .HasColumnType("int"); + + b.Property("PaidById") + .HasColumnType("char(36)"); + + b.Property("PaymentModeId") + .HasColumnType("char(36)"); + + b.Property("PreApproved") + .HasColumnType("tinyint(1)"); + + b.Property("ProcessedById") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReviewedById") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("SupplerName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TransactionDate") + .HasColumnType("datetime(6)"); + + b.Property("TransactionId") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ExpensesTypeId"); + + b.HasIndex("PaidById"); + + b.HasIndex("PaymentModeId"); + + b.HasIndex("ProcessedById"); + + b.HasIndex("ProjectId"); + + b.HasIndex("ReviewedById"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Expenses"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ReimburseById") + .HasColumnType("char(36)"); + + b.Property("ReimburseDate") + .HasColumnType("datetime(6)"); + + b.Property("ReimburseNote") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReimburseTransactionId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ReimburseById"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburse"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpensesId") + .HasColumnType("char(36)"); + + b.Property("ExpensesReimburseId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ExpensesId"); + + b.HasIndex("ExpensesReimburseId"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesReimburseMapping"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("NextStatusId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NextStatusId"); + + b.HasIndex("StatusId"); + + b.ToTable("ExpensesStatusMapping"); + + b.HasData( + new + { + Id = new Guid("5cf7f1df-9d1f-4289-add0-1775ad614f25"), + NextStatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("4ddddc10-0ffd-4884-accf-d4fa0bd97f54"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("36c00548-241c-43ec-bc95-cacebedb925c"), + NextStatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("1fca1700-1266-477d-bba4-9ac3753aa33c"), + NextStatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("6b867bec-66e6-42a7-9611-f4595af9b9ce"), + NextStatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("ef1fcfbc-60e0-4f17-9308-c583a05d48fd"), + NextStatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("af1e4492-98ee-4451-8ab7-fd8323f29c32"), + NextStatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("PermissionId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PermissionId"); + + b.HasIndex("StatusId"); + + b.ToTable("StatusPermissionMapping"); + + b.HasData( + new + { + Id = new Guid("722b0c3c-5a78-456d-b9bb-b6ba1b21d59b"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8") + }, + new + { + Id = new Guid("7deb0945-e1c9-411f-8b3c-c9bdbe3c3c2d"), + PermissionId = new Guid("0f57885d-bcb2-4711-ac95-d841ace6d5a7"), + StatusId = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7") + }, + new + { + Id = new Guid("9e2ec648-1ca2-4747-9329-e911b18edb3e"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b") + }, + new + { + Id = new Guid("0b7926fc-a34b-4a5b-8c7d-1003480cf0fa"), + PermissionId = new Guid("1f4bda08-1873-449a-bb66-3e8222bd871b"), + StatusId = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8") + }, + new + { + Id = new Guid("cd15f9b9-be45-4deb-9c71-2f23f872dbcd"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729") + }, + new + { + Id = new Guid("f6f26b2f-2fa6-40b7-8601-cbd4bcdda0cc"), + PermissionId = new Guid("eaafdd76-8aac-45f9-a530-315589c6deca"), + StatusId = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27") + }, + new + { + Id = new Guid("214354e5-daad-4569-ad69-eb5bf4e87fbc"), + PermissionId = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), + StatusId = new Guid("61578360-3a49-4c34-8604-7b35a3787b95") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.CurrencyMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CurrencyCode") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CurrencyName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CurrencyMaster"); + + b.HasData( + new + { + Id = new Guid("78e96e4a-7ce0-4164-ae3a-c833ad45ec2c"), + CurrencyCode = "INR", + CurrencyName = "Indian Rupee", + IsActive = true, + Symbol = "₹" + }, + new + { + Id = new Guid("2f672568-a67b-4961-acb2-a8c7834e1762"), + CurrencyCode = "USD", + CurrencyName = "US Dollar", + IsActive = true, + Symbol = "$" + }, + new + { + Id = new Guid("4d1155bb-1448-4d97-a732-96c92eb99c45"), + CurrencyCode = "EUR", + CurrencyName = "Euro", + IsActive = true, + Symbol = "€" + }, + new + { + Id = new Guid("3e456237-ef06-4ea1-a261-188c9b0c6df6"), + CurrencyCode = "GBP", + CurrencyName = "Pound Sterling", + IsActive = true, + Symbol = "£" + }, + new + { + Id = new Guid("297e237a-56d3-48f6-b39d-ec3991dea8bf"), + CurrencyCode = "JPY", + CurrencyName = "Japanese Yen", + IsActive = true, + Symbol = "¥" + }, + new + { + Id = new Guid("efe9b4f6-64d6-446e-a42d-1c7aaf6dd70d"), + CurrencyCode = "RUB", + CurrencyName = "Russian Ruble", + IsActive = true, + Symbol = "₽" + }, + new + { + Id = new Guid("b960166a-f7e9-49e3-bb4b-28511f126c08"), + CurrencyCode = "CNY", + CurrencyName = "Chinese Yuan (Renminbi)", + IsActive = true, + Symbol = "¥" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Color") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("ExpensesStatusMaster"); + + b.HasData( + new + { + Id = new Guid("297e0d8f-f668-41b5-bfea-e03b354251c8"), + Color = "#8592a3", + Description = "Expense has been created but not yet submitted.", + DisplayName = "Draft", + IsActive = true, + IsSystem = true, + Name = "Draft" + }, + new + { + Id = new Guid("6537018f-f4e9-4cb3-a210-6c3b2da999d7"), + Color = "#696cff", + Description = "Reviewer is currently reviewing the expense.", + DisplayName = "Submit", + IsActive = true, + IsSystem = true, + Name = "Review Pending" + }, + new + { + Id = new Guid("965eda62-7907-4963-b4a1-657fb0b2724b"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(review rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Reviewer" + }, + new + { + Id = new Guid("4068007f-c92f-4f37-a907-bc15fe57d4d8"), + Color = "#03c3ec", + Description = "Review is completed, waiting for action of approver.", + DisplayName = "Mark as Reviewed", + IsActive = true, + IsSystem = true, + Name = "Approval Pending" + }, + new + { + Id = new Guid("d1ee5eec-24b6-4364-8673-a8f859c60729"), + Color = "#ff3e1d", + Description = "Expense was declined, often with a reason(approval rejected).", + DisplayName = "Reject", + IsActive = true, + IsSystem = true, + Name = "Rejected by Approver" + }, + new + { + Id = new Guid("f18c5cfd-7815-4341-8da2-2c2d65778e27"), + Color = "#ffab00", + Description = "Approved expense is awaiting final payment.", + DisplayName = "Mark as Approved", + IsActive = true, + IsSystem = true, + Name = "Payment Pending" + }, + new + { + Id = new Guid("61578360-3a49-4c34-8604-7b35a3787b95"), + Color = "#71dd37", + Description = "Expense has been settled.", + DisplayName = "Mark as Processed", + IsActive = true, + IsSystem = true, + Name = "Processed" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NoOfPersonsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ExpensesTypeMaster"); + + b.HasData( + new + { + Id = new Guid("5e0c6227-d49d-41ff-9f1f-781f0aee2469"), + Description = "Materials, equipment and supplies purchased for site operations.", + IsActive = true, + Name = "Procurement", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2de53163-0dbd-404b-8e60-1b02e6b4886a"), + Description = "Vehicle fuel, logistics services and delivery of goods or personnel.", + IsActive = true, + Name = "Transport", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("dd120bc4-ab0a-45ba-8450-5cd45ff221ca"), + Description = "Delivery of personnel.", + IsActive = true, + Name = "Travelling", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("52484820-1b54-4865-8f0f-baa2b1d339b9"), + Description = "Site setup costs including equipment deployment and temporary infrastructure.", + IsActive = true, + Name = "Mobilization", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("fc59eb90-98ea-481c-b421-54bfa9e42d8f"), + Description = " Worker amenities like snacks, meals, safety gear, accommodation, medical support etc.", + IsActive = true, + Name = "Employee Welfare", + NoOfPersonsRequired = true, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("77013784-9324-4d8b-bd36-d6f928e68942"), + Description = "Machinery servicing, electricity, water, and temporary office needs.", + IsActive = true, + Name = "Maintenance & Utilities", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("1e2d697a-76b4-4be8-bc66-87144561a1a0"), + Description = "Scheduled payments for external services or goods.", + IsActive = true, + Name = "Vendor/Supplier Payments", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("4842fa61-64eb-4241-aebd-8282065af9f9"), + Description = "Government fees, insurance, inspections and safety-related expenditures.", + IsActive = true, + Name = "Compliance & Safety", + NoOfPersonsRequired = false, + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), + Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Expense Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("PaymentModeMatser"); + + b.HasData( + new + { + Id = new Guid("24e6b0df-7929-47d2-88a3-4cf14c1f28f9"), + Description = "Physical currency; still used for small or informal transactions.", + IsActive = true, + Name = "Cash", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("48d9b462-5d87-4dec-8dec-2bc943943172"), + Description = "Paper-based payment order; less common now due to processing delays and fraud risks.", + IsActive = true, + Name = "Cheque", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ed667353-8eea-4fd1-8750-719405932480"), + Description = "Online banking portals used to transfer funds directly between accounts", + IsActive = true, + Name = "NetBanking", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2e919e94-694c-41d9-9489-0a2b4208a027"), + Description = "Real-time bank-to-bank transfer using mobile apps; widely used for peer-to-peer and merchant payments.", + IsActive = true, + Name = "UPI", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#8592a3", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.BillAttachments", b => + { + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Document"); + + b.Navigation("Expenses"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpenseLog", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expense") + .WithMany() + .HasForeignKey("ExpenseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expense"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.Expenses", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType") + .WithMany() + .HasForeignKey("ExpensesTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "PaidBy") + .WithMany() + .HasForeignKey("PaidById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.PaymentModeMatser", "PaymentMode") + .WithMany() + .HasForeignKey("PaymentModeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ProcessedBy") + .WithMany() + .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") + .WithMany() + .HasForeignKey("ReviewedById"); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApprovedBy"); + + b.Navigation("CreatedBy"); + + b.Navigation("ExpensesType"); + + b.Navigation("PaidBy"); + + b.Navigation("PaymentMode"); + + b.Navigation("ProcessedBy"); + + b.Navigation("Project"); + + b.Navigation("ReviewedBy"); + + b.Navigation("Status"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburse", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReimburseBy") + .WithMany() + .HasForeignKey("ReimburseById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReimburseBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesReimburseMapping", b => + { + b.HasOne("Marco.Pms.Model.Expenses.Expenses", "Expenses") + .WithMany() + .HasForeignKey("ExpensesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Expenses.ExpensesReimburse", "ExpensesReimburse") + .WithMany() + .HasForeignKey("ExpensesReimburseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expenses"); + + b.Navigation("ExpensesReimburse"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.ExpensesStatusMapping", b => + { + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "NextStatus") + .WithMany() + .HasForeignKey("NextStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NextStatus"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Expenses.StatusPermissionMapping", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.ExpensesStatusMaster", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ExpensesTypeMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.PaymentModeMatser", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.cs b/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.cs new file mode 100644 index 0000000..0a60584 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250804053705_Added_Updated_At_In_UpdateLogs.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_Updated_At_In_UpdateLogs : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UpdateAt", + table: "ExpenseLogs", + type: "datetime(6)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UpdateAt", + table: "ExpenseLogs"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 6953947..98a3e93 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1311,6 +1311,9 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("TenantId") .HasColumnType("char(36)"); + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + b.Property("UpdatedById") .HasColumnType("char(36)"); diff --git a/Marco.Pms.Model/Expenses/ExpenseLog.cs b/Marco.Pms.Model/Expenses/ExpenseLog.cs index e0eaa21..afee5fc 100644 --- a/Marco.Pms.Model/Expenses/ExpenseLog.cs +++ b/Marco.Pms.Model/Expenses/ExpenseLog.cs @@ -18,6 +18,7 @@ namespace Marco.Pms.Model.Expenses [ValidateNever] [ForeignKey("UpdatedById")] public Employee? UpdatedBy { get; set; } + public DateTime? UpdateAt { get; set; } public string Action { get; set; } = string.Empty; public string? Comment { get; set; } } diff --git a/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs b/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs index 6a05ff7..4875eaf 100644 --- a/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs +++ b/Marco.Pms.Model/ViewModels/Expenses/ExpenseLogVM.cs @@ -7,6 +7,7 @@ namespace Marco.Pms.Model.ViewModels.Expenses public Guid Id { get; set; } public BasicEmployeeVM? UpdatedBy { get; set; } public string Action { get; set; } = string.Empty; + public DateTime? UpdateAt { get; set; } public string? Comment { get; set; } } } From b9f2bc53c88f12ea01ba91416bac497c28995cdc Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 12:26:33 +0530 Subject: [PATCH 72/81] Added updated at in action API --- Marco.Pms.Services/Service/ExpensesService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index dd0bf95..38d554d 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -737,6 +737,7 @@ namespace Marco.Pms.Services.Service ExpenseId = expense.Id, Action = $"Status changed to '{statusTransition.NextStatus?.Name}'", UpdatedById = loggedInEmployee.Id, + UpdateAt = DateTime.UtcNow, Comment = model.Comment, TenantId = tenantId }); From c3571f76b820781d769a7e64d305dc7bb93e6cfa Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 14:46:40 +0530 Subject: [PATCH 73/81] Changed the if condition in expense list API --- Marco.Pms.Services/Service/ExpensesService.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 38d554d..0443b2b 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -132,17 +132,16 @@ namespace Marco.Pms.Services.Service await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync(), tenantId); // Apply permission-based filtering BEFORE any other filters or pagination. - - if (!hasViewAllPermissionTask.Result && hasViewSelfPermissionTask.Result) + if (hasViewAllPermissionTask.Result) + { + expensesQuery = expensesQuery.Where(e => e.CreatedById != loggedInEmployeeId || e.StatusId != Draft); + } + else if (hasViewSelfPermissionTask.Result) { // User only has 'View Self' permission, so restrict the query to their own expenses. _logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId); expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId); } - else - { - expensesQuery = expensesQuery.Where(e => e.CreatedById != loggedInEmployeeId || e.StatusId != Draft); - } if (expenseFilter != null) { From 33538c25b71f821f17c8432fc7dee7d2adfcddc3 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 14:51:05 +0530 Subject: [PATCH 74/81] Chnaged get query --- Marco.Pms.Services/Service/ExpensesService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index 0443b2b..cc3fbaa 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -134,7 +134,7 @@ namespace Marco.Pms.Services.Service // Apply permission-based filtering BEFORE any other filters or pagination. if (hasViewAllPermissionTask.Result) { - expensesQuery = expensesQuery.Where(e => e.CreatedById != loggedInEmployeeId || e.StatusId != Draft); + expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId || e.StatusId != Draft); } else if (hasViewSelfPermissionTask.Result) { From 19aedfb64842cc2370ea395f2b86b02c5274867d Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 4 Aug 2025 15:45:04 +0530 Subject: [PATCH 75/81] Chnage the cache logic --- Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs index 11e4554..9c030ed 100644 --- a/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs +++ b/Marco.Pms.Helpers/CacheHelper/ExpenseCache.cs @@ -50,7 +50,7 @@ namespace Marco.Pms.Helpers.CacheHelper else { filter &= filterBuilder.Or( - filterBuilder.Ne(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()), + filterBuilder.Eq(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()), filterBuilder.Ne(e => e.Status.Id, "297e0d8f-f668-41b5-bfea-e03b354251c8") ); } From fb1f34f950d161104b0dac42b0b1f32c7e0ac486 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 6 Aug 2025 12:14:18 +0530 Subject: [PATCH 76/81] Added new condition for checking the permission for expense Action API --- Marco.Pms.Services/Service/ExpensesService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index cc3fbaa..cfcac91 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -674,7 +674,7 @@ namespace Marco.Pms.Services.Service var permissionService = scope.ServiceProvider.GetRequiredService(); foreach (var permission in requiredPermissions) { - if (await permissionService.HasPermission(permission.PermissionId, loggedInEmployee.Id)) + if (await permissionService.HasPermission(permission.PermissionId, loggedInEmployee.Id) && model.StatusId != Review) { hasPermission = true; break; @@ -847,7 +847,7 @@ namespace Marco.Pms.Services.Service try { await _context.SaveChangesAsync(); - _logger.LogInfo("Successfully updated project {ProjectId} by user {UserId}.", id, loggedInEmployee.Id); + _logger.LogInfo("Successfully updated Expense {ExpenseId} by user {UserId}.", id, loggedInEmployee.Id); } catch (DbUpdateConcurrencyException ex) { From 9edc0e645edd4666ecdb0e3cc6f718ee3d67a40f Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 6 Aug 2025 13:07:41 +0530 Subject: [PATCH 77/81] Added to an API to get project assignment histery of an employee --- .../Controllers/ProjectController.cs | 17 +++++++++++++++++ Marco.Pms.Services/Service/ProjectServices.cs | 19 +++++++++++++++++++ .../ServiceInterfaces/IProjectServices.cs | 2 ++ 3 files changed, 38 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 2c03d69..0520414 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -276,6 +276,23 @@ namespace MarcoBMS.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpGet("allocation-histery/{employeeId}")] + public async Task GetProjectByEmployeeBasic([FromRoute] Guid employeeId) + { + // --- Step 1: Input Validation --- + if (!ModelState.IsValid) + { + var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList(); + _logger.LogWarning("Get project list by employee Id called with invalid model state \n Errors: {Errors}", string.Join(", ", errors)); + return BadRequest(ApiResponse.ErrorResponse("Invalid request data provided.", errors, 400)); + } + + // --- Step 2: Prepare data without I/O --- + Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _projectServices.GetProjectByEmployeeBasicAsync(employeeId, tenantId, loggedInEmployee); + return StatusCode(response.StatusCode, response); + } + [HttpPost("assign-projects/{employeeId}")] public async Task AssigneProjectsToEmployee([FromBody] List projectAllocationDtos, [FromRoute] Guid employeeId) { diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index 9406ec9..c92adbe 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -895,6 +895,25 @@ namespace Marco.Pms.Services.Service return ApiResponse>.SuccessResponse(resultVm, "Assignments managed successfully.", 200); } + public async Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee) + { + var projectAllocation = await _context.ProjectAllocations + .Include(pa => pa.Project) + .Include(pa => pa.Employee).ThenInclude(e => e!.JobRole) + .Where(pa => pa.EmployeeId == employeeId && pa.TenantId == tenantId && pa.Project != null && pa.Employee != null) + .Select(pa => new + { + ProjectName = pa.Project!.Name, + ProjectShortName = pa.Project.ShortName, + AssignedDate = pa.AllocationDate, + RemovedDate = pa.ReAllocationDate, + Designation = pa.Employee!.JobRole!.Name + }) + .ToListAsync(); + + return ApiResponse.SuccessResponse(projectAllocation, $"{projectAllocation.Count} records provided employee assigned to projects fetched", 200); + } + #endregion #region =================================================================== Project InfraStructure Get APIs =================================================================== diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs index b5acccc..e76df7f 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs @@ -20,6 +20,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task>> ManageAllocationAsync(List projectAllocationDots, Guid tenantId, Employee loggedInEmployee); Task> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); Task>> AssigneProjectsToEmployeeAsync(List projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee); + Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); + Task> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); Task> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee); Task ManageProjectInfraAsync(List infraDtos, Guid tenantId, Employee loggedInEmployee); From 7555b73f020f4d82b4ffe6ce24ba02a66b02fd08 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 6 Aug 2025 14:51:55 +0530 Subject: [PATCH 78/81] Added an API to get task by employeeId --- .../Controllers/ProjectController.cs | 19 +++ Marco.Pms.Services/Service/ProjectServices.cs | 135 ++++++++++++++++-- .../ServiceInterfaces/IProjectServices.cs | 1 + 3 files changed, 141 insertions(+), 14 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index 0520414..436dff9 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -355,6 +355,25 @@ namespace MarcoBMS.Services.Controllers var response = await _projectServices.GetWorkItemsAsync(workAreaId, tenantId, loggedInEmployee); return StatusCode(response.StatusCode, response); } + [HttpGet("tasks-employee/{employeeId}")] + public async Task GetTasksByEmployee(Guid employeeId, [FromQuery] DateTime? fromDate, DateTime? toDate) + { + // --- Step 1: Input Validation --- + if (!ModelState.IsValid) + { + var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList(); + _logger.LogWarning("Get Work Items by employeeId called with invalid model state \n Errors: {Errors}", string.Join(", ", errors)); + return BadRequest(ApiResponse.ErrorResponse("Invalid request data provided.", errors, 400)); + } + + if (!toDate.HasValue) toDate = DateTime.UtcNow; + if (!fromDate.HasValue) fromDate = toDate.Value.AddDays(-7); + + // --- Step 2: Prepare data without I/O --- + Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _projectServices.GetTasksByEmployeeAsync(employeeId, fromDate.Value, toDate.Value, tenantId, loggedInEmployee); + return StatusCode(response.StatusCode, response); + } #endregion diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index c92adbe..f3299fa 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -897,23 +897,53 @@ namespace Marco.Pms.Services.Service public async Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee) { - var projectAllocation = await _context.ProjectAllocations - .Include(pa => pa.Project) - .Include(pa => pa.Employee).ThenInclude(e => e!.JobRole) - .Where(pa => pa.EmployeeId == employeeId && pa.TenantId == tenantId && pa.Project != null && pa.Employee != null) - .Select(pa => new - { - ProjectName = pa.Project!.Name, - ProjectShortName = pa.Project.ShortName, - AssignedDate = pa.AllocationDate, - RemovedDate = pa.ReAllocationDate, - Designation = pa.Employee!.JobRole!.Name - }) - .ToListAsync(); + // Log the start of the method execution with key input parameters + _logger.LogInfo("Fetching projects for EmployeeId: {EmployeeId}, TenantId: {TenantId} by User: {UserId}", + employeeId, tenantId, loggedInEmployee.Id); - return ApiResponse.SuccessResponse(projectAllocation, $"{projectAllocation.Count} records provided employee assigned to projects fetched", 200); + try + { + // Retrieve project allocations linked to the specified employee and tenant + var projectAllocation = await _context.ProjectAllocations + .AsNoTracking() // Optimization: no tracking since entities are not updated + .Include(pa => pa.Project) // Include related Project data + .Include(pa => pa.Employee).ThenInclude(e => e!.JobRole) // Include related Employee and their JobRole + .Where(pa => pa.EmployeeId == employeeId + && pa.TenantId == tenantId + && pa.Project != null + && pa.Employee != null) + .Select(pa => new + { + ProjectName = pa.Project!.Name, + ProjectShortName = pa.Project.ShortName, + AssignedDate = pa.AllocationDate, + RemovedDate = pa.ReAllocationDate, + Designation = pa.Employee!.JobRole!.Name + }) + .ToListAsync(); + + // Log successful retrieval including count of records + _logger.LogInfo("Successfully fetched {Count} projects for EmployeeId: {EmployeeId}", + projectAllocation.Count, employeeId); + + return ApiResponse.SuccessResponse( + projectAllocation, + $"{projectAllocation.Count} project assignments fetched for employee.", + 200); + } + catch (Exception ex) + { + // Log the exception with stack trace for debugging + _logger.LogError(ex, "Error occurred while fetching projects for EmployeeId: {EmployeeId}, TenantId: {TenantId}", + employeeId, tenantId); + + return ApiResponse.ErrorResponse( + "An error occurred while fetching project assignments.", + 500); + } } + #endregion #region =================================================================== Project InfraStructure Get APIs =================================================================== @@ -1044,6 +1074,83 @@ namespace Marco.Pms.Services.Service } } + /// + /// Retrieves tasks assigned to a specific employee within a date range for a tenant. + /// + /// The ID of the employee to filter tasks. + /// The start date to filter task assignments. + /// The end date to filter task assignments. + /// The tenant ID to filter tasks. + /// The employee requesting the data (for authorization/logging). + /// An ApiResponse containing the task details. + public async Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee) + { + _logger.LogInfo("Fetching tasks for EmployeeId: {EmployeeId} from {FromDate} to {ToDate} for TenantId: {TenantId}", + employeeId, fromDate, toDate, tenantId); + + try + { + // Query TaskMembers with related necessary fields in one projection to minimize DB calls and data size + var taskData = await _context.TaskMembers + .Where(tm => tm.EmployeeId == employeeId && + tm.TenantId == tenantId && + tm.TaskAllocation != null && + tm.TaskAllocation.AssignmentDate.Date >= fromDate.Date && + tm.TaskAllocation.AssignmentDate.Date <= toDate.Date) + .Select(tm => new + { + AssignmentDate = tm.TaskAllocation!.AssignmentDate, + PlannedTask = tm.TaskAllocation.PlannedTask, + CompletedTask = tm.TaskAllocation.CompletedTask, + ProjectId = tm.TaskAllocation.WorkItem!.WorkArea!.Floor!.Building!.ProjectId, + BuildingName = tm.TaskAllocation.WorkItem.WorkArea.Floor.Building!.Name, + FloorName = tm.TaskAllocation.WorkItem.WorkArea.Floor.FloorName, + AreaName = tm.TaskAllocation.WorkItem.WorkArea.AreaName, + ActivityName = tm.TaskAllocation.WorkItem.ActivityMaster!.ActivityName, + ActivityUnit = tm.TaskAllocation.WorkItem.ActivityMaster.UnitOfMeasurement + }) + .OrderByDescending(t => t.AssignmentDate) + .ToListAsync(); + + _logger.LogInfo("Retrieved {TaskCount} tasks for EmployeeId: {EmployeeId}", taskData.Count, employeeId); + + // Extract distinct project IDs to fetch project details efficiently + var distinctProjectIds = taskData.Select(t => t.ProjectId).Distinct().ToList(); + + var projects = await _context.Projects + .Where(p => distinctProjectIds.Contains(p.Id)) + .Select(p => new { p.Id, p.Name }) + .ToListAsync(); + + // Prepare the response + var response = taskData.Select(t => + { + var project = projects.FirstOrDefault(p => p.Id == t.ProjectId); + + return new + { + ProjectName = project?.Name ?? "Unknown Project", + t.AssignmentDate, + t.PlannedTask, + t.CompletedTask, + Location = $"{t.BuildingName} > {t.FloorName} > {t.AreaName}", + ActivityName = t.ActivityName, + ActivityUnit = t.ActivityUnit + }; + }).ToList(); + + _logger.LogInfo("Successfully prepared task response for EmployeeId: {EmployeeId}", employeeId); + + return ApiResponse.SuccessResponse(response, "Task fetched successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while fetching tasks for EmployeeId: {EmployeeId}", employeeId); + return ApiResponse.ErrorResponse("An error occurred while fetching the tasks.", 500); + } + } + + #endregion #region =================================================================== Project Infrastructre Manage APIs =================================================================== diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs index e76df7f..a1f78f8 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs @@ -24,6 +24,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee); Task> GetWorkItemsAsync(Guid workAreaId, Guid tenantId, Employee loggedInEmployee); + Task> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee); Task ManageProjectInfraAsync(List infraDtos, Guid tenantId, Employee loggedInEmployee); Task>> CreateProjectTaskAsync(List workItemDtos, Guid tenantId, Employee loggedInEmployee); Task DeleteProjectTaskAsync(Guid id, Guid tenantId, Employee loggedInEmployee); From 0aee183fdd820ee45961149e5fe39d9209c6b515 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 6 Aug 2025 17:54:37 +0530 Subject: [PATCH 79/81] Showing profile of all emplyee event if it inactive --- Marco.Pms.Services/Helpers/EmployeeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Helpers/EmployeeHelper.cs b/Marco.Pms.Services/Helpers/EmployeeHelper.cs index 09dcbe2..a23460b 100644 --- a/Marco.Pms.Services/Helpers/EmployeeHelper.cs +++ b/Marco.Pms.Services/Helpers/EmployeeHelper.cs @@ -20,7 +20,7 @@ namespace MarcoBMS.Services.Helpers public async Task GetEmployeeByID(Guid EmployeeID) { - return await _context.Employees.Include(e => e.JobRole).FirstOrDefaultAsync(e => e.Id == EmployeeID && e.IsActive == true) ?? new Employee { }; + return await _context.Employees.Include(e => e.JobRole).FirstOrDefaultAsync(e => e.Id == EmployeeID) ?? new Employee { }; } public async Task GetEmployeeByApplicationUserID(string ApplicationUserID) From 9b241a0c700bad6193b110474a66e6b4ded4b919 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 7 Aug 2025 15:03:52 +0530 Subject: [PATCH 80/81] Made MPIN to be 4 digit --- Marco.Pms.Services/Controllers/AuthController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/AuthController.cs b/Marco.Pms.Services/Controllers/AuthController.cs index 429a38b..67dd74a 100644 --- a/Marco.Pms.Services/Controllers/AuthController.cs +++ b/Marco.Pms.Services/Controllers/AuthController.cs @@ -750,7 +750,7 @@ namespace MarcoBMS.Services.Controllers .FirstOrDefaultAsync(e => e.Id == generateMPINDto.EmployeeId && e.TenantId == tenantId); // Validate employee and MPIN input - if (requestEmployee == null || string.IsNullOrWhiteSpace(generateMPINDto.MPIN) || generateMPINDto.MPIN.Length != 6 || !generateMPINDto.MPIN.All(char.IsDigit)) + if (requestEmployee == null || string.IsNullOrWhiteSpace(generateMPINDto.MPIN) || generateMPINDto.MPIN.Length != 4 || !generateMPINDto.MPIN.All(char.IsDigit)) { _logger.LogWarning("Employee {EmployeeId} provided invalid information to generate MPIN", loggedInEmployee.Id); return BadRequest(ApiResponse.ErrorResponse("Provided invalid information", "Provided invalid information", 400)); From d113fc3c3df34be8ebe6d8e1301a80ba213d3316 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 13 Aug 2025 11:07:36 +0530 Subject: [PATCH 81/81] Sending the project degination in place of employee degination in allocation history API --- .../ViewModels/Projects/ProjectHisteryVM.cs | 11 +++++++++ Marco.Pms.Services/Service/ProjectServices.cs | 24 ++++++++++++++++--- .../appsettings.Development.json | 2 +- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs diff --git a/Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs b/Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs new file mode 100644 index 0000000..4df0480 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Projects/ProjectHisteryVM.cs @@ -0,0 +1,11 @@ +namespace Marco.Pms.Model.ViewModels.Projects +{ + public class ProjectHisteryVM + { + public string? ProjectName { get; set; } + public string? ProjectShortName { get; set; } + public DateTime AssignedDate { get; set; } + public DateTime? RemovedDate { get; set; } + public string? Designation { get; set; } + } +} \ No newline at end of file diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index 0b95cb4..6cb7e68 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -918,17 +918,35 @@ namespace Marco.Pms.Services.Service ProjectShortName = pa.Project.ShortName, AssignedDate = pa.AllocationDate, RemovedDate = pa.ReAllocationDate, - Designation = pa.Employee!.JobRole!.Name + Designation = pa.Employee!.JobRole!.Name, + DesignationId = pa.JobRoleId }) .ToListAsync(); + var designationIds = projectAllocation.Select(pa => pa.DesignationId).ToList(); + + var designations = await _context.JobRoles.Where(jr => designationIds.Contains(jr.Id)).ToListAsync(); + + var response = projectAllocation.Select(pa => + { + var designation = designations.FirstOrDefault(jr => jr.Id == pa.DesignationId); + return new ProjectHisteryVM + { + ProjectName = pa.ProjectName, + ProjectShortName = pa.ProjectShortName, + AssignedDate = pa.AssignedDate, + RemovedDate = pa.RemovedDate, + Designation = designation?.Name + }; + }).ToList(); + // Log successful retrieval including count of records _logger.LogInfo("Successfully fetched {Count} projects for EmployeeId: {EmployeeId}", projectAllocation.Count, employeeId); return ApiResponse.SuccessResponse( - projectAllocation, - $"{projectAllocation.Count} project assignments fetched for employee.", + response, + $"{response.Count} project assignments fetched for employee.", 200); } catch (Exception ex) diff --git a/Marco.Pms.Services/appsettings.Development.json b/Marco.Pms.Services/appsettings.Development.json index 579b059..4bb9519 100644 --- a/Marco.Pms.Services/appsettings.Development.json +++ b/Marco.Pms.Services/appsettings.Development.json @@ -49,6 +49,6 @@ "MongoDB": { "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", "ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500", - "ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500" + "ModificationConnectionString": "mongodb://localhost:27017/ModificationLog?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500&replicaSet=rs01&directConnection=true" } }