feat: Implement Inventory Management Commands and Queries
Build and Deploy / build (push) Successful in 1m46s
Build and Deploy / build (push) Successful in 1m46s
- Added CreateWarehouseCommand and CreateWarehouseCommandHandler for warehouse creation. - Introduced RecordLossCommand and RecordLossCommandHandler to handle stock loss recording. - Created UpdateInventorySettingsCommand and its handler for updating inventory settings. - Implemented GetAllInventoryItemsQuery and its handler to retrieve inventory items with pagination. - Added GetAllWarehousesQuery and handler for fetching all warehouses. - Developed GetLowStockItemsQuery and handler to get items below a specified stock threshold. - Implemented GetStockMovementsQuery and handler for retrieving stock movement records. - Created mappings for inventory-related requests and responses in InventoryProfile. - Developed InventoryService to handle gRPC requests for inventory operations. - Added Protobuf definitions for inventory management services and messages.
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
using BackOffice.BFF.Application.Common.Models;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Commands.AddStock;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Commands.AdjustStock;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Commands.CreateWarehouse;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Commands.RecordLoss;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Commands.UpdateInventorySettings;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Queries.GetAllWarehouses;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems;
|
||||
using BackOffice.BFF.Application.InventoryCQ.Queries.GetStockMovements;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using BffProtos = Foursat.BackOffice.BFF.Inventory.Protos;
|
||||
|
||||
namespace BackOffice.BFF.WebApi.Common.Mappings;
|
||||
|
||||
public class InventoryProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// =============================================
|
||||
// GetAllWarehouses
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.GetAllWarehousesRequest, GetAllWarehousesQuery>()
|
||||
.MapWith(src => new GetAllWarehousesQuery
|
||||
{
|
||||
ActiveOnly = src.ActiveOnly != null ? src.ActiveOnly.Value : null
|
||||
});
|
||||
|
||||
config.NewConfig<GetAllWarehousesResponseDto, BffProtos.GetAllWarehousesResponse>()
|
||||
.MapWith(src => new BffProtos.GetAllWarehousesResponse
|
||||
{
|
||||
Warehouses = { src.Warehouses.Select(w => new BffProtos.WarehouseDto
|
||||
{
|
||||
Id = w.Id,
|
||||
Name = w.Name ?? string.Empty,
|
||||
Code = w.Code ?? string.Empty,
|
||||
Address = w.Address ?? string.Empty,
|
||||
IsDefault = w.IsDefault,
|
||||
IsActive = w.IsActive
|
||||
}) }
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// CreateWarehouse
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.CreateWarehouseRequest, CreateWarehouseCommand>()
|
||||
.MapWith(src => new CreateWarehouseCommand
|
||||
{
|
||||
Name = src.Name,
|
||||
Code = src.Code,
|
||||
Address = src.Address,
|
||||
IsDefault = src.IsDefault,
|
||||
IsActive = true
|
||||
});
|
||||
|
||||
config.NewConfig<long, BffProtos.CreateWarehouseResponse>()
|
||||
.MapWith(src => new BffProtos.CreateWarehouseResponse { Id = src });
|
||||
|
||||
// =============================================
|
||||
// GetAllInventoryItems
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.GetAllInventoryItemsRequest, GetAllInventoryItemsQuery>()
|
||||
.MapWith(src => new GetAllInventoryItemsQuery
|
||||
{
|
||||
PageIndex = src.PageIndex > 0 ? src.PageIndex : 1,
|
||||
PageSize = src.PageSize > 0 ? src.PageSize : 20,
|
||||
WarehouseId = src.WarehouseId,
|
||||
ProductType = src.ProductType != BffProtos.ProductType.Unspecified
|
||||
? (int)src.ProductType
|
||||
: null,
|
||||
SearchTerm = string.IsNullOrWhiteSpace(src.SearchTerm) ? null : src.SearchTerm
|
||||
});
|
||||
|
||||
config.NewConfig<GetAllInventoryItemsResponseDto, BffProtos.GetAllInventoryItemsResponse>()
|
||||
.MapWith(src => new BffProtos.GetAllInventoryItemsResponse
|
||||
{
|
||||
TotalCount = src.TotalCount,
|
||||
MetaData = new BackOffice.BFF.Protobuf.Common.MetaData
|
||||
{
|
||||
CurrentPage = src.MetaData.CurrentPage,
|
||||
PageSize = src.MetaData.PageSize,
|
||||
TotalCount = src.MetaData.TotalCount,
|
||||
TotalPage = src.MetaData.TotalPage
|
||||
},
|
||||
Items = { src.Items.Select(i => new BffProtos.InventoryItemDto
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId.HasValue ? i.ProductId.Value : null,
|
||||
DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null,
|
||||
ProductType = (BffProtos.ProductType)i.ProductType,
|
||||
ProductName = i.ProductName ?? string.Empty,
|
||||
Quantity = i.Quantity,
|
||||
ReservedQuantity = i.ReservedQuantity,
|
||||
AvailableQuantity = i.AvailableQuantity,
|
||||
LowStockThreshold = i.LowStockThreshold,
|
||||
ReorderPoint = i.ReorderPoint,
|
||||
MaxStockLevel = i.MaxStockLevel,
|
||||
LastRestockedAt = i.LastRestockedAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(i.LastRestockedAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
LastSoldAt = i.LastSoldAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(i.LastSoldAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
WarehouseId = i.WarehouseId,
|
||||
WarehouseName = i.WarehouseName ?? string.Empty,
|
||||
IsLowStock = i.IsLowStock
|
||||
}) }
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// GetLowStockItems
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.GetLowStockItemsRequest, GetLowStockItemsQuery>()
|
||||
.MapWith(src => new GetLowStockItemsQuery
|
||||
{
|
||||
Count = src.Count > 0 ? src.Count : 10,
|
||||
WarehouseId = src.WarehouseId,
|
||||
ProductType = src.ProductType != BffProtos.ProductType.Unspecified
|
||||
? (int)src.ProductType
|
||||
: null
|
||||
});
|
||||
|
||||
config.NewConfig<GetLowStockItemsResponseDto, BffProtos.GetLowStockItemsResponse>()
|
||||
.MapWith(src => new BffProtos.GetLowStockItemsResponse
|
||||
{
|
||||
TotalCount = src.TotalCount,
|
||||
Items = { src.Items.Select(i => new BffProtos.LowStockItemDto
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId.HasValue ? i.ProductId.Value : null,
|
||||
DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null,
|
||||
ProductType = (BffProtos.ProductType)i.ProductType,
|
||||
ProductName = i.ProductName ?? string.Empty,
|
||||
Quantity = i.Quantity,
|
||||
ReservedQuantity = i.ReservedQuantity,
|
||||
AvailableQuantity = i.AvailableQuantity,
|
||||
LowStockThreshold = i.LowStockThreshold,
|
||||
ReorderPoint = i.ReorderPoint,
|
||||
WarehouseId = i.WarehouseId,
|
||||
WarehouseName = i.WarehouseName ?? string.Empty
|
||||
}) }
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// GetStockMovements
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.GetStockMovementsRequest, GetStockMovementsQuery>()
|
||||
.MapWith(src => new GetStockMovementsQuery
|
||||
{
|
||||
PageIndex = src.PageIndex > 0 ? src.PageIndex : 1,
|
||||
PageSize = src.PageSize > 0 ? src.PageSize : 20,
|
||||
InventoryItemId = src.InventoryItemId,
|
||||
ProductId = src.ProductId,
|
||||
ProductType = src.ProductType != BffProtos.ProductType.Unspecified
|
||||
? (int)src.ProductType
|
||||
: null,
|
||||
MovementType = src.MovementType != BffProtos.StockMovementType.Unspecified
|
||||
? (int)src.MovementType
|
||||
: null,
|
||||
FromDate = src.FromDate != null ? src.FromDate.ToDateTime() : null,
|
||||
ToDate = src.ToDate != null ? src.ToDate.ToDateTime() : null
|
||||
});
|
||||
|
||||
config.NewConfig<GetStockMovementsResponseDto, BffProtos.GetStockMovementsResponse>()
|
||||
.MapWith(src => new BffProtos.GetStockMovementsResponse
|
||||
{
|
||||
TotalCount = src.TotalCount,
|
||||
MetaData = new BackOffice.BFF.Protobuf.Common.MetaData
|
||||
{
|
||||
CurrentPage = src.MetaData.CurrentPage,
|
||||
PageSize = src.MetaData.PageSize,
|
||||
TotalCount = src.MetaData.TotalCount,
|
||||
TotalPage = src.MetaData.TotalPage
|
||||
},
|
||||
Movements = { src.Movements.Select(m => new BffProtos.StockMovementDto
|
||||
{
|
||||
Id = m.Id,
|
||||
InventoryItemId = m.InventoryItemId,
|
||||
ProductName = m.ProductName ?? string.Empty,
|
||||
MovementType = (BffProtos.StockMovementType)m.MovementType,
|
||||
MovementTypeName = m.MovementTypeName ?? string.Empty,
|
||||
Quantity = m.Quantity,
|
||||
QuantityBefore = m.QuantityBefore,
|
||||
QuantityAfter = m.QuantityAfter,
|
||||
OrderId = m.OrderId.HasValue ? m.OrderId.Value : null,
|
||||
DiscountOrderId = m.DiscountOrderId.HasValue ? m.DiscountOrderId.Value : null,
|
||||
ReferenceNumber = m.ReferenceNumber ?? string.Empty,
|
||||
Note = m.Note ?? string.Empty,
|
||||
PerformedByUserId = m.PerformedByUserId.HasValue ? m.PerformedByUserId.Value : null,
|
||||
PerformedByUserName = m.PerformedByUserName ?? string.Empty,
|
||||
CreatedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.CreatedAt, DateTimeKind.Utc))
|
||||
}) }
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// AddStock
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.AddStockRequest, AddStockCommand>()
|
||||
.MapWith(src => new AddStockCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (int)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
Note = src.Note,
|
||||
WarehouseId = src.WarehouseId
|
||||
});
|
||||
|
||||
config.NewConfig<AddStockResponseDto, BffProtos.AddStockResponse>()
|
||||
.MapWith(src => new BffProtos.AddStockResponse
|
||||
{
|
||||
Success = src.Success,
|
||||
InventoryItemId = src.InventoryItemId,
|
||||
NewQuantity = src.NewQuantity,
|
||||
Message = src.Message ?? string.Empty
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// AdjustStock
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.AdjustStockRequest, AdjustStockCommand>()
|
||||
.MapWith(src => new AdjustStockCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (int)src.ProductType,
|
||||
NewQuantity = src.NewQuantity,
|
||||
Note = src.Note
|
||||
});
|
||||
|
||||
config.NewConfig<AdjustStockResponseDto, BffProtos.AdjustStockResponse>()
|
||||
.MapWith(src => new BffProtos.AdjustStockResponse
|
||||
{
|
||||
Success = src.Success,
|
||||
OldQuantity = src.OldQuantity,
|
||||
NewQuantity = src.NewQuantity,
|
||||
Difference = src.Difference,
|
||||
Message = src.Message ?? string.Empty
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// RecordLoss
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.RecordLossRequest, RecordLossCommand>()
|
||||
.MapWith(src => new RecordLossCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (int)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
LossType = 40, // Loss type
|
||||
Note = src.Reason
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// UpdateInventorySettings
|
||||
// =============================================
|
||||
config.NewConfig<BffProtos.UpdateInventorySettingsRequest, UpdateInventorySettingsCommand>()
|
||||
.MapWith(src => new UpdateInventorySettingsCommand
|
||||
{
|
||||
InventoryItemId = src.InventoryItemId,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = src.ReorderPoint,
|
||||
MaxStockLevel = src.MaxStockLevel
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user