diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs
index e5385653..663c02d0 100644
--- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs
+++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs
@@ -154,7 +154,7 @@ namespace EasyAbp.EShop.Orders.Orders
return PaidTime.HasValue;
}
- public void Refund(Guid orderLineId, int quantity, decimal amount)
+ public void RefundOrderLine(Guid orderLineId, int quantity, decimal amount)
{
if (amount <= decimal.Zero)
{
@@ -163,12 +163,21 @@ namespace EasyAbp.EShop.Orders.Orders
var orderLine = OrderLines.Single(x => x.Id == orderLineId);
- if (orderLine.RefundedQuantity + quantity > orderLine.Quantity)
+ orderLine.Refund(quantity, amount);
+
+ RefundAmount += amount;
+ }
+
+ public void RefundOrderExtraFee([NotNull] string extraFeeName, [CanBeNull] string extraFeeKey, decimal amount)
+ {
+ if (amount <= decimal.Zero)
{
- throw new InvalidRefundQuantityException(quantity);
+ throw new InvalidRefundAmountException(amount);
}
- orderLine.Refund(quantity, amount);
+ var extraFee = OrderExtraFees.Single(x => x.Name == extraFeeName && x.Key == extraFeeKey);
+
+ extraFee.Refund(amount);
RefundAmount += amount;
}
diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs
index 01c72d3a..1d2f85bd 100644
--- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs
+++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs
@@ -15,6 +15,8 @@ namespace EasyAbp.EShop.Orders.Orders
public virtual string Key { get; protected set; }
public virtual decimal Fee { get; protected set; }
+
+ public virtual decimal RefundAmount { get; protected set; }
protected OrderExtraFee()
{
@@ -32,6 +34,11 @@ namespace EasyAbp.EShop.Orders.Orders
Fee = fee;
}
+ internal void Refund(decimal amount)
+ {
+ RefundAmount += amount;
+ }
+
public override object[] GetKeys()
{
return new object[] {OrderId, Name, Key};
diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLine.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLine.cs
index dfcfbe8f..9967f0d2 100644
--- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLine.cs
+++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLine.cs
@@ -115,6 +115,11 @@ namespace EasyAbp.EShop.Orders.Orders
internal void Refund(int quantity, decimal amount)
{
+ if (RefundedQuantity + quantity > Quantity)
+ {
+ throw new InvalidRefundQuantityException(quantity);
+ }
+
RefundedQuantity += quantity;
RefundAmount += amount;
}
diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/RefundCompletedEventHandler.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/RefundCompletedEventHandler.cs
index 6420926a..bd22e387 100644
--- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/RefundCompletedEventHandler.cs
+++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/RefundCompletedEventHandler.cs
@@ -40,7 +40,12 @@ namespace EasyAbp.EShop.Orders.Orders
foreach (var eto in refundItem.RefundItemOrderLines)
{
- order.Refund(eto.OrderLineId, eto.RefundedQuantity, eto.RefundAmount);
+ order.RefundOrderLine(eto.OrderLineId, eto.RefundedQuantity, eto.RefundAmount);
+ }
+
+ foreach (var eto in refundItem.RefundItemOrderExtraFees)
+ {
+ order.RefundOrderExtraFee(eto.Name, eto.Key, eto.RefundAmount);
}
await _orderRepository.UpdateAsync(order, true);
diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/EasyAbp.EShop.Orders.Domain.Tests.csproj b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/EasyAbp.EShop.Orders.Domain.Tests.csproj
index b1396ae3..d35e9448 100644
--- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/EasyAbp.EShop.Orders.Domain.Tests.csproj
+++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/EasyAbp.EShop.Orders.Domain.Tests.csproj
@@ -2,7 +2,7 @@
net6.0
-
+ EasyAbp.EShop.Orders
diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs
index 3aca6c0e..28aa602d 100644
--- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs
+++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs
@@ -1,4 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
+using EasyAbp.EShop.Payments.Refunds;
+using Microsoft.Extensions.DependencyInjection;
+using NSubstitute;
using Shouldly;
using Xunit;
@@ -6,18 +12,200 @@ namespace EasyAbp.EShop.Orders.Orders
{
public class OrderDomainTests : OrdersDomainTestBase
{
+ private Order Order1 { get; set; }
+ private readonly IOrderRepository _orderRepository;
+
public OrderDomainTests()
{
+ _orderRepository = ServiceProvider.GetRequiredService();
+ }
+
+ protected override void AfterAddApplication(IServiceCollection services)
+ {
+ var orderRepository = Substitute.For();
+ Order1 = new Order(
+ OrderTestData.Order1Id,
+ null,
+ OrderTestData.Store1Id,
+ Guid.NewGuid(),
+ "CNY",
+ 1m,
+ 0m,
+ 1.5m,
+ 1.5m,
+ null,
+ null);
+ Order1.OrderLines.Add(new OrderLine(
+ OrderTestData.OrderLine1Id,
+ OrderTestData.Product1Id,
+ OrderTestData.ProductSku1Id,
+ null,
+ DateTime.Now,
+ null,
+ "Default",
+ "Default",
+ null,
+ "Product 1",
+ null,
+ null,
+ null,
+ "CNY",
+ 0.5m,
+ 1m,
+ 0m,
+ 1m,
+ 2
+ ));
+ Order1.OrderExtraFees.Add(new OrderExtraFee(
+ OrderTestData.Order1Id,
+ "Name",
+ "Key",
+ 0.3m
+ ));
+ Order1.SetPaymentId(OrderTestData.Payment1Id);
+ Order1.SetPaidTime(DateTime.Now);
+
+ orderRepository.GetAsync(OrderTestData.Order1Id).Returns(Task.FromResult(Order1));
+
+ services.AddTransient(_ => orderRepository);
}
[Fact]
- public async Task Test1()
+ public async Task Should_Record_Refund()
{
- // Arrange
+ var handler = ServiceProvider.GetRequiredService();
+
+ await handler.HandleEventAsync(new EShopRefundCompletedEto
+ {
+ Refund = new EShopRefundEto
+ {
+ Id = Guid.NewGuid(),
+ TenantId = null,
+ PaymentId = OrderTestData.Payment1Id,
+ Currency = "CNY",
+ RefundAmount = 0.3m,
+ RefundItems = new List
+ {
+ new()
+ {
+ Id = Guid.NewGuid(),
+ PaymentItemId = Guid.NewGuid(),
+ RefundAmount = 0.3m,
+ StoreId = OrderTestData.Store1Id,
+ OrderId = OrderTestData.Order1Id,
+ RefundItemOrderLines = new List
+ {
+ new()
+ {
+ OrderLineId = OrderTestData.OrderLine1Id,
+ RefundedQuantity = 1,
+ RefundAmount = 0.2m
+ }
+ },
+ RefundItemOrderExtraFees = new List
+ {
+ new()
+ {
+ Name = "Name",
+ Key = "Key",
+ RefundAmount = 0.1m
+ }
+ }
+ }
+ }
+ }
+ });
+
+ Order1.RefundAmount.ShouldBe(0.3m);
+
+ var orderLine1 = Order1.OrderLines.Single(x => x.Id == OrderTestData.OrderLine1Id);
+ orderLine1.RefundAmount.ShouldBe(0.2m);
+ orderLine1.RefundedQuantity.ShouldBe(1);
+
+ var extraFee = Order1.OrderExtraFees.Single(x => x.Name == "Name" && x.Key == "Key");
+ extraFee.RefundAmount.ShouldBe(0.1m);
+ }
- // Assert
+ [Fact]
+ public async Task Should_Avoid_Non_Positive_Refund_Amount()
+ {
+ var handler = ServiceProvider.GetRequiredService();
+
+ await Should.ThrowAsync(async () =>
+ {
+ await handler.HandleEventAsync(new EShopRefundCompletedEto
+ {
+ Refund = new EShopRefundEto
+ {
+ Id = Guid.NewGuid(),
+ TenantId = null,
+ PaymentId = OrderTestData.Payment1Id,
+ Currency = "CNY",
+ RefundAmount = -1m,
+ RefundItems = new List
+ {
+ new()
+ {
+ Id = Guid.NewGuid(),
+ PaymentItemId = Guid.NewGuid(),
+ RefundAmount = -1m,
+ StoreId = OrderTestData.Store1Id,
+ OrderId = OrderTestData.Order1Id,
+ RefundItemOrderLines = new List
+ {
+ new()
+ {
+ OrderLineId = OrderTestData.OrderLine1Id,
+ RefundedQuantity = 1,
+ RefundAmount = -1m
+ }
+ }
+ }
+ }
+ }
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Should_Avoid_Over_Quantity_Refund()
+ {
+ var handler = ServiceProvider.GetRequiredService();
- // Assert
+ await Should.ThrowAsync(async () =>
+ {
+ await handler.HandleEventAsync(new EShopRefundCompletedEto
+ {
+ Refund = new EShopRefundEto
+ {
+ Id = Guid.NewGuid(),
+ TenantId = null,
+ PaymentId = OrderTestData.Payment1Id,
+ Currency = "CNY",
+ RefundAmount = 0.3m,
+ RefundItems = new List
+ {
+ new()
+ {
+ Id = Guid.NewGuid(),
+ PaymentItemId = Guid.NewGuid(),
+ RefundAmount = 0.3m,
+ StoreId = OrderTestData.Store1Id,
+ OrderId = OrderTestData.Order1Id,
+ RefundItemOrderLines = new List
+ {
+ new()
+ {
+ OrderLineId = OrderTestData.OrderLine1Id,
+ RefundedQuantity = 3,
+ RefundAmount = 0.2m
+ }
+ }
+ }
+ }
+ }
+ });
+ });
}
}
}
diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/OrderTestData.cs b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/OrderTestData.cs
index b15a517a..a12c181d 100644
--- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/OrderTestData.cs
+++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/OrderTestData.cs
@@ -5,6 +5,12 @@ namespace EasyAbp.EShop.Orders
{
public class OrderTestData
{
+ public static Guid Order1Id { get; } = Guid.NewGuid();
+
+ public static Guid OrderLine1Id { get; } = Guid.NewGuid();
+
+ public static Guid Payment1Id { get; } = Guid.NewGuid();
+
public static Guid Store1Id { get; } = Guid.NewGuid();
public static Guid Product1Id { get; } = Guid.NewGuid();
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundInput.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundInput.cs
index 371ad60a..8007ddb8 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundInput.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundInput.cs
@@ -35,11 +35,36 @@ namespace EasyAbp.EShop.Payments.Refunds.Dtos
);
}
- if (RefundItems.Any(x => x.OrderLines.IsNullOrEmpty()))
+ if (RefundItems.Any(x => x.OrderLines.IsNullOrEmpty() && x.OrderExtraFees.IsNullOrEmpty()))
{
yield return new ValidationResult(
- "RefundItem.OrderLines should not be empty!",
- new[] { nameof(CreateEShopRefundItemInput.OrderLines) }
+ "RefundItem.OrderLines and RefundItem.OrderExtraFees should not both be empty!",
+ new[]
+ {
+ nameof(CreateEShopRefundItemInput.OrderLines), nameof(CreateEShopRefundItemInput.OrderExtraFees)
+ }
+ );
+ }
+
+ if (RefundItems.SelectMany(x => x.OrderLines).Any(x => x.TotalAmount <= decimal.Zero))
+ {
+ yield return new ValidationResult(
+ "RefundAmount should be greater than 0.",
+ new[]
+ {
+ nameof(OrderLineRefundInfoModel.TotalAmount)
+ }
+ );
+ }
+
+ if (RefundItems.SelectMany(x => x.OrderExtraFees).Any(x => x.TotalAmount <= decimal.Zero))
+ {
+ yield return new ValidationResult(
+ "RefundAmount should be greater than 0.",
+ new[]
+ {
+ nameof(OrderExtraFeeRefundInfoModel.TotalAmount)
+ }
);
}
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs
index 89513772..0eb0c99b 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application.Contracts/EasyAbp/EShop/Payments/Refunds/Dtos/CreateEShopRefundItemInput.cs
@@ -16,6 +16,8 @@ namespace EasyAbp.EShop.Payments.Refunds.Dtos
[CanBeNull]
public string StaffRemark { get; set; }
- public List OrderLines { get; set; } = new List();
+ public List OrderLines { get; set; } = new();
+
+ public List OrderExtraFees { get; set; } = new();
}
}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/AnotherRefundTaskIsOnGoingException.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/AnotherRefundTaskIsOnGoingException.cs
new file mode 100644
index 00000000..787a1ae4
--- /dev/null
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/AnotherRefundTaskIsOnGoingException.cs
@@ -0,0 +1,13 @@
+using System;
+using Volo.Abp;
+
+namespace EasyAbp.EShop.Payments.Refunds
+{
+ public class AnotherRefundTaskIsOnGoingException : BusinessException
+ {
+ public AnotherRefundTaskIsOnGoingException(Guid id) : base(PaymentsErrorCodes.AnotherRefundTaskIsOnGoing)
+ {
+ WithData(nameof(id), id);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/InvalidRefundAmountException.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/InvalidRefundAmountException.cs
new file mode 100644
index 00000000..f8e2575e
--- /dev/null
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/InvalidRefundAmountException.cs
@@ -0,0 +1,16 @@
+using System;
+using Volo.Abp;
+
+namespace EasyAbp.EShop.Payments.Refunds
+{
+ public class InvalidRefundAmountException : BusinessException
+ {
+ public InvalidRefundAmountException(Guid paymentId, Guid paymentItemId, decimal refundAmount) : base(
+ PaymentsErrorCodes.InvalidRefundAmount)
+ {
+ WithData(nameof(paymentId), paymentId);
+ WithData(nameof(paymentItemId), paymentItemId);
+ WithData(nameof(refundAmount), refundAmount);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/RefundAppService.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/RefundAppService.cs
index 919fa562..4df5f9bd 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/RefundAppService.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Application/EasyAbp/EShop/Payments/Refunds/RefundAppService.cs
@@ -85,6 +85,11 @@ namespace EasyAbp.EShop.Payments.Refunds
var payment = await _paymentRepository.GetAsync(input.PaymentId);
+ if (payment.PendingRefundAmount != decimal.Zero)
+ {
+ throw new AnotherRefundTaskIsOnGoingException(payment.Id);
+ }
+
var createRefundInput = new CreateRefundInput
{
PaymentId = input.PaymentId,
@@ -103,24 +108,32 @@ namespace EasyAbp.EShop.Payments.Refunds
{
throw new OrderIsNotInSpecifiedPaymentException(order.Id, payment.Id);
}
-
+
await AuthorizationService.CheckMultiStorePolicyAsync(paymentItem.StoreId,
PaymentsPermissions.Refunds.Manage, PaymentsPermissions.Refunds.CrossStore);
- foreach (var orderLineRefundInfoModel in refundItem.OrderLines)
+ var refundAmount = refundItem.OrderLines.Sum(x => x.TotalAmount) +
+ refundItem.OrderExtraFees.Sum(x => x.TotalAmount);
+
+ if (refundAmount + paymentItem.RefundAmount > paymentItem.ActualPaymentAmount)
+ {
+ throw new InvalidRefundAmountException(payment.Id, paymentItem.Id, refundAmount);
+ }
+
+ foreach (var model in refundItem.OrderLines)
{
- var orderLine = order.OrderLines.Single(x => x.Id == orderLineRefundInfoModel.OrderLineId);
+ var orderLine = order.OrderLines.Single(x => x.Id == model.OrderLineId);
- if (orderLine.RefundedQuantity + orderLineRefundInfoModel.Quantity > orderLine.Quantity)
+ if (orderLine.RefundedQuantity + model.Quantity > orderLine.Quantity)
{
- throw new InvalidRefundQuantityException(orderLineRefundInfoModel.Quantity);
+ throw new InvalidRefundQuantityException(model.Quantity);
}
}
var eto = new CreateRefundItemInput
{
PaymentItemId = paymentItem.Id,
- RefundAmount = refundItem.OrderLines.Sum(x => x.TotalAmount),
+ RefundAmount = refundAmount,
CustomerRemark = refundItem.CustomerRemark,
StaffRemark = refundItem.StaffRemark
};
@@ -128,6 +141,7 @@ namespace EasyAbp.EShop.Payments.Refunds
eto.SetProperty("StoreId", order.StoreId.ToString());
eto.SetProperty("OrderId", order.Id.ToString());
eto.SetProperty("OrderLines", _jsonSerializer.Serialize(refundItem.OrderLines));
+ eto.SetProperty("OrderExtraFees", _jsonSerializer.Serialize(refundItem.OrderExtraFees));
createRefundInput.RefundItems.Add(eto);
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/cs.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/cs.json
index a6968e9b..f595f307 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/cs.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/cs.json
@@ -10,6 +10,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/en.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/en.json
index 1bc21dbe..3afdca8e 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/en.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/en.json
@@ -11,6 +11,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pl.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pl.json
index 283301ae..02ac89d7 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pl.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pl.json
@@ -10,6 +10,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pt-BR.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pt-BR.json
index bef301d1..03a75e63 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pt-BR.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/pt-BR.json
@@ -10,6 +10,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/sl.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/sl.json
index a447e1c6..fabd6175 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/sl.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/sl.json
@@ -11,6 +11,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/tr.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/tr.json
index ec1c0532..89722fa6 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/tr.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/tr.json
@@ -11,6 +11,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/vi.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/vi.json
index fdc51ba2..acb0e5ad 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/vi.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/vi.json
@@ -10,6 +10,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "Should create payments for each store.",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "The order ({orderId}) is not in the specified payment ({paymentId}).",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "Payment ({id}) has another ongoing refund task.",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "Refund amount ({refundAmount}) is invalid for the payment (id: {paymentId}, item id: {paymentItemId}).",
"EasyAbp.EShop.Payments:OrderIdNotFound": "Cannot get valid OrderId from ExtraProperties.",
"EasyAbp.EShop.Payments:StoreIdNotFound": "Cannot get valid StoreId from ExtraProperties."
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hans.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hans.json
index 51aea86e..ab595298 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hans.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hans.json
@@ -11,6 +11,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "应该为每个商店创建支付",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "退款数量({quantity})无效",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "订单({orderId})不在指定的支付({paymentId})中",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "支付({id})存在进行中的退款任务",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "退款金额({refundAmount})对于支付(id: {paymentId}, item id: {paymentItemId})不正确",
"EasyAbp.EShop.Payments:OrderIdNotFound": "无法从ExtraProperties获得有效的OrderId",
"EasyAbp.EShop.Payments:StoreIdNotFound": "无法从ExtraProperties获得有效的StoreId"
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hant.json b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hant.json
index a2f2eef6..3c3e2e7b 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hant.json
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Localization/Payments/zh-Hant.json
@@ -11,6 +11,8 @@
"EasyAbp.EShop.Payments:MultiStorePaymentNotSupported": "應該為每個商店創建支付",
"EasyAbp.EShop.Payments:InvalidRefundQuantity": "退款數量({quantity})無效",
"EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment": "訂單({orderId})不在指定的支付({paymentId})中",
+ "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing": "支付({id})存在進行中的退款任務",
+ "EasyAbp.EShop.Payments:InvalidRefundAmount": "退款金額({refundAmount})對於支付(id: {paymentId}, item id: {paymentItemId})不正確",
"EasyAbp.EShop.Payments:OrderIdNotFound": "無法從ExtraProperties獲得有效的OrderId",
"EasyAbp.EShop.Payments:StoreIdNotFound": "無法從ExtraProperties獲得有效的StoreId"
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/PaymentsErrorCodes.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/PaymentsErrorCodes.cs
index 6a07234d..e4d7ce4b 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/PaymentsErrorCodes.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/PaymentsErrorCodes.cs
@@ -5,6 +5,8 @@
public const string MultiStorePaymentNotSupported = "EasyAbp.EShop.Payments:MultiStorePaymentNotSupported";
public const string InvalidRefundQuantity = "EasyAbp.EShop.Payments:InvalidRefundQuantity";
public const string OrderIsNotInSpecifiedPayment = "EasyAbp.EShop.Payments:OrderIsNotInSpecifiedPayment";
+ public const string AnotherRefundTaskIsOnGoing = "EasyAbp.EShop.Payments:AnotherRefundTaskIsOnGoing";
+ public const string InvalidRefundAmount = "EasyAbp.EShop.Payments:InvalidRefundAmount";
public const string OrderIdNotFound = "EasyAbp.EShop.Payments:OrderIdNotFound";
public const string StoreIdNotFound = "EasyAbp.EShop.Payments:StoreIdNotFound";
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/EShopRefundItemEto.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/EShopRefundItemEto.cs
index 9d5118bb..2205196c 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/EShopRefundItemEto.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/EShopRefundItemEto.cs
@@ -26,6 +26,8 @@ namespace EasyAbp.EShop.Payments.Refunds
public Guid OrderId { get; set; }
- public List RefundItemOrderLines { get; set; } = new List();
+ public List RefundItemOrderLines { get; set; } = new();
+
+ public List RefundItemOrderExtraFees { get; set; } = new();
}
}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/OrderExtraFeeRefundInfoModel.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/OrderExtraFeeRefundInfoModel.cs
new file mode 100644
index 00000000..e0062f51
--- /dev/null
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/OrderExtraFeeRefundInfoModel.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace EasyAbp.EShop.Payments.Refunds
+{
+ [Serializable]
+ public class OrderExtraFeeRefundInfoModel
+ {
+ public string Name { get; set; }
+
+ public string Key { get; set; }
+
+ public decimal TotalAmount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFeeEto.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFeeEto.cs
new file mode 100644
index 00000000..4aa7d73c
--- /dev/null
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFeeEto.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace EasyAbp.EShop.Payments.Refunds
+{
+ [Serializable]
+ public class RefundItemOrderExtraFeeEto
+ {
+ public string Name { get; set; }
+
+ public string Key { get; set; }
+
+ public decimal RefundAmount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/PaymentsDomainAutoMapperProfile.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/PaymentsDomainAutoMapperProfile.cs
index 91f63bde..e4ea8985 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/PaymentsDomainAutoMapperProfile.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/PaymentsDomainAutoMapperProfile.cs
@@ -31,6 +31,7 @@ namespace EasyAbp.EShop.Payments
CreateMap();
CreateMap();
CreateMap();
+ CreateMap();
}
}
}
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItem.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItem.cs
index c80fe852..0bd17432 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItem.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItem.cs
@@ -30,10 +30,13 @@ namespace EasyAbp.EShop.Payments.Refunds
public virtual Guid OrderId { get; protected set; }
public virtual List RefundItemOrderLines { get; protected set; }
+
+ public virtual List RefundItemOrderExtraFees { get; protected set; }
protected RefundItem()
{
RefundItemOrderLines = new List();
+ RefundItemOrderExtraFees = new List();
ExtraProperties = new ExtraPropertyDictionary();
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFee.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFee.cs
new file mode 100644
index 00000000..ac11ebdc
--- /dev/null
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFee.cs
@@ -0,0 +1,31 @@
+using System;
+using AutoMapper;
+using JetBrains.Annotations;
+using Volo.Abp.Domain.Entities;
+
+namespace EasyAbp.EShop.Payments.Refunds
+{
+ [AutoMap(typeof(RefundItemOrderExtraFeeEto))]
+ public class RefundItemOrderExtraFee : Entity
+ {
+ [NotNull]
+ public virtual string Name { get; protected set; }
+
+ [CanBeNull]
+ public virtual string Key { get; protected set; }
+
+ public virtual decimal RefundAmount { get; protected set; }
+
+ protected RefundItemOrderExtraFee()
+ {
+ }
+
+ public RefundItemOrderExtraFee(Guid id, [NotNull] string name, [CanBeNull] string key,
+ decimal refundAmount) : base(id)
+ {
+ Name = name;
+ Key = key;
+ RefundAmount = refundAmount;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs
index 6b449163..32712b8f 100644
--- a/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs
+++ b/modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs
@@ -80,7 +80,8 @@ namespace EasyAbp.EShop.Payments.Refunds
});
FillRefundItemOrderLines(refund);
-
+ FillRefundItemOrderExtraFees(refund);
+
await _refundRepository.InsertAsync(refund, true);
if (refund.CompletedTime.HasValue)
@@ -132,6 +133,7 @@ namespace EasyAbp.EShop.Payments.Refunds
refund.RefundItems.RemoveAll(i => !etoRefundItemIds.Contains(i.Id));
FillRefundItemOrderLines(refund);
+ FillRefundItemOrderExtraFees(refund);
await _refundRepository.UpdateAsync(refund, true);
@@ -174,6 +176,38 @@ namespace EasyAbp.EShop.Payments.Refunds
}
}
+ protected virtual void FillRefundItemOrderExtraFees(Refund refund)
+ {
+ foreach (var refundItem in refund.RefundItems)
+ {
+ var orderExtraFeeInfoModels =
+ _jsonSerializer.Deserialize>(
+ refundItem.GetProperty("OrderExtraFees"));
+
+ foreach (var orderExtraFeeInfoModel in orderExtraFeeInfoModels)
+ {
+ var refundItemOrderExtraFeeEntity =
+ refundItem.RefundItemOrderExtraFees.FirstOrDefault(x =>
+ x.Name == orderExtraFeeInfoModel.Name &&
+ x.Key == orderExtraFeeInfoModel.Key);
+
+ if (refundItemOrderExtraFeeEntity == null)
+ {
+ refundItemOrderExtraFeeEntity = new RefundItemOrderExtraFee(_guidGenerator.Create(),
+ orderExtraFeeInfoModel.Name, orderExtraFeeInfoModel.Key,
+ orderExtraFeeInfoModel.TotalAmount);
+
+ refundItem.RefundItemOrderExtraFees.Add(refundItemOrderExtraFeeEntity);
+ }
+
+ var orderExtraFeeIds = orderExtraFeeInfoModels.Select(i => new { i.Name, i.Key }).ToList();
+
+ refundItem.RefundItemOrderExtraFees.RemoveAll(
+ i => !orderExtraFeeIds.Contains(new { i.Name, i.Key }));
+ }
+ }
+ }
+
protected virtual void FillRefundItemStoreId(RefundItem item)
{
if (!Guid.TryParse(item.GetProperty("StoreId"), out var storeId))
diff --git a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/RefundAppServiceTests.cs b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/RefundAppServiceTests.cs
index 02063e80..81cc70c3 100644
--- a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/RefundAppServiceTests.cs
+++ b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/RefundAppServiceTests.cs
@@ -8,12 +8,16 @@ using EasyAbp.EShop.Payments.Refunds.Dtos;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Shouldly;
+using Volo.Abp.Data;
+using Volo.Abp.Json;
+using Volo.Abp.Validation;
using Xunit;
namespace EasyAbp.EShop.Payments.Refunds
{
public class RefundAppServiceTests : PaymentsApplicationTestBase
{
+ private readonly IJsonSerializer _jsonSerializer;
private readonly IRefundAppService _refundAppService;
private readonly TestRefundPaymentEventHandler _testRefundPaymentEventHandler;
@@ -26,6 +30,7 @@ namespace EasyAbp.EShop.Payments.Refunds
private void MockPaymentRepository(IServiceCollection services)
{
var paymentRepository = Substitute.For();
+
paymentRepository.GetAsync(PaymentsTestData.Payment1).Returns(x =>
{
var paymentType = typeof(Payment);
@@ -34,7 +39,7 @@ namespace EasyAbp.EShop.Payments.Refunds
var paymentItem = Activator.CreateInstance(paymentItemType, true) as PaymentItem;
paymentItem.ShouldNotBeNull();
paymentItemType.GetProperty(nameof(PaymentItem.Id))?.SetValue(paymentItem, PaymentsTestData.PaymentItem1);
- paymentItemType.GetProperty(nameof(PaymentItem.ActualPaymentAmount))?.SetValue(paymentItem, 0m);
+ paymentItemType.GetProperty(nameof(PaymentItem.ActualPaymentAmount))?.SetValue(paymentItem, 1m);
paymentItemType.GetProperty(nameof(PaymentItem.ItemType))?.SetValue(paymentItem, PaymentsConsts.PaymentItemType);
paymentItemType.GetProperty(nameof(PaymentItem.ItemKey))?.SetValue(paymentItem, PaymentsTestData.Order1.ToString());
paymentItem.ExtraProperties.Add("StoreId", PaymentsTestData.Store1.ToString());
@@ -43,7 +48,34 @@ namespace EasyAbp.EShop.Payments.Refunds
payment.ShouldNotBeNull();
paymentType.GetProperty(nameof(Payment.Id))?.SetValue(payment, PaymentsTestData.Payment1);
paymentType.GetProperty(nameof(Payment.Currency))?.SetValue(payment, "CNY");
- paymentType.GetProperty(nameof(Payment.ActualPaymentAmount))?.SetValue(payment, 0m);
+ paymentType.GetProperty(nameof(Payment.ActualPaymentAmount))?.SetValue(payment, 1m);
+ paymentType.GetProperty(nameof(Payment.PaymentItems))?.SetValue(payment, new List {paymentItem});
+
+ return payment;
+ });
+
+ paymentRepository.GetAsync(PaymentsTestData.Payment2).Returns(x =>
+ {
+ var paymentType = typeof(Payment);
+ var paymentItemType = typeof(PaymentItem);
+
+ var paymentItem = Activator.CreateInstance(paymentItemType, true) as PaymentItem;
+ paymentItem.ShouldNotBeNull();
+ paymentItemType.GetProperty(nameof(PaymentItem.Id))?.SetValue(paymentItem, PaymentsTestData.PaymentItem1);
+ paymentItemType.GetProperty(nameof(PaymentItem.ActualPaymentAmount))?.SetValue(paymentItem, 1m);
+ // pending refund amount
+ paymentItemType.GetProperty(nameof(PaymentItem.PendingRefundAmount))?.SetValue(paymentItem, 1m);
+ paymentItemType.GetProperty(nameof(PaymentItem.ItemType))?.SetValue(paymentItem, PaymentsConsts.PaymentItemType);
+ paymentItemType.GetProperty(nameof(PaymentItem.ItemKey))?.SetValue(paymentItem, PaymentsTestData.Order1.ToString());
+ paymentItem.ExtraProperties.Add("StoreId", PaymentsTestData.Store1.ToString());
+
+ var payment = Activator.CreateInstance(paymentType, true) as Payment;
+ payment.ShouldNotBeNull();
+ paymentType.GetProperty(nameof(Payment.Id))?.SetValue(payment, PaymentsTestData.Payment1);
+ paymentType.GetProperty(nameof(Payment.Currency))?.SetValue(payment, "CNY");
+ paymentType.GetProperty(nameof(Payment.ActualPaymentAmount))?.SetValue(payment, 1m);
+ // pending refund amount
+ paymentType.GetProperty(nameof(Payment.PendingRefundAmount))?.SetValue(payment, 1m);
paymentType.GetProperty(nameof(Payment.PaymentItems))?.SetValue(payment, new List {paymentItem});
return payment;
@@ -67,7 +99,7 @@ namespace EasyAbp.EShop.Payments.Refunds
{
Id = PaymentsTestData.OrderLine1,
Currency = "CNY",
- ActualTotalPrice = 0,
+ ActualTotalPrice = 1m,
Quantity = 1
}
},
@@ -79,6 +111,7 @@ namespace EasyAbp.EShop.Payments.Refunds
public RefundAppServiceTests()
{
+ _jsonSerializer = GetRequiredService();
_refundAppService = GetRequiredService();
_testRefundPaymentEventHandler = GetRequiredService();
}
@@ -96,18 +129,27 @@ namespace EasyAbp.EShop.Payments.Refunds
StaffRemark = "StaffRemark",
RefundItems = new List
{
- new CreateEShopRefundItemInput
+ new()
{
CustomerRemark = "CustomerRemark",
OrderId = PaymentsTestData.Order1,
StaffRemark = "StaffRemark",
OrderLines = new List
{
- new OrderLineRefundInfoModel
+ new()
{
OrderLineId = PaymentsTestData.OrderLine1,
Quantity = 1,
- TotalAmount = 0
+ TotalAmount = 0.4m
+ }
+ },
+ OrderExtraFees = new List
+ {
+ new()
+ {
+ Name = "Name",
+ Key = "Key",
+ TotalAmount = 0.6m
}
}
}
@@ -118,6 +160,181 @@ namespace EasyAbp.EShop.Payments.Refunds
await _refundAppService.CreateAsync(request);
_testRefundPaymentEventHandler.IsEventPublished.ShouldBe(true);
+
+ var eventData = _testRefundPaymentEventHandler.EventData;
+ eventData.ShouldNotBeNull();
+ eventData.CreateRefundInput.RefundItems.Count.ShouldBe(1);
+
+ var refundItem = eventData.CreateRefundInput.RefundItems[0];
+ refundItem.GetProperty("OrderId").ShouldBe(PaymentsTestData.Order1);
+
+ var orderLines =
+ _jsonSerializer.Deserialize>(
+ refundItem.GetProperty("OrderLines"));
+
+ orderLines.Count.ShouldBe(1);
+ orderLines[0].OrderLineId.ShouldBe(PaymentsTestData.OrderLine1);
+ orderLines[0].Quantity.ShouldBe(1);
+ orderLines[0].TotalAmount.ShouldBe(0.4m);
+
+ var orderExtraFees =
+ _jsonSerializer.Deserialize>(
+ refundItem.GetProperty("OrderExtraFees"));
+
+ orderExtraFees.Count.ShouldBe(1);
+ orderExtraFees[0].Name.ShouldBe("Name");
+ orderExtraFees[0].Key.ShouldBe("Key");
+ orderExtraFees[0].TotalAmount.ShouldBe(0.6m);
+ }
+
+ [Fact]
+ public async Task Should_Avoid_Empty_Refund()
+ {
+ // Arrange
+ var request = new CreateEShopRefundInput
+ {
+ DisplayReason = "Reason",
+ CustomerRemark = "Customer Remark",
+ PaymentId = PaymentsTestData.Payment1,
+ StaffRemark = "StaffRemark",
+ RefundItems = new List
+ {
+ new CreateEShopRefundItemInput
+ {
+ CustomerRemark = "CustomerRemark",
+ OrderId = PaymentsTestData.Order1,
+ StaffRemark = "StaffRemark",
+ OrderLines = new List(), // empty
+ OrderExtraFees = new List() // empty
+ }
+ }
+ };
+
+ // Act & Assert
+ await Should.ThrowAsync(async () =>
+ {
+ await _refundAppService.CreateAsync(request);
+ }, "RefundItem.OrderLines and RefundItem.OrderExtraFees should not both be empty!");
+ }
+
+ [Fact]
+ public async Task Should_Avoid_Over_Refund()
+ {
+ // Arrange
+ var request = new CreateEShopRefundInput
+ {
+ DisplayReason = "Reason",
+ CustomerRemark = "Customer Remark",
+ PaymentId = PaymentsTestData.Payment1,
+ StaffRemark = "StaffRemark",
+ RefundItems = new List
+ {
+ new()
+ {
+ CustomerRemark = "CustomerRemark",
+ OrderId = PaymentsTestData.Order1,
+ StaffRemark = "StaffRemark",
+ OrderLines = new List
+ {
+ new()
+ {
+ OrderLineId = PaymentsTestData.OrderLine1,
+ Quantity = 1,
+ TotalAmount = 1m
+ }
+ },
+ OrderExtraFees = new List
+ {
+ new()
+ {
+ Name = "Name",
+ Key = "Key",
+ TotalAmount = 0.1m
+ }
+ }
+ }
+ }
+ };
+
+ // Act & Assert
+ await Should.ThrowAsync(async () =>
+ {
+ await _refundAppService.CreateAsync(request);
+ });
+ }
+
+ [Fact]
+ public async Task Should_Avoid_Concurrent_Refund()
+ {
+ // Arrange
+ var request = new CreateEShopRefundInput
+ {
+ DisplayReason = "Reason",
+ CustomerRemark = "Customer Remark",
+ PaymentId = PaymentsTestData.Payment2,
+ StaffRemark = "StaffRemark",
+ RefundItems = new List
+ {
+ new CreateEShopRefundItemInput
+ {
+ CustomerRemark = "CustomerRemark",
+ OrderId = PaymentsTestData.Order1,
+ StaffRemark = "StaffRemark",
+ OrderLines = new List
+ {
+ new OrderLineRefundInfoModel
+ {
+ OrderLineId = PaymentsTestData.OrderLine1,
+ Quantity = 1,
+ TotalAmount = 1m
+ }
+ }
+ }
+ }
+ };
+
+ // Act & Assert
+ await Should.ThrowAsync(async () =>
+ {
+ await _refundAppService.CreateAsync(request);
+ });
+ }
+
+ [Fact]
+ public async Task Should_Avoid_Non_Positive_Refund_Amount()
+ {
+ // Arrange
+ var request = new CreateEShopRefundInput
+ {
+ DisplayReason = "Reason",
+ CustomerRemark = "Customer Remark",
+ PaymentId = PaymentsTestData.Payment1,
+ StaffRemark = "StaffRemark",
+ RefundItems = new List
+ {
+ new CreateEShopRefundItemInput
+ {
+ CustomerRemark = "CustomerRemark",
+ OrderId = PaymentsTestData.Order1,
+ StaffRemark = "StaffRemark",
+ OrderLines = new List
+ {
+ new OrderLineRefundInfoModel
+ {
+ OrderLineId = PaymentsTestData.OrderLine1,
+ Quantity = 1,
+ TotalAmount = -1m
+ }
+ }
+ }
+ }
+ };
+
+ // Act & Assert
+ await Should.ThrowAsync(async () =>
+ {
+ await _refundAppService.CreateAsync(request);
+ }, "RefundAmount should be greater than 0.");
}
}
}
diff --git a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/TestRefundPaymentEventHandler.cs b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/TestRefundPaymentEventHandler.cs
index 316d84e8..d84a9ef7 100644
--- a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/TestRefundPaymentEventHandler.cs
+++ b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Application.Tests/Refunds/TestRefundPaymentEventHandler.cs
@@ -9,9 +9,12 @@ namespace EasyAbp.EShop.Payments.Refunds
{
public bool IsEventPublished { get; protected set; }
+ public RefundPaymentEto EventData { get; protected set; }
+
public Task HandleEventAsync(RefundPaymentEto eventData)
{
IsEventPublished = true;
+ EventData = eventData;
return Task.CompletedTask;
}
diff --git a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.TestBase/PaymentsTestData.cs b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.TestBase/PaymentsTestData.cs
index b564f4c0..301ecfe1 100644
--- a/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.TestBase/PaymentsTestData.cs
+++ b/modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.TestBase/PaymentsTestData.cs
@@ -14,6 +14,8 @@ namespace EasyAbp.EShop.Payments
public static Guid Payment1 { get; } = Guid.NewGuid();
+ public static Guid Payment2 { get; } = Guid.NewGuid();
+
public static Guid PaymentItem1 { get; } = Guid.NewGuid();
}
}
\ No newline at end of file