mirror of https://github.com/EasyAbp/EShop.git
committed by
GitHub
4 changed files with 226 additions and 2 deletions
@ -0,0 +1,47 @@ |
|||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Products.Products |
||||
|
{ |
||||
|
// see: https://github.com/EasyAbp/EShop/issues/139
|
||||
|
public class InventoryRollbackOrderCanceledEventHandler : IDistributedEventHandler<OrderCanceledEto>, ITransientDependency |
||||
|
{ |
||||
|
private readonly IProductManager _productManager; |
||||
|
private readonly IProductRepository _productRepository; |
||||
|
|
||||
|
public InventoryRollbackOrderCanceledEventHandler( |
||||
|
IProductManager productManager, |
||||
|
IProductRepository productRepository) |
||||
|
{ |
||||
|
_productManager = productManager; |
||||
|
_productRepository = productRepository; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork(true)] |
||||
|
public virtual async Task HandleEventAsync(OrderCanceledEto eventData) |
||||
|
{ |
||||
|
if (eventData.Order.PaidTime.HasValue) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (var orderLine in eventData.Order.OrderLines) |
||||
|
{ |
||||
|
var product = await _productRepository.GetAsync(orderLine.ProductId); |
||||
|
|
||||
|
if (product.InventoryStrategy is InventoryStrategy.NoNeed or InventoryStrategy.ReduceAfterPayment) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var productSku = product.ProductSkus.Single(x => x.Id == orderLine.ProductSkuId); |
||||
|
|
||||
|
await _productManager.TryIncreaseInventoryAsync(product, productSku, orderLine.Quantity, true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Products.Products |
||||
|
{ |
||||
|
public class InventoryRollbackTests : ProductsDomainTestBase |
||||
|
{ |
||||
|
private InventoryRollbackOrderCanceledEventHandler EventHandler { get; } |
||||
|
private IProductRepository ProductRepository { get; } |
||||
|
private IProductManager ProductManager { get; } |
||||
|
|
||||
|
public InventoryRollbackTests() |
||||
|
{ |
||||
|
EventHandler = ServiceProvider.GetRequiredService<InventoryRollbackOrderCanceledEventHandler>(); |
||||
|
ProductRepository = ServiceProvider.GetRequiredService<IProductRepository>(); |
||||
|
ProductManager = ServiceProvider.GetRequiredService<IProductManager>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Roll_Back_ReduceAfterPlacing_Inventory_If_Order_Is_Not_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.ReduceAfterPlacing, false, true); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Roll_Back_ReduceAfterPlacing_Inventory_If_Order_Is_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.ReduceAfterPlacing, true, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Roll_Back_ReduceAfterPayment_Inventory_If_Order_Is_Not_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.ReduceAfterPayment, false, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Roll_Back_ReduceAfterPayment_Inventory_If_Order_Is_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.ReduceAfterPayment, true, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Roll_Back_NoNeed_Inventory_If_Order_Is_Not_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.NoNeed, false, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Roll_Back_NoNeed_Inventory_If_Order_Is_Paid() |
||||
|
{ |
||||
|
await TestAsync(InventoryStrategy.NoNeed, true, false); |
||||
|
} |
||||
|
|
||||
|
protected async Task TestAsync(InventoryStrategy inventoryStrategy, bool orderPaid, bool expectRollback) |
||||
|
{ |
||||
|
var product = await ProductRepository.GetAsync(ProductsTestData.Product1Id); |
||||
|
var productSku = product.ProductSkus.Single(x => x.Id == ProductsTestData.Product1Sku1Id); |
||||
|
|
||||
|
typeof(Product).GetProperty("InventoryStrategy")!.SetValue(product, inventoryStrategy); |
||||
|
|
||||
|
await ProductRepository.UpdateAsync(product, true); |
||||
|
|
||||
|
(await ProductManager.TryIncreaseInventoryAsync(product, productSku, 3, false)).ShouldBeTrue(); |
||||
|
(await ProductManager.TryReduceInventoryAsync(product, productSku, 3, true)).ShouldBeTrue(); |
||||
|
|
||||
|
var inventoryDataModel = await ProductManager.GetInventoryDataAsync(product, productSku); |
||||
|
|
||||
|
inventoryDataModel.Inventory.ShouldBe(0); |
||||
|
|
||||
|
await EventHandler.HandleEventAsync(new OrderCanceledEto( |
||||
|
new OrderEto |
||||
|
{ |
||||
|
#region properties
|
||||
|
|
||||
|
Id = Guid.NewGuid(), |
||||
|
TenantId = null, |
||||
|
StoreId = ProductsTestData.Store1Id, |
||||
|
OrderNumber = null, |
||||
|
CustomerUserId = Guid.NewGuid(), |
||||
|
OrderStatus = OrderStatus.Processing, |
||||
|
Currency = null, |
||||
|
ProductTotalPrice = 0, |
||||
|
TotalDiscount = 0, |
||||
|
TotalPrice = 0, |
||||
|
ActualTotalPrice = 0, |
||||
|
RefundAmount = 0, |
||||
|
CustomerRemark = null, |
||||
|
StaffRemark = null, |
||||
|
PaymentId = orderPaid ? Guid.NewGuid() : null, |
||||
|
PaidTime = orderPaid ? DateTime.Now : null, |
||||
|
CompletionTime = null, |
||||
|
CanceledTime = null, |
||||
|
CancellationReason = null, |
||||
|
ReducedInventoryAfterPlacingTime = null, |
||||
|
ReducedInventoryAfterPaymentTime = null, |
||||
|
PaymentExpiration = null, |
||||
|
OrderLines = new List<OrderLineEto> |
||||
|
{ |
||||
|
new() |
||||
|
{ |
||||
|
Id = Guid.NewGuid(), |
||||
|
ProductId = product.Id, |
||||
|
ProductSkuId = productSku.Id, |
||||
|
ProductModificationTime = default, |
||||
|
ProductDetailModificationTime = default, |
||||
|
ProductGroupName = null, |
||||
|
ProductGroupDisplayName = null, |
||||
|
ProductUniqueName = null, |
||||
|
ProductDisplayName = null, |
||||
|
SkuName = null, |
||||
|
SkuDescription = null, |
||||
|
MediaResources = null, |
||||
|
Currency = null, |
||||
|
UnitPrice = 0, |
||||
|
TotalPrice = 0, |
||||
|
TotalDiscount = 0, |
||||
|
ActualTotalPrice = 0, |
||||
|
Quantity = 3, |
||||
|
RefundedQuantity = 0, |
||||
|
RefundAmount = 0 |
||||
|
} |
||||
|
}, |
||||
|
CreationTime = default, |
||||
|
CreatorId = null, |
||||
|
LastModificationTime = null, |
||||
|
LastModifierId = null, |
||||
|
IsDeleted = false, |
||||
|
DeletionTime = null, |
||||
|
DeleterId = null |
||||
|
|
||||
|
#endregion
|
||||
|
} |
||||
|
)); |
||||
|
|
||||
|
product = await ProductRepository.GetAsync(ProductsTestData.Product1Id); |
||||
|
productSku = product.ProductSkus.Single(x => x.Id == ProductsTestData.Product1Sku1Id); |
||||
|
|
||||
|
inventoryDataModel = await ProductManager.GetInventoryDataAsync(product, productSku); |
||||
|
|
||||
|
inventoryDataModel.Inventory.ShouldBe(expectRollback ? 3 : 0); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue