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:
@@ -24,6 +24,7 @@ using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.ManualPayment;
|
||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||
using CMSMicroservice.Protobuf.Protos.AppVersion;
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.Common.Interfaces;
|
||||
|
||||
@@ -69,6 +70,9 @@ public interface IApplicationContractContext
|
||||
|
||||
// App Version Management
|
||||
AppVersionContract.AppVersionContractClient AppVersions { get; }
|
||||
|
||||
// Inventory Management System
|
||||
InventoryContract.InventoryContractClient Inventory { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.AddStock;
|
||||
|
||||
public record AddStockCommand : IRequest<AddStockResponseDto>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
public int ProductType { get; init; } // 1=Regular, 2=Discount
|
||||
public int Quantity { get; init; }
|
||||
public string? ReferenceNumber { get; init; }
|
||||
public string? Note { get; init; }
|
||||
public long? WarehouseId { get; init; }
|
||||
}
|
||||
|
||||
public class AddStockResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public long InventoryItemId { get; set; }
|
||||
public int NewQuantity { get; set; }
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.AddStock;
|
||||
|
||||
public class AddStockCommandHandler : IRequestHandler<AddStockCommand, AddStockResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public AddStockCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<AddStockResponseDto> Handle(AddStockCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new AddStockRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
ProductType = (ProductType)request.ProductType,
|
||||
Quantity = request.Quantity
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.ReferenceNumber))
|
||||
protoRequest.ReferenceNumber = request.ReferenceNumber;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Note))
|
||||
protoRequest.Note = request.Note;
|
||||
|
||||
if (request.WarehouseId.HasValue)
|
||||
protoRequest.WarehouseId = request.WarehouseId.Value;
|
||||
|
||||
var response = await _context.Inventory.AddStockAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new AddStockResponseDto
|
||||
{
|
||||
Success = true,
|
||||
InventoryItemId = response.InventoryItemId,
|
||||
NewQuantity = response.NewQuantity,
|
||||
Message = "ورود کالا با موفقیت ثبت شد"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.AdjustStock;
|
||||
|
||||
public record AdjustStockCommand : IRequest<AdjustStockResponseDto>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
public int ProductType { get; init; } // 1=Regular, 2=Discount
|
||||
public int NewQuantity { get; init; }
|
||||
public string? Note { get; init; }
|
||||
public long? WarehouseId { get; init; }
|
||||
}
|
||||
|
||||
public class AdjustStockResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public int OldQuantity { get; set; }
|
||||
public int NewQuantity { get; set; }
|
||||
public int Difference { get; set; }
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.AdjustStock;
|
||||
|
||||
public class AdjustStockCommandHandler : IRequestHandler<AdjustStockCommand, AdjustStockResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public AdjustStockCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<AdjustStockResponseDto> Handle(AdjustStockCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new AdjustStockRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
ProductType = (ProductType)request.ProductType,
|
||||
NewQuantity = request.NewQuantity
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Note))
|
||||
protoRequest.Reason = request.Note;
|
||||
|
||||
var response = await _context.Inventory.AdjustStockAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new AdjustStockResponseDto
|
||||
{
|
||||
Success = true,
|
||||
OldQuantity = response.PreviousQuantity,
|
||||
NewQuantity = response.NewQuantity,
|
||||
Difference = response.Difference,
|
||||
Message = "تعدیل موجودی با موفقیت انجام شد"
|
||||
};
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.CreateWarehouse;
|
||||
|
||||
public record CreateWarehouseCommand : IRequest<long>
|
||||
{
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string Code { get; init; } = string.Empty;
|
||||
public string? Address { get; init; }
|
||||
public bool IsDefault { get; init; }
|
||||
public bool IsActive { get; init; } = true;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.CreateWarehouse;
|
||||
|
||||
public class CreateWarehouseCommandHandler : IRequestHandler<CreateWarehouseCommand, long>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public CreateWarehouseCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(CreateWarehouseCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new CreateWarehouseRequest
|
||||
{
|
||||
Name = request.Name,
|
||||
Code = request.Code,
|
||||
IsDefault = request.IsDefault
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Address))
|
||||
protoRequest.Address = request.Address;
|
||||
|
||||
var response = await _context.Inventory.CreateWarehouseAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
return response.Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.RecordLoss;
|
||||
|
||||
public record RecordLossCommand : IRequest<bool>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
public int ProductType { get; init; } // 1=Regular, 2=Discount
|
||||
public int Quantity { get; init; }
|
||||
public int LossType { get; init; } // 40=Loss, 41=Damaged, 42=Expired
|
||||
public string? Note { get; init; }
|
||||
public long? WarehouseId { get; init; }
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.RecordLoss;
|
||||
|
||||
public class RecordLossCommandHandler : IRequestHandler<RecordLossCommand, bool>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public RecordLossCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(RecordLossCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new RecordLossRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
ProductType = (ProductType)request.ProductType,
|
||||
Quantity = request.Quantity,
|
||||
LossType = (StockMovementType)request.LossType
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Note))
|
||||
protoRequest.Reason = request.Note;
|
||||
|
||||
await _context.Inventory.RecordLossAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.UpdateInventorySettings;
|
||||
|
||||
public record UpdateInventorySettingsCommand : IRequest<bool>
|
||||
{
|
||||
public long InventoryItemId { get; init; }
|
||||
public int LowStockThreshold { get; init; }
|
||||
public int ReorderPoint { get; init; }
|
||||
public int MaxStockLevel { get; init; }
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Commands.UpdateInventorySettings;
|
||||
|
||||
public class UpdateInventorySettingsCommandHandler : IRequestHandler<UpdateInventorySettingsCommand, bool>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateInventorySettingsCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(UpdateInventorySettingsCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new UpdateInventorySettingsRequest
|
||||
{
|
||||
Id = request.InventoryItemId,
|
||||
LowStockThreshold = request.LowStockThreshold,
|
||||
ReorderPoint = request.ReorderPoint,
|
||||
MaxStockLevel = request.MaxStockLevel
|
||||
};
|
||||
|
||||
await _context.Inventory.UpdateInventorySettingsAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
|
||||
|
||||
public record GetAllInventoryItemsQuery : IRequest<GetAllInventoryItemsResponseDto>
|
||||
{
|
||||
public int PageIndex { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 20;
|
||||
public long? WarehouseId { get; init; }
|
||||
public int? ProductType { get; init; } // 1=Regular, 2=Discount
|
||||
public bool? LowStockOnly { get; init; }
|
||||
public string? SearchTerm { get; init; }
|
||||
}
|
||||
|
||||
public class GetAllInventoryItemsResponseDto
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<InventoryItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class InventoryItemDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long? ProductId { get; set; }
|
||||
public long? DiscountProductId { get; set; }
|
||||
public int ProductType { get; set; }
|
||||
public string ProductName { get; set; } = string.Empty;
|
||||
public int Quantity { get; set; }
|
||||
public int ReservedQuantity { get; set; }
|
||||
public int AvailableQuantity { get; set; }
|
||||
public int LowStockThreshold { get; set; }
|
||||
public int ReorderPoint { get; set; }
|
||||
public int MaxStockLevel { get; set; }
|
||||
public DateTime? LastRestockedAt { get; set; }
|
||||
public DateTime? LastSoldAt { get; set; }
|
||||
public long WarehouseId { get; set; }
|
||||
public string WarehouseName { get; set; } = string.Empty;
|
||||
public bool IsLowStock => Quantity <= LowStockThreshold;
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
|
||||
|
||||
public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryItemsQuery, GetAllInventoryItemsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetAllInventoryItemsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllInventoryItemsResponseDto> Handle(GetAllInventoryItemsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new GetAllInventoryItemsRequest
|
||||
{
|
||||
Page = request.PageIndex,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
if (request.WarehouseId.HasValue)
|
||||
protoRequest.WarehouseId = request.WarehouseId.Value;
|
||||
|
||||
if (request.ProductType.HasValue)
|
||||
protoRequest.ProductType = (ProductType)request.ProductType.Value;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.SearchTerm))
|
||||
protoRequest.Search = request.SearchTerm;
|
||||
|
||||
var response = await _context.Inventory.GetAllInventoryItemsAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetAllInventoryItemsResponseDto
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
MetaData = new MetaData
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
PageSize = request.PageSize,
|
||||
CurrentPage = request.PageIndex,
|
||||
TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize)
|
||||
},
|
||||
Items = response.Items.Select(i => new InventoryItemDto
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId,
|
||||
DiscountProductId = i.DiscountProductId,
|
||||
ProductType = (int)i.ProductType,
|
||||
ProductName = i.ProductTitle,
|
||||
Quantity = i.Quantity,
|
||||
ReservedQuantity = i.ReservedQuantity,
|
||||
AvailableQuantity = i.AvailableQuantity,
|
||||
LowStockThreshold = i.LowStockThreshold,
|
||||
ReorderPoint = i.ReorderPoint,
|
||||
MaxStockLevel = i.MaxStockLevel,
|
||||
LastRestockedAt = i.LastRestockedAt?.ToDateTime(),
|
||||
LastSoldAt = i.LastSoldAt?.ToDateTime(),
|
||||
WarehouseId = i.WarehouseId,
|
||||
WarehouseName = i.WarehouseName
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllWarehouses;
|
||||
|
||||
public record GetAllWarehousesQuery : IRequest<GetAllWarehousesResponseDto>
|
||||
{
|
||||
public bool? ActiveOnly { get; init; }
|
||||
}
|
||||
|
||||
public class GetAllWarehousesResponseDto
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<WarehouseDto> Warehouses { get; set; } = new();
|
||||
}
|
||||
|
||||
public class WarehouseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string? Address { get; set; }
|
||||
public bool IsDefault { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllWarehouses;
|
||||
|
||||
public class GetAllWarehousesQueryHandler : IRequestHandler<GetAllWarehousesQuery, GetAllWarehousesResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetAllWarehousesQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllWarehousesResponseDto> Handle(GetAllWarehousesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new GetAllWarehousesRequest();
|
||||
|
||||
if (request.ActiveOnly.HasValue)
|
||||
{
|
||||
protoRequest.IsActive = request.ActiveOnly.Value;
|
||||
}
|
||||
|
||||
var response = await _context.Inventory.GetAllWarehousesAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetAllWarehousesResponseDto
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
Warehouses = response.Warehouses.Select(w => new WarehouseDto
|
||||
{
|
||||
Id = w.Id,
|
||||
Name = w.Name,
|
||||
Code = w.Code,
|
||||
Address = w.Address,
|
||||
IsDefault = w.IsDefault,
|
||||
IsActive = w.IsActive
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems;
|
||||
|
||||
public record GetLowStockItemsQuery : IRequest<GetLowStockItemsResponseDto>
|
||||
{
|
||||
public int? Threshold { get; init; }
|
||||
public long? WarehouseId { get; init; }
|
||||
public int? ProductType { get; init; } // 1=Regular, 2=Discount
|
||||
public int Count { get; init; } = 50;
|
||||
}
|
||||
|
||||
public class GetLowStockItemsResponseDto
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<LowStockItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class LowStockItemDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long? ProductId { get; set; }
|
||||
public long? DiscountProductId { get; set; }
|
||||
public int ProductType { get; set; }
|
||||
public string ProductName { get; set; } = string.Empty;
|
||||
public int Quantity { get; set; }
|
||||
public int ReservedQuantity { get; set; }
|
||||
public int AvailableQuantity { get; set; }
|
||||
public int LowStockThreshold { get; set; }
|
||||
public int ReorderPoint { get; set; }
|
||||
public long WarehouseId { get; set; }
|
||||
public string WarehouseName { get; set; } = string.Empty;
|
||||
public int DeficitAmount => LowStockThreshold - Quantity; // چقدر کم داریم
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems;
|
||||
|
||||
public class GetLowStockItemsQueryHandler : IRequestHandler<GetLowStockItemsQuery, GetLowStockItemsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetLowStockItemsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetLowStockItemsResponseDto> Handle(GetLowStockItemsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new GetLowStockItemsRequest
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = request.Count
|
||||
};
|
||||
|
||||
if (request.WarehouseId.HasValue)
|
||||
protoRequest.WarehouseId = request.WarehouseId.Value;
|
||||
|
||||
if (request.ProductType.HasValue)
|
||||
protoRequest.ProductType = (ProductType)request.ProductType.Value;
|
||||
|
||||
var response = await _context.Inventory.GetLowStockItemsAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetLowStockItemsResponseDto
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
Items = response.Items.Select(i => new LowStockItemDto
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId,
|
||||
DiscountProductId = i.DiscountProductId,
|
||||
ProductType = (int)i.ProductType,
|
||||
ProductName = i.ProductTitle,
|
||||
Quantity = i.Quantity,
|
||||
ReservedQuantity = i.ReservedQuantity,
|
||||
AvailableQuantity = i.AvailableQuantity,
|
||||
LowStockThreshold = i.LowStockThreshold,
|
||||
ReorderPoint = i.ReorderPoint,
|
||||
WarehouseId = i.WarehouseId,
|
||||
WarehouseName = i.WarehouseName
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetStockMovements;
|
||||
|
||||
public record GetStockMovementsQuery : IRequest<GetStockMovementsResponseDto>
|
||||
{
|
||||
public long? InventoryItemId { get; init; }
|
||||
public long? ProductId { get; init; }
|
||||
public int? ProductType { get; init; }
|
||||
public int? MovementType { get; init; }
|
||||
public DateTime? FromDate { get; init; }
|
||||
public DateTime? ToDate { get; init; }
|
||||
public int PageIndex { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
|
||||
public class GetStockMovementsResponseDto
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<StockMovementDto> Movements { get; set; } = new();
|
||||
}
|
||||
|
||||
public class StockMovementDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long InventoryItemId { get; set; }
|
||||
public string ProductName { get; set; } = string.Empty;
|
||||
public int MovementType { get; set; }
|
||||
public string MovementTypeName { get; set; } = string.Empty;
|
||||
public int Quantity { get; set; }
|
||||
public int QuantityBefore { get; set; }
|
||||
public int QuantityAfter { get; set; }
|
||||
public long? OrderId { get; set; }
|
||||
public long? DiscountOrderId { get; set; }
|
||||
public string? ReferenceNumber { get; set; }
|
||||
public string? Note { get; set; }
|
||||
public long? PerformedByUserId { get; set; }
|
||||
public string? PerformedByUserName { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetStockMovements;
|
||||
|
||||
public class GetStockMovementsQueryHandler : IRequestHandler<GetStockMovementsQuery, GetStockMovementsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetStockMovementsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetStockMovementsResponseDto> Handle(GetStockMovementsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var protoRequest = new GetStockMovementsRequest
|
||||
{
|
||||
Page = request.PageIndex,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
if (request.InventoryItemId.HasValue)
|
||||
protoRequest.InventoryItemId = request.InventoryItemId.Value;
|
||||
|
||||
if (request.ProductId.HasValue)
|
||||
protoRequest.ProductId = request.ProductId.Value;
|
||||
|
||||
if (request.ProductType.HasValue)
|
||||
protoRequest.ProductType = (ProductType)request.ProductType.Value;
|
||||
|
||||
if (request.MovementType.HasValue)
|
||||
protoRequest.MovementType = (StockMovementType)request.MovementType.Value;
|
||||
|
||||
if (request.FromDate.HasValue)
|
||||
protoRequest.FromDate = Timestamp.FromDateTime(request.FromDate.Value.ToUniversalTime());
|
||||
|
||||
if (request.ToDate.HasValue)
|
||||
protoRequest.ToDate = Timestamp.FromDateTime(request.ToDate.Value.ToUniversalTime());
|
||||
|
||||
var response = await _context.Inventory.GetStockMovementsAsync(protoRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetStockMovementsResponseDto
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
MetaData = new MetaData
|
||||
{
|
||||
TotalCount = response.TotalCount,
|
||||
PageSize = request.PageSize,
|
||||
CurrentPage = request.PageIndex,
|
||||
TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize)
|
||||
},
|
||||
Movements = response.Movements.Select(m => new StockMovementDto
|
||||
{
|
||||
Id = m.Id,
|
||||
InventoryItemId = m.InventoryItemId,
|
||||
ProductName = m.ProductTitle,
|
||||
MovementType = (int)m.MovementType,
|
||||
MovementTypeName = GetMovementTypeName(m.MovementType),
|
||||
Quantity = m.Quantity,
|
||||
QuantityBefore = m.QuantityBefore,
|
||||
QuantityAfter = m.QuantityAfter,
|
||||
OrderId = m.OrderId,
|
||||
DiscountOrderId = m.DiscountOrderId,
|
||||
ReferenceNumber = string.IsNullOrEmpty(m.ReferenceNumber) ? null : m.ReferenceNumber,
|
||||
Note = string.IsNullOrEmpty(m.Note) ? null : m.Note,
|
||||
PerformedByUserId = m.PerformedByUserId,
|
||||
PerformedByUserName = null,
|
||||
CreatedAt = m.Created?.ToDateTime() ?? DateTime.MinValue
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetMovementTypeName(StockMovementType type) => type switch
|
||||
{
|
||||
StockMovementType.InitialStock => "موجودی اولیه",
|
||||
StockMovementType.Restock => "ورود کالا",
|
||||
StockMovementType.Return => "برگشت از مشتری",
|
||||
StockMovementType.Sale => "فروش",
|
||||
StockMovementType.AdjustmentIncrease => "تعدیل افزایشی",
|
||||
StockMovementType.AdjustmentDecrease => "تعدیل کاهشی",
|
||||
StockMovementType.Reserved => "رزرو",
|
||||
StockMovementType.Released => "آزادسازی رزرو",
|
||||
StockMovementType.Loss => "مفقودی",
|
||||
StockMovementType.Damaged => "ضایعات",
|
||||
StockMovementType.Expired => "منقضی",
|
||||
StockMovementType.TransferOut => "انتقال به انبار",
|
||||
StockMovementType.TransferIn => "انتقال از انبار",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user