Browse Source

Auto cancel and refund order in case of insufficient inventory

pull/164/head
gdlcf88 4 years ago
parent
commit
284f345b32
  1. 1
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersConsts.cs
  2. 72
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/ProductInventoryReductionEventHandler.cs
  3. 16
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs
  4. 22
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/CreateEShopRefundItemInfoModel.cs
  5. 34
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundOrderEto.cs
  6. 65
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundOrderEventHandler.cs

1
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersConsts.cs

@ -3,5 +3,6 @@
public static class OrdersConsts
{
public static string UnpaidAutoCancellationReason = "Order payment timed out and not paid";
public static string InventoryReductionFailedAutoCancellationReason = "Insufficient inventory";
}
}

72
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/ProductInventoryReductionEventHandler.cs

@ -1,6 +1,12 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Refunds;
using EasyAbp.EShop.Products.Products;
using EasyAbp.PaymentService.Refunds;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
@ -11,18 +17,24 @@ namespace EasyAbp.EShop.Orders.Orders
{
private readonly IClock _clock;
private readonly ICurrentTenant _currentTenant;
private readonly IOrderManager _orderManager;
private readonly IOrderRepository _orderRepository;
private readonly IDistributedEventBus _distributedEventBus;
public ProductInventoryReductionEventHandler(
IClock clock,
ICurrentTenant currentTenant,
IOrderRepository orderRepository)
IOrderManager orderManager,
IOrderRepository orderRepository,
IDistributedEventBus distributedEventBus)
{
_clock = clock;
_currentTenant = currentTenant;
_orderManager = orderManager;
_orderRepository = orderRepository;
_distributedEventBus = distributedEventBus;
}
[UnitOfWork(true)]
public virtual async Task HandleEventAsync(ProductInventoryReductionAfterOrderPlacedResultEto eventData)
{
@ -37,10 +49,11 @@ namespace EasyAbp.EShop.Orders.Orders
if (!eventData.IsSuccess)
{
// Todo: Cancel order.
await _orderManager.CancelAsync(order, OrdersConsts.InventoryReductionFailedAutoCancellationReason);
return;
}
order.SetReducedInventoryAfterPlacingTime(_clock.Now);
await _orderRepository.UpdateAsync(order, true);
@ -61,15 +74,58 @@ namespace EasyAbp.EShop.Orders.Orders
if (!eventData.IsSuccess)
{
// Todo: Refund.
// Todo: Cancel order.
var refundOrderEto = CreateRefundOrderEto(order);
await _orderManager.CancelAsync(order, OrdersConsts.InventoryReductionFailedAutoCancellationReason);
await RefundOrderAsync(refundOrderEto);
return;
}
order.SetReducedInventoryAfterPaymentTime(_clock.Now);
await _orderRepository.UpdateAsync(order, true);
}
}
[UnitOfWork(true)]
protected virtual async Task RefundOrderAsync(RefundOrderEto refundOrderEto)
{
await _distributedEventBus.PublishAsync(refundOrderEto);
}
protected virtual RefundOrderEto CreateRefundOrderEto(Order order)
{
if (!order.PaymentId.HasValue)
{
throw new OrderIsInWrongStageException(order.Id);
}
var eto = new RefundOrderEto(
order.TenantId,
order.Id,
order.StoreId,
order.PaymentId.Value,
OrdersConsts.InventoryReductionFailedAutoCancellationReason,
OrdersConsts.InventoryReductionFailedAutoCancellationReason,
OrdersConsts.InventoryReductionFailedAutoCancellationReason);
eto.OrderLines.AddRange(order.OrderLines.Select(x => new OrderLineRefundInfoModel
{
OrderLineId = x.Id,
Quantity = x.Quantity - x.RefundedQuantity,
TotalAmount = x.ActualTotalPrice - x.RefundAmount
}));
eto.OrderExtraFees.AddRange(order.OrderExtraFees.Select(x => new OrderExtraFeeRefundInfoModel
{
Name = x.Name,
Key = x.Key,
TotalAmount = x.Fee - x.RefundAmount
}));
return eto;
}
}
}

16
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs

@ -1,23 +1,9 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Payments.Refunds.Dtos
{
[Serializable]
public class CreateEShopRefundItemInput : ExtensibleObject
public class CreateEShopRefundItemInput : CreateEShopRefundItemInfoModel
{
public Guid OrderId { get; set; }
[CanBeNull]
public string CustomerRemark { get; set; }
[CanBeNull]
public string StaffRemark { get; set; }
public List<OrderLineRefundInfoModel> OrderLines { get; set; } = new();
public List<OrderExtraFeeRefundInfoModel> OrderExtraFees { get; set; } = new();
}
}

22
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/CreateEShopRefundItemInfoModel.cs

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Payments.Refunds;
[Serializable]
public class CreateEShopRefundItemInfoModel : ExtensibleObject
{
public Guid OrderId { get; set; }
[CanBeNull]
public string CustomerRemark { get; set; }
[CanBeNull]
public string StaffRemark { get; set; }
public List<OrderLineRefundInfoModel> OrderLines { get; set; } = new();
public List<OrderExtraFeeRefundInfoModel> OrderExtraFees { get; set; } = new();
}

34
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundOrderEto.cs

@ -0,0 +1,34 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Payments.Refunds;
[Serializable]
public class RefundOrderEto : CreateEShopRefundItemInfoModel, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid StoreId { get; set; }
public Guid PaymentId { get; set; }
[CanBeNull]
public string DisplayReason { get; set; }
protected RefundOrderEto()
{
}
public RefundOrderEto(Guid? tenantId, Guid orderId, Guid storeId, Guid paymentId, [CanBeNull] string displayReason,
[CanBeNull] string customerRemark, [CanBeNull] string staffRemark)
{
TenantId = tenantId;
OrderId = orderId;
StoreId = storeId;
PaymentId = paymentId;
DisplayReason = displayReason;
CustomerRemark = customerRemark;
StaffRemark = staffRemark;
}
}

65
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundOrderEventHandler.cs

@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.PaymentService.Payments;
using EasyAbp.PaymentService.Refunds;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Json;
namespace EasyAbp.EShop.Payments.Refunds;
public class RefundOrderEventHandler : IDistributedEventHandler<RefundOrderEto>, ITransientDependency
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IPaymentRepository _paymentRepository;
private readonly IDistributedEventBus _distributedEventBus;
public RefundOrderEventHandler(
IJsonSerializer jsonSerializer,
IPaymentRepository paymentRepository,
IDistributedEventBus distributedEventBus)
{
_jsonSerializer = jsonSerializer;
_paymentRepository = paymentRepository;
_distributedEventBus = distributedEventBus;
}
public virtual async Task HandleEventAsync(RefundOrderEto eventData)
{
var refundAmount = eventData.OrderLines.Sum(x => x.TotalAmount) +
eventData.OrderExtraFees.Sum(x => x.TotalAmount);
var payment = await _paymentRepository.GetAsync(eventData.PaymentId);
var paymentItem = payment.PaymentItems.Single(x => x.ItemKey == eventData.OrderId.ToString());
var createRefundItemInput = new CreateRefundItemInput
{
PaymentItemId = paymentItem.Id,
RefundAmount = refundAmount,
CustomerRemark = eventData.CustomerRemark,
StaffRemark = eventData.StaffRemark
};
createRefundItemInput.SetProperty(nameof(RefundItem.StoreId), eventData.StoreId);
createRefundItemInput.SetProperty(nameof(RefundItem.OrderId), eventData.OrderId);
createRefundItemInput.SetProperty(nameof(RefundItem.OrderLines),
_jsonSerializer.Serialize(eventData.OrderLines));
createRefundItemInput.SetProperty(nameof(RefundItem.OrderExtraFees),
_jsonSerializer.Serialize(eventData.OrderExtraFees));
var eto = new RefundPaymentEto(eventData.TenantId, new CreateRefundInput
{
PaymentId = eventData.PaymentId,
DisplayReason = eventData.DisplayReason,
CustomerRemark = eventData.CustomerRemark,
StaffRemark = eventData.StaffRemark,
RefundItems = new List<CreateRefundItemInput> { createRefundItemInput }
});
await _distributedEventBus.PublishAsync(eto);
}
}
Loading…
Cancel
Save