Implement Inventory Management Service with CRUD operations for warehouses and inventory items, stock operations, and bulk processing capabilities.
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m48s

This commit is contained in:
masoodafar-web
2026-01-02 00:45:37 +03:30
parent f0117eb1d5
commit 1cf501711f
50 changed files with 10699 additions and 101 deletions
@@ -0,0 +1,234 @@
using CMSMicroservice.Protobuf.Protos.Inventory;
using CMSMicroservice.WebApi.Common.Services;
// Warehouse Commands & Queries
using CMSMicroservice.Application.Features.Warehouses.Commands;
using CMSMicroservice.Application.Features.Warehouses.Queries;
// InventoryItem Commands & Queries
using CMSMicroservice.Application.Features.InventoryItems.Commands;
using CMSMicroservice.Application.Features.InventoryItems.Queries;
// StockMovement Commands & Queries
using CMSMicroservice.Application.Features.StockMovements.Commands;
using CMSMicroservice.Application.Features.StockMovements.Queries;
using CMSMicroservice.Domain.Entities;
using Mapster;
using Google.Protobuf.WellKnownTypes;
using System.Collections.Generic;
using System.Linq;
namespace CMSMicroservice.WebApi.Services;
/// <summary>
/// gRPC Service for Inventory Management
/// </summary>
public class InventoryService : InventoryContract.InventoryContractBase
{
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
public InventoryService(IDispatchRequestToCQRS dispatchRequestToCQRS)
{
_dispatchRequestToCQRS = dispatchRequestToCQRS;
}
#region Warehouse Management
public override async Task<CreateWarehouseResponse> CreateWarehouse(CreateWarehouseRequest request, ServerCallContext context)
{
var id = await _dispatchRequestToCQRS.Handle<CreateWarehouseRequest, CreateWarehouseCommand, long>(request, context);
return new CreateWarehouseResponse { Id = id };
}
public override async Task<Empty> UpdateWarehouse(UpdateWarehouseRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<UpdateWarehouseRequest, UpdateWarehouseCommand, bool>(request, context);
return new Empty();
}
public override async Task<Empty> DeleteWarehouse(DeleteWarehouseRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<DeleteWarehouseRequest, DeleteWarehouseCommand, bool>(request, context);
return new Empty();
}
public override async Task<GetWarehouseResponse> GetWarehouse(GetWarehouseRequest request, ServerCallContext context)
{
var warehouse = await _dispatchRequestToCQRS.Handle<GetWarehouseRequest, GetWarehouseByIdQuery, Warehouse?>(request, context);
return new GetWarehouseResponse
{
Warehouse = warehouse?.Adapt<WarehouseDto>()
};
}
public override async Task<GetAllWarehousesResponse> GetAllWarehouses(GetAllWarehousesRequest request, ServerCallContext context)
{
var warehouses = await _dispatchRequestToCQRS.Handle<GetAllWarehousesRequest, GetAllWarehousesQuery, List<Warehouse>>(request, context);
var response = new GetAllWarehousesResponse { TotalCount = warehouses.Count };
response.Warehouses.AddRange(warehouses.Select(w => w.Adapt<WarehouseDto>()));
return response;
}
public override async Task<Empty> SetDefaultWarehouse(SetDefaultWarehouseRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand, bool>(request, context);
return new Empty();
}
#endregion
#region Inventory Item Management
public override async Task<GetInventoryItemResponse> GetInventoryItem(GetInventoryItemRequest request, ServerCallContext context)
{
var item = await _dispatchRequestToCQRS.Handle<GetInventoryItemRequest, GetInventoryItemByIdQuery, InventoryItem?>(request, context);
return new GetInventoryItemResponse
{
Item = item?.Adapt<InventoryItemDto>()
};
}
public override async Task<GetInventoryByProductResponse> GetInventoryByProduct(GetInventoryByProductRequest request, ServerCallContext context)
{
InventoryItem? item;
if (request.ProductType == Protobuf.Protos.Inventory.ProductType.RegularProduct)
{
item = await _dispatchRequestToCQRS.Handle<GetInventoryByProductRequest, GetInventoryItemByProductIdQuery, InventoryItem?>(request, context);
}
else
{
item = await _dispatchRequestToCQRS.Handle<GetInventoryByProductRequest, GetInventoryItemByDiscountProductIdQuery, InventoryItem?>(request, context);
}
return new GetInventoryByProductResponse
{
Item = item?.Adapt<InventoryItemDto>()
};
}
public override async Task<GetAllInventoryItemsResponse> GetAllInventoryItems(GetAllInventoryItemsRequest request, ServerCallContext context)
{
var items = await _dispatchRequestToCQRS.Handle<GetAllInventoryItemsRequest, SearchInventoryItemsQuery, List<InventoryItem>>(request, context);
var response = new GetAllInventoryItemsResponse { TotalCount = items.Count };
response.Items.AddRange(items.Select(i => i.Adapt<InventoryItemDto>()));
return response;
}
public override async Task<GetLowStockItemsResponse> GetLowStockItems(GetLowStockItemsRequest request, ServerCallContext context)
{
var items = await _dispatchRequestToCQRS.Handle<GetLowStockItemsRequest, GetLowStockItemsQuery, List<InventoryItem>>(request, context);
var response = new GetLowStockItemsResponse { TotalCount = items.Count };
response.Items.AddRange(items.Select(i => i.Adapt<InventoryItemDto>()));
return response;
}
public override async Task<Empty> UpdateInventorySettings(UpdateInventorySettingsRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<UpdateInventorySettingsRequest, UpdateInventoryItemCommand, bool>(request, context);
return new Empty();
}
#endregion
#region Stock Operations
public override async Task<AddStockResponse> AddStock(AddStockRequest request, ServerCallContext context)
{
var success = await _dispatchRequestToCQRS.Handle<AddStockRequest, IncreaseInventoryCommand, bool>(request, context);
return new AddStockResponse
{
InventoryItemId = 0, // Will be filled by mapping
NewQuantity = 0
};
}
public override async Task<AdjustStockResponse> AdjustStock(AdjustStockRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<AdjustStockRequest, UpdateInventoryQuantityCommand, bool>(request, context);
return new AdjustStockResponse();
}
public override async Task<ReserveStockResponse> ReserveStock(ReserveStockRequest request, ServerCallContext context)
{
var success = await _dispatchRequestToCQRS.Handle<ReserveStockRequest, ReserveInventoryCommand, bool>(request, context);
return new ReserveStockResponse
{
Success = success,
Message = success ? "Stock reserved successfully" : "Failed to reserve stock"
};
}
public override async Task<Empty> ReleaseReservation(ReleaseReservationRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<ReleaseReservationRequest, ReleaseReservedInventoryCommand, bool>(request, context);
return new Empty();
}
public override async Task<Empty> ConfirmSale(ConfirmSaleRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<ConfirmSaleRequest, ReduceInventoryCommand, bool>(request, context);
return new Empty();
}
public override async Task<ProcessReturnResponse> ProcessReturn(ProcessReturnRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<ProcessReturnRequest, IncreaseInventoryCommand, bool>(request, context);
return new ProcessReturnResponse { NewQuantity = 0 };
}
public override async Task<Empty> RecordLoss(RecordLossRequest request, ServerCallContext context)
{
await _dispatchRequestToCQRS.Handle<RecordLossRequest, CreateStockMovementCommand, long>(request, context);
return new Empty();
}
#endregion
#region Bulk Operations
public override async Task<BulkAddStockResponse> BulkAddStock(BulkAddStockRequest request, ServerCallContext context)
{
// TODO: Implement bulk add stock
return new BulkAddStockResponse { SuccessCount = 0, FailedCount = 0 };
}
public override async Task<BulkAdjustStockResponse> BulkAdjustStock(BulkAdjustStockRequest request, ServerCallContext context)
{
// TODO: Implement bulk adjust stock
return new BulkAdjustStockResponse { SuccessCount = 0, FailedCount = 0 };
}
#endregion
#region Stock Movements
public override async Task<GetStockMovementsResponse> GetStockMovements(GetStockMovementsRequest request, ServerCallContext context)
{
var movements = await _dispatchRequestToCQRS.Handle<GetStockMovementsRequest, SearchStockMovementsQuery, List<StockMovement>>(request, context);
var response = new GetStockMovementsResponse { TotalCount = movements.Count };
response.Movements.AddRange(movements.Select(m => m.Adapt<StockMovementDto>()));
return response;
}
public override async Task<GetStockMovementsByInventoryItemResponse> GetStockMovementsByInventoryItem(GetStockMovementsByInventoryItemRequest request, ServerCallContext context)
{
var movements = await _dispatchRequestToCQRS.Handle<GetStockMovementsByInventoryItemRequest, GetInventoryItemMovementHistoryQuery, List<StockMovement>>(request, context);
var response = new GetStockMovementsByInventoryItemResponse { TotalCount = movements.Count };
response.Movements.AddRange(movements.Select(m => m.Adapt<StockMovementDto>()));
return response;
}
#endregion
#region Reports
public override async Task<GetInventorySummaryResponse> GetInventorySummary(GetInventorySummaryRequest request, ServerCallContext context)
{
// TODO: Implement summary query
return new GetInventorySummaryResponse();
}
public override async Task<GetStockValueReportResponse> GetStockValueReport(GetStockValueReportRequest request, ServerCallContext context)
{
// TODO: Implement stock value report
return new GetStockValueReportResponse();
}
#endregion
}