From 587b57d83da6a0a78d9b69a735843537b90ffcb1 Mon Sep 17 00:00:00 2001 From: Jadyn Date: Fri, 19 Aug 2022 20:02:13 +0800 Subject: [PATCH 1/2] Add flash-sale order canceled event handler --- .../FlashSaleOrderCanceledEventHandler.cs | 86 ++++++++ .../FlashSalePlans/FlashSalePlanAppService.cs | 33 +-- .../EShop/Products/Products/IProductCache.cs | 11 + .../EShop/Products/Products/ProductCache.cs | 55 +++++ .../Products/ProductCacheInvalidator.cs | 18 +- ...op.Plugins.FlashSales.Domain.Shared.csproj | 1 + .../FlashSaleResultFailedReason.cs | 1 + .../FlashSaleResults/FlashSaleResult.cs | 4 - ...FlashSaleOrderCanceledEventHandlerTests.cs | 207 ++++++++++++++++++ .../FlashSaleResults/FlashSaleResultTests.cs | 22 -- 10 files changed, 375 insertions(+), 63 deletions(-) create mode 100644 plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs create mode 100644 plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/IProductCache.cs create mode 100644 plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCache.cs create mode 100644 plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs new file mode 100644 index 00000000..4258db08 --- /dev/null +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs @@ -0,0 +1,86 @@ +using System.Threading.Tasks; +using EasyAbp.Eshop.Products.Products; +using EasyAbp.EShop.Orders.Orders; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; +using EasyAbp.EShop.Products.Products; +using Microsoft.Extensions.Logging; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Uow; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; + +public class FlashSaleOrderCanceledEventHandler : IDistributedEventHandler, ITransientDependency +{ + protected IFlashSaleResultRepository FlashSaleResultRepository { get; } + + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + protected IAbpApplication AbpApplication { get; } + + protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; } + + protected IProductCache ProductCache { get; } + + protected IFlashSaleCurrentResultCache FlashSaleCurrentResultCache { get; } + + protected ILogger Logger { get; } + + public FlashSaleOrderCanceledEventHandler( + IFlashSaleResultRepository flashSaleResultRepository, + IUnitOfWorkManager unitOfWorkManager, + IAbpApplication abpApplication, + IFlashSaleInventoryManager flashSaleInventoryManager, + IProductCache productCache, + IFlashSaleCurrentResultCache flashSaleCurrentResultCache, + ILogger logger) + { + FlashSaleResultRepository = flashSaleResultRepository; + UnitOfWorkManager = unitOfWorkManager; + AbpApplication = abpApplication; + FlashSaleInventoryManager = flashSaleInventoryManager; + ProductCache = productCache; + FlashSaleCurrentResultCache = flashSaleCurrentResultCache; + Logger = logger; + } + + [UnitOfWork(true)] + public virtual async Task HandleEventAsync(OrderCanceledEto eventData) + { + var flashSaleResult = await FlashSaleResultRepository + .SingleOrDefaultAsync(x => x.Status != FlashSaleResultStatus.Failed && x.StoreId == eventData.Order.StoreId && x.OrderId == eventData.Order.Id); + if (flashSaleResult == null) + { + return; + } + + flashSaleResult.MarkAsFailed(FlashSaleResultFailedReason.OrderCanceled); + + await FlashSaleResultRepository.UpdateAsync(flashSaleResult, autoSave: true); + + UnitOfWorkManager.Current.OnCompleted(async () => + { + if (eventData.Order.OrderLines.Count == 0) + { + Logger.LogWarning("OrderCanceled order {orderId} orderLines is empty.", eventData.Order.Id); + return; + } + var productId = eventData.Order.OrderLines[0].ProductId; + var productSkuId = eventData.Order.OrderLines[0].ProductSkuId; + var product = await ProductCache.GetAsync(productId); + // try to roll back the inventory. + if (!await FlashSaleInventoryManager.TryRollBackInventoryAsync( + eventData.TenantId, product.InventoryProviderName, eventData.Order.StoreId, + productId, productSkuId)) + { + Logger.LogWarning("Failed to roll back the flash sale inventory."); + return; // avoid to remove cache if the rollback failed. + } + + // remove the cache so the user can try to order again. + await FlashSaleCurrentResultCache.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId); + }); + } +} diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs index ab38c192..f9944833 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs @@ -50,13 +50,11 @@ public class FlashSalePlanAppService : protected IFlashSalePlanRepository FlashSalePlanRepository { get; } - protected IProductAppService ProductAppService { get; } - protected IDistributedCache PreOrderDistributedCache { get; } protected IDistributedCache PlanDistributedCache { get; } - protected IDistributedCache ProductDistributedCache { get; } + protected IProductCache ProductCache { get; } protected IDistributedEventBus DistributedEventBus { get; } @@ -74,10 +72,9 @@ public class FlashSalePlanAppService : public FlashSalePlanAppService( IFlashSalePlanRepository flashSalePlanRepository, - IProductAppService productAppService, IDistributedCache tokenDistributedCache, IDistributedCache planDistributedCache, - IDistributedCache productDistributedCache, + IProductCache productCache, IDistributedEventBus distributedEventBus, IFlashSaleResultRepository flashSaleResultRepository, IAbpDistributedLock distributedLock, @@ -88,10 +85,9 @@ public class FlashSalePlanAppService : : base(flashSalePlanRepository) { FlashSalePlanRepository = flashSalePlanRepository; - ProductAppService = productAppService; PreOrderDistributedCache = tokenDistributedCache; PlanDistributedCache = planDistributedCache; - ProductDistributedCache = productDistributedCache; + ProductCache = productCache; DistributedEventBus = distributedEventBus; FlashSaleResultRepository = flashSaleResultRepository; DistributedLock = distributedLock; @@ -131,7 +127,7 @@ public class FlashSalePlanAppService : { await CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName); - var product = await ProductAppService.GetAsync(input.ProductId); + var product = await ProductCache.GetAsync(input.ProductId); var productSku = product.GetSkuById(input.ProductSkuId); await ValidateProductAsync(input.ProductId, product, input.StoreId); @@ -155,7 +151,7 @@ public class FlashSalePlanAppService : public override async Task UpdateAsync(Guid id, FlashSalePlanUpdateDto input) { var flashSalePlan = await GetEntityByIdAsync(id); - var product = await ProductAppService.GetAsync(input.ProductId); + var product = await ProductCache.GetAsync(input.ProductId); var productSku = product.GetSkuById(input.ProductSkuId); await CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName); @@ -210,7 +206,7 @@ public class FlashSalePlanAppService : await CheckPolicyAsync(PreOrderPolicyName); var plan = await GetFlashSalePlanCacheAsync(id); - var product = await GetProductCacheAsync(plan.ProductId); + var product = await ProductCache.GetAsync(plan.ProductId); var productSku = product.GetSkuById(plan.ProductSkuId); var expiresTime = DateTimeOffset.Now.Add(Options.PreOrderExpires); @@ -432,21 +428,4 @@ public class FlashSalePlanAppService : return Task.FromResult(eto); } - - protected virtual async Task GetProductCacheAsync(Guid productId) - { - return await ProductDistributedCache.GetOrAddAsync(productId, async () => - { - var productDto = await ProductAppService.GetAsync(productId); - - var cacheItem = ObjectMapper.Map(productDto); - - if (cacheItem != null) - { - cacheItem.TenantId = CurrentTenant.Id; - } - - return cacheItem; - }); - } } diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/IProductCache.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/IProductCache.cs new file mode 100644 index 00000000..994fba4b --- /dev/null +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/IProductCache.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; + +namespace EasyAbp.EShop.Products.Products; + +public interface IProductCache +{ + Task GetAsync(Guid productId); + + Task RemoveAsync(Guid productId); +} \ No newline at end of file diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCache.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCache.cs new file mode 100644 index 00000000..42c0f1a5 --- /dev/null +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCache.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using EasyAbp.EShop.Products.Products.Dtos; +using Microsoft.Extensions.Caching.Distributed; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.ObjectMapping; + +namespace EasyAbp.EShop.Products.Products; + +public class ProductCache : IProductCache, ITransientDependency +{ + protected IDistributedCache DistributedCache { get; } + + protected IProductAppService ProductAppService { get; } + + protected IObjectMapper ObjectMapper { get; } + + protected ICurrentTenant CurrentTenant { get; } + + public ProductCache( + IDistributedCache productDistributedCache, + IProductAppService productAppService, + IObjectMapper objectMapper, + ICurrentTenant currentTenant) + { + DistributedCache = productDistributedCache; + ProductAppService = productAppService; + ObjectMapper = objectMapper; + CurrentTenant = currentTenant; + } + + public virtual async Task GetAsync(Guid productId) + { + return await DistributedCache.GetOrAddAsync(productId, async () => + { + var productDto = await ProductAppService.GetAsync(productId); + + var cacheItem = ObjectMapper.Map(productDto); + + if (cacheItem != null) + { + cacheItem.TenantId = CurrentTenant.Id; + } + + return cacheItem; + }); + } + + public virtual async Task RemoveAsync(Guid productId) + { + await DistributedCache.RemoveAsync(productId); + } +} diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCacheInvalidator.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCacheInvalidator.cs index 4e975b85..7c9d368c 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCacheInvalidator.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/ProductCacheInvalidator.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using Volo.Abp.Caching; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; @@ -13,34 +11,34 @@ public class ProductCacheInvalidator : IDistributedEventHandler>, ITransientDependency { - protected IDistributedCache DistributedCache { get; } + protected IProductCache ProductCache { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; } public ProductCacheInvalidator( - IDistributedCache distributedCache, + IProductCache productCache, IUnitOfWorkManager unitOfWorkManager) { - DistributedCache = distributedCache; + ProductCache = productCache; UnitOfWorkManager = unitOfWorkManager; } public virtual async Task HandleEventAsync(EntityUpdatedEto eventData) { - await DistributedCache.RemoveAsync(eventData.Entity.Id); + await ProductCache.RemoveAsync(eventData.Entity.Id); UnitOfWorkManager.Current?.OnCompleted(async () => { - await DistributedCache.RemoveAsync(eventData.Entity.Id); + await ProductCache.RemoveAsync(eventData.Entity.Id); }); } public virtual async Task HandleEventAsync(EntityDeletedEto eventData) { - await DistributedCache.RemoveAsync(eventData.Entity.Id); + await ProductCache.RemoveAsync(eventData.Entity.Id); UnitOfWorkManager.Current?.OnCompleted(async () => { - await DistributedCache.RemoveAsync(eventData.Entity.Id); + await ProductCache.RemoveAsync(eventData.Entity.Id); }); } } diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj index 95717151..938cd5be 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared.csproj @@ -22,6 +22,7 @@ + diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultFailedReason.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultFailedReason.cs index d02bcc8d..e500300a 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultFailedReason.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultFailedReason.cs @@ -3,4 +3,5 @@ public static class FlashSaleResultFailedReason { public const string InvalidHashToken = "InvalidHashToken"; + public const string OrderCanceled = "OrderCanceled"; } diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs index a1a25619..fd7ae681 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs @@ -49,10 +49,6 @@ public class FlashSaleResult : FullAuditedAggregateRoot, IFlashSaleResult, public void MarkAsFailed([NotNull] string reason) { - if (Status != FlashSaleResultStatus.Pending) - { - throw new FlashSaleResultStatusNotPendingException(Id); - } Status = FlashSaleResultStatus.Failed; Reason = Check.NotNullOrEmpty(reason, nameof(reason)); } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs new file mode 100644 index 00000000..5a1033d1 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using EasyAbp.Eshop.Products.Products; +using EasyAbp.EShop.Orders.Orders; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; +using EasyAbp.EShop.Products.Products; +using EasyAbp.EShop.Products.Products.Dtos; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; +using Shouldly; +using Volo.Abp.Users; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; + +public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTestBase +{ + protected FlashSaleOrderCanceledEventHandler ResultMarkAsFailedOrderCanceledEventHandler { get; } + + protected IFlashSaleCurrentResultCache FlashSaleCurrentResultCache { get; } + + protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; } + + private ProductDto Product1 { get; set; } + + public FlashSaleOrderCanceledEventHandlerTests() + { + ResultMarkAsFailedOrderCanceledEventHandler = GetRequiredService(); + FlashSaleCurrentResultCache = GetRequiredService(); + FlashSaleInventoryManager = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + Product1 = CreateMockProductDto(); + + var productAppService = Substitute.For(); + productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); + services.Replace(ServiceDescriptor.Singleton(productAppService)); + + var flashSaleInventoryManager = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(flashSaleInventoryManager)); + + var flashSaleCurrentResultCache = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(flashSaleCurrentResultCache)); + } + + [Fact] + public async Task HandleEventAsync() + { + var flashSaleResult = await CreateFlashSaleResultAsync(); + var orderCanceledEto = new OrderCanceledEto(new OrderEto() + { + Id = Guid.NewGuid(), + StoreId = flashSaleResult.StoreId, + OrderLines = new List() + { + new OrderLineEto() + { + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id + } + } + }); + flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id); + FlashSaleInventoryManager + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id) + .Returns(Task.FromResult(true)); + + await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto); + + var existFlashSaleResult = await FlashSaleResultRepository.GetAsync(flashSaleResult.Id); + existFlashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Failed); + existFlashSaleResult.Reason.ShouldBe(FlashSaleResultFailedReason.OrderCanceled); + + await FlashSaleInventoryManager.Received() + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id); + await FlashSaleCurrentResultCache.Received() + .RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId); + } + + [Fact] + public async Task HandleEventAsync_Should_Do_Not_RemoveResultCache_When_TryRollBackInventory_Failed() + { + var flashSaleResult = await CreateFlashSaleResultAsync(); + var orderCanceledEto = new OrderCanceledEto(new OrderEto() + { + Id = Guid.NewGuid(), + StoreId = flashSaleResult.StoreId, + OrderLines = new List() + { + new OrderLineEto() + { + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id + } + } + }); + flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id); + FlashSaleInventoryManager + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id) + .Returns(Task.FromResult(false)); + + await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto); + + var existFlashSaleResult = await FlashSaleResultRepository.GetAsync(flashSaleResult.Id); + existFlashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Failed); + existFlashSaleResult.Reason.ShouldBe(FlashSaleResultFailedReason.OrderCanceled); + + await FlashSaleInventoryManager.Received() + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id); + await FlashSaleCurrentResultCache.DidNotReceive() + .RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId); + } + + [Fact] + public async Task HandleEventAsync_Should_Do_Not_Something_When_Result_Not_Exists() + { + var flashSaleResult = await CreateFlashSaleResultAsync(); + var orderCanceledEto = new OrderCanceledEto(new OrderEto() + { + Id = Guid.NewGuid(), + StoreId = flashSaleResult.StoreId, + OrderLines = new List() + { + new OrderLineEto() + { + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id + } + } + }); + flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id); + flashSaleResult = await MarkAsFailedAsync(flashSaleResult.Id, "UT"); + FlashSaleInventoryManager + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id) + .Returns(Task.FromResult(true)); + + await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto); + + var existFlashSaleResult = await FlashSaleResultRepository.GetAsync(flashSaleResult.Id); + existFlashSaleResult.Status.ShouldBe(flashSaleResult.Status); + existFlashSaleResult.Reason.ShouldBe(flashSaleResult.Reason); + + await FlashSaleInventoryManager.DidNotReceive() + .TryRollBackInventoryAsync(flashSaleResult.TenantId, + Product1.InventoryProviderName, flashSaleResult.StoreId, + FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id); + await FlashSaleCurrentResultCache.DidNotReceive() + .RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId); + } + + protected async Task MarkAsSuccessfulAsync(Guid resultId, Guid orderId) + { + return await WithUnitOfWorkAsync(async () => + { + var flashSaleResult = await FlashSaleResultRepository.GetAsync(resultId); + + flashSaleResult.MarkAsSuccessful(orderId); + await FlashSaleResultRepository.UpdateAsync(flashSaleResult, autoSave: true); + + return flashSaleResult; + }); + } + + protected async Task MarkAsFailedAsync(Guid resultId, string reason) + { + return await WithUnitOfWorkAsync(async () => + { + var flashSaleResult = await FlashSaleResultRepository.GetAsync(resultId); + + flashSaleResult.MarkAsFailed(reason); + await FlashSaleResultRepository.UpdateAsync(flashSaleResult, autoSave: true); + + return flashSaleResult; + }); + } + + protected async Task CreateFlashSaleResultAsync() + { + return await WithUnitOfWorkAsync(async () => + { + var flashSaleResult = new FlashSaleResult( + GuidGenerator.Create(), + null, + FlashSalesTestData.Store1Id, + FlashSalesTestData.Plan1Id, + CurrentUser.GetId(), + DateTime.Now); + await FlashSaleResultRepository.InsertAsync(flashSaleResult, autoSave: true); + + return flashSaleResult; + }); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs index db1466ec..948a2209 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs @@ -75,26 +75,4 @@ public class FlashSaleResultTests flashSaleResult.OrderId.ShouldBe(null); flashSaleResult.Reason.ShouldBe("reason"); } - - [Fact] - public void MarkAsFailed_Should_Throw_FlashSaleResultStatusNotPendingException_When_Status_Not_Pending() - { - var flashSaleResult = new FlashSaleResult( - id: Guid.NewGuid(), - tenantId: null, - storeId: Guid.NewGuid(), - planId: Guid.NewGuid(), - userId: Guid.NewGuid(), - DateTime.Now - ); - - flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Pending); - - flashSaleResult.MarkAsFailed("reason"); - - Assert.Throws(() => - { - flashSaleResult.MarkAsFailed("reason"); - }); - } } From 310c47357a38e3809c32c544a2221f351b263dbe Mon Sep 17 00:00:00 2001 From: Jadyn Date: Fri, 19 Aug 2022 21:24:09 +0800 Subject: [PATCH 2/2] Rename `FlashSaleOrderCanceledEventHandlerTests` methods name --- .../FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs index 5a1033d1..952789d5 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs @@ -86,7 +86,7 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest } [Fact] - public async Task HandleEventAsync_Should_Do_Not_RemoveResultCache_When_TryRollBackInventory_Failed() + public async Task HandleEventAsync_Should_Not_RemoveResultCache_When_TryRollBackInventory_Failed() { var flashSaleResult = await CreateFlashSaleResultAsync(); var orderCanceledEto = new OrderCanceledEto(new OrderEto() @@ -124,7 +124,7 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest } [Fact] - public async Task HandleEventAsync_Should_Do_Not_Something_When_Result_Not_Exists() + public async Task HandleEventAsync_Should_Skip_Handling_If_Result_Does_Not_Exist() { var flashSaleResult = await CreateFlashSaleResultAsync(); var orderCanceledEto = new OrderCanceledEto(new OrderEto()