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 ===================================================================