From 8a36ffe6523b7b2e1d01c181f6f185d74eca6718 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 31 Oct 2025 13:21:13 +0530 Subject: [PATCH] Added the API to Map Requisition Status with child --- .../Inventory/RequisitionStatusMappingDto.cs | 9 ++ .../Inventory/RequisitionStatusMappingVM.cs | 10 ++ .../Controllers/MasterController.cs | 8 ++ .../MappingProfiles/MappingProfile.cs | 1 + Marco.Pms.Services/Service/MasterService.cs | 113 ++++++++++++++++++ .../ServiceInterfaces/IMasterService.cs | 1 + 6 files changed, 142 insertions(+) create mode 100644 Marco.Pms.Model/Dtos/Inventory/RequisitionStatusMappingDto.cs create mode 100644 Marco.Pms.Model/ViewModels/Inventory/RequisitionStatusMappingVM.cs diff --git a/Marco.Pms.Model/Dtos/Inventory/RequisitionStatusMappingDto.cs b/Marco.Pms.Model/Dtos/Inventory/RequisitionStatusMappingDto.cs new file mode 100644 index 0000000..54ff64b --- /dev/null +++ b/Marco.Pms.Model/Dtos/Inventory/RequisitionStatusMappingDto.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.Dtos.Inventory +{ + public class RequisitionStatusMappingDto + { + public Guid RequisitionStatusId { get; set; } + public Guid NextRequisitionStatusId { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/Inventory/RequisitionStatusMappingVM.cs b/Marco.Pms.Model/ViewModels/Inventory/RequisitionStatusMappingVM.cs new file mode 100644 index 0000000..5717c8b --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Inventory/RequisitionStatusMappingVM.cs @@ -0,0 +1,10 @@ +namespace Marco.Pms.Model.ViewModels.Inventory +{ + public class RequisitionStatusMappingVM + { + public Guid Id { get; set; } + public RequisitionStatusVM? PreviousRequisitionStatus { get; set; } + public RequisitionStatusVM? RequisitionStatus { get; set; } + public RequisitionStatusVM? NextRequisitionStatus { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/MasterController.cs b/Marco.Pms.Services/Controllers/MasterController.cs index 5649f63..89d6b62 100644 --- a/Marco.Pms.Services/Controllers/MasterController.cs +++ b/Marco.Pms.Services/Controllers/MasterController.cs @@ -1064,6 +1064,14 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpPost("requisition-status/mapping")] + public async Task AddRequisitionStatusLink([FromBody] RequisitionStatusMappingDto model) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _masterService.AddRequisitionStatusLinkAsync(model, loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + [HttpPut("requisition-status/edit/{id}")] public async Task UpdateRequisitionStatus(Guid id, [FromBody] RequisitionStatusDto model) { diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index cfeb8f3..be90cdd 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -418,6 +418,7 @@ namespace Marco.Pms.Services.MappingProfiles #region ======================================================= Requisition Status Master ======================================================= CreateMap(); CreateMap(); + CreateMap(); #endregion #region ======================================================= Purchase Order Status Master ======================================================= diff --git a/Marco.Pms.Services/Service/MasterService.cs b/Marco.Pms.Services/Service/MasterService.cs index ed1c12a..094f80b 100644 --- a/Marco.Pms.Services/Service/MasterService.cs +++ b/Marco.Pms.Services/Service/MasterService.cs @@ -3377,6 +3377,119 @@ namespace Marco.Pms.Services.Service } } + + public async Task> AddRequisitionStatusLinkAsync(RequisitionStatusMappingDto model, Employee loggedInEmployee, Guid tenantId) + { + // Start: API entry log + _logger.LogInfo("AddRequisitionStatusLinkAsync started by Employee: {EmployeeId} for Tenant: {TenantId}", loggedInEmployee.Id, tenantId); + + // Validate the Requisition Status existence + var requisitionStatus = await _context.RequisitionStatus + .FirstOrDefaultAsync(rs => rs.Id == model.RequisitionStatusId && rs.TenantId == tenantId && rs.IsActive); + if (requisitionStatus == null) + { + _logger.LogWarning("Requisition Status not found for Id: {Id}, Tenant: {TenantId}", model.RequisitionStatusId, tenantId); + return ApiResponse.ErrorResponse( + "Requisition Status not found", "No active requisition status exists with the provided Id.", 404); + } + + // Validate the Next Requisition Status existence + var nextRequisitionStatus = await _context.RequisitionStatus + .FirstOrDefaultAsync(rs => rs.Id == model.NextRequisitionStatusId && rs.TenantId == tenantId && rs.IsActive); + if (nextRequisitionStatus == null) + { + _logger.LogWarning("Next Requisition Status not found for Id: {Id}, Tenant: {TenantId}", model.NextRequisitionStatusId, tenantId); + return ApiResponse.ErrorResponse( + "Next Requisition Status not found", "No active next requisition status exists with the provided Id.", 404); + } + + try + { + if (model.IsActive) + { + // Check if mapping already exists + var alreadyExists = await _context.RequisitionStatusMappings + .AnyAsync(rsm => rsm.RequisitionStatusId == model.RequisitionStatusId + && rsm.NextRequisitionStatusId == model.NextRequisitionStatusId); + if (alreadyExists) + { + _logger.LogWarning("Duplicate mapping attempted between {RequisitionStatusId} and {NextRequisitionStatusId}", model.RequisitionStatusId, model.NextRequisitionStatusId); + return ApiResponse.ErrorResponse( + "Mapping already exists", "A mapping between these statuses already exists.", 409); + } + + // Prevent mapping if next status already has a parent + var hasParent = await _context.RequisitionStatusMappings + .AnyAsync(rsm => rsm.NextRequisitionStatusId == model.NextRequisitionStatusId); + if (hasParent) + { + _logger.LogWarning("Next Requisition Status {NextRequisitionStatusId} already has a parent, cannot re-map.", model.NextRequisitionStatusId); + return ApiResponse.ErrorResponse( + $"Requisition \"{nextRequisitionStatus.Name}\" already has a parent and cannot be mapped again.", + $"Requisition \"{nextRequisitionStatus.Name}\" already has a parent and cannot be mapped again.", 409); + } + + // Find any previous mapping for ordering/trace + var previousMapping = await _context.RequisitionStatusMappings + .Include(rsm => rsm.RequisitionStatus) + .FirstOrDefaultAsync(rsm => rsm.NextRequisitionStatusId == model.RequisitionStatusId); + + // Create a new mapping + var newMapping = new RequisitionStatusMapping + { + Id = Guid.NewGuid(), + PreviousRequisitionStatusId = previousMapping?.RequisitionStatusId, + RequisitionStatusId = requisitionStatus.Id, + NextRequisitionStatusId = nextRequisitionStatus.Id, + TenantId = tenantId + }; + _context.RequisitionStatusMappings.Add(newMapping); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Created mapping: {Id} from {RequisitionStatusId} to {NextRequisitionStatusId} for Tenant {TenantId}", newMapping.Id, requisitionStatus.Id, nextRequisitionStatus.Id, tenantId); + + var vm = new RequisitionStatusMappingVM + { + Id = newMapping.Id, + PreviousRequisitionStatus = _mapper.Map(previousMapping?.RequisitionStatus), + RequisitionStatus = _mapper.Map(requisitionStatus), + NextRequisitionStatus = _mapper.Map(nextRequisitionStatus) + }; + + return ApiResponse.SuccessResponse(vm, "Requisition Status mapping added successfully.", 200); + } + else + { + // Remove mapping + var mapping = await _context.RequisitionStatusMappings + .Include(rsm => rsm.PreviousRequisitionStatus) + .Include(rsm => rsm.RequisitionStatus) + .Include(rsm => rsm.NextRequisitionStatus) + .FirstOrDefaultAsync(rsm => rsm.RequisitionStatusId == model.RequisitionStatusId + && rsm.NextRequisitionStatusId == model.NextRequisitionStatusId); + if (mapping == null) + { + _logger.LogWarning("No mapping found to remove for {RequisitionStatusId} to {NextRequisitionStatusId}", model.RequisitionStatusId, model.NextRequisitionStatusId); + return ApiResponse.ErrorResponse("Mapping not found", "No mapping exists to remove.", 404); + } + + _context.RequisitionStatusMappings.Remove(mapping); + await _context.SaveChangesAsync(); + + _logger.LogInfo("Mapping removed: {Id} from {RequisitionStatusId} to {NextRequisitionStatusId}", mapping.Id, model.RequisitionStatusId, model.NextRequisitionStatusId); + + var vm = _mapper.Map(mapping); + return ApiResponse.SuccessResponse(vm, "Requisition Status mapping removed successfully.", 200); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error processing AddRequisitionStatusLinkAsync for Tenant: {TenantId}, Employee: {EmployeeId}", tenantId, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Server Error", "An error occurred while processing your request.", 500); + } + } + + public async Task> UpdateRequisitionStatusAsync(Guid id, RequisitionStatusDto model, Employee loggedInEmployee, Guid tenantId) { try diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs index aa752d3..b61ef23 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IMasterService.cs @@ -139,6 +139,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetRequisitionStatusListAsync(bool isActive, Employee loggedInEmployee, Guid tenantId); Task> GetRequisitionStatusDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId); Task> CreateRequisitionStatusAsync(RequisitionStatusDto model, Employee loggedInEmployee, Guid tenantId); + Task> AddRequisitionStatusLinkAsync(RequisitionStatusMappingDto model, Employee loggedInEmployee, Guid tenantId); Task> UpdateRequisitionStatusAsync(Guid id, RequisitionStatusDto model, Employee loggedInEmployee, Guid tenantId); Task> DeleteRequisitionStatusAsync(Guid id, bool active, Employee loggedInEmployee, Guid tenantId); #endregion