Added the API to Map Purchase Order Status with child

This commit is contained in:
ashutosh.nehete 2025-10-31 14:44:38 +05:30
parent 8a36ffe652
commit ffb9e6508f
5 changed files with 141 additions and 6 deletions

View File

@ -0,0 +1,9 @@
namespace Marco.Pms.Model.Dtos.Inventory
{
public class PurchaseStatusMappingDto
{
public Guid PurchaseStatusId { get; set; }
public Guid NextPurchaseStatusId { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -0,0 +1,10 @@
namespace Marco.Pms.Model.ViewModels.Inventory
{
public class PurchaseStatusMappingVM
{
public Guid Id { get; set; }
public PurchaseOrderStatusVM? PreviousPurchaseStatus { get; set; }
public PurchaseOrderStatusVM? PurchaseStatus { get; set; }
public PurchaseOrderStatusVM? NextPurchaseStatus { get; set; }
}
}

View File

@ -1116,6 +1116,14 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response);
}
[HttpPost("purchase-order-status/mapping")]
public async Task<IActionResult> AddPurchaseOrderStatusLink([FromBody] PurchaseStatusMappingDto model)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _masterService.AddPurchaseOrderStatusLinkAsync(model, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
}
[HttpPut("purchase-order-status/edit/{id}")]
public async Task<IActionResult> UpdatePurchaseOrderStatus(Guid id, [FromBody] PurchaseOrderStatusDto model)
{

View File

@ -3377,7 +3377,6 @@ namespace Marco.Pms.Services.Service
}
}
public async Task<ApiResponse<object>> AddRequisitionStatusLinkAsync(RequisitionStatusMappingDto model, Employee loggedInEmployee, Guid tenantId)
{
// Start: API entry log
@ -3488,8 +3487,6 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An error occurred while processing your request.", 500);
}
}
public async Task<ApiResponse<object>> UpdateRequisitionStatusAsync(Guid id, RequisitionStatusDto model, Employee loggedInEmployee, Guid tenantId)
{
try
@ -3639,7 +3636,7 @@ namespace Marco.Pms.Services.Service
var purchaseOrderStatus = await _context.PurchaseOrderStatus.FirstOrDefaultAsync(pos => pos.Id == id && pos.TenantId == tenantId);
if (purchaseOrderStatus == null)
{
_logger.LogWarning("Purchase Order Status {PurchaseOrderStatusId} not found in database for tenant {TenantId}", id, tenantId);
_logger.LogWarning("Purchase Order Status {PurchaseStatusId} not found in database for tenant {TenantId}", id, tenantId);
return ApiResponse<object>.ErrorResponse("Purchase Order Status not found", "Purchase Order Status not found in database for current tenant", 404);
}
var purchaseOrderStatusMapping = await _context.PurchaseStatusMappings
@ -3716,6 +3713,116 @@ namespace Marco.Pms.Services.Service
}
}
public async Task<ApiResponse<object>> AddPurchaseOrderStatusLinkAsync(PurchaseStatusMappingDto model, Employee loggedInEmployee, Guid tenantId)
{
// Start: API entry log
_logger.LogInfo("AddPurchaseOrderStatusLinkAsync started by Employee: {EmployeeId} for Tenant: {TenantId}", loggedInEmployee.Id, tenantId);
// Validate the Purchase Order Status existence
var purchaseOrderStatus = await _context.PurchaseOrderStatus
.FirstOrDefaultAsync(rs => rs.Id == model.PurchaseStatusId && rs.TenantId == tenantId && rs.IsActive);
if (purchaseOrderStatus == null)
{
_logger.LogWarning("Purchase Order Status not found for Id: {Id}, Tenant: {TenantId}", model.PurchaseStatusId, tenantId);
return ApiResponse<object>.ErrorResponse(
"Purchase Order Status not found", "No active purchase Order status exists with the provided Id.", 404);
}
// Validate the Next Purchase Order Status existence
var nextPurchaseOrderStatus = await _context.PurchaseOrderStatus
.FirstOrDefaultAsync(rs => rs.Id == model.NextPurchaseStatusId && rs.TenantId == tenantId && rs.IsActive);
if (nextPurchaseOrderStatus == null)
{
_logger.LogWarning("Next Purchase Order Status not found for Id: {Id}, Tenant: {TenantId}", model.NextPurchaseStatusId, tenantId);
return ApiResponse<object>.ErrorResponse(
"Next Purchase Order Status not found", "No active next purchase Order status exists with the provided Id.", 404);
}
try
{
if (model.IsActive)
{
// Check if mapping already exists
var alreadyExists = await _context.PurchaseStatusMappings
.AnyAsync(rsm => rsm.PurchaseStatusId == model.PurchaseStatusId
&& rsm.NextPurchaseStatusId == model.NextPurchaseStatusId);
if (alreadyExists)
{
_logger.LogWarning("Duplicate mapping attempted between {PurchaseStatusId} and {NextPurchaseStatusId}", model.PurchaseStatusId, model.NextPurchaseStatusId);
return ApiResponse<object>.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.PurchaseStatusMappings
.AnyAsync(rsm => rsm.NextPurchaseStatusId == model.NextPurchaseStatusId);
if (hasParent)
{
_logger.LogWarning("Next Purchase Order Status {NextPurchaseStatusId} already has a parent, cannot re-map.", model.NextPurchaseStatusId);
return ApiResponse<object>.ErrorResponse(
$"Purchase Order \"{nextPurchaseOrderStatus.Name}\" already has a parent and cannot be mapped again.",
$"Purchase Order \"{nextPurchaseOrderStatus.Name}\" already has a parent and cannot be mapped again.", 409);
}
// Find any previous mapping for ordering/trace
var previousMapping = await _context.PurchaseStatusMappings
.Include(rsm => rsm.PurchaseStatus)
.FirstOrDefaultAsync(rsm => rsm.NextPurchaseStatusId == model.PurchaseStatusId);
// Create a new mapping
var newMapping = new PurchaseStatusMapping
{
Id = Guid.NewGuid(),
PreviousPurchaseStatusId = previousMapping?.PurchaseStatusId,
PurchaseStatusId = purchaseOrderStatus.Id,
NextPurchaseStatusId = nextPurchaseOrderStatus.Id,
TenantId = tenantId
};
_context.PurchaseStatusMappings.Add(newMapping);
await _context.SaveChangesAsync();
_logger.LogInfo("Created mapping: {Id} from {PurchaseStatusId} to {NextPurchaseStatusId} for Tenant {TenantId}", newMapping.Id, purchaseOrderStatus.Id, nextPurchaseOrderStatus.Id, tenantId);
var vm = new PurchaseStatusMappingVM
{
Id = newMapping.Id,
PreviousPurchaseStatus = _mapper.Map<PurchaseOrderStatusVM>(previousMapping?.PurchaseStatus),
PurchaseStatus = _mapper.Map<PurchaseOrderStatusVM>(purchaseOrderStatus),
NextPurchaseStatus = _mapper.Map<PurchaseOrderStatusVM>(nextPurchaseOrderStatus)
};
return ApiResponse<object>.SuccessResponse(vm, "Purchase Order Status mapping added successfully.", 200);
}
else
{
// Remove mapping
var mapping = await _context.PurchaseStatusMappings
.Include(rsm => rsm.PreviousPurchaseStatus)
.Include(rsm => rsm.PurchaseStatus)
.Include(rsm => rsm.NextPurchaseStatus)
.FirstOrDefaultAsync(rsm => rsm.PurchaseStatusId == model.PurchaseStatusId
&& rsm.NextPurchaseStatusId == model.NextPurchaseStatusId);
if (mapping == null)
{
_logger.LogWarning("No mapping found to remove for {PurchaseStatusId} to {NextPurchaseStatusId}", model.PurchaseStatusId, model.NextPurchaseStatusId);
return ApiResponse<object>.ErrorResponse("Mapping not found", "No mapping exists to remove.", 404);
}
_context.PurchaseStatusMappings.Remove(mapping);
await _context.SaveChangesAsync();
_logger.LogInfo("Mapping removed: {Id} from {PurchaseStatusId} to {NextPurchaseStatusId}", mapping.Id, model.PurchaseStatusId, model.NextPurchaseStatusId);
var vm = _mapper.Map<PurchaseStatusMappingVM>(mapping);
return ApiResponse<object>.SuccessResponse(vm, "Purchase Order Status mapping removed successfully.", 200);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing AddPurchaseOrderStatusLinkAsync for Tenant: {TenantId}, Employee: {EmployeeId}", tenantId, loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An error occurred while processing your request.", 500);
}
}
public async Task<ApiResponse<object>> UpdatePurchaseOrderStatusAsync(Guid id, PurchaseOrderStatusDto model, Employee loggedInEmployee, Guid tenantId)
{
try
@ -3743,7 +3850,7 @@ namespace Marco.Pms.Services.Service
var existingPurchaseStatus = await _context.PurchaseOrderStatus.FirstOrDefaultAsync(pos => pos.Id == id && pos.TenantId == tenantId);
if (existingPurchaseStatus == null)
{
_logger.LogWarning("Purchase Order Status {PurchaseOrderStatusId} not found in database for tenant {TenantId}", id, tenantId);
_logger.LogWarning("Purchase Order Status {PurchaseStatusId} not found in database for tenant {TenantId}", id, tenantId);
return ApiResponse<object>.ErrorResponse("Purchase Order Status not found", "Purchase Order Status not found in database for current tenant", 404);
}
@ -3790,7 +3897,7 @@ namespace Marco.Pms.Services.Service
var existingPurchaseStatus = await _context.PurchaseOrderStatus.FirstOrDefaultAsync(pos => pos.Id == id && pos.TenantId == tenantId);
if (existingPurchaseStatus == null)
{
_logger.LogWarning("Purchase Order Status {PurchaseOrderStatusId} not found in database for tenant {TenantId} while {Message} Purchase Order Status", id, tenantId, message);
_logger.LogWarning("Purchase Order Status {PurchaseStatusId} not found in database for tenant {TenantId} while {Message} Purchase Order Status", id, tenantId, message);
return ApiResponse<object>.ErrorResponse("Purchase Order Status not found", "Purchase Order Status not found in database for current tenant", 404);
}

View File

@ -148,6 +148,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> GetPurchaseOrderStatusListAsync(bool isActive, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetPurchaseOrderStatusDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> CreatePurchaseOrderStatusAsync(PurchaseOrderStatusDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> AddPurchaseOrderStatusLinkAsync(PurchaseStatusMappingDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> UpdatePurchaseOrderStatusAsync(Guid id, PurchaseOrderStatusDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> DeletePurchaseOrderStatusAsync(Guid id, bool active, Employee loggedInEmployee, Guid tenantId);
#endregion