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.ManualPayment;
|
||||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
using CMSMicroservice.Protobuf.Protos.AppVersion;
|
using CMSMicroservice.Protobuf.Protos.AppVersion;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||||
|
|
||||||
namespace BackOffice.BFF.Application.Common.Interfaces;
|
namespace BackOffice.BFF.Application.Common.Interfaces;
|
||||||
|
|
||||||
@@ -70,5 +71,8 @@ public interface IApplicationContractContext
|
|||||||
// App Version Management
|
// App Version Management
|
||||||
AppVersionContract.AppVersionContractClient AppVersions { get; }
|
AppVersionContract.AppVersionContractClient AppVersions { get; }
|
||||||
|
|
||||||
|
// Inventory Management System
|
||||||
|
InventoryContract.InventoryContractClient Inventory { get; }
|
||||||
|
|
||||||
#endregion
|
#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 => "انتقال از انبار",
|
||||||
|
_ => "نامشخص"
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
|||||||
using CMSMicroservice.Protobuf.Protos.ManualPayment;
|
using CMSMicroservice.Protobuf.Protos.ManualPayment;
|
||||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
using CMSMicroservice.Protobuf.Protos.AppVersion;
|
using CMSMicroservice.Protobuf.Protos.AppVersion;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.Inventory;
|
||||||
|
|
||||||
// BFF Protobuf contracts
|
// BFF Protobuf contracts
|
||||||
|
|
||||||
@@ -97,5 +98,8 @@ public class ApplicationContractContext : IApplicationContractContext
|
|||||||
|
|
||||||
// App Version Management
|
// App Version Management
|
||||||
public AppVersionContract.AppVersionContractClient AppVersions => GetService<AppVersionContract.AppVersionContractClient>();
|
public AppVersionContract.AppVersionContractClient AppVersions => GetService<AppVersionContract.AppVersionContractClient>();
|
||||||
|
|
||||||
|
// Inventory Management System
|
||||||
|
public InventoryContract.InventoryContractClient Inventory => GetService<InventoryContract.InventoryContractClient>();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
<ProjectReference Include="..\Protobufs\BackOffice.BFF.DiscountShoppingCart.Protobuf\BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj" />
|
<ProjectReference Include="..\Protobufs\BackOffice.BFF.DiscountShoppingCart.Protobuf\BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj" />
|
||||||
<ProjectReference Include="..\Protobufs\BackOffice.BFF.Tag.Protobuf\BackOffice.BFF.Tag.Protobuf.csproj" />
|
<ProjectReference Include="..\Protobufs\BackOffice.BFF.Tag.Protobuf\BackOffice.BFF.Tag.Protobuf.csproj" />
|
||||||
<ProjectReference Include="..\Protobufs\BackOffice.BFF.ProductTag.Protobuf\BackOffice.BFF.ProductTag.Protobuf.csproj" />
|
<ProjectReference Include="..\Protobufs\BackOffice.BFF.ProductTag.Protobuf\BackOffice.BFF.ProductTag.Protobuf.csproj" />
|
||||||
|
<ProjectReference Include="..\Protobufs\BackOffice.BFF.Inventory.Protobuf\BackOffice.BFF.Inventory.Protobuf.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\.dockerignore">
|
<Content Include="..\.dockerignore">
|
||||||
|
|||||||
@@ -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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using BackOffice.BFF.WebApi.Common.Services;
|
||||||
|
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 Foursat.BackOffice.BFF.Inventory.Protos;
|
||||||
|
|
||||||
|
namespace BackOffice.BFF.WebApi.Services;
|
||||||
|
|
||||||
|
public class InventoryService : InventoryBFFContract.InventoryBFFContractBase
|
||||||
|
{
|
||||||
|
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||||
|
|
||||||
|
public InventoryService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||||
|
{
|
||||||
|
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<GetAllWarehousesResponse> GetAllWarehouses(
|
||||||
|
GetAllWarehousesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<GetAllWarehousesRequest, GetAllWarehousesQuery, GetAllWarehousesResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<CreateWarehouseResponse> CreateWarehouse(
|
||||||
|
CreateWarehouseRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<CreateWarehouseRequest, CreateWarehouseCommand, CreateWarehouseResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<GetAllInventoryItemsResponse> GetAllInventoryItems(
|
||||||
|
GetAllInventoryItemsRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<GetAllInventoryItemsRequest, GetAllInventoryItemsQuery, GetAllInventoryItemsResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<GetLowStockItemsResponse> GetLowStockItems(
|
||||||
|
GetLowStockItemsRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<GetLowStockItemsRequest, GetLowStockItemsQuery, GetLowStockItemsResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<GetStockMovementsResponse> GetStockMovements(
|
||||||
|
GetStockMovementsRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<GetStockMovementsRequest, GetStockMovementsQuery, GetStockMovementsResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<AddStockResponse> AddStock(
|
||||||
|
AddStockRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<AddStockRequest, AddStockCommand, AddStockResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<AdjustStockResponse> AdjustStock(
|
||||||
|
AdjustStockRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<AdjustStockRequest, AdjustStockCommand, AdjustStockResponse>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Empty> RecordLoss(
|
||||||
|
RecordLossRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<RecordLossRequest, RecordLossCommand>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Empty> UpdateInventorySettings(
|
||||||
|
UpdateInventorySettingsRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<UpdateInventorySettingsRequest, UpdateInventorySettingsCommand>(
|
||||||
|
request,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.Configuratio
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.PublicMessage.Protobuf", "Protobufs\BackOffice.BFF.PublicMessage.Protobuf\BackOffice.BFF.PublicMessage.Protobuf.csproj", "{3454F4C0-A6C8-44BC-9389-6248518E3EA6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.PublicMessage.Protobuf", "Protobufs\BackOffice.BFF.PublicMessage.Protobuf\BackOffice.BFF.PublicMessage.Protobuf.csproj", "{3454F4C0-A6C8-44BC-9389-6248518E3EA6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.Inventory.Protobuf", "Protobufs\BackOffice.BFF.Inventory.Protobuf\BackOffice.BFF.Inventory.Protobuf.csproj", "{0FFE3E2F-4F78-4376-B373-51830C447EEE}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -393,6 +395,18 @@ Global
|
|||||||
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x64.Build.0 = Release|Any CPU
|
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x86.ActiveCfg = Release|Any CPU
|
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x86.Build.0 = Release|Any CPU
|
{3454F4C0-A6C8-44BC-9389-6248518E3EA6}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -421,6 +435,7 @@ Global
|
|||||||
{1F95197B-9118-4C19-9C1B-C0872AA8F412} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
{1F95197B-9118-4C19-9C1B-C0872AA8F412} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
{FB2AAF65-F9DC-4315-979E-A77EC44C5FB1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
{FB2AAF65-F9DC-4315-979E-A77EC44C5FB1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
{3454F4C0-A6C8-44BC-9389-6248518E3EA6} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
{3454F4C0-A6C8-44BC-9389-6248518E3EA6} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{0FFE3E2F-4F78-4376-B373-51830C447EEE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {0AE1AB4A-3C91-4853-93C2-C2476E79F845}
|
SolutionGuid = {0AE1AB4A-3C91-4853-93C2-C2476E79F845}
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>true</IsPackable>
|
||||||
|
<PackageId>Foursat.BackOffice.BFF.Inventory.Protobuf</PackageId>
|
||||||
|
<Version>0.0.1</Version>
|
||||||
|
<Authors>FourSat</Authors>
|
||||||
|
<Company>FourSat</Company>
|
||||||
|
<Product>Foursat.BackOffice.BFF.Inventory.Protobuf</Product>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||||
|
<PackageReference Include="Grpc.Core.Api" Version="2.54.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="2.72.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.2.2" />
|
||||||
|
<PackageReference Include="Google.Api.CommonProtos" Version="2.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Protos\inventory.proto" ProtoRoot="Protos\" GrpcServices="Both" AdditionalImportDirs="..\BackOffice.BFF.Common.Protobuf\Protos"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\BackOffice.BFF.Common.Protobuf\BackOffice.BFF.Common.Protobuf.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Target Name="PushToFourSat" AfterTargets="Pack">
|
||||||
|
<PropertyGroup>
|
||||||
|
<NugetPackagePath>$(PackageOutputPath)$(PackageId).$(Version).nupkg</NugetPackagePath>
|
||||||
|
<PushCommand>
|
||||||
|
dotnet nuget push **/*.nupkg --source https://git.afrino.co/api/packages/FourSat/nuget/index.json --api-key 061a5cb15517c6da39c16cfce8556c55ae104d0d --skip-duplicate
|
||||||
|
</PushCommand>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Exec Command="$(PushCommand)" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package inventory;
|
||||||
|
|
||||||
|
import "public_messages.proto";
|
||||||
|
import "google/protobuf/empty.proto";
|
||||||
|
import "google/protobuf/wrappers.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
option csharp_namespace = "Foursat.BackOffice.BFF.Inventory.Protos";
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Service Definition
|
||||||
|
// =============================================
|
||||||
|
service InventoryBFFContract
|
||||||
|
{
|
||||||
|
// Warehouse Management
|
||||||
|
rpc GetAllWarehouses(GetAllWarehousesRequest) returns (GetAllWarehousesResponse);
|
||||||
|
rpc CreateWarehouse(CreateWarehouseRequest) returns (CreateWarehouseResponse);
|
||||||
|
|
||||||
|
// Inventory Items
|
||||||
|
rpc GetAllInventoryItems(GetAllInventoryItemsRequest) returns (GetAllInventoryItemsResponse);
|
||||||
|
rpc GetLowStockItems(GetLowStockItemsRequest) returns (GetLowStockItemsResponse);
|
||||||
|
rpc GetStockMovements(GetStockMovementsRequest) returns (GetStockMovementsResponse);
|
||||||
|
|
||||||
|
// Stock Operations
|
||||||
|
rpc AddStock(AddStockRequest) returns (AddStockResponse);
|
||||||
|
rpc AdjustStock(AdjustStockRequest) returns (AdjustStockResponse);
|
||||||
|
rpc RecordLoss(RecordLossRequest) returns (google.protobuf.Empty);
|
||||||
|
rpc UpdateInventorySettings(UpdateInventorySettingsRequest) returns (google.protobuf.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Enums
|
||||||
|
// =============================================
|
||||||
|
enum ProductType {
|
||||||
|
PRODUCT_TYPE_UNSPECIFIED = 0;
|
||||||
|
REGULAR = 1;
|
||||||
|
DISCOUNT = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StockMovementType {
|
||||||
|
STOCK_MOVEMENT_TYPE_UNSPECIFIED = 0;
|
||||||
|
INITIAL_STOCK = 1;
|
||||||
|
RESTOCK = 2;
|
||||||
|
RETURN = 3;
|
||||||
|
SALE = 4;
|
||||||
|
ADJUSTMENT_INCREASE = 5;
|
||||||
|
ADJUSTMENT_DECREASE = 6;
|
||||||
|
RESERVED = 7;
|
||||||
|
RELEASED = 8;
|
||||||
|
LOSS = 9;
|
||||||
|
DAMAGED = 10;
|
||||||
|
EXPIRED = 11;
|
||||||
|
TRANSFER_OUT = 12;
|
||||||
|
TRANSFER_IN = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Warehouse Messages
|
||||||
|
// =============================================
|
||||||
|
message GetAllWarehousesRequest {
|
||||||
|
google.protobuf.BoolValue active_only = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAllWarehousesResponse {
|
||||||
|
repeated WarehouseDto warehouses = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message WarehouseDto {
|
||||||
|
int64 id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string code = 3;
|
||||||
|
string address = 4;
|
||||||
|
bool is_default = 5;
|
||||||
|
bool is_active = 6;
|
||||||
|
google.protobuf.Timestamp created = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateWarehouseRequest {
|
||||||
|
string name = 1;
|
||||||
|
string code = 2;
|
||||||
|
string address = 3;
|
||||||
|
bool is_default = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateWarehouseResponse {
|
||||||
|
int64 id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Inventory Item Messages
|
||||||
|
// =============================================
|
||||||
|
message GetAllInventoryItemsRequest {
|
||||||
|
int32 page_index = 1;
|
||||||
|
int32 page_size = 2;
|
||||||
|
google.protobuf.Int64Value warehouse_id = 3;
|
||||||
|
ProductType product_type = 4;
|
||||||
|
string search_term = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAllInventoryItemsResponse {
|
||||||
|
int32 total_count = 1;
|
||||||
|
messages.MetaData meta_data = 2;
|
||||||
|
repeated InventoryItemDto items = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message InventoryItemDto {
|
||||||
|
int64 id = 1;
|
||||||
|
google.protobuf.Int64Value product_id = 2;
|
||||||
|
google.protobuf.Int64Value discount_product_id = 3;
|
||||||
|
ProductType product_type = 4;
|
||||||
|
string product_name = 5;
|
||||||
|
int32 quantity = 6;
|
||||||
|
int32 reserved_quantity = 7;
|
||||||
|
int32 available_quantity = 8;
|
||||||
|
int32 low_stock_threshold = 9;
|
||||||
|
int32 reorder_point = 10;
|
||||||
|
int32 max_stock_level = 11;
|
||||||
|
google.protobuf.Timestamp last_restocked_at = 12;
|
||||||
|
google.protobuf.Timestamp last_sold_at = 13;
|
||||||
|
int64 warehouse_id = 14;
|
||||||
|
string warehouse_name = 15;
|
||||||
|
bool is_low_stock = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Low Stock Messages
|
||||||
|
// =============================================
|
||||||
|
message GetLowStockItemsRequest {
|
||||||
|
int32 count = 1;
|
||||||
|
google.protobuf.Int64Value warehouse_id = 2;
|
||||||
|
ProductType product_type = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLowStockItemsResponse {
|
||||||
|
int32 total_count = 1;
|
||||||
|
repeated LowStockItemDto items = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LowStockItemDto {
|
||||||
|
int64 id = 1;
|
||||||
|
google.protobuf.Int64Value product_id = 2;
|
||||||
|
google.protobuf.Int64Value discount_product_id = 3;
|
||||||
|
ProductType product_type = 4;
|
||||||
|
string product_name = 5;
|
||||||
|
int32 quantity = 6;
|
||||||
|
int32 reserved_quantity = 7;
|
||||||
|
int32 available_quantity = 8;
|
||||||
|
int32 low_stock_threshold = 9;
|
||||||
|
int32 reorder_point = 10;
|
||||||
|
int64 warehouse_id = 11;
|
||||||
|
string warehouse_name = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Stock Movement Messages
|
||||||
|
// =============================================
|
||||||
|
message GetStockMovementsRequest {
|
||||||
|
int32 page_index = 1;
|
||||||
|
int32 page_size = 2;
|
||||||
|
google.protobuf.Int64Value inventory_item_id = 3;
|
||||||
|
google.protobuf.Int64Value product_id = 4;
|
||||||
|
ProductType product_type = 5;
|
||||||
|
StockMovementType movement_type = 6;
|
||||||
|
google.protobuf.Timestamp from_date = 7;
|
||||||
|
google.protobuf.Timestamp to_date = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetStockMovementsResponse {
|
||||||
|
int32 total_count = 1;
|
||||||
|
messages.MetaData meta_data = 2;
|
||||||
|
repeated StockMovementDto movements = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StockMovementDto {
|
||||||
|
int64 id = 1;
|
||||||
|
int64 inventory_item_id = 2;
|
||||||
|
string product_name = 3;
|
||||||
|
StockMovementType movement_type = 4;
|
||||||
|
string movement_type_name = 5;
|
||||||
|
int32 quantity = 6;
|
||||||
|
int32 quantity_before = 7;
|
||||||
|
int32 quantity_after = 8;
|
||||||
|
google.protobuf.Int64Value order_id = 9;
|
||||||
|
google.protobuf.Int64Value discount_order_id = 10;
|
||||||
|
string reference_number = 11;
|
||||||
|
string note = 12;
|
||||||
|
google.protobuf.Int64Value performed_by_user_id = 13;
|
||||||
|
string performed_by_user_name = 14;
|
||||||
|
google.protobuf.Timestamp created_at = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Stock Operation Messages
|
||||||
|
// =============================================
|
||||||
|
message AddStockRequest {
|
||||||
|
int64 product_id = 1;
|
||||||
|
ProductType product_type = 2;
|
||||||
|
int32 quantity = 3;
|
||||||
|
string reference_number = 4;
|
||||||
|
string note = 5;
|
||||||
|
google.protobuf.Int64Value warehouse_id = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddStockResponse {
|
||||||
|
bool success = 1;
|
||||||
|
int64 inventory_item_id = 2;
|
||||||
|
int32 new_quantity = 3;
|
||||||
|
string message = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AdjustStockRequest {
|
||||||
|
int64 product_id = 1;
|
||||||
|
ProductType product_type = 2;
|
||||||
|
int32 new_quantity = 3;
|
||||||
|
string note = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AdjustStockResponse {
|
||||||
|
bool success = 1;
|
||||||
|
int32 old_quantity = 2;
|
||||||
|
int32 new_quantity = 3;
|
||||||
|
int32 difference = 4;
|
||||||
|
string message = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RecordLossRequest {
|
||||||
|
int64 product_id = 1;
|
||||||
|
ProductType product_type = 2;
|
||||||
|
int32 quantity = 3;
|
||||||
|
string reason = 4;
|
||||||
|
string reference_number = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateInventorySettingsRequest {
|
||||||
|
int64 inventory_item_id = 1;
|
||||||
|
int32 low_stock_threshold = 2;
|
||||||
|
int32 reorder_point = 3;
|
||||||
|
int32 max_stock_level = 4;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user