Refactor inventory commands and queries for improved clarity and consistency
Build and Deploy / build (push) Failing after 2m12s

- Updated ProductType enum values to be more descriptive (RegularProduct, DiscountProduct).
- Removed unnecessary Success and Message properties from response DTOs in AddStock and AdjustStock commands.
- Renamed Note property to Reason in AdjustStock and RecordLoss commands, and added ReferenceNumber.
- Changed InventoryItemId to Id in UpdateInventorySettingsCommand for consistency.
- Updated pagination properties in various queries (PageIndex to Page).
- Enhanced GetAllInventoryItemsQuery and GetLowStockItemsQuery to include sorting options.
- Updated InventoryProfile mappings to reflect changes in DTOs and Protobuf definitions.
- Adjusted Protobuf definitions to align with new property names and structures.
This commit is contained in:
masoodafar-web
2026-01-03 15:38:22 +03:30
parent 989f4a799a
commit f027fd0b06
18 changed files with 196 additions and 197 deletions
@@ -3,7 +3,7 @@ namespace BackOffice.BFF.Application.InventoryCQ.Commands.AddStock;
public record AddStockCommand : IRequest<AddStockResponseDto> public record AddStockCommand : IRequest<AddStockResponseDto>
{ {
public long ProductId { get; init; } public long ProductId { get; init; }
public int ProductType { get; init; } // 1=Regular, 2=Discount public int ProductType { get; init; } // 1=RegularProduct, 2=DiscountProduct
public int Quantity { get; init; } public int Quantity { get; init; }
public string? ReferenceNumber { get; init; } public string? ReferenceNumber { get; init; }
public string? Note { get; init; } public string? Note { get; init; }
@@ -12,8 +12,6 @@ public record AddStockCommand : IRequest<AddStockResponseDto>
public class AddStockResponseDto public class AddStockResponseDto
{ {
public bool Success { get; set; }
public long InventoryItemId { get; set; } public long InventoryItemId { get; set; }
public int NewQuantity { get; set; } public int NewQuantity { get; set; }
public string? Message { get; set; }
} }
@@ -33,10 +33,8 @@ public class AddStockCommandHandler : IRequestHandler<AddStockCommand, AddStockR
return new AddStockResponseDto return new AddStockResponseDto
{ {
Success = true,
InventoryItemId = response.InventoryItemId, InventoryItemId = response.InventoryItemId,
NewQuantity = response.NewQuantity, NewQuantity = response.NewQuantity
Message = "ورود کالا با موفقیت ثبت شد"
}; };
} }
} }
@@ -3,17 +3,15 @@ namespace BackOffice.BFF.Application.InventoryCQ.Commands.AdjustStock;
public record AdjustStockCommand : IRequest<AdjustStockResponseDto> public record AdjustStockCommand : IRequest<AdjustStockResponseDto>
{ {
public long ProductId { get; init; } public long ProductId { get; init; }
public int ProductType { get; init; } // 1=Regular, 2=Discount public int ProductType { get; init; } // 1=RegularProduct, 2=DiscountProduct
public int NewQuantity { get; init; } public int NewQuantity { get; init; }
public string? Note { get; init; } public string? Reason { get; init; }
public long? WarehouseId { get; init; } public string? ReferenceNumber { get; init; }
} }
public class AdjustStockResponseDto public class AdjustStockResponseDto
{ {
public bool Success { get; set; } public int PreviousQuantity { get; set; }
public int OldQuantity { get; set; }
public int NewQuantity { get; set; } public int NewQuantity { get; set; }
public int Difference { get; set; } public int Difference { get; set; }
public string? Message { get; set; }
} }
@@ -20,18 +20,19 @@ public class AdjustStockCommandHandler : IRequestHandler<AdjustStockCommand, Adj
NewQuantity = request.NewQuantity NewQuantity = request.NewQuantity
}; };
if (!string.IsNullOrWhiteSpace(request.Note)) if (!string.IsNullOrWhiteSpace(request.Reason))
protoRequest.Reason = request.Note; protoRequest.Reason = request.Reason;
if (!string.IsNullOrWhiteSpace(request.ReferenceNumber))
protoRequest.ReferenceNumber = request.ReferenceNumber;
var response = await _context.Inventory.AdjustStockAsync(protoRequest, cancellationToken: cancellationToken); var response = await _context.Inventory.AdjustStockAsync(protoRequest, cancellationToken: cancellationToken);
return new AdjustStockResponseDto return new AdjustStockResponseDto
{ {
Success = true, PreviousQuantity = response.PreviousQuantity,
OldQuantity = response.PreviousQuantity,
NewQuantity = response.NewQuantity, NewQuantity = response.NewQuantity,
Difference = response.Difference, Difference = response.Difference
Message = "تعدیل موجودی با موفقیت انجام شد"
}; };
} }
} }
@@ -3,9 +3,9 @@ namespace BackOffice.BFF.Application.InventoryCQ.Commands.RecordLoss;
public record RecordLossCommand : IRequest<bool> public record RecordLossCommand : IRequest<bool>
{ {
public long ProductId { get; init; } public long ProductId { get; init; }
public int ProductType { get; init; } // 1=Regular, 2=Discount public int ProductType { get; init; } // 1=RegularProduct, 2=DiscountProduct
public int Quantity { get; init; } public int Quantity { get; init; }
public int LossType { get; init; } // 40=Loss, 41=Damaged, 42=Expired public int LossType { get; init; } // 40=Loss, 41=Damaged, 42=Expired
public string? Note { get; init; } public string? Reason { get; init; }
public long? WarehouseId { get; init; } public string? ReferenceNumber { get; init; }
} }
@@ -21,8 +21,11 @@ public class RecordLossCommandHandler : IRequestHandler<RecordLossCommand, bool>
LossType = (StockMovementType)request.LossType LossType = (StockMovementType)request.LossType
}; };
if (!string.IsNullOrWhiteSpace(request.Note)) if (!string.IsNullOrWhiteSpace(request.Reason))
protoRequest.Reason = request.Note; protoRequest.Reason = request.Reason;
if (!string.IsNullOrWhiteSpace(request.ReferenceNumber))
protoRequest.ReferenceNumber = request.ReferenceNumber;
await _context.Inventory.RecordLossAsync(protoRequest, cancellationToken: cancellationToken); await _context.Inventory.RecordLossAsync(protoRequest, cancellationToken: cancellationToken);
return true; return true;
@@ -2,7 +2,7 @@ namespace BackOffice.BFF.Application.InventoryCQ.Commands.UpdateInventorySetting
public record UpdateInventorySettingsCommand : IRequest<bool> public record UpdateInventorySettingsCommand : IRequest<bool>
{ {
public long InventoryItemId { get; init; } public long Id { get; init; }
public int LowStockThreshold { get; init; } public int LowStockThreshold { get; init; }
public int ReorderPoint { get; init; } public int ReorderPoint { get; init; }
public int MaxStockLevel { get; init; } public int MaxStockLevel { get; init; }
@@ -15,7 +15,7 @@ public class UpdateInventorySettingsCommandHandler : IRequestHandler<UpdateInven
{ {
var protoRequest = new UpdateInventorySettingsRequest var protoRequest = new UpdateInventorySettingsRequest
{ {
Id = request.InventoryItemId, Id = request.Id,
LowStockThreshold = request.LowStockThreshold, LowStockThreshold = request.LowStockThreshold,
ReorderPoint = request.ReorderPoint, ReorderPoint = request.ReorderPoint,
MaxStockLevel = request.MaxStockLevel MaxStockLevel = request.MaxStockLevel
@@ -2,12 +2,13 @@ namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
public record GetAllInventoryItemsQuery : IRequest<GetAllInventoryItemsResponseDto> public record GetAllInventoryItemsQuery : IRequest<GetAllInventoryItemsResponseDto>
{ {
public int PageIndex { get; init; } = 1; public int Page { get; init; } = 1;
public int PageSize { get; init; } = 20; public int PageSize { get; init; } = 20;
public long? WarehouseId { get; init; } public long? WarehouseId { get; init; }
public int? ProductType { get; init; } // 1=Regular, 2=Discount public int? ProductType { get; init; } // 1=RegularProduct, 2=DiscountProduct
public bool? LowStockOnly { get; init; } public string? Search { get; init; }
public string? SearchTerm { get; init; } public string? SortBy { get; init; }
public bool SortDesc { get; init; }
} }
public class GetAllInventoryItemsResponseDto public class GetAllInventoryItemsResponseDto
@@ -23,7 +24,8 @@ public class InventoryItemDto
public long? ProductId { get; set; } public long? ProductId { get; set; }
public long? DiscountProductId { get; set; } public long? DiscountProductId { get; set; }
public int ProductType { get; set; } public int ProductType { get; set; }
public string ProductName { get; set; } = string.Empty; public string ProductTitle { get; set; } = string.Empty;
public long ProductPrice { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public int ReservedQuantity { get; set; } public int ReservedQuantity { get; set; }
public int AvailableQuantity { get; set; } public int AvailableQuantity { get; set; }
@@ -34,5 +36,6 @@ public class InventoryItemDto
public DateTime? LastSoldAt { get; set; } public DateTime? LastSoldAt { get; set; }
public long WarehouseId { get; set; } public long WarehouseId { get; set; }
public string WarehouseName { get; set; } = string.Empty; public string WarehouseName { get; set; } = string.Empty;
public bool IsLowStock => Quantity <= LowStockThreshold; public bool IsLowStock { get; set; }
public DateTime? Created { get; set; }
} }
@@ -16,7 +16,7 @@ public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryI
{ {
var protoRequest = new GetAllInventoryItemsRequest var protoRequest = new GetAllInventoryItemsRequest
{ {
Page = request.PageIndex, Page = request.Page,
PageSize = request.PageSize PageSize = request.PageSize
}; };
@@ -26,8 +26,13 @@ public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryI
if (request.ProductType.HasValue) if (request.ProductType.HasValue)
protoRequest.ProductType = (ProductType)request.ProductType.Value; protoRequest.ProductType = (ProductType)request.ProductType.Value;
if (!string.IsNullOrWhiteSpace(request.SearchTerm)) if (!string.IsNullOrWhiteSpace(request.Search))
protoRequest.Search = request.SearchTerm; protoRequest.Search = request.Search;
if (!string.IsNullOrWhiteSpace(request.SortBy))
protoRequest.SortBy = request.SortBy;
protoRequest.SortDesc = request.SortDesc;
var response = await _context.Inventory.GetAllInventoryItemsAsync(protoRequest, cancellationToken: cancellationToken); var response = await _context.Inventory.GetAllInventoryItemsAsync(protoRequest, cancellationToken: cancellationToken);
@@ -38,7 +43,7 @@ public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryI
{ {
TotalCount = response.TotalCount, TotalCount = response.TotalCount,
PageSize = request.PageSize, PageSize = request.PageSize,
CurrentPage = request.PageIndex, CurrentPage = request.Page,
TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize) TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize)
}, },
Items = response.Items.Select(i => new InventoryItemDto Items = response.Items.Select(i => new InventoryItemDto
@@ -47,7 +52,8 @@ public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryI
ProductId = i.ProductId, ProductId = i.ProductId,
DiscountProductId = i.DiscountProductId, DiscountProductId = i.DiscountProductId,
ProductType = (int)i.ProductType, ProductType = (int)i.ProductType,
ProductName = i.ProductTitle, ProductTitle = i.ProductTitle,
ProductPrice = i.ProductPrice,
Quantity = i.Quantity, Quantity = i.Quantity,
ReservedQuantity = i.ReservedQuantity, ReservedQuantity = i.ReservedQuantity,
AvailableQuantity = i.AvailableQuantity, AvailableQuantity = i.AvailableQuantity,
@@ -57,7 +63,9 @@ public class GetAllInventoryItemsQueryHandler : IRequestHandler<GetAllInventoryI
LastRestockedAt = i.LastRestockedAt?.ToDateTime(), LastRestockedAt = i.LastRestockedAt?.ToDateTime(),
LastSoldAt = i.LastSoldAt?.ToDateTime(), LastSoldAt = i.LastSoldAt?.ToDateTime(),
WarehouseId = i.WarehouseId, WarehouseId = i.WarehouseId,
WarehouseName = i.WarehouseName WarehouseName = i.WarehouseName,
IsLowStock = i.Quantity <= i.LowStockThreshold,
Created = i.Created?.ToDateTime()
}).ToList() }).ToList()
}; };
} }
@@ -2,7 +2,7 @@ namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetAllWarehouses;
public record GetAllWarehousesQuery : IRequest<GetAllWarehousesResponseDto> public record GetAllWarehousesQuery : IRequest<GetAllWarehousesResponseDto>
{ {
public bool? ActiveOnly { get; init; } public bool? IsActive { get; init; }
} }
public class GetAllWarehousesResponseDto public class GetAllWarehousesResponseDto
@@ -19,4 +19,6 @@ public class WarehouseDto
public string? Address { get; set; } public string? Address { get; set; }
public bool IsDefault { get; set; } public bool IsDefault { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
public DateTime? Created { get; set; }
public DateTime? LastModified { get; set; }
} }
@@ -15,9 +15,9 @@ public class GetAllWarehousesQueryHandler : IRequestHandler<GetAllWarehousesQuer
{ {
var protoRequest = new CMSMicroservice.Protobuf.Protos.Inventory.GetAllWarehousesRequest(); var protoRequest = new CMSMicroservice.Protobuf.Protos.Inventory.GetAllWarehousesRequest();
if (request.ActiveOnly.HasValue) if (request.IsActive.HasValue)
{ {
protoRequest.IsActive = request.ActiveOnly.Value; protoRequest.IsActive = request.IsActive.Value;
} }
var response = await _context.Inventory.GetAllWarehousesAsync(protoRequest, cancellationToken: cancellationToken); var response = await _context.Inventory.GetAllWarehousesAsync(protoRequest, cancellationToken: cancellationToken);
@@ -32,7 +32,9 @@ public class GetAllWarehousesQueryHandler : IRequestHandler<GetAllWarehousesQuer
Code = w.Code, Code = w.Code,
Address = w.Address, Address = w.Address,
IsDefault = w.IsDefault, IsDefault = w.IsDefault,
IsActive = w.IsActive IsActive = w.IsActive,
Created = w.Created?.ToDateTime(),
LastModified = w.LastModified?.ToDateTime()
}).ToList() }).ToList()
}; };
} }
@@ -1,32 +1,17 @@
using BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems; namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems;
public record GetLowStockItemsQuery : IRequest<GetLowStockItemsResponseDto> public record GetLowStockItemsQuery : IRequest<GetLowStockItemsResponseDto>
{ {
public int? Threshold { get; init; }
public long? WarehouseId { get; init; } public long? WarehouseId { get; init; }
public int? ProductType { get; init; } // 1=Regular, 2=Discount public int? ProductType { get; init; } // 1=RegularProduct, 2=DiscountProduct
public int Count { get; init; } = 50; public int Page { get; init; } = 1;
public int PageSize { get; init; } = 20;
} }
public class GetLowStockItemsResponseDto public class GetLowStockItemsResponseDto
{ {
public int TotalCount { get; set; } public int TotalCount { get; set; }
public List<LowStockItemDto> Items { get; set; } = new(); public List<InventoryItemDto> 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; // چقدر کم داریم
} }
@@ -1,3 +1,4 @@
using BackOffice.BFF.Application.InventoryCQ.Queries.GetAllInventoryItems;
using CMSMicroservice.Protobuf.Protos.Inventory; using CMSMicroservice.Protobuf.Protos.Inventory;
namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems; namespace BackOffice.BFF.Application.InventoryCQ.Queries.GetLowStockItems;
@@ -15,8 +16,8 @@ public class GetLowStockItemsQueryHandler : IRequestHandler<GetLowStockItemsQuer
{ {
var protoRequest = new GetLowStockItemsRequest var protoRequest = new GetLowStockItemsRequest
{ {
Page = 1, Page = request.Page,
PageSize = request.Count PageSize = request.PageSize
}; };
if (request.WarehouseId.HasValue) if (request.WarehouseId.HasValue)
@@ -30,20 +31,23 @@ public class GetLowStockItemsQueryHandler : IRequestHandler<GetLowStockItemsQuer
return new GetLowStockItemsResponseDto return new GetLowStockItemsResponseDto
{ {
TotalCount = response.TotalCount, TotalCount = response.TotalCount,
Items = response.Items.Select(i => new LowStockItemDto Items = response.Items.Select(i => new GetAllInventoryItems.InventoryItemDto
{ {
Id = i.Id, Id = i.Id,
ProductId = i.ProductId, ProductId = i.ProductId,
DiscountProductId = i.DiscountProductId, DiscountProductId = i.DiscountProductId,
ProductType = (int)i.ProductType, ProductType = (int)i.ProductType,
ProductName = i.ProductTitle, ProductTitle = i.ProductTitle,
ProductPrice = i.ProductPrice,
Quantity = i.Quantity, Quantity = i.Quantity,
ReservedQuantity = i.ReservedQuantity, ReservedQuantity = i.ReservedQuantity,
AvailableQuantity = i.AvailableQuantity, AvailableQuantity = i.AvailableQuantity,
LowStockThreshold = i.LowStockThreshold, LowStockThreshold = i.LowStockThreshold,
ReorderPoint = i.ReorderPoint, ReorderPoint = i.ReorderPoint,
MaxStockLevel = i.MaxStockLevel,
WarehouseId = i.WarehouseId, WarehouseId = i.WarehouseId,
WarehouseName = i.WarehouseName WarehouseName = i.WarehouseName,
IsLowStock = true
}).ToList() }).ToList()
}; };
} }
@@ -8,7 +8,7 @@ public record GetStockMovementsQuery : IRequest<GetStockMovementsResponseDto>
public int? MovementType { get; init; } public int? MovementType { get; init; }
public DateTime? FromDate { get; init; } public DateTime? FromDate { get; init; }
public DateTime? ToDate { get; init; } public DateTime? ToDate { get; init; }
public int PageIndex { get; init; } = 1; public int Page { get; init; } = 1;
public int PageSize { get; init; } = 20; public int PageSize { get; init; } = 20;
} }
@@ -23,9 +23,7 @@ public class StockMovementDto
{ {
public long Id { get; set; } public long Id { get; set; }
public long InventoryItemId { get; set; } public long InventoryItemId { get; set; }
public string ProductName { get; set; } = string.Empty;
public int MovementType { get; set; } public int MovementType { get; set; }
public string MovementTypeName { get; set; } = string.Empty;
public int Quantity { get; set; } public int Quantity { get; set; }
public int QuantityBefore { get; set; } public int QuantityBefore { get; set; }
public int QuantityAfter { get; set; } public int QuantityAfter { get; set; }
@@ -34,6 +32,6 @@ public class StockMovementDto
public string? ReferenceNumber { get; set; } public string? ReferenceNumber { get; set; }
public string? Note { get; set; } public string? Note { get; set; }
public long? PerformedByUserId { get; set; } public long? PerformedByUserId { get; set; }
public string? PerformedByUserName { get; set; } public DateTime Created { get; set; }
public DateTime CreatedAt { get; set; } public string ProductTitle { get; set; } = string.Empty;
} }
@@ -16,7 +16,7 @@ public class GetStockMovementsQueryHandler : IRequestHandler<GetStockMovementsQu
{ {
var protoRequest = new GetStockMovementsRequest var protoRequest = new GetStockMovementsRequest
{ {
Page = request.PageIndex, Page = request.Page,
PageSize = request.PageSize PageSize = request.PageSize
}; };
@@ -47,16 +47,14 @@ public class GetStockMovementsQueryHandler : IRequestHandler<GetStockMovementsQu
{ {
TotalCount = response.TotalCount, TotalCount = response.TotalCount,
PageSize = request.PageSize, PageSize = request.PageSize,
CurrentPage = request.PageIndex, CurrentPage = request.Page,
TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize) TotalPage = (int)Math.Ceiling((double)response.TotalCount / request.PageSize)
}, },
Movements = response.Movements.Select(m => new StockMovementDto Movements = response.Movements.Select(m => new StockMovementDto
{ {
Id = m.Id, Id = m.Id,
InventoryItemId = m.InventoryItemId, InventoryItemId = m.InventoryItemId,
ProductName = m.ProductTitle,
MovementType = (int)m.MovementType, MovementType = (int)m.MovementType,
MovementTypeName = GetMovementTypeName(m.MovementType),
Quantity = m.Quantity, Quantity = m.Quantity,
QuantityBefore = m.QuantityBefore, QuantityBefore = m.QuantityBefore,
QuantityAfter = m.QuantityAfter, QuantityAfter = m.QuantityAfter,
@@ -65,8 +63,8 @@ public class GetStockMovementsQueryHandler : IRequestHandler<GetStockMovementsQu
ReferenceNumber = string.IsNullOrEmpty(m.ReferenceNumber) ? null : m.ReferenceNumber, ReferenceNumber = string.IsNullOrEmpty(m.ReferenceNumber) ? null : m.ReferenceNumber,
Note = string.IsNullOrEmpty(m.Note) ? null : m.Note, Note = string.IsNullOrEmpty(m.Note) ? null : m.Note,
PerformedByUserId = m.PerformedByUserId, PerformedByUserId = m.PerformedByUserId,
PerformedByUserName = null, Created = m.Created?.ToDateTime() ?? DateTime.MinValue,
CreatedAt = m.Created?.ToDateTime() ?? DateTime.MinValue ProductTitle = m.ProductTitle
}).ToList() }).ToList()
}; };
} }
@@ -23,12 +23,13 @@ public class InventoryProfile : IRegister
config.NewConfig<BffProtos.GetAllWarehousesRequest, GetAllWarehousesQuery>() config.NewConfig<BffProtos.GetAllWarehousesRequest, GetAllWarehousesQuery>()
.MapWith(src => new GetAllWarehousesQuery .MapWith(src => new GetAllWarehousesQuery
{ {
ActiveOnly = src.ActiveOnly != null ? src.ActiveOnly.Value : null IsActive = src.IsActive != null ? src.IsActive.Value : null
}); });
config.NewConfig<GetAllWarehousesResponseDto, BffProtos.GetAllWarehousesResponse>() config.NewConfig<GetAllWarehousesResponseDto, BffProtos.GetAllWarehousesResponse>()
.MapWith(src => new BffProtos.GetAllWarehousesResponse .MapWith(src => new BffProtos.GetAllWarehousesResponse
{ {
TotalCount = src.TotalCount,
Warehouses = { src.Warehouses.Select(w => new BffProtos.WarehouseDto Warehouses = { src.Warehouses.Select(w => new BffProtos.WarehouseDto
{ {
Id = w.Id, Id = w.Id,
@@ -36,7 +37,13 @@ public class InventoryProfile : IRegister
Code = w.Code ?? string.Empty, Code = w.Code ?? string.Empty,
Address = w.Address ?? string.Empty, Address = w.Address ?? string.Empty,
IsDefault = w.IsDefault, IsDefault = w.IsDefault,
IsActive = w.IsActive IsActive = w.IsActive,
Created = w.Created.HasValue
? Timestamp.FromDateTime(DateTime.SpecifyKind(w.Created.Value, DateTimeKind.Utc))
: null,
LastModified = w.LastModified.HasValue
? Timestamp.FromDateTime(DateTime.SpecifyKind(w.LastModified.Value, DateTimeKind.Utc))
: null
}) } }) }
}); });
@@ -62,13 +69,15 @@ public class InventoryProfile : IRegister
config.NewConfig<BffProtos.GetAllInventoryItemsRequest, GetAllInventoryItemsQuery>() config.NewConfig<BffProtos.GetAllInventoryItemsRequest, GetAllInventoryItemsQuery>()
.MapWith(src => new GetAllInventoryItemsQuery .MapWith(src => new GetAllInventoryItemsQuery
{ {
PageIndex = src.PageIndex > 0 ? src.PageIndex : 1, Page = src.Page > 0 ? src.Page : 1,
PageSize = src.PageSize > 0 ? src.PageSize : 20, PageSize = src.PageSize > 0 ? src.PageSize : 20,
WarehouseId = src.WarehouseId, WarehouseId = src.WarehouseId,
ProductType = src.ProductType != BffProtos.ProductType.Unspecified ProductType = src.ProductType != BffProtos.ProductType.Unspecified
? (int)src.ProductType ? (int)src.ProductType
: null, : null,
SearchTerm = string.IsNullOrWhiteSpace(src.SearchTerm) ? null : src.SearchTerm Search = string.IsNullOrWhiteSpace(src.Search) ? null : src.Search,
SortBy = string.IsNullOrWhiteSpace(src.SortBy) ? null : src.SortBy,
SortDesc = src.SortDesc
}); });
config.NewConfig<GetAllInventoryItemsResponseDto, BffProtos.GetAllInventoryItemsResponse>() config.NewConfig<GetAllInventoryItemsResponseDto, BffProtos.GetAllInventoryItemsResponse>()
@@ -88,7 +97,8 @@ public class InventoryProfile : IRegister
ProductId = i.ProductId.HasValue ? i.ProductId.Value : null, ProductId = i.ProductId.HasValue ? i.ProductId.Value : null,
DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null, DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null,
ProductType = (BffProtos.ProductType)i.ProductType, ProductType = (BffProtos.ProductType)i.ProductType,
ProductName = i.ProductName ?? string.Empty, ProductTitle = i.ProductTitle ?? string.Empty,
ProductPrice = i.ProductPrice,
Quantity = i.Quantity, Quantity = i.Quantity,
ReservedQuantity = i.ReservedQuantity, ReservedQuantity = i.ReservedQuantity,
AvailableQuantity = i.AvailableQuantity, AvailableQuantity = i.AvailableQuantity,
@@ -103,7 +113,10 @@ public class InventoryProfile : IRegister
: null, : null,
WarehouseId = i.WarehouseId, WarehouseId = i.WarehouseId,
WarehouseName = i.WarehouseName ?? string.Empty, WarehouseName = i.WarehouseName ?? string.Empty,
IsLowStock = i.IsLowStock IsLowStock = i.IsLowStock,
Created = i.Created.HasValue
? Timestamp.FromDateTime(DateTime.SpecifyKind(i.Created.Value, DateTimeKind.Utc))
: null
}) } }) }
}); });
@@ -113,7 +126,8 @@ public class InventoryProfile : IRegister
config.NewConfig<BffProtos.GetLowStockItemsRequest, GetLowStockItemsQuery>() config.NewConfig<BffProtos.GetLowStockItemsRequest, GetLowStockItemsQuery>()
.MapWith(src => new GetLowStockItemsQuery .MapWith(src => new GetLowStockItemsQuery
{ {
Count = src.Count > 0 ? src.Count : 10, Page = src.Page > 0 ? src.Page : 1,
PageSize = src.PageSize > 0 ? src.PageSize : 20,
WarehouseId = src.WarehouseId, WarehouseId = src.WarehouseId,
ProductType = src.ProductType != BffProtos.ProductType.Unspecified ProductType = src.ProductType != BffProtos.ProductType.Unspecified
? (int)src.ProductType ? (int)src.ProductType
@@ -124,20 +138,23 @@ public class InventoryProfile : IRegister
.MapWith(src => new BffProtos.GetLowStockItemsResponse .MapWith(src => new BffProtos.GetLowStockItemsResponse
{ {
TotalCount = src.TotalCount, TotalCount = src.TotalCount,
Items = { src.Items.Select(i => new BffProtos.LowStockItemDto Items = { src.Items.Select(i => new BffProtos.InventoryItemDto
{ {
Id = i.Id, Id = i.Id,
ProductId = i.ProductId.HasValue ? i.ProductId.Value : null, ProductId = i.ProductId.HasValue ? i.ProductId.Value : null,
DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null, DiscountProductId = i.DiscountProductId.HasValue ? i.DiscountProductId.Value : null,
ProductType = (BffProtos.ProductType)i.ProductType, ProductType = (BffProtos.ProductType)i.ProductType,
ProductName = i.ProductName ?? string.Empty, ProductTitle = i.ProductTitle ?? string.Empty,
ProductPrice = i.ProductPrice,
Quantity = i.Quantity, Quantity = i.Quantity,
ReservedQuantity = i.ReservedQuantity, ReservedQuantity = i.ReservedQuantity,
AvailableQuantity = i.AvailableQuantity, AvailableQuantity = i.AvailableQuantity,
LowStockThreshold = i.LowStockThreshold, LowStockThreshold = i.LowStockThreshold,
ReorderPoint = i.ReorderPoint, ReorderPoint = i.ReorderPoint,
MaxStockLevel = i.MaxStockLevel,
WarehouseId = i.WarehouseId, WarehouseId = i.WarehouseId,
WarehouseName = i.WarehouseName ?? string.Empty WarehouseName = i.WarehouseName ?? string.Empty,
IsLowStock = i.IsLowStock
}) } }) }
}); });
@@ -147,14 +164,14 @@ public class InventoryProfile : IRegister
config.NewConfig<BffProtos.GetStockMovementsRequest, GetStockMovementsQuery>() config.NewConfig<BffProtos.GetStockMovementsRequest, GetStockMovementsQuery>()
.MapWith(src => new GetStockMovementsQuery .MapWith(src => new GetStockMovementsQuery
{ {
PageIndex = src.PageIndex > 0 ? src.PageIndex : 1, Page = src.Page > 0 ? src.Page : 1,
PageSize = src.PageSize > 0 ? src.PageSize : 20, PageSize = src.PageSize > 0 ? src.PageSize : 20,
InventoryItemId = src.InventoryItemId, InventoryItemId = src.InventoryItemId,
ProductId = src.ProductId, ProductId = src.ProductId,
ProductType = src.ProductType != BffProtos.ProductType.Unspecified ProductType = src.ProductType != BffProtos.ProductType.Unspecified
? (int)src.ProductType ? (int)src.ProductType
: null, : null,
MovementType = src.MovementType != BffProtos.StockMovementType.Unspecified MovementType = src.MovementType != BffProtos.StockMovementType.MovementTypeUnspecified
? (int)src.MovementType ? (int)src.MovementType
: null, : null,
FromDate = src.FromDate != null ? src.FromDate.ToDateTime() : null, FromDate = src.FromDate != null ? src.FromDate.ToDateTime() : null,
@@ -176,9 +193,7 @@ public class InventoryProfile : IRegister
{ {
Id = m.Id, Id = m.Id,
InventoryItemId = m.InventoryItemId, InventoryItemId = m.InventoryItemId,
ProductName = m.ProductName ?? string.Empty,
MovementType = (BffProtos.StockMovementType)m.MovementType, MovementType = (BffProtos.StockMovementType)m.MovementType,
MovementTypeName = m.MovementTypeName ?? string.Empty,
Quantity = m.Quantity, Quantity = m.Quantity,
QuantityBefore = m.QuantityBefore, QuantityBefore = m.QuantityBefore,
QuantityAfter = m.QuantityAfter, QuantityAfter = m.QuantityAfter,
@@ -187,8 +202,8 @@ public class InventoryProfile : IRegister
ReferenceNumber = m.ReferenceNumber ?? string.Empty, ReferenceNumber = m.ReferenceNumber ?? string.Empty,
Note = m.Note ?? string.Empty, Note = m.Note ?? string.Empty,
PerformedByUserId = m.PerformedByUserId.HasValue ? m.PerformedByUserId.Value : null, PerformedByUserId = m.PerformedByUserId.HasValue ? m.PerformedByUserId.Value : null,
PerformedByUserName = m.PerformedByUserName ?? string.Empty, Created = Timestamp.FromDateTime(DateTime.SpecifyKind(m.Created, DateTimeKind.Utc)),
CreatedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.CreatedAt, DateTimeKind.Utc)) ProductTitle = m.ProductTitle ?? string.Empty
}) } }) }
}); });
@@ -209,10 +224,8 @@ public class InventoryProfile : IRegister
config.NewConfig<AddStockResponseDto, BffProtos.AddStockResponse>() config.NewConfig<AddStockResponseDto, BffProtos.AddStockResponse>()
.MapWith(src => new BffProtos.AddStockResponse .MapWith(src => new BffProtos.AddStockResponse
{ {
Success = src.Success,
InventoryItemId = src.InventoryItemId, InventoryItemId = src.InventoryItemId,
NewQuantity = src.NewQuantity, NewQuantity = src.NewQuantity
Message = src.Message ?? string.Empty
}); });
// ============================================= // =============================================
@@ -224,17 +237,16 @@ public class InventoryProfile : IRegister
ProductId = src.ProductId, ProductId = src.ProductId,
ProductType = (int)src.ProductType, ProductType = (int)src.ProductType,
NewQuantity = src.NewQuantity, NewQuantity = src.NewQuantity,
Note = src.Note Reason = src.Reason,
ReferenceNumber = src.ReferenceNumber
}); });
config.NewConfig<AdjustStockResponseDto, BffProtos.AdjustStockResponse>() config.NewConfig<AdjustStockResponseDto, BffProtos.AdjustStockResponse>()
.MapWith(src => new BffProtos.AdjustStockResponse .MapWith(src => new BffProtos.AdjustStockResponse
{ {
Success = src.Success, PreviousQuantity = src.PreviousQuantity,
OldQuantity = src.OldQuantity,
NewQuantity = src.NewQuantity, NewQuantity = src.NewQuantity,
Difference = src.Difference, Difference = src.Difference
Message = src.Message ?? string.Empty
}); });
// ============================================= // =============================================
@@ -246,8 +258,9 @@ public class InventoryProfile : IRegister
ProductId = src.ProductId, ProductId = src.ProductId,
ProductType = (int)src.ProductType, ProductType = (int)src.ProductType,
Quantity = src.Quantity, Quantity = src.Quantity,
LossType = 40, // Loss type LossType = (int)src.LossType,
Note = src.Reason Reason = src.Reason,
ReferenceNumber = src.ReferenceNumber
}); });
// ============================================= // =============================================
@@ -256,7 +269,7 @@ public class InventoryProfile : IRegister
config.NewConfig<BffProtos.UpdateInventorySettingsRequest, UpdateInventorySettingsCommand>() config.NewConfig<BffProtos.UpdateInventorySettingsRequest, UpdateInventorySettingsCommand>()
.MapWith(src => new UpdateInventorySettingsCommand .MapWith(src => new UpdateInventorySettingsCommand
{ {
InventoryItemId = src.InventoryItemId, Id = src.Id,
LowStockThreshold = src.LowStockThreshold, LowStockThreshold = src.LowStockThreshold,
ReorderPoint = src.ReorderPoint, ReorderPoint = src.ReorderPoint,
MaxStockLevel = src.MaxStockLevel MaxStockLevel = src.MaxStockLevel
@@ -31,40 +31,41 @@ service InventoryBFFContract
} }
// ============================================= // =============================================
// Enums // Enums (Aligned with CMS)
// ============================================= // =============================================
enum ProductType { enum ProductType {
PRODUCT_TYPE_UNSPECIFIED = 0; PRODUCT_TYPE_UNSPECIFIED = 0;
REGULAR = 1; REGULAR_PRODUCT = 1;
DISCOUNT = 2; DISCOUNT_PRODUCT = 2;
} }
enum StockMovementType { enum StockMovementType {
STOCK_MOVEMENT_TYPE_UNSPECIFIED = 0; MOVEMENT_TYPE_UNSPECIFIED = 0;
INITIAL_STOCK = 1; INITIAL_STOCK = 1;
RESTOCK = 2; RESTOCK = 2;
RETURN = 3; RETURN = 3;
SALE = 4; SALE = 10;
ADJUSTMENT_INCREASE = 5; ADJUSTMENT_INCREASE = 20;
ADJUSTMENT_DECREASE = 6; ADJUSTMENT_DECREASE = 21;
RESERVED = 7; RESERVED = 30;
RELEASED = 8; RELEASED = 31;
LOSS = 9; LOSS = 40;
DAMAGED = 10; DAMAGED = 41;
EXPIRED = 11; EXPIRED = 42;
TRANSFER_OUT = 12; TRANSFER_OUT = 50;
TRANSFER_IN = 13; TRANSFER_IN = 51;
} }
// ============================================= // =============================================
// Warehouse Messages // Warehouse Messages
// ============================================= // =============================================
message GetAllWarehousesRequest { message GetAllWarehousesRequest {
google.protobuf.BoolValue active_only = 1; google.protobuf.BoolValue is_active = 1;
} }
message GetAllWarehousesResponse { message GetAllWarehousesResponse {
repeated WarehouseDto warehouses = 1; repeated WarehouseDto warehouses = 1;
int32 total_count = 2;
} }
message WarehouseDto { message WarehouseDto {
@@ -75,6 +76,7 @@ message WarehouseDto {
bool is_default = 5; bool is_default = 5;
bool is_active = 6; bool is_active = 6;
google.protobuf.Timestamp created = 7; google.protobuf.Timestamp created = 7;
google.protobuf.Timestamp last_modified = 8;
} }
message CreateWarehouseRequest { message CreateWarehouseRequest {
@@ -92,17 +94,19 @@ message CreateWarehouseResponse {
// Inventory Item Messages // Inventory Item Messages
// ============================================= // =============================================
message GetAllInventoryItemsRequest { message GetAllInventoryItemsRequest {
int32 page_index = 1; google.protobuf.Int64Value warehouse_id = 1;
int32 page_size = 2; ProductType product_type = 2;
google.protobuf.Int64Value warehouse_id = 3; string search = 3;
ProductType product_type = 4; int32 page = 4;
string search_term = 5; int32 page_size = 5;
string sort_by = 6;
bool sort_desc = 7;
} }
message GetAllInventoryItemsResponse { message GetAllInventoryItemsResponse {
int32 total_count = 1; repeated InventoryItemDto items = 1;
messages.MetaData meta_data = 2; int32 total_count = 2;
repeated InventoryItemDto items = 3; messages.MetaData meta_data = 3;
} }
message InventoryItemDto { message InventoryItemDto {
@@ -110,85 +114,71 @@ message InventoryItemDto {
google.protobuf.Int64Value product_id = 2; google.protobuf.Int64Value product_id = 2;
google.protobuf.Int64Value discount_product_id = 3; google.protobuf.Int64Value discount_product_id = 3;
ProductType product_type = 4; ProductType product_type = 4;
string product_name = 5; string product_title = 5;
int32 quantity = 6; int64 product_price = 6;
int32 reserved_quantity = 7; int32 quantity = 7;
int32 available_quantity = 8; int32 reserved_quantity = 8;
int32 low_stock_threshold = 9; int32 available_quantity = 9;
int32 reorder_point = 10; int32 low_stock_threshold = 10;
int32 max_stock_level = 11; int32 reorder_point = 11;
google.protobuf.Timestamp last_restocked_at = 12; int32 max_stock_level = 12;
google.protobuf.Timestamp last_sold_at = 13; google.protobuf.Timestamp last_restocked_at = 13;
int64 warehouse_id = 14; google.protobuf.Timestamp last_sold_at = 14;
string warehouse_name = 15; int64 warehouse_id = 15;
bool is_low_stock = 16; string warehouse_name = 16;
bool is_low_stock = 17;
google.protobuf.Timestamp created = 18;
} }
// ============================================= // =============================================
// Low Stock Messages // Low Stock Messages
// ============================================= // =============================================
message GetLowStockItemsRequest { message GetLowStockItemsRequest {
int32 count = 1; google.protobuf.Int64Value warehouse_id = 1;
google.protobuf.Int64Value warehouse_id = 2; ProductType product_type = 2;
ProductType product_type = 3; int32 page = 3;
int32 page_size = 4;
} }
message GetLowStockItemsResponse { message GetLowStockItemsResponse {
int32 total_count = 1; repeated InventoryItemDto items = 1;
repeated LowStockItemDto items = 2; int32 total_count = 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 // Stock Movement Messages
// ============================================= // =============================================
message GetStockMovementsRequest { message GetStockMovementsRequest {
int32 page_index = 1; google.protobuf.Int64Value inventory_item_id = 1;
int32 page_size = 2; google.protobuf.Int64Value product_id = 2;
google.protobuf.Int64Value inventory_item_id = 3; ProductType product_type = 3;
google.protobuf.Int64Value product_id = 4; StockMovementType movement_type = 4;
ProductType product_type = 5; google.protobuf.Timestamp from_date = 5;
StockMovementType movement_type = 6; google.protobuf.Timestamp to_date = 6;
google.protobuf.Timestamp from_date = 7; int32 page = 7;
google.protobuf.Timestamp to_date = 8; int32 page_size = 8;
} }
message GetStockMovementsResponse { message GetStockMovementsResponse {
int32 total_count = 1; repeated StockMovementDto movements = 1;
messages.MetaData meta_data = 2; int32 total_count = 2;
repeated StockMovementDto movements = 3; messages.MetaData meta_data = 3;
} }
message StockMovementDto { message StockMovementDto {
int64 id = 1; int64 id = 1;
int64 inventory_item_id = 2; int64 inventory_item_id = 2;
string product_name = 3; StockMovementType movement_type = 3;
StockMovementType movement_type = 4; int32 quantity = 4;
string movement_type_name = 5; int32 quantity_before = 5;
int32 quantity = 6; int32 quantity_after = 6;
int32 quantity_before = 7; google.protobuf.Int64Value order_id = 7;
int32 quantity_after = 8; google.protobuf.Int64Value discount_order_id = 8;
google.protobuf.Int64Value order_id = 9; string reference_number = 9;
google.protobuf.Int64Value discount_order_id = 10; string note = 10;
string reference_number = 11; google.protobuf.Int64Value performed_by_user_id = 11;
string note = 12; google.protobuf.Timestamp created = 12;
google.protobuf.Int64Value performed_by_user_id = 13; string product_title = 13;
string performed_by_user_name = 14;
google.protobuf.Timestamp created_at = 15;
} }
// ============================================= // =============================================
@@ -204,37 +194,35 @@ message AddStockRequest {
} }
message AddStockResponse { message AddStockResponse {
bool success = 1; int64 inventory_item_id = 1;
int64 inventory_item_id = 2; int32 new_quantity = 2;
int32 new_quantity = 3;
string message = 4;
} }
message AdjustStockRequest { message AdjustStockRequest {
int64 product_id = 1; int64 product_id = 1;
ProductType product_type = 2; ProductType product_type = 2;
int32 new_quantity = 3; int32 new_quantity = 3;
string note = 4; string reason = 4;
string reference_number = 5;
} }
message AdjustStockResponse { message AdjustStockResponse {
bool success = 1; int32 previous_quantity = 1;
int32 old_quantity = 2; int32 new_quantity = 2;
int32 new_quantity = 3; int32 difference = 3;
int32 difference = 4;
string message = 5;
} }
message RecordLossRequest { message RecordLossRequest {
int64 product_id = 1; int64 product_id = 1;
ProductType product_type = 2; ProductType product_type = 2;
int32 quantity = 3; int32 quantity = 3;
string reason = 4; StockMovementType loss_type = 4; // LOSS, DAMAGED, or EXPIRED
string reference_number = 5; string reason = 5;
string reference_number = 6;
} }
message UpdateInventorySettingsRequest { message UpdateInventorySettingsRequest {
int64 inventory_item_id = 1; int64 id = 1;
int32 low_stock_threshold = 2; int32 low_stock_threshold = 2;
int32 reorder_point = 3; int32 reorder_point = 3;
int32 max_stock_level = 4; int32 max_stock_level = 4;