2241 lines
120 KiB
C#
2241 lines
120 KiB
C#
using AutoMapper;
|
|
using Marco.Pms.DataAccess.Data;
|
|
using Marco.Pms.Helpers.Utility;
|
|
using Marco.Pms.Model.Directory;
|
|
using Marco.Pms.Model.DocumentManager;
|
|
using Marco.Pms.Model.Dtos.Activities;
|
|
using Marco.Pms.Model.Dtos.DocumentManager;
|
|
using Marco.Pms.Model.Dtos.Master;
|
|
using Marco.Pms.Model.Employees;
|
|
using Marco.Pms.Model.Entitlements;
|
|
using Marco.Pms.Model.Mapper;
|
|
using Marco.Pms.Model.Master;
|
|
using Marco.Pms.Model.MongoDBModels.Utility;
|
|
using Marco.Pms.Model.Utilities;
|
|
using Marco.Pms.Model.ViewModels.Activities;
|
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
|
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<ApplicationDbContext> _dbContextFactory;
|
|
private readonly ApplicationDbContext _context;
|
|
private readonly ILoggingService _logger;
|
|
private readonly PermissionServices _permission;
|
|
private readonly IMapper _mapper;
|
|
private readonly UtilityMongoDBHelper _updateLogHelper;
|
|
private readonly CacheUpdateHelper _cache;
|
|
|
|
public MasterService(
|
|
IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
|
ApplicationDbContext context,
|
|
ILoggingService logger,
|
|
PermissionServices permission,
|
|
IMapper mapper,
|
|
UtilityMongoDBHelper updateLogHelper,
|
|
CacheUpdateHelper cache)
|
|
{
|
|
_dbContextFactory = dbContextFactory;
|
|
_context = context;
|
|
_logger = logger;
|
|
_permission = permission;
|
|
_mapper = mapper;
|
|
_updateLogHelper = updateLogHelper;
|
|
_cache = cache;
|
|
}
|
|
|
|
#region =================================================================== Global Services APIs ===================================================================
|
|
public async Task<ApiResponse<object>> GetGlobalServicesAsync(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("GetServices called");
|
|
|
|
try
|
|
{
|
|
// Step 1: Fetch global services
|
|
var services = await _context.GlobalServiceMasters.ToListAsync();
|
|
|
|
_logger.LogInfo("Fetched {Count} global service records for tenantId: {TenantId}", services.Count, tenantId);
|
|
|
|
return ApiResponse<object>.SuccessResponse(services, $"{services.Count} record(s) of services fetched successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error fetching services");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while fetching services", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateGlobalServiceAsync(ServiceMasterDto serviceMasterDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("CreateGlobalService called with Name: {ServiceName}", serviceMasterDto.Name);
|
|
|
|
try
|
|
{
|
|
// Step 1: Permission check
|
|
var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasManagePermission)
|
|
{
|
|
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("You don't have access", "You don't have permission to take this action", 403);
|
|
}
|
|
|
|
// Step 2: Check for duplicate name
|
|
bool isExist = await _context.GlobalServiceMasters
|
|
.AnyAsync(s => s.Name == serviceMasterDto.Name);
|
|
|
|
if (isExist)
|
|
{
|
|
_logger.LogWarning("Duplicate service name '{ServiceName}' attempted by employeeId: {EmployeeId}", serviceMasterDto.Name, loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse(
|
|
$"Service with name '{serviceMasterDto.Name}' already exists",
|
|
$"Service with name '{serviceMasterDto.Name}' already exists", 400);
|
|
}
|
|
|
|
// Step 3: Save new service
|
|
GlobalServiceMaster service = _mapper.Map<GlobalServiceMaster>(serviceMasterDto);
|
|
|
|
_context.GlobalServiceMasters.Add(service);
|
|
await _context.SaveChangesAsync();
|
|
|
|
var response = _mapper.Map<ServiceMasterVM>(service);
|
|
|
|
_logger.LogInfo("New global service '{ServiceName}' created successfully by employeeId: {EmployeeId}", service.Name, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(response, "New global service created successfully", 201);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating service");
|
|
return ApiResponse<object>.ErrorResponse("Failed to create global service", ex.Message, 500);
|
|
}
|
|
}
|
|
|
|
//public async Task<ApiResponse<object>> UpdateGlobalServiceAsync(Guid id, ServiceMasterDto serviceMasterDto, Employee loggedInEmployee, Guid tenantId)
|
|
//{
|
|
// _logger.LogInfo("UpdateService called for Id: {Id}", id);
|
|
|
|
// try
|
|
// {
|
|
|
|
// // Step 1: Permission check
|
|
// var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
// if (!hasPermission)
|
|
// {
|
|
// _logger.LogWarning("Access denied. EmployeeId: {EmployeeId} lacks Manage_Master permission.", loggedInEmployee.Id);
|
|
// return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to take this action", 403);
|
|
// }
|
|
|
|
// // Step 2: Input validation
|
|
// if (serviceMasterDto.Id != id)
|
|
// {
|
|
// _logger.LogWarning("Invalid input data provided for UpdateService. Id: {Id}", id);
|
|
// return ApiResponse<object>.ErrorResponse("Invalid input", "Please provide valid service data", 400);
|
|
// }
|
|
|
|
// // Step 3: Retrieve service
|
|
// var service = await _context.ServiceMasters
|
|
// .FirstOrDefaultAsync(s => s.Id == id && s.TenantId == tenantId && s.IsActive);
|
|
|
|
// if (service == null)
|
|
// {
|
|
// _logger.LogWarning("Service not found for Id: {Id}, Tenant: {TenantId}", id, tenantId);
|
|
// return ApiResponse<object>.ErrorResponse("Service not found", "The requested service does not exist", 404);
|
|
// }
|
|
|
|
// // Step 4: Update and save
|
|
// service.Name = serviceMasterDto.Name.Trim();
|
|
// service.Description = serviceMasterDto.Description.Trim();
|
|
|
|
// await _context.SaveChangesAsync();
|
|
|
|
// var response = _mapper.Map<ServiceMasterVM>(service);
|
|
|
|
// _logger.LogInfo("Service updated successfully. Id: {Id}, TenantId: {TenantId}", service.Id, tenantId);
|
|
// return ApiResponse<object>.SuccessResponse(response, "Service updated successfully", 200);
|
|
// }
|
|
// catch (Exception ex)
|
|
// {
|
|
// _logger.LogError(ex, "Error while updating service Id: {Id}.", id);
|
|
// return ApiResponse<object>.ErrorResponse("An error occurred while updating the service", ex.Message, 500);
|
|
// }
|
|
//}
|
|
|
|
//public async Task<ApiResponse<object>> DeleteGlobalServiceAsync(Guid id, bool active, Employee loggedInEmployee, Guid tenantId)
|
|
//{
|
|
// _logger.LogInfo("DeleteService called with ServiceId: {ServiceId}, IsActive: {IsActive}", id, active);
|
|
|
|
// try
|
|
// {
|
|
// // Step 1: Get validate permission
|
|
// var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
|
|
// if (!hasPermission)
|
|
// {
|
|
// _logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage_Master permission.", loggedInEmployee.Id);
|
|
// return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to delete services", 403);
|
|
// }
|
|
|
|
// // Step 2: Check if the service exists
|
|
// var service = await _context.ServiceMasters
|
|
// .FirstOrDefaultAsync(s => s.Id == id && s.TenantId == tenantId);
|
|
|
|
// if (service == null)
|
|
// {
|
|
// _logger.LogWarning("Service not found. ServiceId: {ServiceId}", id);
|
|
// return ApiResponse<object>.ErrorResponse("Service not found", "Service not found or already deleted", 404);
|
|
// }
|
|
|
|
// // Protect system-defined service
|
|
// if (service.IsSystem)
|
|
// {
|
|
// _logger.LogWarning("Attempt to delete system-defined service. ServiceId: {ServiceId}", id);
|
|
// return ApiResponse<object>.ErrorResponse("Cannot delete system-defined service", "This service is system-defined and cannot be deleted", 400);
|
|
// }
|
|
|
|
// // Step 3: Soft delete or restore
|
|
// service.IsActive = active;
|
|
// await _context.SaveChangesAsync();
|
|
|
|
// var status = active ? "restored" : "deactivated";
|
|
// _logger.LogInfo("Service {ServiceId} has been {Status} successfully by EmployeeId: {EmployeeId}", id, status, loggedInEmployee.Id);
|
|
|
|
// return ApiResponse<object>.SuccessResponse(new { }, $"Service {status} successfully", 200);
|
|
// }
|
|
// catch (Exception ex)
|
|
// {
|
|
// _logger.LogError(ex, "Unexpected error occurred while deleting service {ServiceId}", id);
|
|
// return ApiResponse<object>.ErrorResponse("Error deleting service", ex.Message, 500);
|
|
// }
|
|
//}
|
|
|
|
#endregion
|
|
#region =================================================================== Services APIs ===================================================================
|
|
public async Task<ApiResponse<object>> GetServicesAsync(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("GetServices called");
|
|
|
|
try
|
|
{
|
|
// Step 1: Fetch services for the tenant
|
|
var services = await _context.ServiceMasters
|
|
.Where(s => s.TenantId == tenantId && s.IsActive)
|
|
.Select(s => _mapper.Map<ServiceMasterVM>(s))
|
|
.ToListAsync();
|
|
|
|
_logger.LogInfo("Fetched {Count} service records for tenantId: {TenantId}", services.Count, tenantId);
|
|
|
|
return ApiResponse<object>.SuccessResponse(services, $"{services.Count} record(s) of services fetched successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error fetching services");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while fetching services", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateServiceAsync(ServiceMasterDto serviceMasterDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("CreateService called with Name: {ServiceName}", serviceMasterDto.Name);
|
|
|
|
try
|
|
{
|
|
// Step 1: Permission check
|
|
var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasManagePermission)
|
|
{
|
|
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("You don't have access", "You don't have permission to take this action", 403);
|
|
}
|
|
|
|
// Step 2: Check for duplicate name
|
|
bool isExist = await _context.ServiceMasters
|
|
.AnyAsync(s => s.TenantId == tenantId && s.Name == serviceMasterDto.Name);
|
|
|
|
if (isExist)
|
|
{
|
|
_logger.LogWarning("Duplicate service name '{ServiceName}' attempted by employeeId: {EmployeeId}", serviceMasterDto.Name, loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse(
|
|
$"Service with name '{serviceMasterDto.Name}' already exists",
|
|
$"Service with name '{serviceMasterDto.Name}' already exists", 400);
|
|
}
|
|
|
|
// Step 3: Save new service
|
|
ServiceMaster service = _mapper.Map<ServiceMaster>(serviceMasterDto);
|
|
service.TenantId = tenantId;
|
|
service.IsActive = true;
|
|
service.IsSystem = false;
|
|
_context.ServiceMasters.Add(service);
|
|
await _context.SaveChangesAsync();
|
|
|
|
var response = _mapper.Map<ServiceMasterVM>(service);
|
|
|
|
_logger.LogInfo("New service '{ServiceName}' created successfully by employeeId: {EmployeeId}", service.Name, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(response, "New service created successfully", 201);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating service");
|
|
return ApiResponse<object>.ErrorResponse("Failed to create service", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateServiceAsync(Guid id, ServiceMasterDto serviceMasterDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("UpdateService called for Id: {Id}", id);
|
|
|
|
try
|
|
{
|
|
|
|
// Step 1: Permission check
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} lacks Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to take this action", 403);
|
|
}
|
|
|
|
// Step 2: Input validation
|
|
if (serviceMasterDto.Id != id)
|
|
{
|
|
_logger.LogWarning("Invalid input data provided for UpdateService. Id: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("Invalid input", "Please provide valid service data", 400);
|
|
}
|
|
|
|
// Step 3: Retrieve service
|
|
var service = await _context.ServiceMasters
|
|
.FirstOrDefaultAsync(s => s.Id == id && s.TenantId == tenantId && s.IsActive);
|
|
|
|
if (service == null)
|
|
{
|
|
_logger.LogWarning("Service not found for Id: {Id}, Tenant: {TenantId}", id, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Service not found", "The requested service does not exist", 404);
|
|
}
|
|
|
|
// Step 4: Update and save
|
|
service.Name = serviceMasterDto.Name.Trim();
|
|
service.Description = serviceMasterDto.Description.Trim();
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
var response = _mapper.Map<ServiceMasterVM>(service);
|
|
|
|
_logger.LogInfo("Service updated successfully. Id: {Id}, TenantId: {TenantId}", service.Id, tenantId);
|
|
return ApiResponse<object>.SuccessResponse(response, "Service updated successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error while updating service Id: {Id}.", id);
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while updating the service", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteServiceAsync(Guid id, bool active, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("DeleteService called with ServiceId: {ServiceId}, IsActive: {IsActive}", id, active);
|
|
|
|
try
|
|
{
|
|
// Step 1: Get validate permission
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to delete services", 403);
|
|
}
|
|
|
|
// Step 2: Check if the service exists
|
|
var service = await _context.ServiceMasters
|
|
.FirstOrDefaultAsync(s => s.Id == id && s.TenantId == tenantId);
|
|
|
|
if (service == null)
|
|
{
|
|
_logger.LogWarning("Service not found. ServiceId: {ServiceId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Service not found", "Service not found or already deleted", 404);
|
|
}
|
|
|
|
// Protect system-defined service
|
|
if (service.IsSystem)
|
|
{
|
|
_logger.LogWarning("Attempt to delete system-defined service. ServiceId: {ServiceId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Cannot delete system-defined service", "This service is system-defined and cannot be deleted", 400);
|
|
}
|
|
|
|
// Step 3: Soft delete or restore
|
|
service.IsActive = active;
|
|
await _context.SaveChangesAsync();
|
|
|
|
var status = active ? "restored" : "deactivated";
|
|
_logger.LogInfo("Service {ServiceId} has been {Status} successfully by EmployeeId: {EmployeeId}", id, status, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(new { }, $"Service {status} successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Unexpected error occurred while deleting service {ServiceId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Error deleting service", ex.Message, 500);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region =================================================================== Activity Group APIs ===================================================================
|
|
|
|
public async Task<ApiResponse<object>> GetActivityGroupsAsync(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("GetActivityGroups called");
|
|
|
|
try
|
|
{
|
|
// Step 1: Fetch all activity groups for the tenant
|
|
var activityGroups = await _context.ActivityGroupMasters
|
|
.Include(ag => ag.Service)
|
|
.Where(ag => ag.TenantId == tenantId && ag.IsActive)
|
|
.Select(ag => _mapper.Map<ActivityGroupMasterVM>(ag))
|
|
.ToListAsync();
|
|
|
|
_logger.LogInfo("{Count} activity group(s) fetched for tenantId: {TenantId}", activityGroups.Count, tenantId);
|
|
|
|
return ApiResponse<object>.SuccessResponse(activityGroups, $"{activityGroups.Count} record(s) of activity groups fetched successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error fetching activity groups");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while fetching activity groups", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateActivityGroupAsync(ActivityGroupDto activityGroupDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("CreateActivityGroup called with Name: {Name}", activityGroupDto.Name);
|
|
|
|
try
|
|
{
|
|
// Step 1: Check Manage Master permission
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} lacks Manage_Master permission", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to take this action", 403);
|
|
}
|
|
|
|
// Step 2: Check for duplicate name within ActivityGroupMasters
|
|
bool isExist = await _context.ActivityGroupMasters
|
|
.AnyAsync(ag => ag.TenantId == tenantId && ag.Name.ToLower() == activityGroupDto.Name.ToLower());
|
|
|
|
if (isExist)
|
|
{
|
|
_logger.LogWarning("Duplicate activity group name '{Name}' attempted by employeeId: {EmployeeId}", activityGroupDto.Name, loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse(
|
|
$"Activity group with name '{activityGroupDto.Name}' already exists",
|
|
$"Activity group with name '{activityGroupDto.Name}' already exists", 400);
|
|
}
|
|
|
|
// Step 3: Map and persist
|
|
var activityGroup = _mapper.Map<ActivityGroupMaster>(activityGroupDto);
|
|
activityGroup.TenantId = tenantId;
|
|
activityGroup.IsActive = true;
|
|
activityGroup.IsSystem = false;
|
|
|
|
_context.ActivityGroupMasters.Add(activityGroup);
|
|
await _context.SaveChangesAsync();
|
|
|
|
var service = await _context.ServiceMasters.FirstOrDefaultAsync(s => s.Id == activityGroup.ServiceId);
|
|
|
|
var response = _mapper.Map<ActivityGroupMasterVM>(activityGroup);
|
|
|
|
_logger.LogInfo("New activity group '{Name}' created successfully by employeeId: {EmployeeId}", activityGroup.Name, loggedInEmployee.Id);
|
|
return ApiResponse<object>.SuccessResponse(response, "New activity group created successfully", 201);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating activity group");
|
|
return ApiResponse<object>.ErrorResponse("Failed to create activity group", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateActivityGroupAsync(Guid id, ActivityGroupDto activityGroupDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("UpdateActivityGroup called for Id: {Id}", id);
|
|
|
|
try
|
|
{
|
|
// Step 1: Permission check
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} lacks Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to take this action", 403);
|
|
}
|
|
|
|
// Step 2: Input validation
|
|
if (activityGroupDto.Id != id)
|
|
{
|
|
_logger.LogWarning("Invalid input for activity group update. Id: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("Invalid input", "Please provide valid data to update activity group", 400);
|
|
}
|
|
|
|
var service = await _context.ServiceMasters.FirstOrDefaultAsync(s => s.Id == activityGroupDto.ServiceId && s.IsActive);
|
|
|
|
if (service == null)
|
|
{
|
|
_logger.LogWarning("User tries to update activity group, but service not found");
|
|
return ApiResponse<object>.ErrorResponse("Invalid service ID", "Please provide valid service ID to update activity group", 400);
|
|
}
|
|
|
|
// Step 3: Retrieve existing activity group
|
|
var activityGroup = await _context.ActivityGroupMasters
|
|
.Include(ag => ag.Service)
|
|
.FirstOrDefaultAsync(ag => ag.Id == id && ag.TenantId == tenantId && ag.IsActive);
|
|
|
|
if (activityGroup == null)
|
|
{
|
|
_logger.LogWarning("Activity group not found. Id: {Id}, TenantId: {TenantId}", id, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Activity group not found", "No such activity group exists", 404);
|
|
}
|
|
|
|
// Step 4: Update and save
|
|
activityGroup.Name = activityGroupDto.Name.Trim();
|
|
activityGroup.Description = activityGroupDto.Description.Trim();
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
var response = _mapper.Map<ActivityGroupMasterVM>(activityGroup);
|
|
|
|
_logger.LogInfo("Activity group updated successfully. Id: {Id}, TenantId: {TenantId}", activityGroup.Id, tenantId);
|
|
return ApiResponse<object>.SuccessResponse(response, "Activity group updated successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error while updating activity group Id: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while updating the activity group", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteActivityGroupAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("DeleteActivityGroup called with ActivityGroupId: {ActivityGroupId}, IsActive: {IsActive}", id, isActive);
|
|
|
|
try
|
|
{
|
|
// Step 1: Permission check
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to delete activity groups", 403);
|
|
}
|
|
|
|
// Step 2: Fetch the activity group
|
|
var activityGroup = await _context.ActivityGroupMasters
|
|
.FirstOrDefaultAsync(ag => ag.Id == id && ag.TenantId == tenantId);
|
|
|
|
if (activityGroup == null)
|
|
{
|
|
_logger.LogWarning("ActivityGroup not found. Id: {ActivityGroupId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Activity group not found", "Activity group not found or already deleted", 404);
|
|
}
|
|
|
|
//Protect system-defined activity group
|
|
if (activityGroup.IsSystem)
|
|
{
|
|
_logger.LogWarning("Attempt to delete system-defined activity group. Id: {ActivityGroupId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Cannot delete system-defined activity group", "This activity group is system-defined and cannot be deleted", 400);
|
|
}
|
|
|
|
// Step 3: Perform soft delete or restore
|
|
activityGroup.IsActive = isActive;
|
|
await _context.SaveChangesAsync();
|
|
|
|
var status = isActive ? "restored" : "deactivated";
|
|
_logger.LogInfo("ActivityGroup {ActivityGroupId} has been {Status} by EmployeeId: {EmployeeId}", id, status, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(new { }, $"Activity group {status} successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Unexpected error occurred while deleting ActivityGroup {ActivityGroupId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Error deleting activity group", ex.Message, 500);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Activity APIs ===================================================================
|
|
public async Task<ApiResponse<object>> GetActivitiesMasterAsync(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("GetActivitiesMaster called");
|
|
|
|
try
|
|
{
|
|
// Step 1: Fetch all active activities for the tenant
|
|
var activities = await _context.ActivityMasters
|
|
.Include(c => c.ActivityGroup)
|
|
.ThenInclude(ag => ag!.Service)
|
|
.Where(c => c.TenantId == tenantId && c.IsActive)
|
|
.ToListAsync();
|
|
|
|
if (activities.Count == 0)
|
|
{
|
|
_logger.LogWarning("No active activities found for tenantId: {TenantId}", tenantId);
|
|
return ApiResponse<object>.SuccessResponse(new List<ActivityVM>(), "No activity records found", 200);
|
|
}
|
|
|
|
// Step 2: Fetch all checklists for those activities in a single query to avoid N+1
|
|
var activityIds = activities.Select(a => a.Id).ToList();
|
|
var checkLists = await _context.ActivityCheckLists
|
|
.Where(c => c.TenantId == tenantId && activityIds.Contains(c.ActivityId))
|
|
.ToListAsync();
|
|
|
|
// Step 3: Group checklists by activity
|
|
var groupedChecklists = checkLists
|
|
.GroupBy(c => c.ActivityId)
|
|
.ToDictionary(g => g.Key, g => g.ToList());
|
|
|
|
// Step 4: Map to ViewModel
|
|
var activityVMs = activities.Select(activity =>
|
|
{
|
|
var checklistForActivity = groupedChecklists.ContainsKey(activity.Id)
|
|
? groupedChecklists[activity.Id]
|
|
: new List<ActivityCheckList>();
|
|
|
|
var response = _mapper.Map<ActivityVM>(activity);
|
|
response.CheckLists = _mapper.Map<List<CheckListVM>>(checklistForActivity);
|
|
return response;
|
|
|
|
}).ToList();
|
|
|
|
_logger.LogInfo("{Count} activity records fetched successfully for tenantId: {TenantId}", activityVMs.Count, tenantId);
|
|
|
|
return ApiResponse<object>.SuccessResponse(activityVMs, $"{activityVMs.Count} activity records fetched successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred in GetActivitiesMaster");
|
|
return ApiResponse<object>.ErrorResponse("Failed to fetch activity records", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateActivityAsync(CreateActivityMasterDto createActivity, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("CreateActivity called with ActivityName: {Name}", createActivity?.ActivityName ?? "null");
|
|
|
|
try
|
|
{
|
|
// Step 1: Validate input
|
|
if (createActivity == null)
|
|
{
|
|
_logger.LogWarning("Null request body received in CreateActivity");
|
|
return ApiResponse<object>.ErrorResponse("Invalid input", "Activity data is required", 400);
|
|
}
|
|
|
|
var activityGroup = await _context.ActivityGroupMasters
|
|
.Include(ag => ag.Service)
|
|
.FirstOrDefaultAsync(ag => ag.Id == createActivity.ActitvityGroupId && ag.TenantId == tenantId);
|
|
if (activityGroup == null)
|
|
{
|
|
_logger.LogWarning("User tried to create new activity, but not found activity group");
|
|
return ApiResponse<object>.ErrorResponse("Invalid input", "Activity data is required", 400);
|
|
}
|
|
|
|
// Step 2: Check permissions
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to perform this action", 403);
|
|
}
|
|
|
|
// Step 3: Convert DTO to entity and add activity
|
|
var activityMaster = _mapper.Map<ActivityMaster>(createActivity);
|
|
activityMaster.TenantId = tenantId;
|
|
|
|
_context.ActivityMasters.Add(activityMaster);
|
|
await _context.SaveChangesAsync();
|
|
|
|
List<CheckListVM> checkListVMs = new();
|
|
|
|
// Step 4: Handle checklist items if present
|
|
if (createActivity.CheckList?.Any() == true)
|
|
{
|
|
var activityCheckLists = createActivity.CheckList
|
|
.Select(c =>
|
|
{
|
|
var response = _mapper.Map<ActivityCheckList>(c);
|
|
response.ActivityId = activityMaster.Id;
|
|
response.IsChecked = false;
|
|
response.TenantId = tenantId;
|
|
return response;
|
|
})
|
|
.ToList();
|
|
|
|
_context.ActivityCheckLists.AddRange(activityCheckLists);
|
|
await _context.SaveChangesAsync();
|
|
|
|
checkListVMs = activityCheckLists
|
|
.Select(c =>
|
|
{
|
|
var response = _mapper.Map<CheckListVM>(c);
|
|
return response;
|
|
})
|
|
.ToList();
|
|
}
|
|
|
|
// Step 5: Prepare final response
|
|
var activityVM = _mapper.Map<ActivityVM>(activityMaster);
|
|
activityVM.CheckLists = checkListVMs;
|
|
|
|
_logger.LogInfo("Activity '{Name}' created successfully for tenant {TenantId}", activityMaster.ActivityName, tenantId);
|
|
return ApiResponse<object>.SuccessResponse(activityVM, "Activity created successfully", 201);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while creating activity");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred while creating activity", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateActivityAsync(Guid id, CreateActivityMasterDto createActivity, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("UpdateActivity called for ActivityId: {ActivityId}", id);
|
|
|
|
try
|
|
{
|
|
// Step 1: Validate input
|
|
if (createActivity == null || string.IsNullOrWhiteSpace(createActivity.ActivityName) || string.IsNullOrWhiteSpace(createActivity.UnitOfMeasurement))
|
|
{
|
|
_logger.LogWarning("Invalid activity update input for ActivityId: {ActivityId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Invalid input", "ActivityName and UnitOfMeasurement are required", 400);
|
|
}
|
|
|
|
// Step 2: Check permissions
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to update activities", 403);
|
|
}
|
|
|
|
// Step 3: Validate service, activity group, and activity existence
|
|
var activityGroup = await _context.ActivityGroupMasters.Include(ag => ag.Service).FirstOrDefaultAsync(ag => ag.Id == createActivity.ActitvityGroupId && ag.IsActive);
|
|
|
|
if (activityGroup == null)
|
|
{
|
|
_logger.LogWarning("User tries to update activity, but cannot able found activity group or service");
|
|
return ApiResponse<object>.ErrorResponse("Invalid activity group ID or service ID", "Please provide valid activity group ID or service ID to update activity group", 400);
|
|
}
|
|
|
|
var activity = await _context.ActivityMasters
|
|
.Include(a => a.ActivityGroup)
|
|
.ThenInclude(ag => ag!.Service)
|
|
.FirstOrDefaultAsync(a => a.Id == id && a.IsActive && a.TenantId == tenantId);
|
|
|
|
if (activity == null)
|
|
{
|
|
_logger.LogWarning("Activity not found for ActivityId: {ActivityId}, TenantId: {TenantId}", id, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Activity not found", "Activity not found", 404);
|
|
}
|
|
|
|
// Step 4: Update activity core data
|
|
activity.ActivityName = createActivity.ActivityName.Trim();
|
|
activity.UnitOfMeasurement = createActivity.UnitOfMeasurement.Trim();
|
|
activity.ActivityGroupId = createActivity.ActitvityGroupId;
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
// Step 5: Handle checklist updates
|
|
var existingChecklists = await _context.ActivityCheckLists
|
|
.AsNoTracking()
|
|
.Where(c => c.ActivityId == activity.Id)
|
|
.ToListAsync();
|
|
|
|
var updatedChecklistVMs = new List<CheckListVM>();
|
|
|
|
if (createActivity.CheckList != null && createActivity.CheckList.Any())
|
|
{
|
|
var incomingCheckIds = createActivity.CheckList.Where(c => c.Id != null).Select(c => c.Id!.Value).ToHashSet();
|
|
|
|
// Prepare lists
|
|
var newChecks = createActivity.CheckList.Where(c => c.Id == null);
|
|
var updates = createActivity.CheckList.Where(c => c.Id != null && existingChecklists.Any(ec => ec.Id == c.Id));
|
|
var deletes = existingChecklists.Where(ec => !incomingCheckIds.Contains(ec.Id)).ToList();
|
|
|
|
var toAdd = newChecks
|
|
.Select(c =>
|
|
{
|
|
var response = _mapper.Map<ActivityCheckList>(c);
|
|
response.ActivityId = activity.Id;
|
|
response.IsChecked = false;
|
|
response.TenantId = tenantId;
|
|
return response;
|
|
})
|
|
.ToList();
|
|
|
|
var toUpdate = updates
|
|
.Select(c =>
|
|
{
|
|
var response = _mapper.Map<ActivityCheckList>(c);
|
|
response.ActivityId = activity.Id;
|
|
response.TenantId = tenantId;
|
|
return response;
|
|
})
|
|
.ToList();
|
|
|
|
_context.ActivityCheckLists.AddRange(toAdd);
|
|
_context.ActivityCheckLists.UpdateRange(toUpdate);
|
|
_context.ActivityCheckLists.RemoveRange(deletes);
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
// Prepare view model
|
|
updatedChecklistVMs = toAdd.Concat(toUpdate)
|
|
.Select(c => _mapper.Map<CheckListVM>(c))
|
|
.ToList();
|
|
}
|
|
else if (existingChecklists.Any())
|
|
{
|
|
// If no checklist provided, remove all existing
|
|
_context.ActivityCheckLists.RemoveRange(existingChecklists);
|
|
await _context.SaveChangesAsync();
|
|
}
|
|
|
|
// Step 6: Prepare response
|
|
var activityVM = _mapper.Map<ActivityVM>(activity);
|
|
activityVM.CheckLists = updatedChecklistVMs;
|
|
|
|
_logger.LogInfo("Activity updated successfully. ActivityId: {ActivityId}, TenantId: {TenantId}", activity.Id, tenantId);
|
|
return ApiResponse<object>.SuccessResponse(activityVM, "Activity updated successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception in UpdateActivity");
|
|
return ApiResponse<object>.ErrorResponse("Error updating activity", ex.Message, 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteActivityAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("DeleteActivity called with ActivityId: {ActivityId}, IsActive: {IsActive}", id, isActive);
|
|
|
|
try
|
|
{
|
|
// Step 1: Validate permission
|
|
var hasPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
|
|
if (!hasPermission)
|
|
{
|
|
_logger.LogWarning("Access denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to delete activities", 403);
|
|
}
|
|
|
|
// Step 2: Fetch the activity
|
|
var activity = await _context.ActivityMasters
|
|
.FirstOrDefaultAsync(a => a.Id == id && a.TenantId == tenantId);
|
|
|
|
if (activity == null)
|
|
{
|
|
_logger.LogWarning("Activity not found. ActivityId: {ActivityId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Activity not found", "Activity not found or already deleted", 404);
|
|
}
|
|
|
|
// Step 3: Perform soft delete/restore
|
|
activity.IsActive = isActive;
|
|
await _context.SaveChangesAsync();
|
|
|
|
string status = isActive ? "restored" : "deactivated";
|
|
_logger.LogInfo("Activity {ActivityId} {Status} successfully by EmployeeId: {EmployeeId}", id, status, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(new { }, $"Activity {status} successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Unexpected error while deleting activity {ActivityId}", id);
|
|
return ApiResponse<object>.ErrorResponse("Error deleting activity", ex.Message, 500);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Contact Category APIs ===================================================================
|
|
|
|
public async Task<ApiResponse<object>> CreateContactCategory(CreateContactCategoryDto contactCategoryDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
if (contactCategoryDto != null)
|
|
{
|
|
ContactCategoryMaster? existingContactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Name.ToLower() == (contactCategoryDto.Name != null ? contactCategoryDto.Name.ToLower() : ""));
|
|
if (existingContactCategory == null)
|
|
{
|
|
ContactCategoryMaster contactCategory = contactCategoryDto.ToContactCategoryMasterFromCreateContactCategoryDto(tenantId);
|
|
_context.ContactCategoryMasters.Add(contactCategory);
|
|
await _context.SaveChangesAsync();
|
|
ContactCategoryVM categoryVM = contactCategory.ToContactCategoryVMFromContactCategoryMaster();
|
|
|
|
_logger.LogInfo("Employee ID {LoggedInEmployeeId} created a contact category {ContactCategoryId}.", loggedInEmployee.Id, contactCategory.Id);
|
|
return ApiResponse<object>.SuccessResponse(categoryVM, "Category Created Successfully", 200);
|
|
}
|
|
_logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact category.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Category already existed", "Category already existed", 409);
|
|
}
|
|
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400);
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateContactCategory(Guid id, UpdateContactCategoryDto contactCategoryDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
if (contactCategoryDto != null && id == contactCategoryDto.Id)
|
|
{
|
|
ContactCategoryMaster? contactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Id == id);
|
|
if (contactCategory != null)
|
|
{
|
|
contactCategory.Name = contactCategoryDto.Name ?? "";
|
|
contactCategory.Description = contactCategoryDto.Description ?? "";
|
|
|
|
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
|
{
|
|
RefereanceId = contactCategory.Id,
|
|
UpdatedById = loggedInEmployee.Id,
|
|
UpdateAt = DateTime.UtcNow
|
|
});
|
|
|
|
await _context.SaveChangesAsync();
|
|
ContactCategoryVM categoryVM = contactCategory.ToContactCategoryVMFromContactCategoryMaster();
|
|
|
|
_logger.LogInfo("Employee ID {LoggedInEmployeeId} created a contact category {ContactCategoryId}.", loggedInEmployee.Id, contactCategory.Id);
|
|
return ApiResponse<object>.SuccessResponse(categoryVM, "Category Created Successfully", 200);
|
|
}
|
|
_logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to update a contact category but not found in database.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Category not found", "Category not found", 404);
|
|
}
|
|
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400);
|
|
}
|
|
public async Task<ApiResponse<object>> GetContactCategoriesList(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
var categoryList = await _context.ContactCategoryMasters.Where(c => c.TenantId == tenantId).ToListAsync();
|
|
List<ContactCategoryVM> contactCategories = new List<ContactCategoryVM>();
|
|
foreach (var category in categoryList)
|
|
{
|
|
ContactCategoryVM categoryVM = category.ToContactCategoryVMFromContactCategoryMaster();
|
|
contactCategories.Add(categoryVM);
|
|
}
|
|
_logger.LogInfo("{count} contact categoires are fetched by Employee with ID {LoggedInEmployeeId}", contactCategories.Count, loggedInEmployee.Id);
|
|
return ApiResponse<object>.SuccessResponse(contactCategories, System.String.Format("{0} contact categories fetched successfully", contactCategories.Count), 200);
|
|
}
|
|
public async Task<ApiResponse<object>> GetContactCategoryById(Guid id, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
var category = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId);
|
|
if (category != null)
|
|
{
|
|
ContactCategoryVM categoryVM = category.ToContactCategoryVMFromContactCategoryMaster();
|
|
_logger.LogInfo("Employee {EmployeeId} fetched contact category {ContactCategoryID}", loggedInEmployee.Id, category.Id);
|
|
return ApiResponse<object>.SuccessResponse(categoryVM, "Category fetched successfully", 200);
|
|
}
|
|
|
|
_logger.LogWarning("Employee {EmployeeId} attempted to fetch contact category {ContactCategoryID} but not found in database", loggedInEmployee.Id, id);
|
|
return ApiResponse<object>.ErrorResponse("Category not found", "Category not found", 404);
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteContactCategory(Guid id, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
ContactCategoryMaster? contactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId);
|
|
if (contactCategory != null)
|
|
{
|
|
List<Contact>? existingContacts = await _context.Contacts.AsNoTracking().Where(c => c.ContactCategoryId == contactCategory.Id).ToListAsync();
|
|
if (existingContacts.Count > 0)
|
|
{
|
|
List<Contact>? contacts = new List<Contact>();
|
|
foreach (var contact in existingContacts)
|
|
{
|
|
contact.ContactCategoryId = null;
|
|
contacts.Add(contact);
|
|
}
|
|
_context.Contacts.UpdateRange(contacts);
|
|
}
|
|
_context.ContactCategoryMasters.Remove(contactCategory);
|
|
|
|
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
|
{
|
|
RefereanceId = id,
|
|
UpdatedById = loggedInEmployee.Id,
|
|
UpdateAt = DateTime.UtcNow
|
|
});
|
|
await _context.SaveChangesAsync();
|
|
_logger.LogInfo("Employee {EmployeeId} deleted contact category {ContactCategoryId}", loggedInEmployee.Id, id);
|
|
}
|
|
|
|
_logger.LogWarning("Employee {EmployeeId} tries to delete Category {CategoryId} but not found in database", loggedInEmployee.Id, id);
|
|
return ApiResponse<object>.SuccessResponse(new { }, "Category deleted successfully", 200);
|
|
}
|
|
#endregion
|
|
|
|
#region =================================================================== Contact Tag APIs ===================================================================
|
|
|
|
public async Task<ApiResponse<Object>> GetContactTags(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
var taglist = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync();
|
|
List<ContactTagVM> contactTags = new List<ContactTagVM>();
|
|
foreach (var tag in taglist)
|
|
{
|
|
ContactTagVM tagVm = tag.ToContactTagVMFromContactTagMaster();
|
|
contactTags.Add(tagVm);
|
|
}
|
|
_logger.LogInfo("{count} contact Tags are fetched by Employee with ID {LoggedInEmployeeId}", contactTags.Count, loggedInEmployee.Id);
|
|
return ApiResponse<object>.SuccessResponse(contactTags, System.String.Format("{0} contact tags fetched successfully", contactTags.Count), 200);
|
|
}
|
|
public async Task<ApiResponse<object>> CreateContactTag(CreateContactTagDto contactTagDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
if (contactTagDto != null)
|
|
{
|
|
ContactTagMaster? existingContactTag = await _context.ContactTagMasters.FirstOrDefaultAsync(c => c.TenantId == tenantId && c.Name.ToLower() == (contactTagDto.Name != null ? contactTagDto.Name.ToLower() : ""));
|
|
if (existingContactTag == null)
|
|
{
|
|
ContactTagMaster contactTag = contactTagDto.ToContactTagMasterFromCreateContactTagDto(tenantId);
|
|
_context.ContactTagMasters.Add(contactTag);
|
|
await _context.SaveChangesAsync();
|
|
ContactTagVM tagVM = contactTag.ToContactTagVMFromContactTagMaster();
|
|
|
|
_logger.LogInfo("Employee ID {LoggedInEmployeeId} created a contact tag {ContactTagId}.", loggedInEmployee.Id, contactTag.Id);
|
|
return ApiResponse<object>.SuccessResponse(tagVM, "Tag Created Successfully", 200);
|
|
}
|
|
_logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact tag.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Tag already existed", "Tag already existed", 409);
|
|
}
|
|
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400);
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateContactTag(Guid id, UpdateContactTagDto contactTagDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
if (contactTagDto != null && contactTagDto.Id == id)
|
|
{
|
|
ContactTagMaster? contactTag = await _context.ContactTagMasters.AsNoTracking().FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Id == contactTagDto.Id);
|
|
if (contactTag != null)
|
|
{
|
|
contactTag = contactTagDto.ToContactTagMasterFromUpdateContactTagDto(tenantId);
|
|
_context.ContactTagMasters.Update(contactTag);
|
|
|
|
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
|
{
|
|
RefereanceId = contactTag.Id,
|
|
UpdatedById = loggedInEmployee.Id,
|
|
UpdateAt = DateTime.UtcNow
|
|
});
|
|
await _context.SaveChangesAsync();
|
|
await _context.SaveChangesAsync();
|
|
|
|
ContactTagVM contactTagVm = contactTag.ToContactTagVMFromContactTagMaster();
|
|
|
|
|
|
|
|
_logger.LogInfo("Contact tag master {ConatctTagId} updated successfully by employee {EmployeeId}", contactTagVm.Id, loggedInEmployee.Id);
|
|
return ApiResponse<object>.SuccessResponse(contactTagVm, "Contact Tag master updated successfully", 200);
|
|
}
|
|
_logger.LogWarning("Contact Tag master {ContactTagId} not found in database", id);
|
|
return ApiResponse<object>.ErrorResponse("Contact Tag master not found", "Contact tag master not found", 404);
|
|
}
|
|
_logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400);
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteContactTag(Guid id, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
ContactTagMaster? contactTag = await _context.ContactTagMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId);
|
|
if (contactTag != null)
|
|
{
|
|
List<ContactTagMapping>? tagMappings = await _context.ContactTagMappings.Where(t => t.ContactTagId == contactTag.Id).ToListAsync();
|
|
|
|
_context.ContactTagMasters.Remove(contactTag);
|
|
if (tagMappings.Any())
|
|
{
|
|
_context.ContactTagMappings.RemoveRange(tagMappings);
|
|
}
|
|
_context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog
|
|
{
|
|
RefereanceId = id,
|
|
UpdatedById = loggedInEmployee.Id,
|
|
UpdateAt = DateTime.UtcNow
|
|
});
|
|
await _context.SaveChangesAsync();
|
|
_logger.LogInfo("Employee {EmployeeId} deleted contact tag {ContactTagId}", loggedInEmployee.Id, id);
|
|
}
|
|
|
|
_logger.LogWarning("Employee {EmployeeId} tries to delete Tag {ContactTagId} but not found in database", loggedInEmployee.Id, id);
|
|
return ApiResponse<object>.SuccessResponse(new { }, "Tag deleted successfully", 200);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Work Status APIs ===================================================================
|
|
|
|
public async Task<ApiResponse<object>> GetWorkStatusList(Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("GetWorkStatusList called.");
|
|
|
|
try
|
|
{
|
|
// Step 1: Check permission to view master data
|
|
bool hasViewPermission = await _permission.HasPermission(PermissionsMaster.ViewMasters, loggedInEmployee.Id);
|
|
if (!hasViewPermission)
|
|
{
|
|
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("You don't have access", "Don't have access to take action", 403);
|
|
}
|
|
|
|
// Step 2: Fetch work statuses for the tenant
|
|
var workStatusList = await _context.WorkStatusMasters
|
|
.Where(ws => ws.TenantId == tenantId)
|
|
.Select(ws => new
|
|
{
|
|
ws.Id,
|
|
ws.Name,
|
|
ws.Description,
|
|
ws.IsSystem
|
|
})
|
|
.ToListAsync();
|
|
|
|
_logger.LogInfo("{Count} work statuses fetched for tenantId: {TenantId}", workStatusList.Count, tenantId);
|
|
|
|
// Step 3: Return successful response
|
|
return ApiResponse<object>.SuccessResponse(
|
|
workStatusList,
|
|
$"{workStatusList.Count} work status records fetched successfully",
|
|
200
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while fetching work status list");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred", "Unable to fetch work status list", 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateWorkStatus(CreateWorkStatusMasterDto createWorkStatusDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("CreateWorkStatus called with Name: {Name}", createWorkStatusDto.Name ?? "");
|
|
|
|
try
|
|
{
|
|
|
|
// Step 1: Check if user has permission to manage master data
|
|
var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasManageMasterPermission)
|
|
{
|
|
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("You don't have access", "Don't have access to take action", 403);
|
|
}
|
|
|
|
// Step 2: Check if work status with the same name already exists
|
|
var existingWorkStatus = await _context.WorkStatusMasters
|
|
.FirstOrDefaultAsync(ws => ws.Name == createWorkStatusDto.Name && ws.TenantId == tenantId);
|
|
|
|
if (existingWorkStatus != null)
|
|
{
|
|
_logger.LogWarning("Work status already exists: {Name}", createWorkStatusDto.Name ?? "");
|
|
return ApiResponse<object>.ErrorResponse("Work status already exists", "Work status already exists", 400);
|
|
}
|
|
|
|
// Step 3: Create new WorkStatusMaster entry
|
|
var workStatus = new WorkStatusMaster
|
|
{
|
|
Name = createWorkStatusDto.Name?.Trim() ?? "",
|
|
Description = createWorkStatusDto.Description?.Trim() ?? "",
|
|
IsSystem = false,
|
|
TenantId = tenantId
|
|
};
|
|
|
|
_context.WorkStatusMasters.Add(workStatus);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Work status created successfully: {Id}, Name: {Name}", workStatus.Id, workStatus.Name);
|
|
return ApiResponse<object>.SuccessResponse(workStatus, "Work status created successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while creating work status");
|
|
return ApiResponse<object>.ErrorResponse("An error occurred", "Unable to create work status", 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateWorkStatus(Guid id, UpdateWorkStatusMasterDto updateWorkStatusDto, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("UpdateWorkStatus called for WorkStatus ID: {Id}, New Name: {Name}", id, updateWorkStatusDto.Name ?? "");
|
|
|
|
try
|
|
{
|
|
// Step 1: Validate input
|
|
if (id == Guid.Empty || id != updateWorkStatusDto.Id)
|
|
{
|
|
_logger.LogWarning("Invalid ID provided for update. Route ID: {RouteId}, DTO ID: {DtoId}", id, updateWorkStatusDto.Id);
|
|
return ApiResponse<object>.ErrorResponse("Invalid data provided", "The provided work status ID is invalid", 400);
|
|
}
|
|
|
|
// Step 2: Check permissions
|
|
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);
|
|
return ApiResponse<object>.ErrorResponse("Access denied", "You do not have permission to update this work status", 403);
|
|
}
|
|
|
|
// Step 3: Retrieve the work status record
|
|
var workStatus = await _context.WorkStatusMasters
|
|
.FirstOrDefaultAsync(ws => ws.Id == id && ws.TenantId == tenantId);
|
|
|
|
if (workStatus == null)
|
|
{
|
|
_logger.LogWarning("Work status not found for ID: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("Work status not found", "No work status found with the provided ID", 404);
|
|
}
|
|
|
|
// Step 4: Check for duplicate name (optional)
|
|
var isDuplicate = await _context.WorkStatusMasters
|
|
.AnyAsync(ws => ws.Name == updateWorkStatusDto.Name && ws.Id != id && ws.TenantId == tenantId);
|
|
|
|
if (isDuplicate)
|
|
{
|
|
_logger.LogWarning("Duplicate work status name '{Name}' detected during update. ID: {Id}", updateWorkStatusDto.Name ?? "", id);
|
|
return ApiResponse<object>.ErrorResponse("Work status with the same name already exists", "Duplicate name", 400);
|
|
}
|
|
|
|
// Step 5: Update fields
|
|
workStatus.Name = updateWorkStatusDto.Name?.Trim() ?? "";
|
|
workStatus.Description = updateWorkStatusDto.Description?.Trim() ?? "";
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Work status updated successfully. ID: {Id}", id);
|
|
return ApiResponse<object>.SuccessResponse(workStatus, "Work status updated successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while updating work status ID: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("An error occurred", "Unable to update the work status at this time", 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteWorkStatus(Guid id, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
_logger.LogInfo("DeleteWorkStatus called for Id: {Id}", id);
|
|
|
|
try
|
|
{
|
|
// Step 2: Check permission to manage master data
|
|
var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id);
|
|
if (!hasManageMasterPermission)
|
|
{
|
|
_logger.LogWarning("Delete denied. EmployeeId: {EmployeeId} lacks Manage_Master permission.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("You don't have access", "Access denied for deleting work status", 403);
|
|
}
|
|
|
|
// Step 3: Find the work status
|
|
var workStatus = await _context.WorkStatusMasters
|
|
.FirstOrDefaultAsync(ws => ws.Id == id && ws.TenantId == tenantId);
|
|
|
|
if (workStatus == null)
|
|
{
|
|
_logger.LogWarning("Work status not found for Id: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("Work status not found", "Work status not found", 404);
|
|
}
|
|
|
|
// Step 4: Check for dependencies in TaskAllocations
|
|
bool hasDependency = await _context.TaskAllocations
|
|
.AnyAsync(ta => ta.TenantId == tenantId && ta.WorkStatusId == id);
|
|
|
|
if (hasDependency)
|
|
{
|
|
_logger.LogWarning("Cannot delete WorkStatus Id: {Id} due to existing task dependency", id);
|
|
return ApiResponse<object>.ErrorResponse(
|
|
"Work status has a dependency in assigned tasks and cannot be deleted",
|
|
"Deletion failed due to associated tasks",
|
|
400
|
|
);
|
|
}
|
|
|
|
// Step 5: Delete and persist
|
|
_context.WorkStatusMasters.Remove(workStatus);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Work status deleted successfully. Id: {Id}", id);
|
|
return ApiResponse<object>.SuccessResponse(new { }, "Work status deleted successfully", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while deleting WorkStatus Id: {Id}", id);
|
|
return ApiResponse<object>.ErrorResponse("An error occurred", "Unable to delete work status", 500);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Expenses Type APIs ===================================================================
|
|
|
|
public async Task<ApiResponse<object>> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive)
|
|
{
|
|
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<object>.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 && et.IsActive == isActive).ToListAsync();
|
|
var response = _mapper.Map<List<ExpensesTypeMasterVM>>(typeList);
|
|
|
|
_logger.LogInfo("{Count} records of expense type have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id);
|
|
return ApiResponse<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
|
|
}
|
|
public async Task<ApiResponse<object>> 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<object>.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<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
}
|
|
var expensesType = _mapper.Map<ExpensesTypeMaster>(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<ExpensesTypeMasterVM>(expensesType);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> 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<object>.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<object>.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<object>.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<object>.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("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<ExpensesTypeMasterVM>(expensesType);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteExpenseTypeAsync(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 type in different tenant", loggedInEmployee.Id, action);
|
|
return ApiResponse<object>.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<object>.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<object>.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<ExpensesTypeMasterVM>(expensesType);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Expenses Status APIs ===================================================================
|
|
public async Task<ApiResponse<object>> 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<object>.ErrorResponse("Access Denied", "User do not have access for this information", 403);
|
|
}
|
|
|
|
// Featching the list of Expenses Status.
|
|
var statusList = await _context.ExpensesStatusMaster.ToListAsync();
|
|
var response = _mapper.Map<List<ExpensesStatusMasterVM>>(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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region =================================================================== Payment mode APIs ===================================================================
|
|
public async Task<ApiResponse<object>> GetPaymentModeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive)
|
|
{
|
|
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<object>.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 && pm.IsActive == isActive).ToListAsync();
|
|
var response = _mapper.Map<List<PaymentModeMatserVM>>(paymentModes);
|
|
|
|
_logger.LogInfo("{Count} records of payment modes have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id);
|
|
return ApiResponse<object>.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<object>.ErrorResponse("Internal Error occured while featching list of payment modes list", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> 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<object>.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<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
|
|
}
|
|
// Mapping the DTO to PaymentModeMatser Model
|
|
var paymentMode = _mapper.Map<PaymentModeMatser>(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<PaymentModeMatserVM>(paymentMode);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> 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<object>.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<object>.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<object>.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<object>.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<PaymentModeMatserVM>(paymentMode);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeletePaymentModeAsync(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} Payment Mode in different tenant", loggedInEmployee.Id, action);
|
|
return ApiResponse<object>.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<object>.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<object>.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<PaymentModeMatserVM>(paymentMode);
|
|
return ApiResponse<object>.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<object>.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<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Document Category APIs ===================================================================
|
|
|
|
/// <summary>
|
|
/// Fetches the list of Document Categories for a given tenant and optional entity type.
|
|
/// Ensures tenant validation, mapping, and proper logging.
|
|
/// </summary>
|
|
/// <param name="entityTypeId">Optional entity type filter (e.g., EmployeeEntity, ProjectEntity).</param>
|
|
/// <param name="loggedInEmployee">Currently logged-in employee.</param>
|
|
/// <param name="tenantId">Tenant Id context.</param>
|
|
/// <returns>ApiResponse containing the document categories or error details.</returns>
|
|
public async Task<ApiResponse<object>> GetDocumentCategoryMasterListAsync(Guid? entityTypeId, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
try
|
|
{
|
|
// ✅ Tenant validation
|
|
if (tenantId != loggedInEmployee.TenantId)
|
|
{
|
|
_logger.LogWarning("Access denied. Employee {EmployeeId} (TenantId: {EmployeeTenantId}) attempted to fetch document categories for TenantId: {RequestedTenantId}",
|
|
loggedInEmployee.Id, loggedInEmployee.TenantId, tenantId);
|
|
|
|
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have access to this information", 403);
|
|
}
|
|
|
|
// ✅ Build query
|
|
IQueryable<DocumentCategoryMaster> documentCategoryQuery = _context.DocumentCategoryMasters
|
|
.AsNoTracking() // optimization: read-only
|
|
.Where(dc => dc.TenantId == tenantId);
|
|
|
|
// ✅ Apply optional filter
|
|
if (entityTypeId.HasValue)
|
|
{
|
|
documentCategoryQuery = documentCategoryQuery.Where(dc => dc.EntityTypeId == entityTypeId.Value);
|
|
}
|
|
|
|
// ✅ Fetch and map
|
|
var documentCategories = await documentCategoryQuery.ToListAsync();
|
|
var response = _mapper.Map<List<DocumentCategoryVM>>(documentCategories);
|
|
|
|
_logger.LogInfo("{Count} document categories fetched successfully for TenantId: {TenantId} by Employee {EmployeeId}",
|
|
response.Count, tenantId, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} document categories have been fetched successfully.", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while fetching document categories for TenantId: {TenantId} by Employee {EmployeeId}",
|
|
tenantId, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Server Error occured", 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateDocumentCategoryMasterAsync(CreateDocumentCategoryDto 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 Document Category in different tenant", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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 Document Category Master.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
|
|
}
|
|
var oldExists = await _context.DocumentCategoryMasters
|
|
.AnyAsync(dc => dc.Name == model.Name && dc.EntityTypeId == model.EntityTypeId && dc.TenantId == tenantId);
|
|
if (oldExists)
|
|
{
|
|
_logger.LogWarning("Document Category of {Name} is already exists in database for {TenantId}", model.Name, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Document Category already exists.", "Document Category already exists in database", 409);
|
|
}
|
|
// Mapping the DTO to Document Category Master Model
|
|
var documentCategory = _mapper.Map<DocumentCategoryMaster>(model);
|
|
documentCategory.CreatedAt = DateTime.UtcNow;
|
|
documentCategory.TenantId = tenantId;
|
|
|
|
_context.DocumentCategoryMasters.Add(documentCategory);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("New Document Category {DocumentCategoryId} was added by employee {EmployeeId}", documentCategory.Id, loggedInEmployee.Id);
|
|
|
|
// Mapping the Document Category Master Model to View Model
|
|
var response = _mapper.Map<DocumentCategoryVM>(documentCategory);
|
|
return ApiResponse<object>.SuccessResponse(response, "Document Category craeted Successfully", 201);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while adding new Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while adding new Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateDocumentCategoryMasterAsync(Guid id, CreateDocumentCategoryDto 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 Document Category in different tenant", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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 DOCUMENT CATEGORY MASTER.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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<object>.ErrorResponse("Invalid Data", "User has send invalid payload", 400);
|
|
}
|
|
|
|
var categoryTask = Task.Run(async () =>
|
|
{
|
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
return await context.DocumentCategoryMasters.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId);
|
|
});
|
|
var oldCategoryExistsTask = Task.Run(async () =>
|
|
{
|
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
return await context.DocumentCategoryMasters.AnyAsync(dc => dc.Name == model.Name && dc.Id != model.Id.Value && dc.EntityTypeId == model.EntityTypeId && dc.TenantId == tenantId);
|
|
});
|
|
|
|
await Task.WhenAll(categoryTask, oldCategoryExistsTask);
|
|
|
|
var documentCategory = categoryTask.Result;
|
|
var oldCategoryExists = oldCategoryExistsTask.Result;
|
|
|
|
// Checking if Document Category exists
|
|
if (documentCategory == null)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} tries to update Document Category, but not found in database", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Document Category not found", "Document Category not found", 404);
|
|
}
|
|
if (oldCategoryExists)
|
|
{
|
|
_logger.LogWarning("Document Category of {Name} is already exists in database for {TenantId} while updating document category", model.Name, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Document Category already exists.", "Document Category already exists in database", 409);
|
|
}
|
|
|
|
// Mapping DocumentCategoryMaster to BsonDocument
|
|
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(documentCategory);
|
|
|
|
// Mapping DocumentCategoryDto to DocumentCategoryMaster
|
|
_mapper.Map(model, documentCategory);
|
|
|
|
_context.DocumentCategoryMasters.Update(documentCategory);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Document Category {DocumentCategoryId} was updated by employee {EmployeeId}", documentCategory.Id, loggedInEmployee.Id);
|
|
|
|
// Saving the old entity in mongoDB
|
|
|
|
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
|
|
{
|
|
EntityId = documentCategory.Id.ToString(),
|
|
UpdatedById = loggedInEmployee.Id.ToString(),
|
|
OldObject = existingEntityBson,
|
|
UpdatedAt = DateTime.UtcNow
|
|
}, "DocumentCategoryModificationLog");
|
|
|
|
// Mapping DocumentCategoryMaster to DocumentCategoryVM
|
|
var response = _mapper.Map<DocumentCategoryVM>(documentCategory);
|
|
return ApiResponse<object>.SuccessResponse(response, "Document Category updated Successfully", 200);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while updating Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while updating Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteDocumentCategoryMasterAsync(Guid id, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
try
|
|
{
|
|
// Validation if employee is taking action in same tenant
|
|
if (tenantId != loggedInEmployee.TenantId)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} attempted to delete Document Category in different tenant", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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 DOCUMENT CATEGORY MASTER.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
}
|
|
|
|
var documentCategory = await _context.DocumentCategoryMasters.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId);
|
|
|
|
// Checking if Document Category exists
|
|
if (documentCategory == null)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} tries to delete Document Category, but not found in database", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Document Category not found", "Document Category not found", 404);
|
|
}
|
|
|
|
// Mapping DocumentCategoryMaster to BsonDocument
|
|
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(documentCategory);
|
|
|
|
_context.DocumentCategoryMasters.Remove(documentCategory);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Document Category {DocumentCategoryId} was deleted by employee {EmployeeId}", documentCategory.Id, loggedInEmployee.Id);
|
|
|
|
// Saving the old entity in mongoDB
|
|
|
|
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
|
|
{
|
|
EntityId = documentCategory.Id.ToString(),
|
|
UpdatedById = loggedInEmployee.Id.ToString(),
|
|
OldObject = existingEntityBson,
|
|
UpdatedAt = DateTime.UtcNow
|
|
}, "DocumentCategoryModificationLog");
|
|
|
|
// Mapping DocumentCategoryMatser to DocumentCategoryVM
|
|
var response = _mapper.Map<DocumentCategoryVM>(documentCategory);
|
|
return ApiResponse<object>.SuccessResponse(response, "Document Category deleted Successfully", 200);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while deleteing Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while deleteing Document Category by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region =================================================================== Document Type APIs ===================================================================
|
|
|
|
|
|
public async Task<ApiResponse<object>> GetDocumentTypeMasterListAsync(Guid? documentCategoryId, Employee loggedInEmployee, Guid tenantId)
|
|
{
|
|
try
|
|
{
|
|
// ✅ Tenant validation
|
|
if (tenantId != loggedInEmployee.TenantId)
|
|
{
|
|
_logger.LogWarning("Access denied. Employee {EmployeeId} (TenantId: {EmployeeTenantId}) attempted to fetch document types for TenantId: {RequestedTenantId}",
|
|
loggedInEmployee.Id, loggedInEmployee.TenantId, tenantId);
|
|
|
|
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have access to this information", 403);
|
|
}
|
|
|
|
// ✅ Build query
|
|
IQueryable<DocumentTypeMaster> documentTypeQuery = _context.DocumentTypeMasters
|
|
.AsNoTracking() // optimization: read-only
|
|
.Where(dc => dc.TenantId == tenantId);
|
|
|
|
// ✅ Apply optional filter
|
|
if (documentCategoryId.HasValue)
|
|
{
|
|
documentTypeQuery = documentTypeQuery.Where(dc => dc.DocumentCategoryId == documentCategoryId.Value);
|
|
}
|
|
|
|
// ✅ Fetch and map
|
|
var documentType = await documentTypeQuery.Include(dt => dt.DocumentCategory).ToListAsync();
|
|
var response = _mapper.Map<List<DocumentTypeVM>>(documentType);
|
|
|
|
_logger.LogInfo("{Count} document type fetched successfully for TenantId: {TenantId} by Employee {EmployeeId}",
|
|
response.Count, tenantId, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} document type have been fetched successfully.", 200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error occurred while fetching document type for TenantId: {TenantId} by Employee {EmployeeId}",
|
|
tenantId, loggedInEmployee.Id);
|
|
|
|
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Server Error occured", 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> CreateDocumentTypeMasterAsync(CreateDocumentTypeDto 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 Document Type in different tenant", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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 DOCUMENT TYPE MASTER.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
|
|
}
|
|
var oldExists = await _context.DocumentTypeMasters
|
|
.AnyAsync(dt => dt.Name == model.Name && dt.DocumentCategoryId == model.DocumentCategoryId && dt.TenantId == tenantId);
|
|
if (oldExists)
|
|
{
|
|
_logger.LogWarning("Document Type of {Name} is already exists in database for {TenantId} while creating new document type", model.Name, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Document Type already exists.", "Document Type already exists in database", 409);
|
|
}
|
|
// Mapping the DTO to Document Type Master Model
|
|
var documentType = _mapper.Map<DocumentTypeMaster>(model);
|
|
if (string.IsNullOrWhiteSpace(model.RegexExpression))
|
|
{
|
|
documentType.IsValidationRequired = false;
|
|
}
|
|
documentType.IsSystem = false;
|
|
documentType.IsActive = true;
|
|
documentType.CreatedAt = DateTime.UtcNow;
|
|
documentType.TenantId = tenantId;
|
|
|
|
_context.DocumentTypeMasters.Add(documentType);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("New Document Type {DocumentTypeId} was added by employee {EmployeeId}", documentType.Id, loggedInEmployee.Id);
|
|
|
|
// Mapping the Document Type Master Model to View Model
|
|
var response = _mapper.Map<DocumentTypeVM>(documentType);
|
|
return ApiResponse<object>.SuccessResponse(response, "Document Type craeted Successfully", 201);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while adding new Document Type by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while adding new Document Type by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> UpdateDocumentTypeMasterAsync(Guid id, CreateDocumentTypeDto 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 Document Type in different tenant", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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 DOCUMENT TYPE MASTER.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.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<object>.ErrorResponse("Invalid Data", "User has send invalid payload", 400);
|
|
}
|
|
|
|
var documentTypeTask = Task.Run(async () =>
|
|
{
|
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
return await context.DocumentTypeMasters.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.Id.Value && et.TenantId == tenantId);
|
|
});
|
|
var oldTypeExistsTask = Task.Run(async () =>
|
|
{
|
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
return await context.DocumentTypeMasters
|
|
.AnyAsync(dt => dt.Name == model.Name && dt.Id != model.Id.Value && dt.DocumentCategoryId == model.DocumentCategoryId && dt.TenantId == tenantId);
|
|
});
|
|
|
|
await Task.WhenAll(documentTypeTask, oldTypeExistsTask);
|
|
|
|
var documentType = documentTypeTask.Result;
|
|
var oldTypeExists = oldTypeExistsTask.Result;
|
|
|
|
// Checking if Document Type exists
|
|
if (documentType == null)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} tries to update Document Type, but not found in database", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Document Type not found", "Document Type not found", 404);
|
|
}
|
|
if (oldTypeExists)
|
|
{
|
|
_logger.LogWarning("Document Type of {Name} is already exists in database for {TenantId} while updating document Type", model.Name, tenantId);
|
|
return ApiResponse<object>.ErrorResponse("Document Type already exists.", "Document Type already exists in database", 409);
|
|
}
|
|
|
|
// Mapping DocumentTypeMaster to BsonDocument
|
|
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(documentType);
|
|
|
|
// Mapping DocumentTypeDto to DocumentTypeMaster
|
|
_mapper.Map(model, documentType);
|
|
|
|
_context.DocumentTypeMasters.Update(documentType);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Document Type {DocumentTypeId} was updated by employee {EmployeeId}", documentType.Id, loggedInEmployee.Id);
|
|
|
|
// Saving the old entity in mongoDB
|
|
|
|
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
|
|
{
|
|
EntityId = documentType.Id.ToString(),
|
|
UpdatedById = loggedInEmployee.Id.ToString(),
|
|
OldObject = existingEntityBson,
|
|
UpdatedAt = DateTime.UtcNow
|
|
}, "DocumentTypeModificationLog");
|
|
|
|
// Mapping DocumentTypeMaster to DocumentTypeVM
|
|
var response = _mapper.Map<DocumentTypeVM>(documentType);
|
|
return ApiResponse<object>.SuccessResponse(response, "Document Type updated Successfully", 200);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while updating Document Type by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while updating Document Type by employee {EmployeeId}", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500);
|
|
}
|
|
}
|
|
public async Task<ApiResponse<object>> DeleteDocumentTypeMasterAsync(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} Document Type in different tenant", loggedInEmployee.Id, action);
|
|
return ApiResponse<object>.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 DOCUMENT TYPE MASTER.", loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403);
|
|
}
|
|
|
|
var documentType = await _context.DocumentTypeMasters.FirstOrDefaultAsync(et => et.Id == id && et.TenantId == tenantId);
|
|
|
|
// Checking if Document Type exists
|
|
if (documentType == null)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} tries to {Action} Document Type, but not found in database", loggedInEmployee.Id, action);
|
|
return ApiResponse<object>.ErrorResponse("Document Type not found", "Document Type not found", 404);
|
|
}
|
|
if (documentType.IsSystem)
|
|
{
|
|
_logger.LogWarning("Employee {EmployeeId} tries to {Action} Document Type, but could not take action on system defined entity", loggedInEmployee.Id, action);
|
|
return ApiResponse<object>.ErrorResponse($"Document is system defined cannot be {action}d", $"Document is system defined cannot be {action}d", 400);
|
|
}
|
|
// Mapping DocumentTypeMatser to BsonDocument
|
|
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(documentType);
|
|
|
|
documentType.IsActive = isActive;
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInfo("Document Type {DocumentTypeId} was {Action}d by employee {EmployeeId}", documentType.Id, action, loggedInEmployee.Id);
|
|
|
|
// Saving the old entity in mongoDB
|
|
|
|
var mongoDBTask = _updateLogHelper.PushToUpdateLogsAsync(new UpdateLogsObject
|
|
{
|
|
EntityId = documentType.Id.ToString(),
|
|
UpdatedById = loggedInEmployee.Id.ToString(),
|
|
OldObject = existingEntityBson,
|
|
UpdatedAt = DateTime.UtcNow
|
|
}, "DocumentTypeModificationLog");
|
|
|
|
// Mapping DocumentTypeMatser to DocumentTypeVM
|
|
var response = _mapper.Map<DocumentTypeVM>(documentType);
|
|
return ApiResponse<object>.SuccessResponse(response, $"Document Type {action}d Successfully", 200);
|
|
}
|
|
catch (DbUpdateException dbEx)
|
|
{
|
|
_logger.LogError(dbEx, "Database Exception occured while {Action}ing Document Type by employee {EmployeeId}", action, loggedInEmployee.Id);
|
|
return ApiResponse<object>.ErrorResponse("Internal Error occured", ExceptionMapper(dbEx), 500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Exception occured while {Action}ing Document Type by employee {EmployeeId}", action, loggedInEmployee.Id);
|
|
return ApiResponse<object>.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
|
|
}
|
|
}
|