diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs index be1225ae..fa253029 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs @@ -93,6 +93,13 @@ namespace EasyAbp.EShop.Orders.Orders order.SetOrderNumber(await _orderNumberGenerator.CreateAsync(order)); + // set ReducedInventoryAfterPlacingTime directly if an order contains no OrderLine with `InventoryStrategy.ReduceAfterPlacing`. + // see https://github.com/EasyAbp/EShop/issues/214 + if (order.OrderLines.All(x => x.ProductInventoryStrategy != InventoryStrategy.ReduceAfterPlacing)) + { + order.SetReducedInventoryAfterPlacingTime(_clock.Now); + } + return order; } diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs index bc99825f..3da6263f 100644 --- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs +++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs @@ -591,5 +591,85 @@ namespace EasyAbp.EShop.Orders.Orders throw; } } + + [Fact] + public async Task Should_Set_ReducedInventoryAfterPlacingTime_If_No_ReduceAfterPlacing_OrderLine() + { + var createOrderDto = new CreateOrderDto + { + CustomerRemark = "customer remark", + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 10 + }, + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku2Id, + Quantity = 1 + } + } + }; + + OrderDto createResponse = null; + await WithUnitOfWorkAsync(async () => + { + createResponse = await _orderAppService.CreateAsync(createOrderDto); + }); + + var order = await _orderAppService.GetAsync(createResponse.Id); + + // The fake inventory reducer (OrderCreatedEventHandler) should skip handling. + OrderCreatedEventHandler.LastOrderId.ShouldBe(order.Id); + OrderCreatedEventHandler.SkippedHandling.ShouldBeTrue(); + + order.ReducedInventoryAfterPlacingTime.ShouldNotBeNull(); + } + + [Fact] + public async Task Should_Not_Set_ReducedInventoryAfterPlacingTime_If_Contains_ReduceAfterPlacing_OrderLine() + { + Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; + + var createOrderDto = new CreateOrderDto + { + CustomerRemark = "customer remark", + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 10 + }, + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku2Id, + Quantity = 1 + } + } + }; + + OrderDto createResponse = null; + await WithUnitOfWorkAsync(async () => + { + createResponse = await _orderAppService.CreateAsync(createOrderDto); + }); + + var order = await _orderAppService.GetAsync(createResponse.Id); + + // The fake inventory reducer (OrderCreatedEventHandler) should handle it. + OrderCreatedEventHandler.LastOrderId.ShouldBe(order.Id); + OrderCreatedEventHandler.SkippedHandling.ShouldBeFalse(); + + order.ReducedInventoryAfterPlacingTime.ShouldNotBeNull(); + } } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderCreatedEventHandler.cs b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderCreatedEventHandler.cs index ea8e7ae3..da491e8b 100644 --- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderCreatedEventHandler.cs +++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderCreatedEventHandler.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using EasyAbp.EShop.Products.Products; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; @@ -9,6 +10,9 @@ namespace EasyAbp.EShop.Orders.Orders { public class OrderCreatedEventHandler : IDistributedEventHandler>, ITransientDependency { + public static Guid LastOrderId { get; set; } + public static bool SkippedHandling { get; set; } + private readonly ICurrentTenant _currentTenant; private readonly IDistributedEventBus _distributedEventBus; @@ -19,9 +23,21 @@ namespace EasyAbp.EShop.Orders.Orders _currentTenant = currentTenant; _distributedEventBus = distributedEventBus; } - + public virtual async Task HandleEventAsync(EntityCreatedEto eventData) { + LastOrderId = eventData.Entity.Id; + + // skip if an order contains no OrderLine with `InventoryStrategy.ReduceAfterPlacing`. + // see https://github.com/EasyAbp/EShop/issues/214 + if (eventData.Entity.ReducedInventoryAfterPlacingTime is not null) + { + SkippedHandling = true; + return; + } + + SkippedHandling = false; + using var changeTenant = _currentTenant.Change(eventData.Entity.TenantId); await _distributedEventBus.PublishAsync(new ProductInventoryReductionAfterOrderPlacedResultEto diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs index 1e16d1ba..c0d80119 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs @@ -39,25 +39,36 @@ namespace EasyAbp.EShop.Products.Products [UnitOfWork(true)] public virtual async Task HandleEventAsync(EntityCreatedEto eventData) { + // skip if an order contains no OrderLine with `InventoryStrategy.ReduceAfterPlacing`. + // see https://github.com/EasyAbp/EShop/issues/214 + if (eventData.Entity.ReducedInventoryAfterPlacingTime is not null) + { + return; + } + using var changeTenant = _currentTenant.Change(eventData.Entity.TenantId); var models = new List(); foreach (var orderLine in eventData.Entity.OrderLines) { - // Todo: Should use ProductHistory. - var product = await _productRepository.FindAsync(orderLine.ProductId); + var inventoryStrategy = orderLine.ProductInventoryStrategy; + if (inventoryStrategy is not null && inventoryStrategy != InventoryStrategy.ReduceAfterPlacing) + { + continue; + } + var product = await _productRepository.FindAsync(orderLine.ProductId); var productSku = product?.ProductSkus.FirstOrDefault(sku => sku.Id == orderLine.ProductSkuId); - if (productSku == null) { await PublishInventoryReductionResultEventAsync(eventData, false); return; } - - if (product.InventoryStrategy != InventoryStrategy.ReduceAfterPlacing) + + inventoryStrategy ??= product.InventoryStrategy; + if (inventoryStrategy != InventoryStrategy.ReduceAfterPlacing) { continue; } diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs index 0d2a82fc..4f3b5140 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs @@ -44,11 +44,14 @@ namespace EasyAbp.EShop.Products.Products foreach (var orderLine in eventData.Order.OrderLines) { - // Todo: Should use ProductHistory. - var product = await _productRepository.FindAsync(orderLine.ProductId); + var inventoryStrategy = orderLine.ProductInventoryStrategy; + if (inventoryStrategy is not null && inventoryStrategy != InventoryStrategy.ReduceAfterPayment) + { + continue; + } + var product = await _productRepository.FindAsync(orderLine.ProductId); var productSku = product?.ProductSkus.FirstOrDefault(sku => sku.Id == orderLine.ProductSkuId); - if (productSku == null) { await PublishInventoryReductionResultEventAsync(eventData, false); @@ -56,7 +59,8 @@ namespace EasyAbp.EShop.Products.Products return; } - if (product.InventoryStrategy != InventoryStrategy.ReduceAfterPayment) + inventoryStrategy ??= product.InventoryStrategy; + if (inventoryStrategy != InventoryStrategy.ReduceAfterPayment) { continue; }