From 6f6292b16765e99d7cddc742896174dad16e2e44 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 12 Dec 2025 19:11:24 +0530 Subject: [PATCH 1/2] Added Inventory module and changed the view model for market feature plan API --- .../Dtos/Tenant/InventoryModuleDetailsDto.cs | 9 ++++ .../Dtos/Tenant/ModulesDetailsDto.cs | 5 +- .../MongoDBModel/InventoryModuleDetails.cs | 18 +++++++ .../MongoDBModel/ModulesDetails.cs | 1 + .../ViewModels/Master/FeatureVM.cs | 6 +++ .../ViewModels/Tenant/AttendanceDetailsVM.cs | 15 ++++++ .../ViewModels/Tenant/DirectoryDetailsVM.cs | 14 ++++++ .../Tenant/ExpenseModuleDetailsVM.cs | 12 +++++ .../ViewModels/Tenant/FeatureDetailsVM.cs | 13 +++++ .../Tenant/InventoryModuleDetailsVM.cs | 17 +++++++ .../ViewModels/Tenant/ModulesDetailsVM.cs | 14 ++++++ .../Tenant/ProjectManagementDetailsVM.cs | 16 ++++++ .../ViewModels/Tenant/SubscriptionPlanVM.cs | 14 ++++++ .../Controllers/MarketController.cs | 49 +++++++++++++++++-- .../MappingProfiles/MappingProfile.cs | 27 ++++++++++ 15 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/Tenant/InventoryModuleDetailsDto.cs create mode 100644 Marco.Pms.Model/TenantModels/MongoDBModel/InventoryModuleDetails.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/AttendanceDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/DirectoryDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/ExpenseModuleDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/FeatureDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/InventoryModuleDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/ModulesDetailsVM.cs create mode 100644 Marco.Pms.Model/ViewModels/Tenant/ProjectManagementDetailsVM.cs diff --git a/Marco.Pms.Model/Dtos/Tenant/InventoryModuleDetailsDto.cs b/Marco.Pms.Model/Dtos/Tenant/InventoryModuleDetailsDto.cs new file mode 100644 index 0000000..0e184c3 --- /dev/null +++ b/Marco.Pms.Model/Dtos/Tenant/InventoryModuleDetailsDto.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.Dtos.Tenant +{ + public class InventoryModuleDetailsDto + { + public List? FeatureId { get; set; } + public string Name { get; set; } = "Expense Management"; + public bool Enabled { get; set; } = false; + } +} diff --git a/Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs b/Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs index 5a828f9..7144443 100644 --- a/Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs +++ b/Marco.Pms.Model/Dtos/Tenant/ModulesDetailsDto.cs @@ -1,4 +1,6 @@ -namespace Marco.Pms.Model.Dtos.Tenant +using Marco.Pms.Model.TenantModels.MongoDBModel; + +namespace Marco.Pms.Model.Dtos.Tenant { public class ModulesDetailsDto { @@ -6,5 +8,6 @@ public AttendanceDetailsDto? Attendance { get; set; } public DirectoryDetailsDto? Directory { get; set; } public ExpenseModuleDetailsDto? Expense { get; set; } + public InventoryModuleDetailsDto? Inventory { get; set; } } } diff --git a/Marco.Pms.Model/TenantModels/MongoDBModel/InventoryModuleDetails.cs b/Marco.Pms.Model/TenantModels/MongoDBModel/InventoryModuleDetails.cs new file mode 100644 index 0000000..59f1131 --- /dev/null +++ b/Marco.Pms.Model/TenantModels/MongoDBModel/InventoryModuleDetails.cs @@ -0,0 +1,18 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace Marco.Pms.Model.TenantModels.MongoDBModel +{ + public class InventoryModuleDetails + { + [BsonId] + [BsonRepresentation(BsonType.String)] + public Guid Id { get; set; } = Guid.NewGuid(); + + public string? Name { get; set; } + + [BsonRepresentation(BsonType.String)] + public List FeatureId { get; set; } = new List(); + public bool Enabled { get; set; } = false; + } +} diff --git a/Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs b/Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs index 7b682f2..17e24a9 100644 --- a/Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs +++ b/Marco.Pms.Model/TenantModels/MongoDBModel/ModulesDetails.cs @@ -12,5 +12,6 @@ namespace Marco.Pms.Model.TenantModels.MongoDBModel public AttendanceDetails? Attendance { get; set; } public DirectoryDetails? Directory { get; set; } public ExpenseModuleDetails? Expense { get; set; } + public InventoryModuleDetails? Inventory { get; set; } } } diff --git a/Marco.Pms.Model/ViewModels/Master/FeatureVM.cs b/Marco.Pms.Model/ViewModels/Master/FeatureVM.cs index 935dd23..b1a7767 100644 --- a/Marco.Pms.Model/ViewModels/Master/FeatureVM.cs +++ b/Marco.Pms.Model/ViewModels/Master/FeatureVM.cs @@ -14,4 +14,10 @@ public ICollection? FeaturePermissions { get; set; } } + public class BasicFeatureVM + { + public Guid Id { get; set; } // Unique identifier for the permission + public string? Name { get; set; } // Feature name + public string? Description { get; set; } // Feature description + } } diff --git a/Marco.Pms.Model/ViewModels/Tenant/AttendanceDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/AttendanceDetailsVM.cs new file mode 100644 index 0000000..ad4a990 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/AttendanceDetailsVM.cs @@ -0,0 +1,15 @@ +using Marco.Pms.Model.ViewModels.Master; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class AttendanceDetailsVM + { + public Guid Id { get; set; } + public string? Name { get; set; } + public List? Features { get; set; } + public bool Enabled { get; set; } + public bool ManualEntry { get; set; } + public bool LocationTracking { get; set; } + public bool ShiftManagement { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/DirectoryDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/DirectoryDetailsVM.cs new file mode 100644 index 0000000..5e566c4 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/DirectoryDetailsVM.cs @@ -0,0 +1,14 @@ +using Marco.Pms.Model.ViewModels.Master; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class DirectoryDetailsVM + { + public Guid Id { get; set; } + public string? Name { get; set; } + public List? Features { get; set; } + public bool Enabled { get; set; } + public int BucketLimit { get; set; } + public bool OrganizationChart { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/ExpenseModuleDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/ExpenseModuleDetailsVM.cs new file mode 100644 index 0000000..d037797 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/ExpenseModuleDetailsVM.cs @@ -0,0 +1,12 @@ +using Marco.Pms.Model.ViewModels.Master; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class ExpenseModuleDetailsVM + { + public Guid Id { get; set; } + public string? Name { get; set; } + public List? Features { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/FeatureDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/FeatureDetailsVM.cs new file mode 100644 index 0000000..2953284 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/FeatureDetailsVM.cs @@ -0,0 +1,13 @@ +using Marco.Pms.Model.TenantModels.MongoDBModel; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class FeatureDetailsVM + { + public Guid Id { get; set; } + public ModulesDetailsVM? Modules { get; set; } + public ReportDetails? Reports { get; set; } + public SupportDetails? Supports { get; set; } + public List? SubscriptionCheckList { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/InventoryModuleDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/InventoryModuleDetailsVM.cs new file mode 100644 index 0000000..f9a1ab5 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/InventoryModuleDetailsVM.cs @@ -0,0 +1,17 @@ +using Marco.Pms.Model.ViewModels.Master; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class InventoryModuleDetailsVM + { + public Guid Id { get; set; } + public string? Name { get; set; } + public List? Features { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/ModulesDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/ModulesDetailsVM.cs new file mode 100644 index 0000000..f362936 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/ModulesDetailsVM.cs @@ -0,0 +1,14 @@ +using Marco.Pms.Model.TenantModels.MongoDBModel; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class ModulesDetailsVM + { + public Guid Id { get; set; } + public ProjectManagementDetailsVM? ProjectManagement { get; set; } + public AttendanceDetailsVM? Attendance { get; set; } + public DirectoryDetailsVM? Directory { get; set; } + public ExpenseModuleDetailsVM? Expense { get; set; } + public InventoryModuleDetailsVM? Inventory { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/ProjectManagementDetailsVM.cs b/Marco.Pms.Model/ViewModels/Tenant/ProjectManagementDetailsVM.cs new file mode 100644 index 0000000..e307822 --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Tenant/ProjectManagementDetailsVM.cs @@ -0,0 +1,16 @@ +using Marco.Pms.Model.ViewModels.Master; + +namespace Marco.Pms.Model.ViewModels.Tenant +{ + public class ProjectManagementDetailsVM + { + public Guid Id { get; set; } + public string? Name { get; set; } + public List? Features { get; set; } + public bool Enabled { get; set; } + public int MaxProject { get; set; } + public double MaxTaskPerProject { get; set; } + public bool GanttChart { get; set; } + public bool ResourceAllocation { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs b/Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs index 546ab0c..9960410 100644 --- a/Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs +++ b/Marco.Pms.Model/ViewModels/Tenant/SubscriptionPlanVM.cs @@ -17,4 +17,18 @@ namespace Marco.Pms.Model.ViewModels.Tenant public FeatureDetails? Features { get; set; } public CurrencyMaster? Currency { get; set; } } + + public class MarketSubscriptionPlanVM + { + public Guid Id { get; set; } + public string? PlanName { get; set; } + public string? Description { get; set; } + public double? Price { get; set; } + public PLAN_FREQUENCY? Frequency { get; set; } + public int TrialDays { get; set; } + public double MaxUser { get; set; } + public double MaxStorage { get; set; } + public FeatureDetailsVM? Features { get; set; } + public CurrencyMaster? Currency { get; set; } + } } diff --git a/Marco.Pms.Services/Controllers/MarketController.cs b/Marco.Pms.Services/Controllers/MarketController.cs index 290266e..7ed3c15 100644 --- a/Marco.Pms.Services/Controllers/MarketController.cs +++ b/Marco.Pms.Services/Controllers/MarketController.cs @@ -1,4 +1,6 @@ using AutoMapper; +using AutoMapper.QueryableExtensions; +using FirebaseAdmin.Auth.Multitenancy; using Marco.Pms.DataAccess.Data; using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Dtos.Util; @@ -6,6 +8,7 @@ using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Master; using Marco.Pms.Model.TenantModels; using Marco.Pms.Model.Utilities; +using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Tenant; using Marco.Pms.Services.Helpers; using MarcoBMS.Services.Service; @@ -82,7 +85,7 @@ namespace Marco.Pms.Services.Controllers _logger.LogInfo("GetSubscriptionPlanList called with frequency: {Frequency}", frequency ?? PLAN_FREQUENCY.MONTHLY); // Initialize the list to store subscription plan view models - List detailsVM = new List(); + List detailsVM = new List(); try { @@ -104,14 +107,54 @@ namespace Marco.Pms.Services.Controllers var subscriptionPlans = await query.ToListAsync(); + var features = await _context.Features + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + // Map and fetch feature details for each subscription plan foreach (var subscriptionPlan in subscriptionPlans) { - var response = _mapper.Map(subscriptionPlan); + var response = _mapper.Map(subscriptionPlan); try { - response.Features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId); + var featureDetails = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId); + + if (featureDetails == null) continue; + + var attendanceFeatures = featureDetails.Modules?.Attendance?.FeatureId ?? new List(); + var projectManagementFeatures = featureDetails.Modules?.ProjectManagement?.FeatureId ?? new List(); + var directoryFeatures = featureDetails.Modules?.Directory?.FeatureId ?? new List(); + var expenseFeatures = featureDetails.Modules?.Expense?.FeatureId ?? new List(); + var inventoryFeatures = featureDetails.Modules?.Inventory?.FeatureId ?? new List(); + + var featureDetailsVM = _mapper.Map(featureDetails); + + //var featureDetailsVM = new FeatureDetailsVM + //{ + // Id = featureDetails.Id, + // Modules = _mapper.Map(featureDetails.Modules), + // Reports = featureDetails.Reports, + // Supports = featureDetails.Supports, + // SubscriptionCheckList = featureDetails.SubscriptionCheckList + //}; + + if (featureDetailsVM.Modules?.Attendance != null) + featureDetailsVM.Modules.Attendance.Features = features.Where(f => attendanceFeatures.Contains(f.Id)).ToList(); + + if (featureDetailsVM.Modules?.ProjectManagement != null) + featureDetailsVM.Modules.ProjectManagement.Features = features.Where(f => projectManagementFeatures.Contains(f.Id)).ToList(); + + if (featureDetailsVM.Modules?.Directory != null) + featureDetailsVM.Modules.Directory.Features = features.Where(f => directoryFeatures.Contains(f.Id)).ToList(); + + if (featureDetailsVM.Modules?.Expense != null) + featureDetailsVM.Modules.Expense.Features = features.Where(f => expenseFeatures.Contains(f.Id)).ToList(); + + if (featureDetailsVM.Modules?.Inventory != null) + featureDetailsVM.Modules.Inventory.Features = features.Where(f => inventoryFeatures.Contains(f.Id)).ToList(); + + response.Features = featureDetailsVM; } catch (Exception exFeature) { diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 5188464..2742018 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -100,6 +100,15 @@ namespace Marco.Pms.Services.MappingProfiles dest => dest.Description, opt => opt.MapFrom(src => src.Plan != null ? src.Plan.Description : "") ); + CreateMap() + .ForMember( + dest => dest.PlanName, + opt => opt.MapFrom(src => src.Plan != null ? src.Plan.PlanName : "") + ) + .ForMember( + dest => dest.Description, + opt => opt.MapFrom(src => src.Plan != null ? src.Plan.Description : "") + ); CreateMap() .ForMember( dest => dest.PlanName, @@ -121,14 +130,31 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + #endregion @@ -410,6 +436,7 @@ namespace Marco.Pms.Services.MappingProfiles #region ======================================================= Master ======================================================= CreateMap(); + CreateMap(); #region ======================================================= Global Service Master ======================================================= From e0656b6734a8f4f46085f5e3982fbfe3703d9fb2 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 13 Dec 2025 09:54:48 +0530 Subject: [PATCH 2/2] Bypassing the signalR loggin in logger middleware --- .../Controllers/MarketController.cs | 9 -------- .../Middleware/LoggingMiddleware.cs | 23 ++++++++++++++----- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Marco.Pms.Services/Controllers/MarketController.cs b/Marco.Pms.Services/Controllers/MarketController.cs index 7ed3c15..66de06e 100644 --- a/Marco.Pms.Services/Controllers/MarketController.cs +++ b/Marco.Pms.Services/Controllers/MarketController.cs @@ -130,15 +130,6 @@ namespace Marco.Pms.Services.Controllers var featureDetailsVM = _mapper.Map(featureDetails); - //var featureDetailsVM = new FeatureDetailsVM - //{ - // Id = featureDetails.Id, - // Modules = _mapper.Map(featureDetails.Modules), - // Reports = featureDetails.Reports, - // Supports = featureDetails.Supports, - // SubscriptionCheckList = featureDetails.SubscriptionCheckList - //}; - if (featureDetailsVM.Modules?.Attendance != null) featureDetailsVM.Modules.Attendance.Features = features.Where(f => attendanceFeatures.Contains(f.Id)).ToList(); diff --git a/Marco.Pms.Services/Middleware/LoggingMiddleware.cs b/Marco.Pms.Services/Middleware/LoggingMiddleware.cs index 3821aff..5929817 100644 --- a/Marco.Pms.Services/Middleware/LoggingMiddleware.cs +++ b/Marco.Pms.Services/Middleware/LoggingMiddleware.cs @@ -1,6 +1,6 @@ -using MarcoBMS.Services.Service; -using Serilog.Context; +using Serilog.Context; using System.Diagnostics; +using System.Security.Claims; namespace MarcoBMS.Services.Middleware { @@ -8,22 +8,32 @@ namespace MarcoBMS.Services.Middleware { private readonly RequestDelegate _next; private readonly ILogger _logger; - private readonly ILoggingService _loggingService; //private readonly UserHelper _userHelper; - public LoggingMiddleware(RequestDelegate next, ILogger logger, ILoggingService loggingService) + private readonly List _ignoredPaths = new List + { + "/hubs/marco", + "/hubs/marco/negotiate", + "/swagger" + }; + public LoggingMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; - //_userHelper = userHelper; - _loggingService = loggingService; } public async Task Invoke(HttpContext context) { + if (_ignoredPaths.Any(path => context.Request.Path.StartsWithSegments(path, StringComparison.OrdinalIgnoreCase))) + { + await _next(context); + return; + } + var stopwatch = Stopwatch.StartNew(); var response = context.Response; var request = context.Request; var tenantId = context.User.FindFirst("TenantId")?.Value; + var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier); string origin = request.Headers["Origin"].FirstOrDefault() ?? ""; using (LogContext.PushProperty("TenantId", tenantId)) @@ -35,6 +45,7 @@ namespace MarcoBMS.Services.Middleware using (LogContext.PushProperty("RequestPath", request.Path)) using (LogContext.PushProperty("Origin", origin)) using (LogContext.PushProperty("LogOrigin", "ASP .NET Api")) + using (LogContext.PushProperty("UserId", userId))