Files
CMS/src/CMSMicroservice.WebApi/Services/InventoryService.cs
T
masoodafar-web 70c4b15a23
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 2m18s
fix: Refactor AdjustStock method to streamline inventory updates and improve response structure
2026-01-04 22:58:25 +03:30

278 lines
12 KiB
C#

using CMSMicroservice.Protobuf.Protos.Inventory;
using CMSMicroservice.WebApi.Common.Services;
using CMSMicroservice.Application.WarehouseCQ.Commands.CreateWarehouse;
using CMSMicroservice.Application.WarehouseCQ.Commands.UpdateWarehouse;
using CMSMicroservice.Application.WarehouseCQ.Commands.DeleteWarehouse;
using CMSMicroservice.Application.WarehouseCQ.Commands.SetDefaultWarehouse;
using CMSMicroservice.Application.WarehouseCQ.Queries.GetWarehouse;
using CMSMicroservice.Application.WarehouseCQ.Queries.GetAllWarehouses;
using CMSMicroservice.Application.InventoryItemCQ.Commands.UpdateInventoryItem;
using CMSMicroservice.Application.InventoryItemCQ.Commands.IncreaseInventory;
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReduceInventory;
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReserveInventory;
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReleaseReservedInventory;
using CMSMicroservice.Application.InventoryItemCQ.Queries.GetInventoryItem;
using CMSMicroservice.Application.InventoryItemCQ.Queries.GetInventoryByProduct;
using CMSMicroservice.Application.InventoryItemCQ.Queries.GetAllInventoryItems;
using CMSMicroservice.Application.InventoryItemCQ.Queries.GetLowStockItems;
using CMSMicroservice.Application.StockMovementCQ.Commands.CreateStockMovement;
using CMSMicroservice.Application.StockMovementCQ.Queries.GetStockMovements;
using CMSMicroservice.Application.StockMovementCQ.Queries.GetStockMovementsByInventoryItem;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using MediatR;
namespace CMSMicroservice.WebApi.Services;
public class InventoryService : InventoryContract.InventoryContractBase
{
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
private readonly IMediator _mediator;
public InventoryService(IDispatchRequestToCQRS dispatchRequestToCQRS, IMediator mediator)
{
_dispatchRequestToCQRS = dispatchRequestToCQRS;
_mediator = mediator;
}
// ========== Warehouse Management ==========
public override async Task<CreateWarehouseResponse> CreateWarehouse(CreateWarehouseRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<CreateWarehouseRequest, CreateWarehouseCommand, CreateWarehouseResponse>(request, context);
}
public override async Task<Empty> UpdateWarehouse(UpdateWarehouseRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<UpdateWarehouseRequest, UpdateWarehouseCommand>(request, context);
}
public override async Task<Empty> DeleteWarehouse(DeleteWarehouseRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<DeleteWarehouseRequest, DeleteWarehouseCommand>(request, context);
}
public override async Task<GetWarehouseResponse> GetWarehouse(GetWarehouseRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetWarehouseRequest, GetWarehouseQuery, GetWarehouseResponse>(request, context);
}
public override async Task<GetAllWarehousesResponse> GetAllWarehouses(GetAllWarehousesRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetAllWarehousesRequest, GetAllWarehousesQuery, GetAllWarehousesResponse>(request, context);
}
public override async Task<Empty> SetDefaultWarehouse(SetDefaultWarehouseRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand>(request, context);
}
// ========== Inventory Item Management ==========
public override async Task<GetInventoryItemResponse> GetInventoryItem(GetInventoryItemRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetInventoryItemRequest, GetInventoryItemQuery, GetInventoryItemResponse>(request, context);
}
public override async Task<GetInventoryByProductResponse> GetInventoryByProduct(GetInventoryByProductRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetInventoryByProductRequest, GetInventoryByProductQuery, GetInventoryByProductResponse>(request, context);
}
public override async Task<GetAllInventoryItemsResponse> GetAllInventoryItems(GetAllInventoryItemsRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetAllInventoryItemsRequest, GetAllInventoryItemsQuery, GetAllInventoryItemsResponse>(request, context);
}
public override async Task<GetLowStockItemsResponse> GetLowStockItems(GetLowStockItemsRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetLowStockItemsRequest, GetLowStockItemsQuery, GetLowStockItemsResponse>(request, context);
}
public override async Task<Empty> UpdateInventorySettings(UpdateInventorySettingsRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<UpdateInventorySettingsRequest, UpdateInventoryItemCommand>(request, context);
}
// ========== Stock Operations ==========
public override async Task<AddStockResponse> AddStock(AddStockRequest request, ServerCallContext context)
{
// Lookup InventoryItem by ProductId + ProductType
var inventoryItem = await _mediator.Send(
new GetInventoryByProductQuery
{
ProductId = request.ProductId,
ProductType = (Domain.Enums.ProductType)request.ProductType
},
context.CancellationToken);
if (inventoryItem == null)
{
throw new RpcException(new Status(StatusCode.NotFound,
$"Inventory item not found for ProductId={request.ProductId}, ProductType={request.ProductType}"));
}
// Execute IncreaseInventoryCommand
var response = await _mediator.Send(
new IncreaseInventoryCommand
{
Id = inventoryItem.Id,
Quantity = request.Quantity,
ReferenceNumber = request.ReferenceNumber
},
context.CancellationToken);
return new AddStockResponse
{
InventoryItemId = inventoryItem.Id,
NewQuantity = response.NewQuantity
};
}
public override async Task<AdjustStockResponse> AdjustStock(AdjustStockRequest request, ServerCallContext context)
{
// Lookup InventoryItem
var inventoryItem = await _mediator.Send(
new GetInventoryByProductQuery
{
ProductId = request.ProductId,
ProductType = (Domain.Enums.ProductType)request.ProductType
},
context.CancellationToken);
if (inventoryItem == null)
{
throw new RpcException(new Status(StatusCode.NotFound,
$"Inventory item not found for ProductId={request.ProductId}, ProductType={request.ProductType}"));
}
// Determine if increase or decrease
var difference = request.NewQuantity - inventoryItem.Quantity;
if (difference > 0)
{
await _mediator.Send(
new IncreaseInventoryCommand
{
Id = inventoryItem.Id,
Quantity = difference,
ReferenceNumber = request.ReferenceNumber
},
context.CancellationToken);
return new AdjustStockResponse
{
PreviousQuantity = inventoryItem.Quantity,
NewQuantity = request.NewQuantity,
Difference = difference
};
}
else if (difference < 0)
{
await _mediator.Send(
new ReduceInventoryCommand
{
Id = inventoryItem.Id,
Quantity = Math.Abs(difference),
FromReserved = false,
ReferenceNumber = request.ReferenceNumber
},
context.CancellationToken);
return new AdjustStockResponse
{
PreviousQuantity = inventoryItem.Quantity,
NewQuantity = request.NewQuantity,
Difference = difference
};
}
else
{
return new AdjustStockResponse
{
PreviousQuantity = inventoryItem.Quantity,
NewQuantity = inventoryItem.Quantity,
Difference = 0
};
}
}
public override Task<ReserveStockResponse> ReserveStock(ReserveStockRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "ReserveStock requires product lookup - not yet implemented"));
}
public override Task<Empty> ReleaseReservation(ReleaseReservationRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "ReleaseReservation requires product lookup - not yet implemented"));
}
public override Task<Empty> ConfirmSale(ConfirmSaleRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "ConfirmSale requires product lookup - not yet implemented"));
}
public override Task<ProcessReturnResponse> ProcessReturn(ProcessReturnRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "ProcessReturn requires product lookup - not yet implemented"));
}
public override Task<Empty> RecordLoss(RecordLossRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "RecordLoss requires product lookup - not yet implemented"));
}
// ========== Bulk Operations ==========
public override Task<BulkAddStockResponse> BulkAddStock(BulkAddStockRequest request, ServerCallContext context)
{
// TODO: Implement with product lookup
throw new RpcException(new Status(StatusCode.Unimplemented, "BulkAddStock requires product lookup - not yet implemented"));
}
// ========== Stock Movements ==========
public override async Task<GetStockMovementsResponse> GetStockMovements(GetStockMovementsRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetStockMovementsRequest, GetStockMovementsQuery, GetStockMovementsResponse>(request, context);
}
public override async Task<GetStockMovementsByInventoryItemResponse> GetStockMovementsByInventoryItem(GetStockMovementsByInventoryItemRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetStockMovementsByInventoryItemRequest, GetStockMovementsByInventoryItemQuery, GetStockMovementsByInventoryItemResponse>(request, context);
}
// ========== Reports ==========
public override Task<GetInventorySummaryResponse> GetInventorySummary(GetInventorySummaryRequest request, ServerCallContext context)
{
// TODO: Implement summary query
return Task.FromResult(new GetInventorySummaryResponse
{
TotalProducts = 0,
TotalDiscountProducts = 0,
TotalQuantity = 0,
TotalReserved = 0,
LowStockCount = 0,
OutOfStockCount = 0,
TotalStockValue = 0
});
}
public override Task<GetStockValueReportResponse> GetStockValueReport(GetStockValueReportRequest request, ServerCallContext context)
{
// TODO: Implement stock value report query
return Task.FromResult(new GetStockValueReportResponse
{
TotalValue = 0,
TotalItems = 0
});
}
}