From 525f1c415d05e75a43702d0c9b0c4002410b3d9b Mon Sep 17 00:00:00 2001 From: gdlcf88 Date: Mon, 18 Jul 2022 22:06:22 +0800 Subject: [PATCH] Introduce `IOrderAppService.CheckCreateAsync` method --- .../Orders/Dtos/CheckCreateOrderInput.cs | 8 ++ .../Orders/Dtos/CheckCreateOrderResultDto.cs | 11 +++ .../EShop/Orders/Orders/IOrderAppService.cs | 2 + .../EShop/Orders/Orders/OrderAppService.cs | 43 ++++++++-- .../EShop/Orders/Orders/OrderController.cs | 7 ++ .../Orders/OrderAppServiceTests.cs | 83 +++++++++++++++++++ 6 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderInput.cs create mode 100644 modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderResultDto.cs diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderInput.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderInput.cs new file mode 100644 index 00000000..c9b83892 --- /dev/null +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderInput.cs @@ -0,0 +1,8 @@ +using System; + +namespace EasyAbp.EShop.Orders.Orders.Dtos; + +[Serializable] +public class CheckCreateOrderInput : CreateOrderDto +{ +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderResultDto.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderResultDto.cs new file mode 100644 index 00000000..f6add213 --- /dev/null +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CheckCreateOrderResultDto.cs @@ -0,0 +1,11 @@ +using System; + +namespace EasyAbp.EShop.Orders.Orders.Dtos; + +[Serializable] +public class CheckCreateOrderResultDto +{ + public bool CanCreate { get; set; } + + public string Reason { get; set; } +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/IOrderAppService.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/IOrderAppService.cs index 5c6ae2cc..081c7b0b 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/IOrderAppService.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/IOrderAppService.cs @@ -19,5 +19,7 @@ namespace EasyAbp.EShop.Orders.Orders Task CancelAsync(Guid id, CancelOrderInput input); Task UpdateStaffRemarkAsync(Guid id, UpdateStaffRemarkInput input); + + Task CheckCreateAsync(CheckCreateOrderInput input); } } \ No newline at end of file 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 f8759d9a..b2317415 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 @@ -12,6 +12,7 @@ using EasyAbp.EShop.Stores.Stores; using Microsoft.AspNetCore.Authorization; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Uow; using Volo.Abp.Users; namespace EasyAbp.EShop.Orders.Orders @@ -91,7 +92,7 @@ namespace EasyAbp.EShop.Orders.Orders var productDict = await GetProductDictionaryAsync(input.OrderLines.Select(dto => dto.ProductId).ToList()); ThrowIfExistFlashSalesProduct(productDict); - + await AuthorizationService.CheckAsync( new OrderCreationResource { @@ -108,11 +109,12 @@ namespace EasyAbp.EShop.Orders.Orders .Where(x => x.HasValue) .Select(x => x.Value) .ToList(); - + var productDetailDict = await GetProductDetailDictionaryAsync(productDetailIds); // Todo: Can we use IProductDataScopedCache/IProductDetailDataScopedCache instead of productDict/productDetailDict? - var order = await _newOrderGenerator.GenerateAsync(CurrentUser.GetId(), input, productDict, productDetailDict); + var order = await _newOrderGenerator.GenerateAsync(CurrentUser.GetId(), input, productDict, + productDetailDict); await DiscountOrderAsync(order, productDict); @@ -203,11 +205,11 @@ namespace EasyAbp.EShop.Orders.Orders return await MapToGetOutputDtoAsync(order); } - + public virtual async Task CancelAsync(Guid id, CancelOrderInput input) { var order = await GetEntityByIdAsync(id); - + await AuthorizationService.CheckAsync( order, new OrderOperationAuthorizationRequirement(OrderOperation.Cancellation) @@ -225,10 +227,39 @@ namespace EasyAbp.EShop.Orders.Orders await CheckMultiStorePolicyAsync(order.StoreId, OrdersPermissions.Orders.Manage); order.SetStaffRemark(input.StaffRemark); - + await Repository.UpdateAsync(order, true); return await MapToGetOutputDtoAsync(order); } + + public virtual async Task CheckCreateAsync(CheckCreateOrderInput input) + { + var requiresNewUow = !UnitOfWorkManager.Current?.Options.IsTransactional ?? false; + using var uow = UnitOfWorkManager.Begin(new AbpUnitOfWorkOptions(true), requiresNewUow); + + try + { + await CreateAsync(input); + + await uow.RollbackAsync(); + } + catch + { + await uow.RollbackAsync(); + + return new CheckCreateOrderResultDto + { + CanCreate = false, + Reason = "Unknown" // Todo: get failure reason + }; + } + + return new CheckCreateOrderResultDto + { + CanCreate = true, + Reason = null, + }; + } } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.HttpApi/EasyAbp/EShop/Orders/Orders/OrderController.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.HttpApi/EasyAbp/EShop/Orders/Orders/OrderController.cs index b109f3af..644e636a 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.HttpApi/EasyAbp/EShop/Orders/Orders/OrderController.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.HttpApi/EasyAbp/EShop/Orders/Orders/OrderController.cs @@ -81,5 +81,12 @@ namespace EasyAbp.EShop.Orders.Orders { return _service.UpdateStaffRemarkAsync(id, input); } + + [HttpPost] + [Route("check-create")] + public virtual Task CheckCreateAsync(CheckCreateOrderInput input) + { + return _service.CheckCreateAsync(input); + } } } 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..a2f4896b 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 @@ -13,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; using Volo.Abp; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Settings; using Volo.Abp.Timing; using Xunit; @@ -113,6 +114,88 @@ namespace EasyAbp.EShop.Orders.Orders services.AddTransient(_ => productDetailAppService); } + [Fact] + public async Task Check_Create_Order_Should_Succeed() + { + var orderRepository = ServiceProvider.GetRequiredService(); + var orderCount = 0; + await WithUnitOfWorkAsync(async () => + { + orderCount = await orderRepository.CountAsync(); + }); + + // Arrange + var checkCreateOrderInput = new CheckCreateOrderInput + { + CustomerRemark = "customer remark", + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 10 + } + } + }; + + CheckCreateOrderResultDto resultDto = null; + // Act + await WithUnitOfWorkAsync(async () => + { + resultDto = await _orderAppService.CheckCreateAsync(checkCreateOrderInput); + }); + + // Assert + resultDto.CanCreate.ShouldBeTrue(); + await WithUnitOfWorkAsync(async () => + { + orderCount.ShouldBeEquivalentTo(await orderRepository.CountAsync()); + }); + } + + [Fact] + public async Task Check_Create_Order_Should_Fail() + { + var orderRepository = ServiceProvider.GetRequiredService(); + var orderCount = 0; + await WithUnitOfWorkAsync(async () => + { + orderCount = await orderRepository.CountAsync(); + }); + + // Arrange + var checkCreateOrderInput = new CheckCreateOrderInput + { + CustomerRemark = "customer remark", + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new CreateOrderLineDto + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 101 // limited range: 1-100 + } + } + }; + + CheckCreateOrderResultDto resultDto = null; + // Act + await WithUnitOfWorkAsync(async () => + { + resultDto = await _orderAppService.CheckCreateAsync(checkCreateOrderInput); + }); + + // Assert + resultDto.CanCreate.ShouldBeFalse(); + await WithUnitOfWorkAsync(async () => + { + orderCount.ShouldBeEquivalentTo(await orderRepository.CountAsync()); + }); + } + [Fact] public async Task Order_Should_Be_Created() {