diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs index 2e432276..f8759d9a 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs @@ -90,6 +90,8 @@ namespace EasyAbp.EShop.Orders.Orders var productDict = await GetProductDictionaryAsync(input.OrderLines.Select(dto => dto.ProductId).ToList()); + ThrowIfExistFlashSalesProduct(productDict); + await AuthorizationService.CheckAsync( new OrderCreationResource { @@ -118,7 +120,15 @@ namespace EasyAbp.EShop.Orders.Orders return await MapToGetOutputDtoAsync(order); } - + + protected virtual void ThrowIfExistFlashSalesProduct(Dictionary productDict) + { + if (productDict.Any(x => x.Value.InventoryStrategy is InventoryStrategy.FlashSales)) + { + throw new BusinessException(OrdersErrorCodes.ExistFlashSalesProduct); + } + } + protected virtual async Task DiscountOrderAsync(Order order, Dictionary productDict) { foreach (var provider in LazyServiceProvider.LazyGetService>()) diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/cs.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/cs.json index 9b750849..6439cee2 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/cs.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/cs.json @@ -48,6 +48,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json index 201bb4a9..e38c1204 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json @@ -49,6 +49,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pl.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pl.json index 7294c67d..ca55263b 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pl.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pl.json @@ -48,6 +48,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pt-BR.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pt-BR.json index 95619934..4bc83e2a 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pt-BR.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/pt-BR.json @@ -48,6 +48,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/sl.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/sl.json index 8bcfdbba..0f17c8e7 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/sl.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/sl.json @@ -49,6 +49,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/tr.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/tr.json index 5d4c6d9a..459c51e1 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/tr.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/tr.json @@ -49,6 +49,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/vi.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/vi.json index 4fc7ff3e..265b82f8 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/vi.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/vi.json @@ -48,6 +48,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.", "EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage." + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json index e5834c7b..d57a1822 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json @@ -49,6 +49,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "付款{paymentId}有无效的订单配置{orderId}", "EasyAbp.EShop.Orders:InvalidRefundAmount": "退款金额({amount})无效", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款数量({quantity})无效", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "订单{orderId}处于错误的阶段" + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "订单{orderId}处于错误的阶段", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清单中不允许存在闪购产品" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json index 72c277f7..24703c1d 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json @@ -49,6 +49,7 @@ "EasyAbp.EShop.Orders:InvalidPayment": "付款{paymentId}有無效的訂單配置{orderId}", "EasyAbp.EShop.Orders:InvalidRefundAmount": "退款金額({amount})無效", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款數量({quantity})無效", - "EasyAbp.EShop.Orders:OrderIsInWrongStage": "訂單{orderId}處於錯誤的階段" + "EasyAbp.EShop.Orders:OrderIsInWrongStage": "訂單{orderId}處於錯誤的階段", + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清單中不允許存在閃購產品" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs index 8a1af850..d87dd982 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs @@ -11,5 +11,6 @@ public const string InvalidRefundAmount = "EasyAbp.EShop.Orders:InvalidRefundAmount"; public const string InvalidRefundQuantity = "EasyAbp.EShop.Orders:InvalidRefundQuantity"; public const string OrderIsInWrongStage = "EasyAbp.EShop.Orders:OrderIsInWrongStage"; + public const string ExistFlashSalesProduct = "EasyAbp.EShop.Orders:ExistFlashSalesProduct"; } } 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 18e5b70b..b7f2eebd 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 @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; +using Volo.Abp; using Volo.Abp.Timing; using Xunit; @@ -21,6 +22,8 @@ namespace EasyAbp.EShop.Orders.Orders private readonly IClock _clock; private readonly IOrderAppService _orderAppService; + private ProductDto Product1 { get; set; } + public OrderAppServiceTests() { _clock = GetRequiredService(); @@ -29,8 +32,7 @@ namespace EasyAbp.EShop.Orders.Orders protected override void AfterAddApplication(IServiceCollection services) { - var productAppService = Substitute.For(); - productAppService.GetAsync(OrderTestData.Product1Id).Returns(Task.FromResult(new ProductDto + Product1 = new ProductDto { CreationTime = DateTime.Now, IsPublished = true, @@ -79,10 +81,13 @@ namespace EasyAbp.EShop.Orders.Orders }, InventoryStrategy = InventoryStrategy.NoNeed, LastModificationTime = OrderTestData.ProductLastModificationTime - })); + }; + + var productAppService = Substitute.For(); + productAppService.GetAsync(OrderTestData.Product1Id).Returns(Task.FromResult(Product1)); services.AddTransient(_ => productAppService); - + var productDetailAppService = Substitute.For(); productDetailAppService.GetAsync(OrderTestData.ProductDetail1Id).Returns(Task.FromResult( @@ -186,7 +191,7 @@ namespace EasyAbp.EShop.Orders.Orders orderLine1.ProductDetailModificationTime.ShouldBe(OrderTestData.ProductDetailLastModificationTime); orderLine1.RefundAmount.ShouldBe(0m); orderLine1.RefundedQuantity.ShouldBe(0); - + var orderLine2 = response.OrderLines.Single(x => x.ProductSkuId == OrderTestData.ProductSku2Id); orderLine2.ProductDetailId.ShouldBe(OrderTestData.ProductDetail2Id); }); @@ -245,7 +250,7 @@ namespace EasyAbp.EShop.Orders.Orders response.OrderStatus.ShouldBe(OrderStatus.Canceled); response.CanceledTime.ShouldNotBeNull(); response.CancellationReason.ShouldBe("Repeat orders."); - + UsingDbContext(db => { var order = db.Orders.FirstOrDefault(o => o.Id == orderId); @@ -280,7 +285,7 @@ namespace EasyAbp.EShop.Orders.Orders order.SetPaymentId(null); await orderRepository.UpdateAsync(order, true); }); - + var response = await _orderAppService.GetAsync(orderId); // Assert @@ -290,7 +295,7 @@ namespace EasyAbp.EShop.Orders.Orders response.OrderStatus.ShouldBe(OrderStatus.Canceled); response.CanceledTime.ShouldNotBeNull(); response.CancellationReason.ShouldBe(OrdersConsts.UnpaidAutoCancellationReason); - + UsingDbContext(db => { var order = db.Orders.FirstOrDefault(o => o.Id == orderId); @@ -349,7 +354,7 @@ namespace EasyAbp.EShop.Orders.Orders response.OrderStatus.ShouldBe(OrderStatus.Processing); response.CanceledTime.ShouldBeNull(); response.CancellationReason.ShouldBeNull(); - + UsingDbContext(db => { var order = db.Orders.FirstOrDefault(o => o.Id == orderId); @@ -361,7 +366,7 @@ namespace EasyAbp.EShop.Orders.Orders order.CancellationReason.ShouldBeNull(); }); } - + [Fact] public async Task Unpaid_Order_Should_Be_Auto_Canceled_When_Payment_Overtime() { @@ -404,7 +409,7 @@ namespace EasyAbp.EShop.Orders.Orders response.OrderStatus.ShouldBe(OrderStatus.Canceled); response.CanceledTime.ShouldNotBeNull(); response.CancellationReason.ShouldBe(OrdersConsts.UnpaidAutoCancellationReason); - + UsingDbContext(db => { var order = db.Orders.FirstOrDefault(o => o.Id == orderId); @@ -416,7 +421,7 @@ namespace EasyAbp.EShop.Orders.Orders order.CancellationReason.ShouldBe(OrdersConsts.UnpaidAutoCancellationReason); }); } - + [Fact] public async Task Payment_Pending_Order_Should_Be_Auto_Canceled_When_Payment_Overtime() { @@ -461,7 +466,7 @@ namespace EasyAbp.EShop.Orders.Orders response.OrderStatus.ShouldBe(OrderStatus.Canceled); response.CanceledTime.ShouldNotBeNull(); response.CancellationReason.ShouldBe(OrdersConsts.UnpaidAutoCancellationReason); - + UsingDbContext(db => { var order = db.Orders.FirstOrDefault(o => o.Id == orderId); @@ -497,17 +502,47 @@ namespace EasyAbp.EShop.Orders.Orders } } }; - + await WithUnitOfWorkAsync(async () => { var order = await _orderAppService.CreateAsync(createOrderDto); var orderLine = order.OrderLines.Find(x => x.ProductSkuId == OrderTestData.ProductSku3Id); - + order.ProductTotalPrice.ShouldBe(10 * 1m + 2 * TestOrderLinePriceOverrider.Sku3UnitPrice); orderLine.ShouldNotBeNull(); orderLine.UnitPrice.ShouldBe(TestOrderLinePriceOverrider.Sku3UnitPrice); orderLine.TotalPrice.ShouldBe(orderLine.Quantity * orderLine.UnitPrice); }); } + + [Fact] + public async Task Should_Not_Create_Order_With_Flash_Sales_Products() + { + var createOrderDto = new CreateOrderDto + { + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new() + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 1 + } + } + }; + + Product1.InventoryStrategy = InventoryStrategy.FlashSales; + + await WithUnitOfWorkAsync(async () => + { + var exception = + await Should.ThrowAsync(() => _orderAppService.CreateAsync(createOrderDto)); + + exception.Code.ShouldBe(OrdersErrorCodes.ExistFlashSalesProduct); + }); + + Product1.InventoryStrategy = InventoryStrategy.NoNeed; + } } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/InventoryStrategy.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/InventoryStrategy.cs index 301d6684..257d0b13 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/InventoryStrategy.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/InventoryStrategy.cs @@ -7,6 +7,7 @@ namespace EasyAbp.EShop.Products.Products { NoNeed = 1, ReduceAfterPlacing = 2, - ReduceAfterPayment = 4 + ReduceAfterPayment = 4, + FlashSales = 8 } } \ No newline at end of file