From 1d50d4987a0ba5541595ac54fe6559b261f70db9 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 2 Sep 2025 14:19:03 +0530 Subject: [PATCH] added the crud opration for document modules --- .../CreateDocumentCategoryDto.cs | 10 + .../DocumentManager/CreateDocumentTypeDto.cs | 14 + .../Controllers/MasterController.cs | 143 +-- Marco.Pms.Services/Helpers/MasterHelper.cs | 459 ---------- .../MappingProfiles/MappingProfile.cs | 2 + Marco.Pms.Services/Program.cs | 1 - Marco.Pms.Services/Service/MasterService.cs | 816 +++++++++++++++++- .../ServiceInterfaces/IMasterService.cs | 21 + 8 files changed, 906 insertions(+), 560 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentCategoryDto.cs create mode 100644 Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentTypeDto.cs delete mode 100644 Marco.Pms.Services/Helpers/MasterHelper.cs diff --git a/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentCategoryDto.cs b/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentCategoryDto.cs new file mode 100644 index 0000000..743c2cb --- /dev/null +++ b/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentCategoryDto.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.Dtos.DocumentManager +{ + public class CreateDocumentCategoryDto + { + public Guid? Id { get; set; } + public required string Name { get; set; } + public required string Description { get; set; } + public required Guid EntityTypeId { get; set; } + } +} diff --git a/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentTypeDto.cs b/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentTypeDto.cs new file mode 100644 index 0000000..b32302a --- /dev/null +++ b/Marco.Pms.Model/Dtos/DocumentManager/CreateDocumentTypeDto.cs @@ -0,0 +1,14 @@ +namespace Marco.Pms.Model.Dtos.DocumentManager +{ + public class CreateDocumentTypeDto + { + public Guid? Id { get; set; } + public required string Name { get; set; } = string.Empty; + public string? RegexExpression { get; set; } + public required string AllowedContentType { get; set; } + public required double MaxSizeAllowedInMB { get; set; } = 2; + public bool IsValidationRequired { get; set; } + public bool IsMandatory { get; set; } + public required Guid DocumentCategoryId { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index bab2a5c..0c4e0e1 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -9,7 +9,6 @@ using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Forum; using Marco.Pms.Model.ViewModels.Master; -using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; @@ -27,15 +26,13 @@ namespace Marco.Pms.Services.Controllers private readonly ApplicationDbContext _context; private readonly UserHelper _userHelper; private readonly ILoggingService _logger; - private readonly MasterHelper _masterHelper; private readonly IMasterService _masterService; private readonly Guid tenantId; - public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, MasterHelper masterHelper, IMasterService masterService) + public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, IMasterService masterService) { _context = context; _userHelper = userHelper; _logger = logger; - _masterHelper = masterHelper; _masterService = masterService; tenantId = userHelper.GetTenantId(); } @@ -696,37 +693,32 @@ namespace Marco.Pms.Services.Controllers [HttpGet("work-status")] public async Task GetWorkStatusMasterList() { - var response = await _masterHelper.GetWorkStatusList(); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetWorkStatusList(loggedInEmpoyee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("work-status")] public async Task CreateWorkStatusMaster([FromBody] CreateWorkStatusMasterDto createWorkStatusDto) { - if (!ModelState.IsValid) - { - var errors = ModelState.Values - .SelectMany(v => v.Errors) - .Select(e => e.ErrorMessage) - .ToList(); - _logger.LogWarning("User sent Invalid Date while marking attendance"); - return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); - } - var response = await _masterHelper.CreateWorkStatus(createWorkStatusDto); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.CreateWorkStatus(createWorkStatusDto, loggedInEmpoyee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("work-status/edit/{id}")] public async Task UpdateWorkStatusMaster(Guid id, [FromBody] UpdateWorkStatusMasterDto updateWorkStatusDto) { - var response = await _masterHelper.UpdateWorkStatus(id, updateWorkStatusDto); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdateWorkStatus(id, updateWorkStatusDto, loggedInEmpoyee, tenantId); return StatusCode(response.StatusCode, response); } [HttpDelete("work-status/{id}")] public async Task DeleteWorkStatusMaster(Guid id) { - var response = await _masterHelper.DeleteWorkStatus(id); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeleteWorkStatus(id, loggedInEmpoyee, tenantId); return StatusCode(response.StatusCode, response); } @@ -737,68 +729,44 @@ namespace Marco.Pms.Services.Controllers [HttpGet("contact-categories")] public async Task GetContactCategoryMasterList() { - var response = await _masterHelper.GetContactCategoriesList(); - return Ok(response); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetContactCategoriesList(loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); } [HttpGet("contact-category/{id}")] public async Task GetContactCategoryMaster(Guid id) { - var response = await _masterHelper.GetContactCategoryById(id); - if (response.StatusCode == 200) - { - return Ok(response); - } - else if (response.StatusCode == 404) - { - return NotFound(response); - } - else - { - return BadRequest(response); - } + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetContactCategoryById(id, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } [HttpPost("contact-category")] public async Task CreateContactCategoryMaster([FromBody] CreateContactCategoryDto contactCategoryDto) { - var response = await _masterHelper.CreateContactCategory(contactCategoryDto); - if (response.StatusCode == 200) - { - return Ok(response); - } - else if (response.StatusCode == 409) - { - return Conflict(response); - } - else - { - return BadRequest(response); - } + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.CreateContactCategory(contactCategoryDto, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } [HttpPost("contact-category/edit/{id}")] public async Task UpdateContactCategoryMaster(Guid id, [FromBody] UpdateContactCategoryDto updateContactCategoryDto) { - var response = await _masterHelper.UpdateContactCategory(id, updateContactCategoryDto); - if (response.StatusCode == 200) - { - return Ok(response); - } - else if (response.StatusCode == 404) - { - return NotFound(response); - } - else - { - return BadRequest(response); - } + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdateContactCategory(id, updateContactCategoryDto, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } [HttpDelete("contact-category/{id}")] public async Task DeletecontactCategoryMaster(Guid id) { - var response = await _masterHelper.DeleteContactCategory(id); - return Ok(response); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeleteContactCategory(id, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion @@ -808,61 +776,37 @@ namespace Marco.Pms.Services.Controllers [HttpGet("contact-tags")] public async Task GetContactTagMasterList() { - var response = await _masterHelper.GetContactTags(); - return Ok(response); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.GetContactTags(loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } [HttpPost("contact-tag")] public async Task CreateContactTagMaster([FromBody] CreateContactTagDto contactTagDto) { - if (!ModelState.IsValid) - { - var errors = ModelState.Values - .SelectMany(v => v.Errors) - .Select(e => e.ErrorMessage) - .ToList(); - _logger.LogWarning("User sent Invalid Date while marking attendance"); - return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); - } - var response = await _masterHelper.CreateContactTag(contactTagDto); - if (response.StatusCode == 200) - { - return Ok(response); - } - else if (response.StatusCode == 409) - { - return Conflict(response); - } - else - { - return BadRequest(response); - } + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.CreateContactTag(contactTagDto, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } [HttpPost("contact-tag/edit/{id}")] public async Task UpdateContactTagMaster(Guid id, [FromBody] UpdateContactTagDto updateContactTagDto) { - var response = await _masterHelper.UpdateContactTag(id, updateContactTagDto); - if (response.StatusCode == 200) - { - return Ok(response); - } - else if (response.StatusCode == 404) - { - return NotFound(response); - } - else - { - return BadRequest(response); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.UpdateContactTag(id, updateContactTagDto, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); - } } [HttpDelete("contact-tag/{id}")] public async Task DeletecontactTagMaster(Guid id) { - var response = await _masterHelper.DeleteContactTag(id); - return Ok(response); + var loggedInEmpoyee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.DeleteContactTag(id, loggedInEmpoyee, tenantId); + return StatusCode(response.StatusCode, response); + } #endregion @@ -961,6 +905,7 @@ namespace Marco.Pms.Services.Controllers } #endregion + #region =================================================================== Document Type APIs =================================================================== [HttpGet("document-type/list")] diff --git a/Marco.Pms.Services/Helpers/MasterHelper.cs b/Marco.Pms.Services/Helpers/MasterHelper.cs deleted file mode 100644 index d50a603..0000000 --- a/Marco.Pms.Services/Helpers/MasterHelper.cs +++ /dev/null @@ -1,459 +0,0 @@ -using Marco.Pms.DataAccess.Data; -using Marco.Pms.Model.Directory; -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.Utilities; -using Marco.Pms.Model.ViewModels.Master; -using Marco.Pms.Services.Service; -using MarcoBMS.Services.Helpers; -using MarcoBMS.Services.Service; -using Microsoft.EntityFrameworkCore; - -namespace Marco.Pms.Services.Helpers -{ - public class MasterHelper - { - private readonly ApplicationDbContext _context; - private readonly ILoggingService _logger; - private readonly UserHelper _userHelper; - private readonly PermissionServices _permission; - private readonly Guid tenantId; - - public MasterHelper(ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permission) - { - _context = context; - _logger = logger; - _userHelper = userHelper; - _permission = permission; - tenantId = userHelper.GetTenantId(); - } - #region =================================================================== Contact Category APIs =================================================================== - - public async Task> CreateContactCategory(CreateContactCategoryDto contactCategoryDto) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - 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.SuccessResponse(categoryVM, "Category Created Successfully", 200); - } - _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact category.", LoggedInEmployee.Id); - return ApiResponse.ErrorResponse("Category already existed", "Category already existed", 409); - } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); - return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); - } - public async Task> UpdateContactCategory(Guid id, UpdateContactCategoryDto contactCategoryDto) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - 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.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.ErrorResponse("Category not found", "Category not found", 404); - } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); - return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); - } - public async Task> GetContactCategoriesList() - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - var categoryList = await _context.ContactCategoryMasters.Where(c => c.TenantId == tenantId).ToListAsync(); - List contactCategories = new List(); - 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.SuccessResponse(contactCategories, System.String.Format("{0} contact categories fetched successfully", contactCategories.Count), 200); - } - public async Task> GetContactCategoryById(Guid id) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - 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.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.ErrorResponse("Category not found", "Category not found", 404); - } - public async Task> DeleteContactCategory(Guid id) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - ContactCategoryMaster? contactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); - if (contactCategory != null) - { - List? existingContacts = await _context.Contacts.AsNoTracking().Where(c => c.ContactCategoryId == contactCategory.Id).ToListAsync(); - if (existingContacts.Count > 0) - { - List? contacts = new List(); - 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.SuccessResponse(new { }, "Category deleted successfully", 200); - } - #endregion - - #region =================================================================== Contact Tag APIs =================================================================== - - public async Task> GetContactTags() - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - var taglist = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync(); - List contactTags = new List(); - 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.SuccessResponse(contactTags, System.String.Format("{0} contact tags fetched successfully", contactTags.Count), 200); - } - public async Task> CreateContactTag(CreateContactTagDto contactTagDto) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - 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.SuccessResponse(tagVM, "Tag Created Successfully", 200); - } - _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact tag.", LoggedInEmployee.Id); - return ApiResponse.ErrorResponse("Tag already existed", "Tag already existed", 409); - } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); - return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); - } - public async Task> UpdateContactTag(Guid id, UpdateContactTagDto contactTagDto) - { - Employee LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - 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(); - - ContactTagVM contactTagVm = contactTag.ToContactTagVMFromContactTagMaster(); - - - - _logger.LogInfo("Contact tag master {ConatctTagId} updated successfully by employee {EmployeeId}", contactTagVm.Id, LoggedInEmployee.Id); - return ApiResponse.SuccessResponse(contactTagVm, "Contact Tag master updated successfully", 200); - } - _logger.LogWarning("Contact Tag master {ContactTagId} not found in database", id); - return ApiResponse.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.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); - } - public async Task> DeleteContactTag(Guid id) - { - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - ContactTagMaster? contactTag = await _context.ContactTagMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); - if (contactTag != null) - { - List? 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.SuccessResponse(new { }, "Tag deleted successfully", 200); - } - - #endregion - - #region =================================================================== Work Status APIs =================================================================== - - public async Task> GetWorkStatusList() - { - _logger.LogInfo("GetWorkStatusList called."); - - try - { - // Step 1: Get logged-in employee info - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - // Step 2: 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.ErrorResponse("You don't have access", "Don't have access to take action", 403); - } - - // Step 3: 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 4: Return successful response - return ApiResponse.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.ErrorResponse("An error occurred", "Unable to fetch work status list", 500); - } - } - public async Task> CreateWorkStatus(CreateWorkStatusMasterDto createWorkStatusDto) - { - _logger.LogInfo("CreateWorkStatus called with Name: {Name}", createWorkStatusDto.Name ?? ""); - - try - { - // Step 1: Get logged-in employee - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - // Step 2: Check if user has permission to manage master data - var hasManageMasterPermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); - if (!hasManageMasterPermission) - { - _logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id); - return ApiResponse.ErrorResponse("You don't have access", "Don't have access to take action", 403); - } - - // Step 3: 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.ErrorResponse("Work status already exists", "Work status already exists", 400); - } - - // Step 4: 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.SuccessResponse(workStatus, "Work status created successfully", 200); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurred while creating work status"); - return ApiResponse.ErrorResponse("An error occurred", "Unable to create work status", 500); - } - } - public async Task> UpdateWorkStatus(Guid id, UpdateWorkStatusMasterDto updateWorkStatusDto) - { - _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.ErrorResponse("Invalid data provided", "The provided work status ID is invalid", 400); - } - - // Step 2: Get logged-in employee - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - // Step 3: 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.ErrorResponse("Access denied", "You do not have permission to update this work status", 403); - } - - // Step 4: 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.ErrorResponse("Work status not found", "No work status found with the provided ID", 404); - } - - // Step 5: 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.ErrorResponse("Work status with the same name already exists", "Duplicate name", 400); - } - - // Step 6: 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.SuccessResponse(workStatus, "Work status updated successfully", 200); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurred while updating work status ID: {Id}", id); - return ApiResponse.ErrorResponse("An error occurred", "Unable to update the work status at this time", 500); - } - } - public async Task> DeleteWorkStatus(Guid id) - { - _logger.LogInfo("DeleteWorkStatus called for Id: {Id}", id); - - try - { - // Step 1: Get logged-in employee - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - - // 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.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.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.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.SuccessResponse(new { }, "Work status deleted successfully", 200); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error occurred while deleting WorkStatus Id: {Id}", id); - return ApiResponse.ErrorResponse("An error occurred", "Unable to delete work status", 500); - } - } - - #endregion - } -} diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 8549bcf..d58ebe1 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -314,8 +314,10 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); CreateMap(); + CreateMap(); CreateMap(); + CreateMap(); #endregion diff --git a/Marco.Pms.Services/Program.cs b/Marco.Pms.Services/Program.cs index 0b06de0..811c3de 100644 --- a/Marco.Pms.Services/Program.cs +++ b/Marco.Pms.Services/Program.cs @@ -186,7 +186,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index 290ec3d..1e3ede3 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -1,10 +1,13 @@ 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.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; @@ -46,6 +49,410 @@ namespace Marco.Pms.Services.Service _cache = cache; } + #region =================================================================== Contact Category APIs =================================================================== + + public async Task> 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.SuccessResponse(categoryVM, "Category Created Successfully", 200); + } + _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact category.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Category already existed", "Category already existed", 409); + } + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); + } + public async Task> 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.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.ErrorResponse("Category not found", "Category not found", 404); + } + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); + } + public async Task> GetContactCategoriesList(Employee loggedInEmployee, Guid tenantId) + { + var categoryList = await _context.ContactCategoryMasters.Where(c => c.TenantId == tenantId).ToListAsync(); + List contactCategories = new List(); + 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.SuccessResponse(contactCategories, System.String.Format("{0} contact categories fetched successfully", contactCategories.Count), 200); + } + public async Task> 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.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.ErrorResponse("Category not found", "Category not found", 404); + } + public async Task> DeleteContactCategory(Guid id, Employee loggedInEmployee, Guid tenantId) + { + ContactCategoryMaster? contactCategory = await _context.ContactCategoryMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); + if (contactCategory != null) + { + List? existingContacts = await _context.Contacts.AsNoTracking().Where(c => c.ContactCategoryId == contactCategory.Id).ToListAsync(); + if (existingContacts.Count > 0) + { + List? contacts = new List(); + 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.SuccessResponse(new { }, "Category deleted successfully", 200); + } + #endregion + + #region =================================================================== Contact Tag APIs =================================================================== + + public async Task> GetContactTags(Employee loggedInEmployee, Guid tenantId) + { + var taglist = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync(); + List contactTags = new List(); + 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.SuccessResponse(contactTags, System.String.Format("{0} contact tags fetched successfully", contactTags.Count), 200); + } + public async Task> 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.SuccessResponse(tagVM, "Tag Created Successfully", 200); + } + _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing contact tag.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Tag already existed", "Tag already existed", 409); + } + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); + } + public async Task> 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.SuccessResponse(contactTagVm, "Contact Tag master updated successfully", 200); + } + _logger.LogWarning("Contact Tag master {ContactTagId} not found in database", id); + return ApiResponse.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.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); + } + public async Task> DeleteContactTag(Guid id, Employee loggedInEmployee, Guid tenantId) + { + ContactTagMaster? contactTag = await _context.ContactTagMasters.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); + if (contactTag != null) + { + List? 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.SuccessResponse(new { }, "Tag deleted successfully", 200); + } + + #endregion + + #region =================================================================== Work Status APIs =================================================================== + + public async Task> 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.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.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.ErrorResponse("An error occurred", "Unable to fetch work status list", 500); + } + } + public async Task> 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.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.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.SuccessResponse(workStatus, "Work status created successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while creating work status"); + return ApiResponse.ErrorResponse("An error occurred", "Unable to create work status", 500); + } + } + public async Task> 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.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.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.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.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.SuccessResponse(workStatus, "Work status updated successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while updating work status ID: {Id}", id); + return ApiResponse.ErrorResponse("An error occurred", "Unable to update the work status at this time", 500); + } + } + public async Task> 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.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.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.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.SuccessResponse(new { }, "Work status deleted successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while deleting WorkStatus Id: {Id}", id); + return ApiResponse.ErrorResponse("An error occurred", "Unable to delete work status", 500); + } + } + + #endregion + #region =================================================================== Expenses Type APIs =================================================================== public async Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive) @@ -442,7 +849,7 @@ namespace Marco.Pms.Services.Service var hasManagePermission = await _permission.HasPermission(PermissionsMaster.ManageMasters, loggedInEmployee.Id); if (!hasManagePermission) { - _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing EXPENSE STATUS MASTER.", loggedInEmployee.Id); + _logger.LogWarning("Access DENIED for employee {EmployeeId} for managing PAYMENT MODE MASTER.", loggedInEmployee.Id); return ApiResponse.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); } @@ -542,6 +949,206 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Server Error", "Server Error occured", 500); } } + public async Task> 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.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.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.ErrorResponse("Document Category already exists.", "Document Category already exists in database", 409); + } + // Mapping the DTO to Document Category Master Model + var documentCategory = _mapper.Map(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(documentCategory); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } + public async Task> 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.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.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + // Validating the prvided data + if (model.Id != id) + { + _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); + } + + var 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.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.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.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(documentCategory); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } + public async Task> 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.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.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.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(documentCategory); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion @@ -590,7 +1197,214 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("Internal Server Error", "Server Error occured", 500); } } + public async Task> 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.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.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.ErrorResponse("Document Type already exists.", "Document Type already exists in database", 409); + } + // Mapping the DTO to Document Type Master Model + var documentType = _mapper.Map(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(documentType); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } + public async Task> 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.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.ErrorResponse("Access Denied.", "You do not have permission to Manage masters", 403); + } + + // Validating the prvided data + if (model.Id != id) + { + _logger.LogWarning("Employee {EmployeeId} provide different Ids in payload and path variable", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Invalid Data", "User has send invalid payload", 400); + } + + var 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.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.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.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(documentType); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } + public async Task> 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.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.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.ErrorResponse("Document Type not found", "Document Type not found", 404); + } + + // 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(documentType); + return ApiResponse.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.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.ErrorResponse("Internal Error occured", ExceptionMapper(ex), 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index c85b183..b39abfd 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -6,6 +6,27 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces { public interface IMasterService { + #region =================================================================== Contact Category APIs =================================================================== + Task> CreateContactCategory(CreateContactCategoryDto contactCategoryDto, Employee loggedInEmployee, Guid tenantId); + Task> UpdateContactCategory(Guid id, UpdateContactCategoryDto contactCategoryDto, Employee loggedInEmployee, Guid tenantId); + Task> GetContactCategoriesList(Employee loggedInEmployee, Guid tenantId); + Task> GetContactCategoryById(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> DeleteContactCategory(Guid id, Employee loggedInEmployee, Guid tenantId); + #endregion + #region =================================================================== Contact Tag APIs =================================================================== + Task> GetContactTags(Employee loggedInEmployee, Guid tenantId); + Task> CreateContactTag(CreateContactTagDto contactTagDto, Employee loggedInEmployee, Guid tenantId); + Task> UpdateContactTag(Guid id, UpdateContactTagDto contactTagDto, Employee loggedInEmployee, Guid tenantId); + Task> DeleteContactTag(Guid id, Employee loggedInEmployee, Guid tenantId); + + #endregion + #region =================================================================== Work Status APIs =================================================================== + Task> GetWorkStatusList(Employee loggedInEmployee, Guid tenantId); + Task> CreateWorkStatus(CreateWorkStatusMasterDto createWorkStatusDto, Employee loggedInEmployee, Guid tenantId); + Task> UpdateWorkStatus(Guid id, UpdateWorkStatusMasterDto updateWorkStatusDto, Employee loggedInEmployee, Guid tenantId); + Task> DeleteWorkStatus(Guid id, Employee loggedInEmployee, Guid tenantId); + #endregion + #region =================================================================== Expenses Type APIs =================================================================== Task> GetExpenseTypeListAsync(Employee loggedInEmployee, Guid tenantId, bool isActive); Task> CreateExpenseTypeAsync(ExpensesTypeMasterDto model, Employee loggedInEmployee, Guid tenantId);