Add pricing and supplier master data

This commit is contained in:
2026-08-20 17:28:55 +05:30
parent 7a2494c156
commit 63bc6e9cd8
26 changed files with 6138 additions and 9 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
namespace Distribution.Features.Order;
public record OrderItemRequest(Guid ItemId, int Quantity);
public record OrderItemRequest(Guid ItemId, int Quantity, decimal? UnitPrice = null);
public record CreateOrderRequest(Guid StoreId, DateTime OrderDate, decimal TotalAmount, List<OrderItemRequest> Items);
public record UpdateOrderRequest(DateTime OrderDate, decimal TotalAmount);
public record OrderItemResponse(Guid ItemId, int Quantity);
public record OrderItemResponse(Guid ItemId, int Quantity, decimal UnitPrice);
public record OrderResponse(
Guid Id,
+42 -7
View File
@@ -1,3 +1,5 @@
using Distribution.Features.Item;
using Distribution.Features.PriceList;
using Distribution.Features.Store;
using Distribution.Infra.Authorization;
using Distribution.Infra.UoW;
@@ -9,6 +11,8 @@ namespace Distribution.Features.Order;
public class OrderService(
IOrderRepository repo,
IStoreRepository storeRepo,
IItemRepository itemRepo,
PriceListService priceListService,
IUnitOfWork uow,
ICurrentUserService currentUser,
IScopeAccessService scopeAccess,
@@ -18,7 +22,7 @@ public class OrderService(
private static OrderResponse ToResponse(Models.Order o, List<Models.OrderItem> items) =>
new(o.Id, o.OrderDate, o.FK_StoreId, o.TotalAmount,
items.Select(i => new OrderItemResponse(i.FK_ItemId, i.Quantity)).ToList(),
items.Select(i => new OrderItemResponse(i.FK_ItemId, i.Quantity, i.UnitPrice)).ToList(),
o.IsActive, o.CreatedAt);
private bool HasGlobalScope => currentUser.RoleLevel >= GlobalScopeRoleLevel;
@@ -29,6 +33,29 @@ public class OrderService(
return await scopeAccess.HasStoreScopeAsync(currentUser.UserId.Value, storeId);
}
/// <summary>
/// applyPricingAndDiscounts (price-list half, 14_pricing_and_suppliers.md): resolves the
/// region-scoped active price list, then global, then Item.SalePrice, and validates any
/// caller-supplied override falls within [MinPrice ?? Price, Price]. Returns null if no price
/// can be resolved, or if the requested price is outside the allowed band.
/// </summary>
private async Task<decimal?> ResolveUnitPriceAsync(Guid itemId, decimal? requestedUnitPrice, Models.Store store, DateTime orderDate)
{
var item = await itemRepo.GetByIdAsync(itemId);
if (item is null) return null;
var regionId = store.Route?.FK_RegionId;
var resolution = await priceListService.ResolvePriceAsync(itemId, regionId, item.SalePrice, orderDate);
if (resolution is null) return null;
if (!requestedUnitPrice.HasValue) return resolution.Price;
var min = resolution.MinPrice ?? resolution.Price;
var max = resolution.Price;
if (requestedUnitPrice.Value < min || requestedUnitPrice.Value > max) return null;
return requestedUnitPrice.Value;
}
public async Task<List<OrderResponse>> GetAllAsync()
{
var orders = (await repo.GetAllAsync()).Where(o => o.IsActive).ToList();
@@ -72,7 +99,7 @@ public class OrderService(
{
if (!await HasStoreScopeAsync(request.StoreId)) return null;
var store = await storeRepo.GetByIdAsync(request.StoreId);
var store = await storeRepo.GetByIdWithRegionAsync(request.StoreId);
if (store is null || !store.IsActive) return null;
if (store.KycStatus != KycStatus.Verified)
{
@@ -86,12 +113,20 @@ public class OrderService(
OrderDate = request.OrderDate,
TotalAmount = request.TotalAmount
};
var orderItems = request.Items.Select(i => new Models.OrderItem
var orderItems = new List<Models.OrderItem>();
foreach (var i in request.Items)
{
FK_OrderId = order.Id,
FK_ItemId = i.ItemId,
Quantity = i.Quantity
}).ToList();
var unitPrice = await ResolveUnitPriceAsync(i.ItemId, i.UnitPrice, store, request.OrderDate);
if (unitPrice is null) return null;
orderItems.Add(new Models.OrderItem
{
FK_OrderId = order.Id,
FK_ItemId = i.ItemId,
Quantity = i.Quantity,
UnitPrice = unitPrice.Value
});
}
await uow.BeginAsync(ct);
try