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.Expenses; 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.Service; using Microsoft.EntityFrameworkCore; namespace Marco.Pms.Services.Service { public class MasterService : IMasterService { private readonly ApplicationDbContext _context; private readonly ILoggingService _logger; private readonly PermissionServices _permission; private readonly IMapper _mapper; public MasterService( ApplicationDbContext context, ILoggingService logger, PermissionServices permission, IMapper mapper) { _context = context; _logger = logger; _permission = permission; _mapper = mapper; } #region =================================================================== Expenses Type APIs =================================================================== public async Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId) { 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 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 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; _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 #region =================================================================== Expenses Status APIs =================================================================== public async Task> GetExpensesStatusListAsync(Employee loggedInEmployee, Guid tenantId) { 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); } } 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 #region =================================================================== Payment mode APIs =================================================================== public async Task> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId) { 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); } } 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 #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, } }; } #endregion } }