feat: Implement inventory and warehouse management features
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 2m33s
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 2m33s
- Add GetLowStockItemsResponseDto and LowStockItemDto for low stock item queries. - Create CreateStockMovementCommand and its handler for managing stock movements. - Implement CreateStockMovementCommandValidator for validating stock movement commands. - Add GetStockMovementsQuery and its handler to retrieve stock movement records. - Create GetStockMovementsResponseDto and StockMovementListDto for stock movement responses. - Implement GetStockMovementsByInventoryItemQuery and its handler for fetching movements by inventory item. - Add CreateWarehouseCommand and its handler for creating new warehouses. - Implement CreateWarehouseCommandValidator for warehouse creation validation. - Add DeleteWarehouseCommand and its handler for removing warehouses. - Implement SetDefaultWarehouseCommand and its handler for setting a default warehouse. - Create UpdateWarehouseCommand and its handler for updating warehouse details. - Implement GetAllWarehousesQuery and its handler to retrieve all warehouses. - Add GetWarehouseQuery and its handler for fetching a specific warehouse by ID. - Implement SearchWarehousesQuery and its handler for searching warehouses based on criteria.
This commit is contained in:
@@ -1,247 +1,484 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
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.UpdateInventoryQuantity;
|
||||
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReserveInventory;
|
||||
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReleaseReservedInventory;
|
||||
using CMSMicroservice.Application.InventoryItemCQ.Commands.ReduceInventory;
|
||||
using CMSMicroservice.Application.InventoryItemCQ.Commands.IncreaseInventory;
|
||||
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 CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
using CMSMicroservice.Application.Features.Warehouses.Commands;
|
||||
using CMSMicroservice.Application.Features.Warehouses.Queries;
|
||||
using CMSMicroservice.Application.Features.InventoryItems.Commands;
|
||||
using CMSMicroservice.Application.Features.InventoryItems.Queries;
|
||||
using CMSMicroservice.Application.Features.StockMovements.Commands;
|
||||
using CMSMicroservice.Application.Features.StockMovements.Queries;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ProtoProductType = CMSMicroservice.Protobuf.Protos.Inventory.ProductType;
|
||||
using DomainProductType = CMSMicroservice.Domain.Enums.ProductType;
|
||||
using ProtoStockMovementType = CMSMicroservice.Protobuf.Protos.Inventory.StockMovementType;
|
||||
using Mapster;
|
||||
using DomainStockMovementType = CMSMicroservice.Domain.Enums.StockMovementType;
|
||||
using ProtoStockMovementType = CMSMicroservice.Protobuf.Protos.Inventory.StockMovementType;
|
||||
using DomainProductType = CMSMicroservice.Domain.Enums.ProductType;
|
||||
using ProtoProductType = CMSMicroservice.Protobuf.Protos.Inventory.ProductType;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Common.Mappings;
|
||||
|
||||
/// <summary>
|
||||
/// Mapster profile برای Inventory Protobuf به CQRS و Entities به DTOs
|
||||
/// </summary>
|
||||
public class InventoryProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
// =============================================
|
||||
// Protobuf Request به CQRS Query/Command Mappings
|
||||
// =============================================
|
||||
|
||||
// Warehouse Commands
|
||||
// ==================== Warehouse Mappings ====================
|
||||
|
||||
// CreateWarehouse: Proto -> Command
|
||||
config.NewConfig<CreateWarehouseRequest, CreateWarehouseCommand>()
|
||||
.MapWith(src => new CreateWarehouseCommand
|
||||
{
|
||||
Name = src.Name,
|
||||
Code = src.Code,
|
||||
Address = src.Address,
|
||||
IsDefault = src.IsDefault
|
||||
});
|
||||
.Map(dest => dest.Name, src => src.Name)
|
||||
.Map(dest => dest.Code, src => src.Code)
|
||||
.Map(dest => dest.Address, src => src.Address)
|
||||
.Map(dest => dest.IsDefault, src => src.IsDefault)
|
||||
.Map(dest => dest.IsActive, src => true); // Proto ندارد
|
||||
|
||||
// CreateWarehouse: ResponseDto -> Proto Response
|
||||
config.NewConfig<CreateWarehouseResponseDto, CreateWarehouseResponse>()
|
||||
.Map(dest => dest.Id, src => src.Id);
|
||||
|
||||
// UpdateWarehouse: Proto -> Command
|
||||
config.NewConfig<UpdateWarehouseRequest, UpdateWarehouseCommand>()
|
||||
.MapWith(src => new UpdateWarehouseCommand
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.Name, src => src.Name)
|
||||
.Map(dest => dest.Code, src => src.Code)
|
||||
.Map(dest => dest.Address, src => src.Address)
|
||||
.Map(dest => dest.IsActive, src => src.IsActive);
|
||||
|
||||
// DeleteWarehouse: Proto -> Command
|
||||
config.NewConfig<DeleteWarehouseRequest, DeleteWarehouseCommand>()
|
||||
.Map(dest => dest.Id, src => src.Id);
|
||||
|
||||
// SetDefaultWarehouse: Proto -> Command
|
||||
config.NewConfig<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand>()
|
||||
.Map(dest => dest.Id, src => src.Id);
|
||||
|
||||
// GetWarehouse Query: Proto -> Query
|
||||
config.NewConfig<GetWarehouseRequest, GetWarehouseQuery>()
|
||||
.MapWith(src => new GetWarehouseQuery(src.Id));
|
||||
|
||||
// GetWarehouse Response: ResponseDto -> Proto (با WarehouseDto)
|
||||
config.NewConfig<GetWarehouseResponseDto, GetWarehouseResponse>()
|
||||
.Map(dest => dest.Warehouse, src => new WarehouseDto
|
||||
{
|
||||
Id = src.Id,
|
||||
Name = src.Name,
|
||||
Code = src.Code,
|
||||
Address = src.Address,
|
||||
IsActive = src.IsActive
|
||||
Address = src.Address ?? string.Empty,
|
||||
IsDefault = src.IsDefault,
|
||||
IsActive = src.IsActive,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)),
|
||||
LastModified = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc))
|
||||
});
|
||||
|
||||
config.NewConfig<DeleteWarehouseRequest, DeleteWarehouseCommand>()
|
||||
.MapWith(src => new DeleteWarehouseCommand(src.Id));
|
||||
|
||||
config.NewConfig<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand>()
|
||||
.MapWith(src => new SetDefaultWarehouseCommand(src.Id));
|
||||
|
||||
// Warehouse Queries
|
||||
config.NewConfig<GetWarehouseRequest, GetWarehouseByIdQuery>()
|
||||
.MapWith(src => new GetWarehouseByIdQuery(src.Id));
|
||||
|
||||
// GetAllWarehouses Query: Proto -> Query
|
||||
config.NewConfig<GetAllWarehousesRequest, GetAllWarehousesQuery>()
|
||||
.MapWith(src => new GetAllWarehousesQuery());
|
||||
|
||||
// Inventory Item Queries
|
||||
config.NewConfig<GetInventoryItemRequest, GetInventoryItemByIdQuery>()
|
||||
.MapWith(src => new GetInventoryItemByIdQuery(src.Id));
|
||||
// GetAllWarehouses Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetAllWarehousesResponseDto, GetAllWarehousesResponse>()
|
||||
.Map(dest => dest.TotalCount, src => src.TotalCount)
|
||||
.AfterMapping((src, dest) =>
|
||||
{
|
||||
dest.Warehouses.Clear();
|
||||
foreach (var warehouse in src.Warehouses)
|
||||
{
|
||||
dest.Warehouses.Add(new WarehouseDto
|
||||
{
|
||||
Id = warehouse.Id,
|
||||
Name = warehouse.Name,
|
||||
Code = warehouse.Code,
|
||||
Address = warehouse.Address ?? string.Empty,
|
||||
IsDefault = warehouse.IsDefault,
|
||||
IsActive = warehouse.IsActive,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)),
|
||||
LastModified = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
config.NewConfig<GetInventoryByProductRequest, GetInventoryItemByProductIdQuery>()
|
||||
.MapWith(src => new GetInventoryItemByProductIdQuery(src.ProductId, null));
|
||||
// ==================== Inventory Item Query Mappings ====================
|
||||
|
||||
config.NewConfig<GetInventoryByProductRequest, GetInventoryItemByDiscountProductIdQuery>()
|
||||
.MapWith(src => new GetInventoryItemByDiscountProductIdQuery(src.ProductId, null));
|
||||
// GetInventoryItem: Proto -> Query
|
||||
config.NewConfig<GetInventoryItemRequest, GetInventoryItemQuery>()
|
||||
.MapWith(src => new GetInventoryItemQuery(src.Id));
|
||||
|
||||
config.NewConfig<GetAllInventoryItemsRequest, SearchInventoryItemsQuery>()
|
||||
.MapWith(src => new SearchInventoryItemsQuery(
|
||||
null, // SearchTerm
|
||||
null, // ProductType
|
||||
null, // WarehouseId
|
||||
null, // MinQuantity
|
||||
null, // MaxQuantity
|
||||
0, // Skip
|
||||
50 // Take
|
||||
));
|
||||
// GetInventoryItem Response: ResponseDto -> Proto (با InventoryItemDto)
|
||||
config.NewConfig<GetInventoryItemResponseDto, GetInventoryItemResponse>()
|
||||
.Map(dest => dest.Item, src => MapToInventoryItemDto(src));
|
||||
|
||||
// GetInventoryByProduct: Proto -> Query
|
||||
config.NewConfig<GetInventoryByProductRequest, GetInventoryByProductQuery>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId)
|
||||
.Map(dest => dest.ProductType, src => MapToDomainProductType(src.ProductType));
|
||||
|
||||
// GetInventoryByProduct Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetInventoryByProductResponseDto, GetInventoryByProductResponse>()
|
||||
.Map(dest => dest.Item, src => MapToInventoryItemDto(src));
|
||||
|
||||
// GetAllInventoryItems: Proto -> Query
|
||||
config.NewConfig<GetAllInventoryItemsRequest, GetAllInventoryItemsQuery>()
|
||||
.Map(dest => dest.WarehouseId, src => src.WarehouseId != null ? (long?)src.WarehouseId.Value : null)
|
||||
.Map(dest => dest.ProductType, src => src.ProductType != ProtoProductType.Unspecified
|
||||
? (DomainProductType?)MapToDomainProductType(src.ProductType) : null)
|
||||
.Map(dest => dest.SearchTerm, src => src.Search)
|
||||
.Map(dest => dest.Skip, src => src.Page > 0 ? (src.Page - 1) * src.PageSize : 0)
|
||||
.Map(dest => dest.Take, src => src.PageSize > 0 ? src.PageSize : 50);
|
||||
|
||||
// GetAllInventoryItems Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetAllInventoryItemsResponseDto, GetAllInventoryItemsResponse>()
|
||||
.Map(dest => dest.TotalCount, src => src.TotalCount)
|
||||
.AfterMapping((src, dest) =>
|
||||
{
|
||||
dest.Items.Clear();
|
||||
foreach (var item in src.Items)
|
||||
{
|
||||
dest.Items.Add(MapListItemToInventoryItemDto(item));
|
||||
}
|
||||
});
|
||||
|
||||
// GetLowStockItems: Proto -> Query
|
||||
config.NewConfig<GetLowStockItemsRequest, GetLowStockItemsQuery>()
|
||||
.MapWith(src => new GetLowStockItemsQuery(null, 1));
|
||||
.Map(dest => dest.WarehouseId, src => src.WarehouseId != null ? (long?)src.WarehouseId.Value : null)
|
||||
.Map(dest => dest.Count, src => src.PageSize > 0 ? src.PageSize : 50);
|
||||
|
||||
// Inventory Item Commands
|
||||
// GetLowStockItems Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetLowStockItemsResponseDto, GetLowStockItemsResponse>()
|
||||
.Map(dest => dest.TotalCount, src => src.TotalCount)
|
||||
.AfterMapping((src, dest) =>
|
||||
{
|
||||
dest.Items.Clear();
|
||||
foreach (var item in src.Items)
|
||||
{
|
||||
dest.Items.Add(MapLowStockItemToInventoryItemDto(item));
|
||||
}
|
||||
});
|
||||
|
||||
// UpdateInventorySettings: Proto -> UpdateInventoryItemCommand
|
||||
config.NewConfig<UpdateInventorySettingsRequest, UpdateInventoryItemCommand>()
|
||||
.MapWith(src => new UpdateInventoryItemCommand
|
||||
{
|
||||
Id = src.Id,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = src.ReorderPoint,
|
||||
MaxStockLevel = src.MaxStockLevel
|
||||
});
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.MinimumStock, src => (int?)src.LowStockThreshold)
|
||||
.Map(dest => dest.MaximumStock, src => (int?)src.MaxStockLevel)
|
||||
.Map(dest => dest.ReorderPoint, src => (int?)src.ReorderPoint);
|
||||
|
||||
// Stock Operation Commands
|
||||
// ==================== Stock Operation Mappings ====================
|
||||
|
||||
// AddStock: Proto -> IncreaseInventoryCommand
|
||||
// نکته: این نیاز به lookup در Service داره چون Proto از ProductId استفاده میکنه
|
||||
config.NewConfig<AddStockRequest, IncreaseInventoryCommand>()
|
||||
.MapWith(src => new IncreaseInventoryCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
Note = src.Note,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.ReferenceNumber, src => src.ReferenceNumber)
|
||||
.Map(dest => dest.Note, src => src.Note);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// AdjustStock: Proto -> UpdateInventoryQuantityCommand
|
||||
config.NewConfig<AdjustStockRequest, UpdateInventoryQuantityCommand>()
|
||||
.MapWith(src => new UpdateInventoryQuantityCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
NewQuantity = src.NewQuantity,
|
||||
Note = src.Note,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.NewQuantity, src => src.NewQuantity)
|
||||
.Map(dest => dest.Note, src => src.Reason)
|
||||
.Map(dest => dest.ReferenceNumber, src => src.ReferenceNumber);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// ReserveStock: Proto -> ReserveInventoryCommand
|
||||
config.NewConfig<ReserveStockRequest, ReserveInventoryCommand>()
|
||||
.MapWith(src => new ReserveInventoryCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
Note = src.Note,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
OrderId = src.OrderId?.Value,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.OrderId, src => src.OrderId != null ? (long?)src.OrderId.Value : null)
|
||||
.Map(dest => dest.DiscountOrderId, src => src.DiscountOrderId != null ? (long?)src.DiscountOrderId.Value : null);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// ReleaseReservation: Proto -> ReleaseReservedInventoryCommand
|
||||
config.NewConfig<ReleaseReservationRequest, ReleaseReservedInventoryCommand>()
|
||||
.MapWith(src => new ReleaseReservedInventoryCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
Note = src.Note,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.OrderId, src => src.OrderId != null ? (long?)src.OrderId.Value : null)
|
||||
.Map(dest => dest.DiscountOrderId, src => src.DiscountOrderId != null ? (long?)src.DiscountOrderId.Value : null);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// ConfirmSale: Proto -> ReduceInventoryCommand
|
||||
config.NewConfig<ConfirmSaleRequest, ReduceInventoryCommand>()
|
||||
.MapWith(src => new ReduceInventoryCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
Note = src.Note,
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
OrderId = src.OrderId?.Value,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.OrderId, src => src.OrderId != null ? (long?)src.OrderId.Value : null)
|
||||
.Map(dest => dest.DiscountOrderId, src => src.DiscountOrderId != null ? (long?)src.DiscountOrderId.Value : null)
|
||||
.Map(dest => dest.FromReserved, src => src.FromReservation);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// ProcessReturn: Proto -> IncreaseInventoryCommand
|
||||
config.NewConfig<ProcessReturnRequest, IncreaseInventoryCommand>()
|
||||
.MapWith(src => new IncreaseInventoryCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
Quantity = src.Quantity,
|
||||
Note = !string.IsNullOrEmpty(src.Note) ? src.Note : "Product return",
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
OrderId = src.OrderId?.Value,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.Note, src => src.Reason);
|
||||
// Id باید در Service تنظیم بشه
|
||||
|
||||
// RecordLoss: Proto -> CreateStockMovementCommand
|
||||
config.NewConfig<RecordLossRequest, CreateStockMovementCommand>()
|
||||
.MapWith(src => new CreateStockMovementCommand
|
||||
{
|
||||
ProductId = src.ProductId,
|
||||
ProductType = (DomainProductType)src.ProductType,
|
||||
MovementType = DomainStockMovementType.Loss,
|
||||
Quantity = src.Quantity,
|
||||
Note = !string.IsNullOrEmpty(src.Note) ? src.Note : "Stock loss/damage",
|
||||
ReferenceNumber = src.ReferenceNumber,
|
||||
WarehouseId = src.WarehouseId?.Value ?? 1
|
||||
});
|
||||
|
||||
// Stock Movement Queries
|
||||
config.NewConfig<GetStockMovementsRequest, SearchStockMovementsQuery>()
|
||||
.MapWith(src => new SearchStockMovementsQuery
|
||||
{
|
||||
InventoryItemId = src.InventoryItemId?.Value,
|
||||
ProductId = src.ProductId?.Value,
|
||||
ProductType = src.ProductType != ProtoProductType.Unspecified ? (DomainProductType?)src.ProductType : null,
|
||||
MovementType = src.MovementType != ProtoStockMovementType.Unspecified ? (DomainStockMovementType?)src.MovementType : null,
|
||||
StartDate = src.StartDate?.ToDateTime(),
|
||||
EndDate = src.EndDate?.ToDateTime(),
|
||||
Skip = src.Skip,
|
||||
Take = src.Take > 0 ? src.Take : 50
|
||||
});
|
||||
|
||||
config.NewConfig<GetStockMovementsByInventoryItemRequest, GetInventoryItemMovementHistoryQuery>()
|
||||
.MapWith(src => new GetInventoryItemMovementHistoryQuery
|
||||
{
|
||||
InventoryItemId = src.InventoryItemId,
|
||||
Skip = (src.Page - 1) * src.PageSize,
|
||||
Take = src.PageSize > 0 ? src.PageSize : 50
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// Entity به Protobuf DTO Mappings
|
||||
// =============================================
|
||||
// Warehouse Entity به WarehouseDto
|
||||
config.NewConfig<Warehouse, WarehouseDto>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.Name, src => src.Name)
|
||||
.Map(dest => dest.Code, src => src.Code ?? string.Empty)
|
||||
.Map(dest => dest.Address, src => src.Address ?? string.Empty)
|
||||
.Map(dest => dest.IsDefault, src => src.IsDefault)
|
||||
.Map(dest => dest.IsActive, src => src.IsActive);
|
||||
|
||||
// InventoryItem Entity به InventoryItemDto
|
||||
config.NewConfig<InventoryItem, InventoryItemDto>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.WarehouseId, src => src.WarehouseId)
|
||||
.Map(dest => dest.WarehouseName, src => src.Warehouse != null ? src.Warehouse.Name : string.Empty)
|
||||
.Map(dest => dest.ProductId, src => src.ProductId.HasValue ? new Int64Value { Value = src.ProductId.Value } : null)
|
||||
.Map(dest => dest.DiscountProductId, src => src.DiscountProductId.HasValue ? new Int64Value { Value = src.DiscountProductId.Value } : null)
|
||||
.Map(dest => dest.ProductType, src => (ProtoProductType)src.ProductType)
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.ReservedQuantity, src => src.ReservedQuantity)
|
||||
.Map(dest => dest.AvailableQuantity, src => src.AvailableQuantity)
|
||||
.Map(dest => dest.LowStockThreshold, src => src.LowStockThreshold)
|
||||
.Map(dest => dest.ReorderPoint, src => src.ReorderPoint)
|
||||
.Map(dest => dest.MaxStockLevel, src => src.MaxStockLevel)
|
||||
.Map(dest => dest.LastRestockedAt, src => src.LastRestockedAt.HasValue ? Timestamp.FromDateTime(src.LastRestockedAt.Value.ToUniversalTime()) : null)
|
||||
.Map(dest => dest.LastSoldAt, src => src.LastSoldAt.HasValue ? Timestamp.FromDateTime(src.LastSoldAt.Value.ToUniversalTime()) : null)
|
||||
.Map(dest => dest.ProductTitle, src => src.Product != null ? src.Product.Title : (src.DiscountProduct != null ? src.DiscountProduct.Title : string.Empty))
|
||||
.Map(dest => dest.ProductPrice, src => src.Product != null ? src.Product.Price : (src.DiscountProduct != null ? src.DiscountProduct.Price : 0))
|
||||
.Map(dest => dest.Created, src => Timestamp.FromDateTime(src.Created.ToUniversalTime()));
|
||||
.Map(dest => dest.MovementType, src => MapToDomainStockMovementType(src.LossType))
|
||||
.Map(dest => dest.Note, src => src.Reason)
|
||||
.Map(dest => dest.ReferenceNumber, src => src.ReferenceNumber);
|
||||
// InventoryItemId باید در Service تنظیم بشه
|
||||
|
||||
// StockMovement Entity به StockMovementDto
|
||||
config.NewConfig<StockMovement, StockMovementDto>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
// ==================== Stock Movement Query Mappings ====================
|
||||
|
||||
// GetStockMovements: Proto -> Query
|
||||
config.NewConfig<GetStockMovementsRequest, GetStockMovementsQuery>()
|
||||
.Map(dest => dest.InventoryItemId, src => src.InventoryItemId != null ? (long?)src.InventoryItemId.Value : null)
|
||||
.Map(dest => dest.ProductId, src => src.ProductId != null ? (long?)src.ProductId.Value : null)
|
||||
.Map(dest => dest.ProductType, src => src.ProductType != ProtoProductType.Unspecified
|
||||
? (DomainProductType?)MapToDomainProductType(src.ProductType) : null)
|
||||
.Map(dest => dest.MovementType, src => src.MovementType != ProtoStockMovementType.MovementTypeUnspecified
|
||||
? (DomainStockMovementType?)MapToDomainStockMovementType(src.MovementType) : null)
|
||||
.Map(dest => dest.StartDate, src => src.FromDate != null ? (DateTime?)src.FromDate.ToDateTime() : null)
|
||||
.Map(dest => dest.EndDate, src => src.ToDate != null ? (DateTime?)src.ToDate.ToDateTime() : null)
|
||||
.Map(dest => dest.Skip, src => src.Page > 0 ? (src.Page - 1) * src.PageSize : 0)
|
||||
.Map(dest => dest.Take, src => src.PageSize > 0 ? src.PageSize : 50);
|
||||
|
||||
// GetStockMovements Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetStockMovementsResponseDto, GetStockMovementsResponse>()
|
||||
.Map(dest => dest.TotalCount, src => src.TotalCount)
|
||||
.AfterMapping((src, dest) =>
|
||||
{
|
||||
dest.Movements.Clear();
|
||||
foreach (var movement in src.Movements)
|
||||
{
|
||||
dest.Movements.Add(MapToStockMovementDto(movement));
|
||||
}
|
||||
});
|
||||
|
||||
// GetStockMovementsByInventoryItem: Proto -> Query
|
||||
config.NewConfig<GetStockMovementsByInventoryItemRequest, GetStockMovementsByInventoryItemQuery>()
|
||||
.Map(dest => dest.InventoryItemId, src => src.InventoryItemId)
|
||||
.Map(dest => dest.MovementType, src => (ProtoStockMovementType)src.MovementType)
|
||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||
.Map(dest => dest.QuantityBefore, src => src.QuantityBefore)
|
||||
.Map(dest => dest.QuantityAfter, src => src.QuantityAfter)
|
||||
.Map(dest => dest.Note, src => src.Note ?? string.Empty)
|
||||
.Map(dest => dest.ReferenceNumber, src => src.ReferenceNumber ?? string.Empty)
|
||||
.Map(dest => dest.OrderId, src => src.OrderId.HasValue ? new Int64Value { Value = src.OrderId.Value } : null)
|
||||
.Map(dest => dest.DiscountOrderId, src => src.DiscountOrderId.HasValue ? new Int64Value { Value = src.DiscountOrderId.Value } : null)
|
||||
.Map(dest => dest.PerformedByUserId, src => src.PerformedByUserId.HasValue ? new Int64Value { Value = src.PerformedByUserId.Value } : null)
|
||||
.Map(dest => dest.Created, src => Timestamp.FromDateTime(src.Created.ToUniversalTime()))
|
||||
.Map(dest => dest.ProductTitle, src => src.InventoryItem != null && src.InventoryItem.Product != null ? src.InventoryItem.Product.Title : (src.InventoryItem != null && src.InventoryItem.DiscountProduct != null ? src.InventoryItem.DiscountProduct.Title : string.Empty));
|
||||
.Map(dest => dest.Skip, src => src.Page > 0 ? (src.Page - 1) * src.PageSize : 0)
|
||||
.Map(dest => dest.Take, src => src.PageSize > 0 ? src.PageSize : 50);
|
||||
|
||||
// GetStockMovementsByInventoryItem Response: ResponseDto -> Proto
|
||||
config.NewConfig<GetStockMovementsByInventoryItemResponseDto, GetStockMovementsByInventoryItemResponse>()
|
||||
.Map(dest => dest.TotalCount, src => src.TotalCount)
|
||||
.AfterMapping((src, dest) =>
|
||||
{
|
||||
dest.Movements.Clear();
|
||||
foreach (var movement in src.Movements)
|
||||
{
|
||||
dest.Movements.Add(MapHistoryToStockMovementDto(movement));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Helper Methods ====================
|
||||
|
||||
private static InventoryItemDto MapToInventoryItemDto(GetInventoryItemResponseDto src)
|
||||
{
|
||||
return new InventoryItemDto
|
||||
{
|
||||
Id = src.Id,
|
||||
ProductId = src.ProductId,
|
||||
DiscountProductId = src.DiscountProductId,
|
||||
ProductType = MapToProtoProductType(src.ProductType),
|
||||
Quantity = src.Quantity,
|
||||
ReservedQuantity = src.ReservedQuantity,
|
||||
AvailableQuantity = src.AvailableQuantity,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = 0, // Entity ندارد
|
||||
MaxStockLevel = src.MaxStockLevel,
|
||||
LastRestockedAt = src.LastRestockedAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastRestockedAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
LastSoldAt = src.LastSoldAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastSoldAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
WarehouseId = src.WarehouseId,
|
||||
WarehouseName = src.WarehouseName ?? string.Empty,
|
||||
ProductTitle = src.ProductTitle ?? string.Empty,
|
||||
ProductPrice = src.ProductPrice.HasValue ? (long)src.ProductPrice.Value : 0,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc))
|
||||
};
|
||||
}
|
||||
|
||||
private static InventoryItemDto MapToInventoryItemDto(GetInventoryByProductResponseDto src)
|
||||
{
|
||||
return new InventoryItemDto
|
||||
{
|
||||
Id = src.Id,
|
||||
ProductId = src.ProductId,
|
||||
DiscountProductId = src.DiscountProductId,
|
||||
ProductType = MapToProtoProductType(src.ProductType),
|
||||
Quantity = src.Quantity,
|
||||
ReservedQuantity = src.ReservedQuantity,
|
||||
AvailableQuantity = src.AvailableQuantity,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = 0,
|
||||
MaxStockLevel = src.MaxStockLevel,
|
||||
LastRestockedAt = src.LastRestockedAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastRestockedAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
LastSoldAt = src.LastSoldAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastSoldAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
WarehouseId = src.WarehouseId,
|
||||
WarehouseName = src.WarehouseName ?? string.Empty,
|
||||
ProductTitle = src.ProductTitle ?? string.Empty,
|
||||
ProductPrice = src.ProductPrice.HasValue ? (long)src.ProductPrice.Value : 0,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc))
|
||||
};
|
||||
}
|
||||
|
||||
private static InventoryItemDto MapListItemToInventoryItemDto(InventoryItemListDto src)
|
||||
{
|
||||
return new InventoryItemDto
|
||||
{
|
||||
Id = src.Id,
|
||||
ProductId = src.ProductId,
|
||||
DiscountProductId = src.DiscountProductId,
|
||||
ProductType = MapToProtoProductType(src.ProductType),
|
||||
Quantity = src.Quantity,
|
||||
ReservedQuantity = src.ReservedQuantity,
|
||||
AvailableQuantity = src.AvailableQuantity,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = 0,
|
||||
MaxStockLevel = src.MaxStockLevel,
|
||||
LastRestockedAt = src.LastRestockedAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastRestockedAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
LastSoldAt = src.LastSoldAt.HasValue
|
||||
? Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastSoldAt.Value, DateTimeKind.Utc))
|
||||
: null,
|
||||
WarehouseId = src.WarehouseId,
|
||||
WarehouseName = src.WarehouseName ?? string.Empty,
|
||||
ProductTitle = src.ProductTitle ?? string.Empty,
|
||||
ProductPrice = src.ProductPrice.HasValue ? (long)src.ProductPrice.Value : 0,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc))
|
||||
};
|
||||
}
|
||||
|
||||
private static InventoryItemDto MapLowStockItemToInventoryItemDto(LowStockItemDto src)
|
||||
{
|
||||
return new InventoryItemDto
|
||||
{
|
||||
Id = src.Id,
|
||||
ProductId = src.ProductId,
|
||||
DiscountProductId = src.DiscountProductId,
|
||||
ProductType = MapToProtoProductType(src.ProductType),
|
||||
Quantity = src.Quantity,
|
||||
ReservedQuantity = src.ReservedQuantity,
|
||||
AvailableQuantity = src.AvailableQuantity,
|
||||
LowStockThreshold = src.LowStockThreshold,
|
||||
ReorderPoint = 0,
|
||||
MaxStockLevel = 0,
|
||||
LastRestockedAt = null,
|
||||
LastSoldAt = null,
|
||||
WarehouseId = src.WarehouseId,
|
||||
WarehouseName = src.WarehouseName ?? string.Empty,
|
||||
ProductTitle = src.ProductTitle ?? string.Empty,
|
||||
ProductPrice = 0,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc))
|
||||
};
|
||||
}
|
||||
|
||||
private static StockMovementDto MapToStockMovementDto(StockMovementListDto src)
|
||||
{
|
||||
return new StockMovementDto
|
||||
{
|
||||
Id = src.Id,
|
||||
InventoryItemId = src.InventoryItemId,
|
||||
MovementType = MapToProtoStockMovementType(src.MovementType),
|
||||
Quantity = src.Quantity,
|
||||
QuantityBefore = src.QuantityBefore,
|
||||
QuantityAfter = src.QuantityAfter,
|
||||
OrderId = src.OrderId,
|
||||
DiscountOrderId = src.DiscountOrderId,
|
||||
ReferenceNumber = src.ReferenceNumber ?? string.Empty,
|
||||
Note = src.Note ?? string.Empty,
|
||||
PerformedByUserId = src.PerformedByUserId,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc)),
|
||||
ProductTitle = src.ProductTitle ?? string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private static StockMovementDto MapHistoryToStockMovementDto(StockMovementHistoryDto src)
|
||||
{
|
||||
return new StockMovementDto
|
||||
{
|
||||
Id = src.Id,
|
||||
InventoryItemId = 0, // Not available in history DTO
|
||||
MovementType = MapToProtoStockMovementType(src.MovementType),
|
||||
Quantity = src.Quantity,
|
||||
QuantityBefore = src.QuantityBefore,
|
||||
QuantityAfter = src.QuantityAfter,
|
||||
OrderId = src.OrderId,
|
||||
DiscountOrderId = src.DiscountOrderId,
|
||||
ReferenceNumber = src.ReferenceNumber ?? string.Empty,
|
||||
Note = src.Note ?? string.Empty,
|
||||
PerformedByUserId = src.PerformedByUserId,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc)),
|
||||
ProductTitle = string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
// ==================== Enum Mapping Methods ====================
|
||||
|
||||
private static DomainProductType MapToDomainProductType(ProtoProductType protoType)
|
||||
{
|
||||
return protoType switch
|
||||
{
|
||||
ProtoProductType.RegularProduct => DomainProductType.RegularProduct,
|
||||
ProtoProductType.DiscountProduct => DomainProductType.DiscountProduct,
|
||||
_ => DomainProductType.RegularProduct
|
||||
};
|
||||
}
|
||||
|
||||
private static ProtoProductType MapToProtoProductType(DomainProductType domainType)
|
||||
{
|
||||
return domainType switch
|
||||
{
|
||||
DomainProductType.RegularProduct => ProtoProductType.RegularProduct,
|
||||
DomainProductType.DiscountProduct => ProtoProductType.DiscountProduct,
|
||||
_ => ProtoProductType.Unspecified
|
||||
};
|
||||
}
|
||||
|
||||
private static DomainStockMovementType MapToDomainStockMovementType(ProtoStockMovementType protoType)
|
||||
{
|
||||
return protoType switch
|
||||
{
|
||||
ProtoStockMovementType.InitialStock => DomainStockMovementType.InitialStock,
|
||||
ProtoStockMovementType.Restock => DomainStockMovementType.Restock,
|
||||
ProtoStockMovementType.Return => DomainStockMovementType.Return,
|
||||
ProtoStockMovementType.Sale => DomainStockMovementType.Sale,
|
||||
ProtoStockMovementType.AdjustmentIncrease => DomainStockMovementType.AdjustmentPlus,
|
||||
ProtoStockMovementType.AdjustmentDecrease => DomainStockMovementType.AdjustmentMinus,
|
||||
ProtoStockMovementType.Reserved => DomainStockMovementType.Reserved,
|
||||
ProtoStockMovementType.Released => DomainStockMovementType.Released,
|
||||
ProtoStockMovementType.Loss => DomainStockMovementType.Lost,
|
||||
ProtoStockMovementType.Damaged => DomainStockMovementType.Damaged,
|
||||
ProtoStockMovementType.Expired => DomainStockMovementType.Damaged, // Domain ندارد Expired
|
||||
ProtoStockMovementType.TransferOut => DomainStockMovementType.TransferOut,
|
||||
ProtoStockMovementType.TransferIn => DomainStockMovementType.TransferIn,
|
||||
_ => DomainStockMovementType.AdjustmentPlus
|
||||
};
|
||||
}
|
||||
|
||||
private static ProtoStockMovementType MapToProtoStockMovementType(DomainStockMovementType domainType)
|
||||
{
|
||||
return domainType switch
|
||||
{
|
||||
DomainStockMovementType.InitialStock => ProtoStockMovementType.InitialStock,
|
||||
DomainStockMovementType.Restock => ProtoStockMovementType.Restock,
|
||||
DomainStockMovementType.Return => ProtoStockMovementType.Return,
|
||||
DomainStockMovementType.Sale => ProtoStockMovementType.Sale,
|
||||
DomainStockMovementType.AdjustmentPlus => ProtoStockMovementType.AdjustmentIncrease,
|
||||
DomainStockMovementType.AdjustmentMinus => ProtoStockMovementType.AdjustmentDecrease,
|
||||
DomainStockMovementType.Reserved => ProtoStockMovementType.Reserved,
|
||||
DomainStockMovementType.Released => ProtoStockMovementType.Released,
|
||||
DomainStockMovementType.Lost => ProtoStockMovementType.Loss,
|
||||
DomainStockMovementType.Damaged => ProtoStockMovementType.Damaged,
|
||||
DomainStockMovementType.TransferOut => ProtoStockMovementType.TransferOut,
|
||||
DomainStockMovementType.TransferIn => ProtoStockMovementType.TransferIn,
|
||||
_ => ProtoStockMovementType.MovementTypeUnspecified
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
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 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 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;
|
||||
@@ -29,206 +31,161 @@ public class InventoryService : InventoryContract.InventoryContractBase
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
#region Warehouse Management
|
||||
// ========== 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 };
|
||||
return await _dispatchRequestToCQRS.Handle<CreateWarehouseRequest, CreateWarehouseCommand, CreateWarehouseResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateWarehouse(UpdateWarehouseRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<UpdateWarehouseRequest, UpdateWarehouseCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateWarehouseRequest, UpdateWarehouseCommand>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Empty> DeleteWarehouse(DeleteWarehouseRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<DeleteWarehouseRequest, DeleteWarehouseCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
return await _dispatchRequestToCQRS.Handle<DeleteWarehouseRequest, DeleteWarehouseCommand>(request, context);
|
||||
}
|
||||
|
||||
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>()
|
||||
};
|
||||
return await _dispatchRequestToCQRS.Handle<GetWarehouseRequest, GetWarehouseQuery, GetWarehouseResponse>(request, context);
|
||||
}
|
||||
|
||||
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;
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllWarehousesRequest, GetAllWarehousesQuery, GetAllWarehousesResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Empty> SetDefaultWarehouse(SetDefaultWarehouseRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
return await _dispatchRequestToCQRS.Handle<SetDefaultWarehouseRequest, SetDefaultWarehouseCommand>(request, context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inventory Item Management
|
||||
// ========== 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>()
|
||||
};
|
||||
return await _dispatchRequestToCQRS.Handle<GetInventoryItemRequest, GetInventoryItemQuery, GetInventoryItemResponse>(request, context);
|
||||
}
|
||||
|
||||
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>()
|
||||
};
|
||||
return await _dispatchRequestToCQRS.Handle<GetInventoryByProductRequest, GetInventoryByProductQuery, GetInventoryByProductResponse>(request, context);
|
||||
}
|
||||
|
||||
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;
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllInventoryItemsRequest, GetAllInventoryItemsQuery, GetAllInventoryItemsResponse>(request, context);
|
||||
}
|
||||
|
||||
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;
|
||||
return await _dispatchRequestToCQRS.Handle<GetLowStockItemsRequest, GetLowStockItemsQuery, GetLowStockItemsResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateInventorySettings(UpdateInventorySettingsRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<UpdateInventorySettingsRequest, UpdateInventoryItemCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateInventorySettingsRequest, UpdateInventoryItemCommand>(request, context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
// ========== Stock Operations ==========
|
||||
// Note: These operations need lookup by ProductId/ProductType which requires additional implementation
|
||||
// For now, returning stub responses - actual implementation needs custom handlers
|
||||
|
||||
#region Stock Operations
|
||||
|
||||
public override async Task<AddStockResponse> AddStock(AddStockRequest request, ServerCallContext context)
|
||||
public override 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
|
||||
};
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "AddStock requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<AdjustStockResponse> AdjustStock(AdjustStockRequest request, ServerCallContext context)
|
||||
public override Task<AdjustStockResponse> AdjustStock(AdjustStockRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<AdjustStockRequest, UpdateInventoryQuantityCommand, bool>(request, context);
|
||||
return new AdjustStockResponse();
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "AdjustStock requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<ReserveStockResponse> ReserveStock(ReserveStockRequest request, ServerCallContext context)
|
||||
public override 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"
|
||||
};
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "ReserveStock requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> ReleaseReservation(ReleaseReservationRequest request, ServerCallContext context)
|
||||
public override Task<Empty> ReleaseReservation(ReleaseReservationRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<ReleaseReservationRequest, ReleaseReservedInventoryCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "ReleaseReservation requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> ConfirmSale(ConfirmSaleRequest request, ServerCallContext context)
|
||||
public override Task<Empty> ConfirmSale(ConfirmSaleRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<ConfirmSaleRequest, ReduceInventoryCommand, bool>(request, context);
|
||||
return new Empty();
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "ConfirmSale requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<ProcessReturnResponse> ProcessReturn(ProcessReturnRequest request, ServerCallContext context)
|
||||
public override Task<ProcessReturnResponse> ProcessReturn(ProcessReturnRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<ProcessReturnRequest, IncreaseInventoryCommand, bool>(request, context);
|
||||
return new ProcessReturnResponse { NewQuantity = 0 };
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "ProcessReturn requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> RecordLoss(RecordLossRequest request, ServerCallContext context)
|
||||
public override Task<Empty> RecordLoss(RecordLossRequest request, ServerCallContext context)
|
||||
{
|
||||
await _dispatchRequestToCQRS.Handle<RecordLossRequest, CreateStockMovementCommand, long>(request, context);
|
||||
return new Empty();
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "RecordLoss requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
// ========== Bulk Operations ==========
|
||||
|
||||
#region Bulk Operations
|
||||
|
||||
public override async Task<BulkAddStockResponse> BulkAddStock(BulkAddStockRequest request, ServerCallContext context)
|
||||
public override Task<BulkAddStockResponse> BulkAddStock(BulkAddStockRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement bulk add stock
|
||||
return new BulkAddStockResponse { SuccessCount = 0, FailedCount = 0 };
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "BulkAddStock requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
public override async Task<BulkAdjustStockResponse> BulkAdjustStock(BulkAdjustStockRequest request, ServerCallContext context)
|
||||
public override Task<BulkAdjustStockResponse> BulkAdjustStock(BulkAdjustStockRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement bulk adjust stock
|
||||
return new BulkAdjustStockResponse { SuccessCount = 0, FailedCount = 0 };
|
||||
// TODO: Implement with product lookup
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "BulkAdjustStock requires product lookup - not yet implemented"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stock Movements
|
||||
// ========== 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;
|
||||
return await _dispatchRequestToCQRS.Handle<GetStockMovementsRequest, GetStockMovementsQuery, GetStockMovementsResponse>(request, context);
|
||||
}
|
||||
|
||||
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;
|
||||
return await _dispatchRequestToCQRS.Handle<GetStockMovementsByInventoryItemRequest, GetStockMovementsByInventoryItemQuery, GetStockMovementsByInventoryItemResponse>(request, context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
// ========== Reports ==========
|
||||
|
||||
#region Reports
|
||||
|
||||
public override async Task<GetInventorySummaryResponse> GetInventorySummary(GetInventorySummaryRequest request, ServerCallContext context)
|
||||
public override Task<GetInventorySummaryResponse> GetInventorySummary(GetInventorySummaryRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement summary query
|
||||
return new GetInventorySummaryResponse();
|
||||
return Task.FromResult(new GetInventorySummaryResponse
|
||||
{
|
||||
TotalProducts = 0,
|
||||
TotalDiscountProducts = 0,
|
||||
TotalQuantity = 0,
|
||||
TotalReserved = 0,
|
||||
LowStockCount = 0,
|
||||
OutOfStockCount = 0,
|
||||
TotalStockValue = 0
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task<GetStockValueReportResponse> GetStockValueReport(GetStockValueReportRequest request, ServerCallContext context)
|
||||
public override Task<GetStockValueReportResponse> GetStockValueReport(GetStockValueReportRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement stock value report
|
||||
return new GetStockValueReportResponse();
|
||||
// TODO: Implement stock value report query
|
||||
return Task.FromResult(new GetStockValueReportResponse
|
||||
{
|
||||
TotalValue = 0,
|
||||
TotalItems = 0
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user