Browse Source

Fix a bug of the order discount and create UTs

pull/260/head
gdlcf88 3 years ago
parent
commit
9dcdfa33ce
  1. 4
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderDiscountDistributor.cs
  2. 25
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountDistributor.cs
  3. 7
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountResolver.cs
  4. 18
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/DemoOrderDiscountProvider.cs
  5. 12
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountDistributorTests.cs
  6. 47
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountProviderTests.cs

4
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderDiscountDistributor.cs

@ -5,6 +5,6 @@ namespace EasyAbp.EShop.Orders.Orders;
public interface IOrderDiscountDistributor
{
Task<OrderDiscountDistributionModel> DistributeAsync(IOrder order, Dictionary<IOrderLine, decimal> currentPrices,
OrderDiscountInfoModel discount);
Task<OrderDiscountDistributionModel> DistributeAsync(IOrder order,
Dictionary<IOrderLine, decimal> currentTotalPrices, OrderDiscountInfoModel discount);
}

25
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountDistributor.cs

@ -11,16 +11,17 @@ namespace EasyAbp.EShop.Orders.Orders;
public class OrderDiscountDistributor : IOrderDiscountDistributor, ITransientDependency
{
public virtual Task<OrderDiscountDistributionModel> DistributeAsync(IOrder order,
Dictionary<IOrderLine, decimal> currentPrices, OrderDiscountInfoModel discount)
Dictionary<IOrderLine, decimal> currentTotalPrices, OrderDiscountInfoModel discount)
{
var affectedOrderLines = discount.AffectedOrderLineIds
.Select(orderLineId => order.OrderLines.Single(x => x.Id == orderLineId))
.ToList();
var affectedOrderLinesCurrentPrice =
new Money(affectedOrderLines.Sum(x => currentPrices[x]), order.Currency);
var affectedOrderLinesCurrentTotalPrice =
new Money(affectedOrderLines.Sum(x => currentTotalPrices[x]), order.Currency);
var totalDiscountAmount = discount.CalculateDiscountAmount(affectedOrderLinesCurrentPrice.Amount, order.Currency);
var totalDiscountAmount =
discount.CalculateDiscountAmount(affectedOrderLinesCurrentTotalPrice.Amount, order.Currency);
var distributions = new Dictionary<Guid, decimal>();
var remainingDiscountAmount = totalDiscountAmount;
@ -28,31 +29,31 @@ public class OrderDiscountDistributor : IOrderDiscountDistributor, ITransientDep
foreach (var orderLine in affectedOrderLines)
{
var calculatedDiscountAmount = new Money(
currentPrices[orderLine] / affectedOrderLinesCurrentPrice.Amount *
currentTotalPrices[orderLine] / affectedOrderLinesCurrentTotalPrice.Amount *
totalDiscountAmount, order.Currency, MidpointRounding.ToZero);
var discountAmount = calculatedDiscountAmount.Amount > currentPrices[orderLine]
? currentPrices[orderLine]
var discountAmount = calculatedDiscountAmount.Amount > currentTotalPrices[orderLine]
? currentTotalPrices[orderLine]
: calculatedDiscountAmount.Amount;
distributions[orderLine.Id] = discountAmount;
currentPrices[orderLine] -= discountAmount;
currentTotalPrices[orderLine] -= discountAmount;
remainingDiscountAmount -= discountAmount;
}
foreach (var orderLine in affectedOrderLines.OrderByDescending(x => currentPrices[x]))
foreach (var orderLine in affectedOrderLines.OrderByDescending(x => currentTotalPrices[x]))
{
if (remainingDiscountAmount == decimal.Zero)
{
break;
}
var discountAmount = remainingDiscountAmount > currentPrices[orderLine]
? currentPrices[orderLine]
var discountAmount = remainingDiscountAmount > currentTotalPrices[orderLine]
? currentTotalPrices[orderLine]
: remainingDiscountAmount;
distributions[orderLine.Id] += discountAmount;
currentPrices[orderLine] -= discountAmount;
currentTotalPrices[orderLine] -= discountAmount;
remainingDiscountAmount -= discountAmount;
}

7
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountResolver.cs

@ -55,8 +55,8 @@ public class OrderDiscountResolver : IOrderDiscountResolver, ITransientDependenc
var affectedOrderLineIdsInEffectGroup = new Dictionary<string, List<Guid>>();
var usedDiscountNameKeyPairs = new HashSet<(string, string)>();
var currentPrices =
new Dictionary<IOrderLine, decimal>(order.OrderLines.ToDictionary(x => x, x => x.UnitPrice));
var currentTotalPrices =
new Dictionary<IOrderLine, decimal>(order.OrderLines.ToDictionary(x => x, x => x.TotalPrice));
var distributionModels = new List<OrderDiscountDistributionModel>();
@ -88,7 +88,8 @@ public class OrderDiscountResolver : IOrderDiscountResolver, ITransientDependenc
electionModel.TryEnqueue(newCandidateDiscounts);
}
var distributionResult = await OrderDiscountDistributor.DistributeAsync(order, currentPrices, discount);
var distributionResult =
await OrderDiscountDistributor.DistributeAsync(order, currentTotalPrices, discount);
distributionModels.Add(new OrderDiscountDistributionModel(discount, distributionResult.Distributions));
}

18
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/DemoOrderDiscountProvider.cs

@ -14,16 +14,24 @@ public class DemoOrderDiscountProvider : IOrderDiscountProvider
public Task DiscountAsync(OrderDiscountContext context)
{
var firstOrderLine = context.Order.OrderLines.First();
var orderLines = context.Order.OrderLines.ToList();
var firstOrderLine = orderLines[0];
var secondOrderLine = orderLines[1];
var models = new List<OrderDiscountInfoModel>
{
new(new List<Guid> { firstOrderLine.Id }, null, "DemoDiscount1", "1", "Demo Discount 1",
new DynamicDiscountAmountModel("USD", 0.01m, 0m, null)),
new(new List<Guid> { firstOrderLine.Id }, "A", "DemoDiscount2", "2", "Demo Discount 2",
new DynamicDiscountAmountModel("USD", 0.1m, 0m, null)),
new(new List<Guid> { firstOrderLine.Id }, "A", "DemoDiscount3", "3", "Demo Discount 3",
new DynamicDiscountAmountModel("USD", 5.00m, 0m, null)),
new(new List<Guid> { secondOrderLine.Id }, "A", "DemoDiscount2", "2", "Demo Discount 2",
new DynamicDiscountAmountModel("USD", 0.10m, 0m, null)),
new(new List<Guid> { secondOrderLine.Id }, "A", "DemoDiscount3", "3", "Demo Discount 3",
new DynamicDiscountAmountModel("USD", 0.05m, 0m, null)),
new(new List<Guid> { firstOrderLine.Id, secondOrderLine.Id }, "B", "DemoDiscount4", "4", "Demo Discount 4",
new DynamicDiscountAmountModel("USD", 0.01m, 0m, null)),
new(new List<Guid> { firstOrderLine.Id, secondOrderLine.Id }, null, "DemoDiscount5", "5", "Demo Discount 5",
new DynamicDiscountAmountModel("USD", 0.01m, 0m, null)),
new(new List<Guid> { firstOrderLine.Id }, "B", "DemoDiscount6", "6", "Demo Discount 6",
new DynamicDiscountAmountModel("USD", 0.00m, 0.55m, null)),
};
foreach (var model in models)

12
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountDistributorTests.cs

@ -57,11 +57,11 @@ public class OrderDiscountDistributorTests : OrdersDomainTestBase
var discount = new OrderDiscountInfoModel(order.OrderLines.Select(x => x.Id).ToList(), null, "Test", null,
null, new DynamicDiscountAmountModel("USD", 0m, discountRate, null));
var currentPrices =
var currentTotalPrices =
new Dictionary<IOrderLine, decimal>(order.OrderLines.ToDictionary(x => (IOrderLine)x,
x => x.UnitPrice));
x => x.TotalPrice));
var distributionResult = await OrderDiscountDistributor.DistributeAsync(order, currentPrices, discount);
var distributionResult = await OrderDiscountDistributor.DistributeAsync(order, currentTotalPrices, discount);
order.AddDiscounts(distributionResult);
@ -128,11 +128,11 @@ public class OrderDiscountDistributorTests : OrdersDomainTestBase
var discount = new OrderDiscountInfoModel(order.OrderLines.Select(x => x.Id).ToList(), null, "Test", null,
null, new DynamicDiscountAmountModel("USD", discountedAmount, 0m, null));
var currentPrices =
var currentTotalPrices =
new Dictionary<IOrderLine, decimal>(order.OrderLines.ToDictionary(x => (IOrderLine)x,
x => x.UnitPrice));
x => x.TotalPrice));
var distributionResult = await OrderDiscountDistributor.DistributeAsync(order, currentPrices, discount);
var distributionResult = await OrderDiscountDistributor.DistributeAsync(order, currentTotalPrices, discount);
order.AddDiscounts(distributionResult);

47
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountProviderTests.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products;
using Microsoft.Extensions.DependencyInjection;
using NodaMoney;
using Shouldly;
using Xunit;
@ -25,7 +26,8 @@ public class OrderDiscountProviderTests : OrdersDomainTestBase
var createOrderInfoModel = new CreateOrderInfoModel(OrderTestData.Store1Id, null,
new List<CreateOrderLineInfoModel>
{
new(OrderTestData.Product1Id, OrderTestData.ProductSku1Id, 2)
new(OrderTestData.Product1Id, OrderTestData.ProductSku1Id, 2),
new(OrderTestData.Product1Id, OrderTestData.ProductSku2Id, 1),
}
);
@ -42,7 +44,16 @@ public class OrderDiscountProviderTests : OrdersDomainTestBase
{
Id = OrderTestData.ProductSku1Id,
AttributeOptionIds = new List<Guid>(),
Price = 1m,
Price = 100m,
Currency = "USD",
OrderMinQuantity = 1,
OrderMaxQuantity = 100,
},
new()
{
Id = OrderTestData.ProductSku2Id,
AttributeOptionIds = new List<Guid>(),
Price = 2m,
Currency = "USD",
OrderMinQuantity = 1,
OrderMaxQuantity = 100,
@ -52,14 +63,32 @@ public class OrderDiscountProviderTests : OrdersDomainTestBase
}
}, new Dictionary<Guid, DateTime>());
order.ActualTotalPrice.ShouldBe(1.89m);
order.TotalDiscount.ShouldBe(0.11m);
order.OrderDiscounts.Count.ShouldBe(2);
var orderLines = order.OrderLines;
const decimal orderLine1PriceWithoutDiscount = 2 * 100m;
const decimal orderLine2PriceWithoutDiscount = 1 * 2m;
var orderLine1ExpectedPrice = new Money((orderLine1PriceWithoutDiscount - 5m - 0.01m) * (1 - 0.55m), "USD",
MidpointRounding.AwayFromZero).Amount;
var orderLine2ExpectedPrice = orderLine2PriceWithoutDiscount - 0.1m;
order.ActualTotalPrice.ShouldBe(orderLine1ExpectedPrice + orderLine2ExpectedPrice);
order.TotalDiscount.ShouldBe(order.TotalPrice - order.ActualTotalPrice);
order.OrderDiscounts.Count.ShouldBe(5);
order.OrderDiscounts.ShouldContain(x =>
x.OrderId == order.Id && x.OrderLineId == orderLines[0].Id && x.Name == "DemoDiscount1" &&
x.Key == "1" && x.DisplayName == "Demo Discount 1" && x.DiscountedAmount == 5.00m);
order.OrderDiscounts.ShouldContain(x =>
x.OrderId == order.Id && x.OrderLineId == orderLines[1].Id && x.Name == "DemoDiscount2" &&
x.Key == "2" && x.DisplayName == "Demo Discount 2" && x.DiscountedAmount == 0.10m);
order.OrderDiscounts.ShouldContain(x =>
x.OrderId == order.Id && x.OrderLineId == orderLines[0].Id && x.Name == "DemoDiscount5" &&
x.Key == "5" && x.DisplayName == "Demo Discount 5" && x.DiscountedAmount == 0.01m);
order.OrderDiscounts.ShouldContain(x =>
x.OrderId == order.Id && x.OrderLineId == order.OrderLines.First().Id && x.Name == "DemoDiscount1" &&
x.Key == "1" && x.DisplayName == "Demo Discount 1" && x.DiscountedAmount == 0.01m);
x.OrderId == order.Id && x.OrderLineId == orderLines[1].Id && x.Name == "DemoDiscount5" &&
x.Key == "5" && x.DisplayName == "Demo Discount 5" && x.DiscountedAmount == 0m);
order.OrderDiscounts.ShouldContain(x =>
x.OrderId == order.Id && x.OrderLineId == order.OrderLines.First().Id && x.Name == "DemoDiscount2" &&
x.Key == "2" && x.DisplayName == "Demo Discount 2" && x.DiscountedAmount == 0.1m);
x.OrderId == order.Id && x.OrderLineId == orderLines[0].Id && x.Name == "DemoDiscount6" &&
x.Key == "6" && x.DisplayName == "Demo Discount 6" && x.DiscountedAmount == 107.24m);
}
}
Loading…
Cancel
Save