Browse Source

Refactor Order aggregate and move business to domain layer

pull/242/head
gdlcf88 3 years ago
parent
commit
4524c33498
  1. 18
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CreateOrderDto.cs
  2. 8
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CreateOrderLineDto.cs
  3. 16
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/OrderDiscountDto.cs
  4. 6
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/OrderExtraFeeDto.cs
  5. 4
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/BasicOrderCreationAuthorizationHandler.cs
  6. 15
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/INewOrderGenerator.cs
  7. 12
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/IOrderLinePriceOverrider.cs
  8. 43
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs
  9. 3
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderCreationResource.cs
  10. 1
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/OrdersApplicationAutoMapperProfile.cs
  11. 21
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json
  12. 17
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json
  13. 17
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json
  14. 27
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/CreateOrderInfoModel.cs
  15. 25
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/CreateOrderLineInfoModel.cs
  16. 12
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/ICreateOrderInfo.cs
  17. 13
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/ICreateOrderLineInfo.cs
  18. 2
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrder.cs
  19. 11
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrderExtraFee.cs
  20. 7
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrderLine.cs
  21. 2
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/OrderExtraFeeEto.cs
  22. 3
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs
  23. 16
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/DuplicateOrderDiscountException.cs
  24. 13
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/INewOrderGenerator.cs
  25. 4
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderDiscountProvider.cs
  26. 7
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderExtraFeeProvider.cs
  27. 11
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderLinePriceOverrider.cs
  28. 104
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs
  29. 76
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs
  30. 48
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscount.cs
  31. 34
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountInfoModel.cs
  32. 5
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs
  33. 9
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFeeInfoModel.cs
  34. 0
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLineInvalidQuantityException.cs
  35. 1
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/ProductInventoryReductionEventHandler.cs
  36. 0
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/UnexpectedCurrencyException.cs
  37. 1
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.EntityFrameworkCore/EasyAbp/EShop/Orders/EntityFrameworkCore/OrdersDbContext.cs
  38. 9
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.EntityFrameworkCore/EasyAbp/EShop/Orders/EntityFrameworkCore/OrdersDbContextModelCreatingExtensions.cs
  39. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/EasyAbp.EShop.Orders.Application.Tests.csproj
  40. 26
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs
  41. 9
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/TestOrderLinePriceOverrider.cs
  42. 19
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/DemoOrderDiscountProvider.cs
  43. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/InventoryReductionResultTests.cs
  44. 65
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountTests.cs
  45. 1
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs
  46. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.EntityFrameworkCore.Tests/EasyAbp.EShop.Orders.EntityFrameworkCore.Tests.csproj
  47. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.HttpApi.Client.ConsoleTestApp/EasyAbp.EShop.Orders.HttpApi.Client.ConsoleTestApp.csproj
  48. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.MongoDB.Tests/EasyAbp.EShop.Orders.MongoDB.Tests.csproj
  49. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/EasyAbp.EShop.Orders.TestBase.csproj
  50. 6
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/OrderExtraFeeRefundInfoModel.cs
  51. 6
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFeeEto.cs
  52. 14
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFee.cs
  53. 2
      modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs
  54. 2
      modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Domain.Tests/Refunds/RefundOrderEventHandlerTests.cs
  55. 20
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductDto.cs
  56. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductViewDto.cs
  57. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp.EShop.Products.Domain.Shared.csproj
  58. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/EShopProductsDomainSharedModule.cs
  59. 9
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IHasProductGroupDisplayName.cs
  60. 5
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductAttribute.cs
  61. 5
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductAttributeOption.cs
  62. 12
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductBase.cs
  63. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductSku.cs
  64. 3
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductSkuDescriptionProvider.cs
  65. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductEto.cs
  66. 24
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductExtensions.cs
  67. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductSkuDescriptionProvider.cs
  68. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductSkuEto.cs
  69. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Options/ProductGroups/IProductGroup.cs
  70. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/Product.cs
  71. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductView.cs
  72. 2
      plugins/Baskets/src/EasyAbp.EShop.Plugins.Baskets.Application/EasyAbp/EShop/Plugins/Baskets/BasketItems/BasicBasketItemProductInfoUpdater.cs
  73. 10
      plugins/Booking/src/EasyAbp.EShop.Orders.Booking.Application/EasyAbp/EShop/Orders/Booking/Authorization/BookingOrderCreationAuthorizationHandler.cs
  74. 13
      plugins/Booking/src/EasyAbp.EShop.Orders.Booking.Application/EasyAbp/EShop/Orders/Booking/BookingOrderLinePriceOverrider.cs
  75. 35
      plugins/Booking/src/EasyAbp.EShop.Plugins.Booking.Application.Contracts/EasyAbp/EShop/Orders/CreateOrderLineInfoExtensions.cs
  76. 85
      plugins/Coupons/src/EasyAbp.EShop.Orders.Plugins.Coupons/EasyAbp/EShop/Orders/Plugins/Coupons/OrderDiscount/CouponOrderDiscountProvider.cs
  77. 10
      plugins/Coupons/src/EasyAbp.EShop.Plugins.Coupons.Domain.Shared/EasyAbp/EShop/Plugins/Coupons/Coupons/ICoupon.cs
  78. 48
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/CreateFlashSaleOrderEventHandler.cs
  79. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs
  80. 6
      plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs
  81. 6406
      samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/20230329111403_RefactordOrderAndSomeOthers.Designer.cs
  82. 74
      samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/20230329111403_RefactordOrderAndSomeOthers.cs
  83. 57
      samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/EShopSampleDbContextModelSnapshot.cs

18
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CreateOrderDto.cs

@ -3,13 +3,16 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using EasyAbp.EShop.Orders.Localization;
using EasyAbp.EShop.Stores.Stores;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Orders.Orders.Dtos
{
[Serializable]
public class CreateOrderDto : ExtensibleObject, IMultiStore
public class CreateOrderDto : ExtensibleObject, ICreateOrderInfo
{
[DisplayName("OrderStoreId")]
public Guid StoreId { get; set; }
@ -17,6 +20,8 @@ namespace EasyAbp.EShop.Orders.Orders.Dtos
[DisplayName("OrderCustomerRemark")]
public string CustomerRemark { get; set; }
IEnumerable<ICreateOrderLineInfo> ICreateOrderInfo.OrderLines => OrderLines;
[DisplayName("OrderLine")]
public List<CreateOrderLineDto> OrderLines { get; set; }
@ -26,19 +31,20 @@ namespace EasyAbp.EShop.Orders.Orders.Dtos
{
yield return result;
}
var localizer = validationContext.GetRequiredService<IStringLocalizer<OrdersResource>>();
if (OrderLines.Count == 0)
{
yield return new ValidationResult(
"OrderLines should not be empty.",
localizer[OrdersErrorCodes.OrderLinesShouldNotBeEmpty],
new[] { "OrderLines" }
);
}
if (OrderLines.Any(orderLine => orderLine.Quantity <= 0))
if (OrderLines.Any(orderLine => orderLine.Quantity < 1))
{
yield return new ValidationResult(
"Quantity should be greater than 0.",
localizer[OrdersErrorCodes.QuantityShouldBeGreaterThanZero],
new[] { "OrderLines" }
);
}

8
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/CreateOrderLineDto.cs

@ -6,17 +6,17 @@ using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Orders.Orders.Dtos
{
[Serializable]
public class CreateOrderLineDto : ExtensibleObject
public class CreateOrderLineDto : ExtensibleObject, ICreateOrderLineInfo
{
public const int MinimumQuantity = 1;
public const int MaximumQuantity = int.MaxValue;
[DisplayName("OrderLineProductId")]
public Guid ProductId { get; set; }
[DisplayName("OrderLineProductSkuId")]
public Guid ProductSkuId { get; set; }
[DisplayName("OrderLineQuantity")]
[Range(MinimumQuantity, MaximumQuantity)]
public int Quantity { get; set; }

16
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/OrderDiscountDto.cs

@ -0,0 +1,16 @@
using System;
namespace EasyAbp.EShop.Orders.Orders.Dtos;
public class OrderDiscountDto
{
public Guid OrderLineId { get; set; }
public string Name { get; set; }
public string Key { get; set; }
public string DisplayName { get; set; }
public decimal DiscountedAmount { get; set; }
}

6
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application.Contracts/EasyAbp/EShop/Orders/Orders/Dtos/OrderExtraFeeDto.cs

@ -4,14 +4,16 @@ namespace EasyAbp.EShop.Orders.Orders.Dtos
{
public class OrderExtraFeeDto : IOrderExtraFee
{
public Guid OrderId { get; }
public Guid OrderId { get; set; }
public string Name { get; set; }
public string Key { get; set; }
public string DisplayName { get; set; }
public decimal Fee { get; set; }
public decimal RefundAmount { get; }
public decimal RefundAmount { get; set; }
}
}

4
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/BasicOrderCreationAuthorizationHandler.cs

@ -44,7 +44,7 @@ namespace EasyAbp.EShop.Orders.Orders
context.Succeed(requirement);
}
protected virtual Task<bool> IsProductsPublishedAsync(CreateOrderDto input,
protected virtual Task<bool> IsProductsPublishedAsync(ICreateOrderInfo input,
Dictionary<Guid, ProductDto> productDictionary)
{
return Task.FromResult(
@ -53,7 +53,7 @@ namespace EasyAbp.EShop.Orders.Orders
);
}
protected virtual Task<bool> IsInventoriesSufficientAsync(CreateOrderDto input,
protected virtual Task<bool> IsInventoriesSufficientAsync(ICreateOrderInfo input,
Dictionary<Guid, ProductDto> productDictionary)
{
return Task.FromResult(

15
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/INewOrderGenerator.cs

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
namespace EasyAbp.EShop.Orders.Orders
{
public interface INewOrderGenerator
{
Task<Order> GenerateAsync(Guid customerUserId, CreateOrderDto input, Dictionary<Guid, ProductDto> productDict,
Dictionary<Guid, ProductDetailDto> productDetailDict);
}
}

12
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/IOrderLinePriceOverrider.cs

@ -1,12 +0,0 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
using NodaMoney;
namespace EasyAbp.EShop.Orders.Orders;
public interface IOrderLinePriceOverrider
{
Task<Money?> GetUnitPriceOrNullAsync(CreateOrderDto input, CreateOrderLineDto inputOrderLine, ProductDto product,
ProductSkuDto productSku, Currency effectiveCurrency);
}

43
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs

@ -5,7 +5,6 @@ using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Authorization;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Stores.Stores;
@ -102,21 +101,12 @@ namespace EasyAbp.EShop.Orders.Orders
new OrderOperationAuthorizationRequirement(OrderOperation.Creation)
);
var productDetailIds = input.OrderLines
.Select(dto =>
productDict[dto.ProductId].GetSkuById(dto.ProductSkuId).ProductDetailId ??
productDict[dto.ProductId].ProductDetailId)
.Where(x => x.HasValue)
.Select(x => x.Value)
.ToList();
var productDetailDict = await GetProductDetailDictionaryAsync(productDetailIds);
var productDetailModificationTimeDict =
await GetProductDetailModificationTimeDictionaryAsync(input, productDict);
// Todo: Can we use IProductDataScopedCache/IProductDetailDataScopedCache instead of productDict/productDetailDict?
var order = await _newOrderGenerator.GenerateAsync(CurrentUser.GetId(), input, productDict,
productDetailDict);
await DiscountOrderAsync(order, productDict);
var order = await _newOrderGenerator.GenerateAsync(CurrentUser.GetId(), input,
productDict.ToDictionary(x => x.Key, x => (IProduct)x.Value), productDetailModificationTimeDict);
await Repository.InsertAsync(order, autoSave: true);
@ -131,14 +121,6 @@ namespace EasyAbp.EShop.Orders.Orders
}
}
protected virtual async Task DiscountOrderAsync(Order order, Dictionary<Guid, ProductDto> productDict)
{
foreach (var provider in LazyServiceProvider.LazyGetService<IEnumerable<IOrderDiscountProvider>>())
{
await provider.DiscountAsync(order, productDict);
}
}
protected virtual async Task<Dictionary<Guid, ProductDto>> GetProductDictionaryAsync(
IEnumerable<Guid> productIds)
{
@ -152,14 +134,23 @@ namespace EasyAbp.EShop.Orders.Orders
return dict;
}
protected virtual async Task<Dictionary<Guid, ProductDetailDto>> GetProductDetailDictionaryAsync(
IEnumerable<Guid> productDetailIds)
protected virtual async Task<Dictionary<Guid, DateTime>> GetProductDetailModificationTimeDictionaryAsync(
ICreateOrderInfo input, Dictionary<Guid, ProductDto> productDict)
{
var dict = new Dictionary<Guid, ProductDetailDto>();
var productDetailIds = input.OrderLines
.Select(dto =>
productDict[dto.ProductId].GetSkuById(dto.ProductSkuId).ProductDetailId ??
productDict[dto.ProductId].ProductDetailId)
.Where(x => x.HasValue)
.Select(x => x.Value)
.ToList();
var dict = new Dictionary<Guid, DateTime>();
foreach (var productDetailId in productDetailIds.Distinct())
{
dict.Add(productDetailId, await _productDetailAppService.GetAsync(productDetailId));
var product = await _productDetailAppService.GetAsync(productDetailId);
dict.Add(productDetailId, product.LastModificationTime ?? product.CreationTime);
}
return dict;

3
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderCreationResource.cs

@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
namespace EasyAbp.EShop.Orders.Orders
{
public class OrderCreationResource
{
public CreateOrderDto Input { get; set; }
public ICreateOrderInfo Input { get; set; }
public Dictionary<Guid, ProductDto> ProductDictionary { get; set; }
}

1
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/OrdersApplicationAutoMapperProfile.cs

@ -14,6 +14,7 @@ namespace EasyAbp.EShop.Orders
* into multiple profile classes for a better organization. */
CreateMap<Order, OrderDto>();
CreateMap<OrderLine, OrderLineDto>();
CreateMap<OrderDiscount, OrderDiscountDto>(MemberList.Destination);
CreateMap<OrderExtraFee, OrderExtraFeeDto>(MemberList.Destination);
}
}

21
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json

@ -45,16 +45,33 @@
"OrderLineTotalDiscount": "Total discount",
"OrderLineActualTotalPrice": "Actual total price",
"OrderLineQuantity": "Quantity",
"OrderDiscount": "Order discount",
"OrderDiscountOrderId": "Order ID",
"OrderDiscountOrderLineId": "Order line ID",
"OrderDiscountName": "Name",
"OrderDiscountKey": "Key",
"OrderDiscountDisplayName": "Display name",
"OrderDiscountDiscountedAmount": "Discounted amount",
"OrderExtraFee": "Order extra fee",
"OrderExtraFeeOrderId": "Order ID",
"OrderExtraFeeName": "Extra fee name",
"OrderExtraFeeKey": "Extra fee key",
"OrderExtraFeeDisplayName": "Display name",
"OrderExtraFeeFee": "Fee",
"OrderExtraFeeRefundAmount": "Refund amount",
"EasyAbp.EShop.Orders:UnexpectedCurrency": "Only the specified currency {expectedCurrency} is allowed.",
"EasyAbp.EShop.Orders:OrderLineInvalidQuantity": "Invalid quantity {quantity} for product {productId} (SKU: {productSkuId}).",
"EasyAbp.EShop.Orders:DiscountAmountOverflow": "The discount amount overflow.",
"EasyAbp.EShop.Orders:DuplicateOrderExtraFee": "The extra fee {extraFeeName} (key: {extraFeeKey}) is existed.",
"EasyAbp.EShop.Orders:DuplicateOrderDiscount": "The discount {discountName} (key: {discountKey}) of order line {orderLineId} already exists.",
"EasyAbp.EShop.Orders:DuplicateOrderExtraFee": "The extra fee {extraFeeName} (key: {extraFeeKey}) already exists.",
"EasyAbp.EShop.Orders:InvalidOrderExtraFee": "The extra fee {extraFee} is invalid.",
"EasyAbp.EShop.Orders:InvalidPayment": "The payment {paymentId} has invalid configurations for the order {orderId}.",
"EasyAbp.EShop.Orders:InvalidRefundAmount": "The refund amount ({amount}) is invalid.",
"EasyAbp.EShop.Orders:InvalidRefundQuantity": "The refund quantity ({quantity}) is invalid.",
"EasyAbp.EShop.Orders:OrderIsInWrongStage": "The order {orderId} is in the wrong stage.",
"EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product",
"EasyAbp.EShop.Orders:ExistFlashSalesProduct": "Exist unexpected flash-sales product.",
"EasyAbp.EShop.Orders:OrderLinesShouldNotBeEmpty": "OrderLines should not be empty.",
"EasyAbp.EShop.Orders:QuantityShouldBeGreaterThanZero": "Quantity should be greater than 0.",
"DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "Currency code",
"Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 code (see https://en.wikipedia.org/wiki/ISO_4217)"
}

17
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json

@ -45,9 +45,24 @@
"OrderLineTotalDiscount": "总折扣",
"OrderLineActualTotalPrice": "折后总价",
"OrderLineQuantity": "数量",
"OrderDiscount": "订单折扣项",
"OrderDiscountOrderId": "订单 ID",
"OrderDiscountOrderLineId": "订单项 ID",
"OrderDiscountName": "折扣项名称",
"OrderDiscountKey": "折扣项 Key",
"OrderDiscountDisplayName": "显示名称",
"OrderDiscountDiscountedAmount": "折扣金额",
"OrderExtraFee": "订单额外费用",
"OrderExtraFeeOrderId": "订单 ID",
"OrderExtraFeeName": "额外费用名称",
"OrderExtraFeeKey": "额外费用 Key",
"OrderExtraFeeDisplayName": "显示名称",
"OrderExtraFeeFee": "金额",
"OrderExtraFeeRefundAmount": "已退款金额",
"EasyAbp.EShop.Orders:UnexpectedCurrency": "只允许指定的{expectedCurrency}货币",
"EasyAbp.EShop.Orders:OrderLineInvalidQuantity": "产品{productId}(SKU: {productSkuId})的{quantity}数量无效",
"EasyAbp.EShop.Orders:DiscountAmountOverflow": "折扣金额溢出",
"EasyAbp.EShop.Orders:DuplicateOrderDiscount": "订单项{orderLineId}的折扣项{discountName}(key: {discountKey})已经存在",
"EasyAbp.EShop.Orders:DuplicateOrderExtraFee": "额外费用{extraFeeName}(key: {extraFeeKey})已经存在",
"EasyAbp.EShop.Orders:InvalidOrderExtraFee": "额外费用{extraFee}无效",
"EasyAbp.EShop.Orders:InvalidPayment": "付款{paymentId}有无效的订单配置{orderId}",
@ -55,6 +70,8 @@
"EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款数量({quantity})无效",
"EasyAbp.EShop.Orders:OrderIsInWrongStage": "订单{orderId}处于错误的阶段",
"EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清单中不允许存在闪购产品",
"EasyAbp.EShop.Orders:OrderLinesShouldNotBeEmpty": "订单项不可为空",
"EasyAbp.EShop.Orders:QuantityShouldBeGreaterThanZero": "购买数量应大于0",
"DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "货币代码",
"Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 货币代码 (详见 https://en.wikipedia.org/wiki/ISO_4217)"
}

17
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json

@ -45,9 +45,24 @@
"OrderLineTotalDiscount": "總折扣",
"OrderLineActualTotalPrice": "折後總價",
"OrderLineQuantity": "數量",
"OrderDiscount": "訂單折扣項",
"OrderDiscountOrderId": "訂單 ID",
"OrderDiscountOrderLineId": "訂單項 ID",
"OrderDiscountName": "折扣項名稱",
"OrderDiscountKey": "折扣項 Key",
"OrderDiscountDisplayName": "顯示名稱",
"OrderDiscountDiscountedAmount": "折扣金額",
"OrderExtraFee": "訂單額外費用",
"OrderExtraFeeOrderId": "訂單 ID",
"OrderExtraFeeName": "額外費用名稱",
"OrderExtraFeeKey": "額外費用 Key",
"OrderExtraFeeDisplayName": "顯示名稱",
"OrderExtraFeeFee": "金額",
"OrderExtraFeeRefundAmount": "已退款金額",
"EasyAbp.EShop.Orders:UnexpectedCurrency": "只允許指定的{expectedCurrency}貨幣",
"EasyAbp.EShop.Orders:OrderLineInvalidQuantity": "產品{productId}(SKU: {productSkuId})的{quantity}數量無效",
"EasyAbp.EShop.Orders:DiscountAmountOverflow": "折扣金額溢出",
"EasyAbp.EShop.Orders:DuplicateOrderDiscount": "訂單項{orderLineId}的折扣項{discountName}(key: {discountKey})已經存在",
"EasyAbp.EShop.Orders:DuplicateOrderExtraFee": "額外費用{extraFeeName}(key: {extraFeeKey})已經存在",
"EasyAbp.EShop.Orders:InvalidOrderExtraFee": "額外費用{extraFee}無效",
"EasyAbp.EShop.Orders:InvalidPayment": "付款{paymentId}有無效的訂單配置{orderId}",
@ -55,6 +70,8 @@
"EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款數量({quantity})無效",
"EasyAbp.EShop.Orders:OrderIsInWrongStage": "訂單{orderId}處於錯誤的階段",
"EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清單中不允許存在閃購產品",
"EasyAbp.EShop.Orders:OrderLinesShouldNotBeEmpty": "訂單項不可為空",
"EasyAbp.EShop.Orders:QuantityShouldBeGreaterThanZero": "購買數量應大於0",
"DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "貨幣代碼",
"Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 貨幣代碼 (詳見 https://en.wikipedia.org/wiki/ISO_4217)"
}

27
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/CreateOrderInfoModel.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Orders.Orders;
[Serializable]
public class CreateOrderInfoModel : ExtensibleObject, ICreateOrderInfo
{
public Guid StoreId { get; set; }
public string CustomerRemark { get; set; }
IEnumerable<ICreateOrderLineInfo> ICreateOrderInfo.OrderLines => OrderLines;
public List<CreateOrderLineInfoModel> OrderLines { get; set; }
public CreateOrderInfoModel()
{
}
public CreateOrderInfoModel(Guid storeId, string customerRemark, List<CreateOrderLineInfoModel> orderLines)
{
StoreId = storeId;
CustomerRemark = customerRemark;
OrderLines = orderLines;
}
}

25
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/CreateOrderLineInfoModel.cs

@ -0,0 +1,25 @@
using System;
using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Orders.Orders;
[Serializable]
public class CreateOrderLineInfoModel : ExtensibleObject, ICreateOrderLineInfo
{
public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; }
public int Quantity { get; set; }
public CreateOrderLineInfoModel()
{
}
public CreateOrderLineInfoModel(Guid productId, Guid productSkuId, int quantity)
{
ProductId = productId;
ProductSkuId = productSkuId;
Quantity = quantity;
}
}

12
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/ICreateOrderInfo.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.Data;
namespace EasyAbp.EShop.Orders.Orders;
public interface ICreateOrderInfo : IMultiStore, IHasExtraProperties
{
string CustomerRemark { get; }
IEnumerable<ICreateOrderLineInfo> OrderLines { get; }
}

13
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/ICreateOrderLineInfo.cs

@ -0,0 +1,13 @@
using System;
using Volo.Abp.Data;
namespace EasyAbp.EShop.Orders.Orders;
public interface ICreateOrderLineInfo : IHasExtraProperties
{
Guid ProductId { get; }
Guid ProductSkuId { get; }
int Quantity { get; }
}

2
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrder.cs

@ -8,6 +8,8 @@ namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrder : IMultiStore, IHasExtraProperties
{
Guid Id { get; }
[NotNull]
string OrderNumber { get; }

11
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrderExtraFee.cs

@ -6,15 +6,18 @@ namespace EasyAbp.EShop.Orders.Orders
public interface IOrderExtraFee
{
Guid OrderId { get; }
[NotNull]
string Name { get; }
[CanBeNull]
string Key { get; }
[CanBeNull]
string DisplayName { get; }
decimal Fee { get; }
decimal RefundAmount { get; }
}
}

7
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/IOrderLine.cs

@ -5,8 +5,10 @@ using Volo.Abp.Data;
namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrderLine : IHasExtraProperties
public interface IOrderLine : IHasExtraProperties, IHasProductGroupDisplayName
{
Guid Id { get; }
Guid ProductId { get; }
Guid ProductSkuId { get; }
@ -20,9 +22,6 @@ namespace EasyAbp.EShop.Orders.Orders
[NotNull]
string ProductGroupName { get; }
[NotNull]
string ProductGroupDisplayName { get; }
[CanBeNull]
string ProductUniqueName { get; }

2
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Orders/OrderExtraFeeEto.cs

@ -11,6 +11,8 @@ namespace EasyAbp.EShop.Orders.Orders
public string Key { get; set; }
public string DisplayName { get; set; }
public decimal Fee { get; set; }
public decimal RefundAmount { get; set; }

3
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/OrdersErrorCodes.cs

@ -6,11 +6,14 @@
public const string OrderLineInvalidQuantity = "EasyAbp.EShop.Orders:OrderLineInvalidQuantity";
public const string DiscountAmountOverflow = "EasyAbp.EShop.Orders:DiscountAmountOverflow";
public const string DuplicateOrderExtraFee = "EasyAbp.EShop.Orders:DuplicateOrderExtraFee";
public const string DuplicateOrderDiscount = "EasyAbp.EShop.Orders:DuplicateOrderDiscount";
public const string InvalidOrderExtraFee = "EasyAbp.EShop.Orders:InvalidOrderExtraFee";
public const string InvalidPayment = "EasyAbp.EShop.Orders:InvalidPayment";
public const string InvalidRefundAmount = "EasyAbp.EShop.Orders:InvalidRefundAmount";
public const string InvalidRefundQuantity = "EasyAbp.EShop.Orders:InvalidRefundQuantity";
public const string OrderIsInWrongStage = "EasyAbp.EShop.Orders:OrderIsInWrongStage";
public const string ExistFlashSalesProduct = "EasyAbp.EShop.Orders:ExistFlashSalesProduct";
public const string OrderLinesShouldNotBeEmpty = "EasyAbp.EShop.Orders:OrderLinesShouldNotBeEmpty";
public const string QuantityShouldBeGreaterThanZero = "EasyAbp.EShop.Orders:QuantityShouldBeGreaterThanZero";
}
}

16
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/DuplicateOrderDiscountException.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Orders.Orders
{
public class DuplicateOrderDiscountException : BusinessException
{
public DuplicateOrderDiscountException(Guid orderLineId, string discountName, string discountKey) : base(
OrdersErrorCodes.DuplicateOrderDiscount)
{
WithData(nameof(orderLineId), orderLineId);
WithData(nameof(discountName), discountName);
WithData(nameof(discountKey), discountKey);
}
}
}

13
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/INewOrderGenerator.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Orders.Orders
{
public interface INewOrderGenerator
{
Task<Order> GenerateAsync(Guid customerUserId, ICreateOrderInfo input, Dictionary<Guid, IProduct> productDict,
Dictionary<Guid, DateTime> productDetailModificationTimeDict);
}
}

4
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/IOrderDiscountProvider.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderDiscountProvider.cs

@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrderDiscountProvider
{
Task<Order> DiscountAsync(Order order, Dictionary<Guid, ProductDto> productDict);
Task<List<OrderDiscountInfoModel>> GetAllAsync(Order order, Dictionary<Guid, IProduct> productDict);
}
}

7
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/IOrderExtraFeeProvider.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderExtraFeeProvider.cs

@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.Products;
using NodaMoney;
namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrderExtraFeeProvider
{
Task<List<OrderExtraFeeInfoModel>> GetListAsync(Guid customerUserId, CreateOrderDto input,
Dictionary<Guid, ProductDto> productDict, Currency effectiveCurrency);
Task<List<OrderExtraFeeInfoModel>> GetListAsync(Guid customerUserId, ICreateOrderInfo input,
Dictionary<Guid, IProduct> productDict, Currency effectiveCurrency);
}
}

11
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/IOrderLinePriceOverrider.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products;
using NodaMoney;
namespace EasyAbp.EShop.Orders.Orders;
public interface IOrderLinePriceOverrider
{
Task<Money?> GetUnitPriceOrNullAsync(ICreateOrderInfo input, ICreateOrderLineInfo inputOrderLine,
IProduct product, IProductSku productSku, Currency effectiveCurrency);
}

104
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs

@ -2,57 +2,42 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Orders.Settings;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using Microsoft.Extensions.DependencyInjection;
using NodaMoney;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Domain.Services;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Settings;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Orders.Orders
{
public class NewOrderGenerator : INewOrderGenerator, ITransientDependency
public class NewOrderGenerator : DomainService, INewOrderGenerator, ITransientDependency
{
private readonly IClock _clock;
private readonly IGuidGenerator _guidGenerator;
private readonly ICurrentTenant _currentTenant;
private readonly ISettingProvider _settingProvider;
private readonly IServiceProvider _serviceProvider;
private readonly IOrderNumberGenerator _orderNumberGenerator;
private readonly IProductSkuDescriptionProvider _productSkuDescriptionProvider;
private readonly IEnumerable<IOrderLinePriceOverrider> _orderLinePriceOverriders;
public NewOrderGenerator(
IClock clock,
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant,
ISettingProvider settingProvider,
IServiceProvider serviceProvider,
IOrderNumberGenerator orderNumberGenerator,
IProductSkuDescriptionProvider productSkuDescriptionProvider,
IEnumerable<IOrderLinePriceOverrider> orderLinePriceOverriders)
{
_clock = clock;
_guidGenerator = guidGenerator;
_currentTenant = currentTenant;
_settingProvider = settingProvider;
_serviceProvider = serviceProvider;
_orderNumberGenerator = orderNumberGenerator;
_productSkuDescriptionProvider = productSkuDescriptionProvider;
_orderLinePriceOverriders = orderLinePriceOverriders;
}
public virtual async Task<Order> GenerateAsync(Guid customerUserId, CreateOrderDto input,
Dictionary<Guid, ProductDto> productDict, Dictionary<Guid, ProductDetailDto> productDetailDict)
public virtual async Task<Order> GenerateAsync(Guid customerUserId, ICreateOrderInfo input,
Dictionary<Guid, IProduct> productDict, Dictionary<Guid, DateTime> productDetailModificationTimeDict)
{
await ValidateInputAsync(input);
var effectiveCurrency = await GetEffectiveCurrencyAsync();
var orderLines = new List<OrderLine>();
@ -60,7 +45,7 @@ namespace EasyAbp.EShop.Orders.Orders
foreach (var inputOrderLine in input.OrderLines)
{
orderLines.Add(await GenerateOrderLineAsync(
input, inputOrderLine, productDict, productDetailDict, effectiveCurrency));
input, inputOrderLine, productDict, productDetailModificationTimeDict, effectiveCurrency));
}
var productTotalPrice = orderLines.Select(x => x.TotalPrice).Sum();
@ -72,8 +57,8 @@ namespace EasyAbp.EShop.Orders.Orders
var totalDiscount = orderLines.Select(x => x.TotalDiscount).Sum();
var order = new Order(
id: _guidGenerator.Create(),
tenantId: _currentTenant.Id,
id: GuidGenerator.Create(),
tenantId: CurrentTenant.Id,
storeId: input.StoreId,
customerUserId: customerUserId,
currency: effectiveCurrency.Code,
@ -82,7 +67,7 @@ namespace EasyAbp.EShop.Orders.Orders
totalPrice: totalPrice,
actualTotalPrice: totalPrice - totalDiscount,
customerRemark: input.CustomerRemark,
paymentExpiration: paymentExpireIn.HasValue ? _clock.Now.Add(paymentExpireIn.Value) : null
paymentExpiration: paymentExpireIn.HasValue ? Clock.Now.Add(paymentExpireIn.Value) : null
);
input.MapExtraPropertiesTo(order, MappingPropertyDefinitionChecks.Destination);
@ -97,16 +82,47 @@ namespace EasyAbp.EShop.Orders.Orders
// see https://github.com/EasyAbp/EShop/issues/214
if (order.OrderLines.All(x => x.ProductInventoryStrategy != InventoryStrategy.ReduceAfterPlacing))
{
order.SetReducedInventoryAfterPlacingTime(_clock.Now);
order.SetReducedInventoryAfterPlacingTime(Clock.Now);
}
await DiscountOrderAsync(order, productDict);
return order;
}
protected virtual Task ValidateInputAsync(ICreateOrderInfo info)
{
if (!info.OrderLines.Any())
{
throw new BusinessException(OrdersErrorCodes.OrderLinesShouldNotBeEmpty);
}
if (info.OrderLines.Any(orderLine => orderLine.Quantity < 1))
{
throw new BusinessException(OrdersErrorCodes.QuantityShouldBeGreaterThanZero);
}
return Task.CompletedTask;
}
protected virtual async Task DiscountOrderAsync(Order order, Dictionary<Guid, IProduct> productDict)
{
foreach (var provider in LazyServiceProvider.LazyGetService<IEnumerable<IOrderDiscountProvider>>())
{
var discounts = await provider.GetAllAsync(order, productDict);
foreach (var discount in discounts)
{
order.AddDiscount(discount.OrderLineId, discount.Name, discount.Key, discount.DisplayName,
discount.DiscountedAmount);
}
}
}
protected virtual async Task AddOrderExtraFeesAsync(Order order, Guid customerUserId,
CreateOrderDto input, Dictionary<Guid, ProductDto> productDict, Currency effectiveCurrency)
ICreateOrderInfo input, Dictionary<Guid, IProduct> productDict, Currency effectiveCurrency)
{
var providers = _serviceProvider.GetServices<IOrderExtraFeeProvider>();
var providers = LazyServiceProvider.LazyGetService<IEnumerable<IOrderExtraFeeProvider>>();
foreach (var provider in providers)
{
@ -115,25 +131,27 @@ namespace EasyAbp.EShop.Orders.Orders
foreach (var infoModel in infoModels)
{
var fee = new Money(infoModel.Fee, effectiveCurrency);
order.AddOrderExtraFee(fee.Amount, infoModel.Name, infoModel.Key);
order.AddOrderExtraFee(fee.Amount, infoModel.Name, infoModel.Key, infoModel.DisplayName);
}
}
}
protected virtual async Task<OrderLine> GenerateOrderLineAsync(CreateOrderDto input,
CreateOrderLineDto inputOrderLine, Dictionary<Guid, ProductDto> productDict,
Dictionary<Guid, ProductDetailDto> productDetailDict, Currency effectiveCurrency)
protected virtual async Task<OrderLine> GenerateOrderLineAsync(ICreateOrderInfo input,
ICreateOrderLineInfo inputOrderLine, Dictionary<Guid, IProduct> productDict,
Dictionary<Guid, DateTime> productDetailModificationTimeDict, Currency effectiveCurrency)
{
var product = productDict[inputOrderLine.ProductId];
var productSku = product.GetSkuById(inputOrderLine.ProductSkuId);
if (productSku.Currency != effectiveCurrency.Code)
{
throw new UnexpectedCurrencyException(effectiveCurrency.Code);
}
var productDetailId = productSku.ProductDetailId ?? product.ProductDetailId;
var productDetail = productDetailId.HasValue ? productDetailDict[productDetailId.Value] : null;
var productDetailModificationTime = productDetailId.HasValue
? productDetailModificationTimeDict[productDetailId.Value]
: (DateTime?)null;
if (!inputOrderLine.Quantity.IsBetween(productSku.OrderMinQuantity, productSku.OrderMaxQuantity))
{
@ -145,14 +163,18 @@ namespace EasyAbp.EShop.Orders.Orders
var totalPrice = unitPrice * inputOrderLine.Quantity;
var orderLine = new OrderLine(
id: _guidGenerator.Create(),
id: GuidGenerator.Create(),
productId: product.Id,
productSkuId: productSku.Id,
productDetailId: productDetailId,
productModificationTime: product.LastModificationTime ?? product.CreationTime,
productDetailModificationTime: productDetail?.LastModificationTime ?? productDetail?.CreationTime,
productModificationTime: product is IAuditedObject auditedProduct
? auditedProduct.LastModificationTime ?? auditedProduct.CreationTime
: Clock.Now,
productDetailModificationTime: productDetailModificationTime,
productGroupName: product.ProductGroupName,
productGroupDisplayName: product.ProductGroupDisplayName,
productGroupDisplayName: product is IHasProductGroupDisplayName hasProductGroupDisplayName
? hasProductGroupDisplayName.ProductGroupDisplayName
: product.ProductGroupName,
productUniqueName: product.UniqueName,
productDisplayName: product.DisplayName,
productInventoryStrategy: product.InventoryStrategy,
@ -172,8 +194,8 @@ namespace EasyAbp.EShop.Orders.Orders
return orderLine;
}
protected virtual async Task<Money> GetUnitPriceAsync(CreateOrderDto input, CreateOrderLineDto inputOrderLine,
ProductDto product, ProductSkuDto productSku, Currency effectiveCurrency)
protected virtual async Task<Money> GetUnitPriceAsync(ICreateOrderInfo input,
ICreateOrderLineInfo inputOrderLine, IProduct product, IProductSku productSku, Currency effectiveCurrency)
{
foreach (var overrider in _orderLinePriceOverriders)
{

76
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/Order.cs

@ -10,51 +10,54 @@ namespace EasyAbp.EShop.Orders.Orders
public class Order : FullAuditedAggregateRoot<Guid>, IOrder, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid StoreId { get; protected set; }
public virtual string OrderNumber { get; protected set; }
public virtual Guid CustomerUserId { get; protected set; }
public virtual OrderStatus OrderStatus { get; protected set; }
public virtual string Currency { get; protected set; }
public virtual decimal ProductTotalPrice { get; protected set; }
public virtual decimal TotalDiscount { get; protected set; }
public virtual decimal TotalPrice { get; protected set; }
public virtual decimal ActualTotalPrice { get; protected set; }
public virtual decimal RefundAmount { get; protected set; }
public virtual string CustomerRemark { get; protected set; }
public virtual string StaffRemark { get; protected set; }
public virtual Guid? PaymentId { get; protected set; }
public virtual DateTime? PaidTime { get; protected set; }
public virtual DateTime? CompletionTime { get; protected set; }
public virtual DateTime? CanceledTime { get; protected set; }
public virtual string CancellationReason { get; protected set; }
public virtual DateTime? ReducedInventoryAfterPlacingTime { get; protected set; }
public virtual DateTime? ReducedInventoryAfterPaymentTime { get; protected set; }
public virtual DateTime? PaymentExpiration { get; protected set; }
IEnumerable<IOrderLine> IOrder.OrderLines => OrderLines;
public virtual List<OrderLine> OrderLines { get; protected set; }
IEnumerable<IOrderExtraFee> IOrder.OrderExtraFees => OrderExtraFees;
public virtual List<OrderDiscount> OrderDiscounts { get; protected set; }
public virtual List<OrderExtraFee> OrderExtraFees { get; protected set; }
protected Order()
@ -87,9 +90,10 @@ namespace EasyAbp.EShop.Orders.Orders
PaymentExpiration = paymentExpiration;
RefundAmount = 0;
OrderStatus = OrderStatus.Pending;
OrderLines = new List<OrderLine>();
OrderDiscounts = new List<OrderDiscount>();
OrderExtraFees = new List<OrderExtraFee>();
}
@ -182,35 +186,47 @@ namespace EasyAbp.EShop.Orders.Orders
return !(!PaymentId.HasValue || PaidTime.HasValue);
}
public void AddDiscount(Guid orderLineId, decimal expectedDiscountAmount)
public void AddDiscount(Guid orderLineId, [NotNull] string discountName, [CanBeNull] string discountKey,
[CanBeNull] string discountDisplayName, decimal discountedAmount)
{
var orderLine = OrderLines.Single(x => x.Id == orderLineId);
orderLine.AddDiscount(expectedDiscountAmount);
TotalDiscount += expectedDiscountAmount;
ActualTotalPrice -= expectedDiscountAmount;
orderLine.AddDiscount(discountedAmount);
TotalDiscount += discountedAmount;
ActualTotalPrice -= discountedAmount;
if (ActualTotalPrice < decimal.Zero)
{
throw new DiscountAmountOverflowException();
}
if (OrderDiscounts.Any(x => x.OrderLineId == orderLineId && x.Name == discountName && x.Key == discountKey))
{
throw new DuplicateOrderDiscountException(orderLineId, discountName, discountKey);
}
var orderDiscount = new OrderDiscount(
Id, orderLineId, discountName, discountKey, discountDisplayName, discountedAmount);
OrderDiscounts.Add(orderDiscount);
}
public void AddOrderExtraFee(decimal extraFee, [NotNull] string extraFeeName, [CanBeNull] string extraFeeKey)
public void AddOrderExtraFee(decimal extraFee, [NotNull] string extraFeeName, [CanBeNull] string extraFeeKey,
[CanBeNull] string extraFeeDisplayName)
{
if (extraFee <= decimal.Zero)
{
throw new InvalidOrderExtraFeeException(extraFee);
}
var orderExtraFee = new OrderExtraFee(Id, extraFeeName, extraFeeKey, extraFee);
if (OrderExtraFees.Any(x => x.EntityEquals(orderExtraFee)))
if (OrderExtraFees.Any(x => x.Name == extraFeeName && x.Key == extraFeeKey))
{
throw new DuplicateOrderExtraFeeException(extraFeeName, extraFeeKey);
}
var orderExtraFee = new OrderExtraFee(Id, extraFeeName, extraFeeKey, extraFeeDisplayName, extraFee);
OrderExtraFees.Add(orderExtraFee);
TotalPrice += extraFee;
@ -228,4 +244,4 @@ namespace EasyAbp.EShop.Orders.Orders
PaidTime.HasValue && !ReducedInventoryAfterPaymentTime.HasValue;
}
}
}
}

48
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscount.cs

@ -0,0 +1,48 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Orders.Orders;
public class OrderDiscount : Entity
{
public virtual Guid OrderId { get; protected set; }
public virtual Guid OrderLineId { get; protected set; }
[NotNull]
public virtual string Name { get; protected set; }
[CanBeNull]
public virtual string Key { get; protected set; }
[CanBeNull]
public virtual string DisplayName { get; protected set; }
public virtual decimal DiscountedAmount { get; protected set; }
protected OrderDiscount()
{
}
public OrderDiscount(
Guid orderId,
Guid orderLineId,
[NotNull] string name,
[CanBeNull] string key,
[CanBeNull] string displayName,
decimal discountedAmount)
{
OrderId = orderId;
OrderLineId = orderLineId;
Name = name;
Key = key;
DisplayName = displayName;
DiscountedAmount = discountedAmount;
}
public override object[] GetKeys()
{
return new object[] { OrderId, OrderLineId, Name, Key };
}
}

34
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderDiscountInfoModel.cs

@ -0,0 +1,34 @@
using System;
using JetBrains.Annotations;
namespace EasyAbp.EShop.Orders.Orders;
public class OrderDiscountInfoModel
{
public Guid OrderLineId { get; set; }
[NotNull]
public string Name { get; set; }
[CanBeNull]
public string Key { get; set; }
[CanBeNull]
public string DisplayName { get; set; }
public decimal DiscountedAmount { get; set; }
public OrderDiscountInfoModel(
Guid orderLineId,
[NotNull] string name,
[CanBeNull] string key,
[CanBeNull] string displayName,
decimal discountedAmount)
{
OrderLineId = orderLineId;
Name = name;
Key = key ?? string.Empty;
DisplayName = displayName;
DiscountedAmount = discountedAmount;
}
}

5
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFee.cs

@ -13,6 +13,9 @@ namespace EasyAbp.EShop.Orders.Orders
[CanBeNull]
public virtual string Key { get; protected set; }
[CanBeNull]
public virtual string DisplayName { get; protected set; }
public virtual decimal Fee { get; protected set; }
@ -26,11 +29,13 @@ namespace EasyAbp.EShop.Orders.Orders
Guid orderId,
[NotNull] string name,
[CanBeNull] string key,
[CanBeNull] string displayName,
decimal fee)
{
OrderId = orderId;
Name = name;
Key = key;
DisplayName = displayName;
Fee = fee;
}

9
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderExtraFeeInfoModel.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderExtraFeeInfoModel.cs

@ -6,18 +6,23 @@ namespace EasyAbp.EShop.Orders.Orders
{
[NotNull]
public string Name { get; set; }
[CanBeNull]
public string Key { get; set; }
[CanBeNull]
public string DisplayName { get; set; }
public decimal Fee { get; set; }
public OrderExtraFeeInfoModel(
[NotNull] string name,
[CanBeNull] string key,
[CanBeNull] string displayName,
decimal fee)
{
Name = name;
DisplayName = displayName;
Key = key ?? string.Empty;
Fee = fee;
}

0
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderLineInvalidQuantityException.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/OrderLineInvalidQuantityException.cs

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

@ -121,6 +121,7 @@ namespace EasyAbp.EShop.Orders.Orders
{
Name = x.Name,
Key = x.Key,
DisplayName = x.DisplayName,
TotalAmount = x.Fee - x.RefundAmount
}));

0
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/UnexpectedCurrencyException.cs → modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Orders/UnexpectedCurrencyException.cs

1
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.EntityFrameworkCore/EasyAbp/EShop/Orders/EntityFrameworkCore/OrdersDbContext.cs

@ -13,6 +13,7 @@ namespace EasyAbp.EShop.Orders.EntityFrameworkCore
*/
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines { get; set; }
public DbSet<OrderDiscount> OrderDiscounts { get; set; }
public DbSet<OrderExtraFee> OrderExtraFees { get; set; }
public OrdersDbContext(DbContextOptions<OrdersDbContext> options)

9
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.EntityFrameworkCore/EasyAbp/EShop/Orders/EntityFrameworkCore/OrdersDbContextModelCreatingExtensions.cs

@ -66,6 +66,15 @@ namespace EasyAbp.EShop.Orders.EntityFrameworkCore
b.Property(x => x.RefundAmount).HasColumnType("decimal(20,8)");
});
builder.Entity<OrderDiscount>(b =>
{
b.ToTable(options.TablePrefix + "OrderDiscounts", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
b.Property(x => x.DiscountedAmount).HasColumnType("decimal(20,8)");
b.HasKey(x => new {x.OrderId, x.OrderLineId, x.Name, x.Key});
});
builder.Entity<OrderExtraFee>(b =>
{
b.ToTable(options.TablePrefix + "OrderExtraFees", options.Schema);

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/EasyAbp.EShop.Orders.Application.Tests.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace />
<RootNamespace>EasyAbp.EShop.Orders</RootNamespace>
</PropertyGroup>
<ItemGroup>

26
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs

@ -119,10 +119,7 @@ namespace EasyAbp.EShop.Orders.Orders
{
var orderRepository = ServiceProvider.GetRequiredService<IOrderRepository>();
var orderCount = 0;
await WithUnitOfWorkAsync(async () =>
{
orderCount = await orderRepository.CountAsync();
});
await WithUnitOfWorkAsync(async () => { orderCount = await orderRepository.CountAsync(); });
// Arrange
var checkCreateOrderInput = new CheckCreateOrderInput
@ -131,7 +128,7 @@ namespace EasyAbp.EShop.Orders.Orders
StoreId = OrderTestData.Store1Id,
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku1Id,
@ -160,10 +157,7 @@ namespace EasyAbp.EShop.Orders.Orders
{
var orderRepository = ServiceProvider.GetRequiredService<IOrderRepository>();
var orderCount = 0;
await WithUnitOfWorkAsync(async () =>
{
orderCount = await orderRepository.CountAsync();
});
await WithUnitOfWorkAsync(async () => { orderCount = await orderRepository.CountAsync(); });
// Arrange
var checkCreateOrderInput = new CheckCreateOrderInput
@ -172,7 +166,7 @@ namespace EasyAbp.EShop.Orders.Orders
StoreId = OrderTestData.Store1Id,
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku1Id,
@ -206,13 +200,13 @@ namespace EasyAbp.EShop.Orders.Orders
StoreId = OrderTestData.Store1Id,
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku1Id,
Quantity = 10
},
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku2Id,
@ -684,13 +678,13 @@ namespace EasyAbp.EShop.Orders.Orders
StoreId = OrderTestData.Store1Id,
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku1Id,
Quantity = 10
},
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku2Id,
@ -725,13 +719,13 @@ namespace EasyAbp.EShop.Orders.Orders
StoreId = OrderTestData.Store1Id,
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku1Id,
Quantity = 10
},
new CreateOrderLineDto
new()
{
ProductId = OrderTestData.Product1Id,
ProductSkuId = OrderTestData.ProductSku2Id,

9
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/TestOrderLinePriceOverrider.cs

@ -1,6 +1,5 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.Products;
using NodaMoney;
using Volo.Abp.DependencyInjection;
@ -9,9 +8,9 @@ namespace EasyAbp.EShop.Orders.Orders;
public class TestOrderLinePriceOverrider : IOrderLinePriceOverrider, ITransientDependency
{
public static decimal Sku3UnitPrice { get; set; } = 100m;
public async Task<Money?> GetUnitPriceOrNullAsync(CreateOrderDto input, CreateOrderLineDto inputOrderLine,
ProductDto product, ProductSkuDto productSku, Currency effectiveCurrency)
public async Task<Money?> GetUnitPriceOrNullAsync(ICreateOrderInfo input, ICreateOrderLineInfo inputOrderLine,
IProduct product, IProductSku productSku, Currency effectiveCurrency)
{
if (inputOrderLine.ProductSkuId == OrderTestData.ProductSku3Id)
{

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

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products;
namespace EasyAbp.EShop.Orders.Orders;
public class DemoOrderDiscountProvider : IOrderDiscountProvider
{
public Task<List<OrderDiscountInfoModel>> GetAllAsync(Order order, Dictionary<Guid, IProduct> productDict)
{
return Task.FromResult(new List<OrderDiscountInfoModel>
{
new(order.OrderLines.First().Id, "DemoDiscount1", "1", "Demo Discount 1", 0.01m),
new(order.OrderLines.First().Id, "DemoDiscount2", "2", "Demo Discount 2", 0.1m),
});
}
}

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/InventoryReductionResultTests.cs

@ -53,6 +53,7 @@ public class InventoryReductionResultTests : OrdersDomainTestBase
OrderTestData.Order1Id,
"Name",
"Key",
"DisplayName",
0.3m
));
@ -153,6 +154,7 @@ public class InventoryReductionResultTests : OrdersDomainTestBase
var orderExtraFee = eventData.OrderExtraFees[0];
orderExtraFee.Name.ShouldBe("Name");
orderExtraFee.Key.ShouldBe("Key");
orderExtraFee.DisplayName.ShouldBe("DisplayName");
orderExtraFee.TotalAmount.ShouldBe(0.3m);
Order1.CanceledTime.ShouldNotBeNull();

65
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDiscountTests.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace EasyAbp.EShop.Orders.Orders;
public class OrderDiscountTests : OrdersDomainTestBase
{
protected override void AfterAddApplication(IServiceCollection services)
{
services.AddTransient<IOrderDiscountProvider, DemoOrderDiscountProvider>();
base.AfterAddApplication(services);
}
[Fact]
public async Task Should_Create_Order_With_Discount()
{
var orderGenerator = GetRequiredService<INewOrderGenerator>();
var createOrderInfoModel = new CreateOrderInfoModel(OrderTestData.Store1Id, null,
new List<CreateOrderLineInfoModel>
{
new(OrderTestData.Product1Id, OrderTestData.ProductSku1Id, 2)
}
);
var order = await orderGenerator.GenerateAsync(Guid.NewGuid(), createOrderInfoModel,
new Dictionary<Guid, IProduct>
{
{
OrderTestData.Product1Id, new ProductEto
{
Id = OrderTestData.Product1Id,
ProductSkus = new List<ProductSkuEto>
{
new()
{
Id = OrderTestData.ProductSku1Id,
AttributeOptionIds = new List<Guid>(),
Price = 1m,
Currency = "USD",
OrderMinQuantity = 1,
OrderMaxQuantity = 100,
}
}
}
}
}, new Dictionary<Guid, DateTime>());
order.ActualTotalPrice.ShouldBe(1.89m);
order.TotalDiscount.ShouldBe(0.11m);
order.OrderDiscounts.Count.ShouldBe(2);
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);
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);
}
}

1
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Domain.Tests/Orders/OrderDomainTests.cs

@ -62,6 +62,7 @@ namespace EasyAbp.EShop.Orders.Orders
OrderTestData.Order1Id,
"Name",
"Key",
"DisplayName",
0.3m
));

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.EntityFrameworkCore.Tests/EasyAbp.EShop.Orders.EntityFrameworkCore.Tests.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace />
<RootNamespace>EasyAbp.EShop.Orders</RootNamespace>
</PropertyGroup>
<ItemGroup>

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.HttpApi.Client.ConsoleTestApp/EasyAbp.EShop.Orders.HttpApi.Client.ConsoleTestApp.csproj

@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace />
<RootNamespace>EasyAbp.EShop.Orders</RootNamespace>
</PropertyGroup>
<ItemGroup>

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.MongoDB.Tests/EasyAbp.EShop.Orders.MongoDB.Tests.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace />
<RootNamespace>EasyAbp.EShop.Orders</RootNamespace>
</PropertyGroup>
<ItemGroup>

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.TestBase/EasyAbp.EShop.Orders.TestBase.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace />
<RootNamespace>EasyAbp.EShop.Orders</RootNamespace>
</PropertyGroup>
<ItemGroup>

6
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/OrderExtraFeeRefundInfoModel.cs

@ -6,9 +6,11 @@ namespace EasyAbp.EShop.Payments.Refunds
public class OrderExtraFeeRefundInfoModel
{
public string Name { get; set; }
public string Key { get; set; }
public string DisplayName { get; set; }
public decimal TotalAmount { get; set; }
}
}

6
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain.Shared/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFeeEto.cs

@ -6,9 +6,11 @@ namespace EasyAbp.EShop.Payments.Refunds
public class RefundItemOrderExtraFeeEto
{
public string Name { get; set; }
public string Key { get; set; }
public string DisplayName { get; set; }
public decimal RefundAmount { get; set; }
}
}

14
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundItemOrderExtraFee.cs

@ -10,21 +10,29 @@ namespace EasyAbp.EShop.Payments.Refunds
{
[NotNull]
public virtual string Name { get; protected set; }
[CanBeNull]
public virtual string Key { get; protected set; }
[CanBeNull]
public virtual string DisplayName { get; protected set; }
public virtual decimal RefundAmount { get; protected set; }
protected RefundItemOrderExtraFee()
{
}
public RefundItemOrderExtraFee(Guid id, [NotNull] string name, [CanBeNull] string key,
public RefundItemOrderExtraFee(
Guid id,
[NotNull] string name,
[CanBeNull] string key,
[CanBeNull] string displayName,
decimal refundAmount) : base(id)
{
Name = name;
Key = key;
DisplayName = displayName;
RefundAmount = refundAmount;
}
}

2
modules/EasyAbp.EShop.Payments/src/EasyAbp.EShop.Payments.Domain/EasyAbp/EShop/Payments/Refunds/RefundSynchronizer.cs

@ -195,7 +195,7 @@ namespace EasyAbp.EShop.Payments.Refunds
{
refundItemOrderExtraFeeEntity = new RefundItemOrderExtraFee(_guidGenerator.Create(),
orderExtraFeeInfoModel.Name, orderExtraFeeInfoModel.Key,
orderExtraFeeInfoModel.TotalAmount);
orderExtraFeeInfoModel.DisplayName, orderExtraFeeInfoModel.TotalAmount);
refundItem.OrderExtraFees.Add(refundItemOrderExtraFeeEntity);
}

2
modules/EasyAbp.EShop.Payments/test/EasyAbp.EShop.Payments.Domain.Tests/Refunds/RefundOrderEventHandlerTests.cs

@ -82,6 +82,7 @@ public class RefundOrderEventHandlerTests : PaymentsDomainTestBase
{
Name = "Name",
Key = "Key",
DisplayName = "DisplayName",
TotalAmount = 0.6m
});
@ -111,6 +112,7 @@ public class RefundOrderEventHandlerTests : PaymentsDomainTestBase
orderExtraFees.Count.ShouldBe(1);
orderExtraFees[0].Name.ShouldBe("Name");
orderExtraFees[0].Key.ShouldBe("Key");
orderExtraFees[0].DisplayName.ShouldBe("DisplayName");
orderExtraFees[0].TotalAmount.ShouldBe(0.6m);
}
}

20
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductDto.cs

@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Products.Products.Dtos
{
[Serializable]
public class ProductDto : ExtensibleFullAuditedEntityDto<Guid>, IProduct
public class ProductDto : ExtensibleFullAuditedEntityDto<Guid>, IProduct, IHasProductGroupDisplayName
{
public Guid StoreId { get; set; }
@ -49,22 +48,5 @@ namespace EasyAbp.EShop.Products.Products.Dtos
IEnumerable<IProductSku> IProduct.ProductSkus => ProductSkus;
public List<ProductSkuDto> ProductSkus { get; set; }
public ProductSkuDto GetSkuById(Guid skuId)
{
return ProductSkus.Single(x => x.Id == skuId);
}
public ProductSkuDto FindSkuById(Guid skuId)
{
return ProductSkus.FirstOrDefault(x => x.Id == skuId);
}
public TimeSpan? GetSkuPaymentExpireIn(Guid skuId)
{
var sku = GetSkuById(skuId);
return sku.PaymentExpireIn ?? PaymentExpireIn;
}
}
}

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductViewDto.cs

@ -4,7 +4,7 @@ using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Products.Products.Dtos
{
[Serializable]
public class ProductViewDto : ExtensibleCreationAuditedEntityDto<Guid>, IProductBase
public class ProductViewDto : ExtensibleCreationAuditedEntityDto<Guid>, IProductBase, IHasProductGroupDisplayName
{
public Guid StoreId { get; set; }
@ -32,6 +32,8 @@ namespace EasyAbp.EShop.Products.Products.Dtos
public bool IsHidden { get; set; }
public TimeSpan? PaymentExpireIn { get; set; }
public decimal? MinimumPrice { get; set; }
public decimal? MaximumPrice { get; set; }

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp.EShop.Products.Domain.Shared.csproj

@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="EasyAbp.Abp.Trees.Domain.Shared" Version="$(EasyAbpAbpTreesModuleVersion)" />
<PackageReference Include="Volo.Abp.Validation" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Json.Abstractions" Version="$(AbpVersion)" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
</ItemGroup>

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/EShopProductsDomainSharedModule.cs

@ -3,6 +3,7 @@ using Volo.Abp.Modularity;
using Volo.Abp.Localization;
using EasyAbp.EShop.Products.Localization;
using EasyAbp.EShop.Stores;
using Volo.Abp.Json;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
@ -12,6 +13,7 @@ namespace EasyAbp.EShop.Products
{
[DependsOn(
typeof(AbpValidationModule),
typeof(AbpJsonAbstractionsModule),
typeof(AbpTreesDomainSharedModule),
typeof(EShopStoresDomainSharedModule)
)]

9
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IHasProductGroupDisplayName.cs

@ -0,0 +1,9 @@
using JetBrains.Annotations;
namespace EasyAbp.EShop.Products.Products;
public interface IHasProductGroupDisplayName
{
[NotNull]
string ProductGroupDisplayName { get; }
}

5
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductAttribute.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Data;
@ -6,6 +7,8 @@ namespace EasyAbp.EShop.Products.Products
{
public interface IProductAttribute : IHasExtraProperties
{
Guid Id { get; }
[NotNull]
string DisplayName { get; }

5
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductAttributeOption.cs

@ -1,10 +1,13 @@
using JetBrains.Annotations;
using System;
using JetBrains.Annotations;
using Volo.Abp.Data;
namespace EasyAbp.EShop.Products.Products
{
public interface IProductAttributeOption : IHasExtraProperties
{
Guid Id { get; }
[NotNull]
string DisplayName { get; }

12
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductBase.cs

@ -7,14 +7,23 @@ namespace EasyAbp.EShop.Products.Products
{
public interface IProductBase : IHasExtraProperties, IMultiStore
{
Guid Id { get; }
[NotNull]
string ProductGroupName { get; }
Guid? ProductDetailId { get; }
[CanBeNull]
string UniqueName { get; }
[NotNull]
string DisplayName { get; }
/// <summary>
/// Tell your customer what the product is. It is usually shown in the product list.
/// </summary>
[CanBeNull]
string Overview { get; }
InventoryStrategy InventoryStrategy { get; }
@ -22,6 +31,7 @@ namespace EasyAbp.EShop.Products.Products
[CanBeNull]
string InventoryProviderName { get; }
[CanBeNull]
string MediaResources { get; }
int DisplayOrder { get; }
@ -31,5 +41,7 @@ namespace EasyAbp.EShop.Products.Products
bool IsStatic { get; }
bool IsHidden { get; }
TimeSpan? PaymentExpireIn { get; }
}
}

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductSku.cs

@ -6,6 +6,8 @@ namespace EasyAbp.EShop.Products.Products
{
public interface IProductSku : IHasAttributeOptionIds, IHasExtraProperties
{
Guid Id { get; }
[CanBeNull]
string Name { get; }
@ -20,6 +22,8 @@ namespace EasyAbp.EShop.Products.Products
int OrderMaxQuantity { get; }
TimeSpan? PaymentExpireIn { get; }
[CanBeNull]
string MediaResources { get; }

3
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductSkuDescriptionProvider.cs → modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProductSkuDescriptionProvider.cs

@ -1,10 +1,9 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products.Dtos;
namespace EasyAbp.EShop.Products.Products
{
public interface IProductSkuDescriptionProvider
{
Task<string> GenerateAsync(ProductDto productDto, ProductSkuDto productSkuDto);
Task<string> GenerateAsync(IProduct product, IProductSku productSku);
}
}

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductEto.cs

@ -37,6 +37,8 @@ namespace EasyAbp.EShop.Products.Products
public bool IsHidden { get; set; }
public TimeSpan? PaymentExpireIn { get; set; }
IEnumerable<IProductAttribute> IProduct.ProductAttributes => ProductAttributes;
public List<ProductAttributeEto> ProductAttributes { get; set; }

24
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductExtensions.cs

@ -0,0 +1,24 @@
using System;
using System.Linq;
namespace EasyAbp.EShop.Products.Products;
public static class ProductExtensions
{
public static IProductSku GetSkuById(this IProduct product, Guid skuId)
{
return product.ProductSkus.Single(x => x.Id == skuId);
}
public static IProductSku FindSkuById(this IProduct product, Guid skuId)
{
return product.ProductSkus.FirstOrDefault(x => x.Id == skuId);
}
public static TimeSpan? GetSkuPaymentExpireIn(this IProduct product, Guid skuId)
{
var sku = product.GetSkuById(skuId);
return sku.PaymentExpireIn ?? product.PaymentExpireIn;
}
}

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/ProductSkuDescriptionProvider.cs → modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductSkuDescriptionProvider.cs

@ -1,7 +1,6 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
@ -16,13 +15,13 @@ namespace EasyAbp.EShop.Products.Products
_jsonSerializer = jsonSerializer;
}
public virtual Task<string> GenerateAsync(ProductDto productDto, ProductSkuDto productSkuDto)
public virtual Task<string> GenerateAsync(IProduct product, IProductSku productSku)
{
var names = new Collection<string[]>();
foreach (var attributeOptionId in productSkuDto.AttributeOptionIds)
foreach (var attributeOptionId in productSku.AttributeOptionIds)
{
names.Add(productDto.ProductAttributes.SelectMany(
names.Add(product.ProductAttributes.SelectMany(
attribute => attribute.ProductAttributeOptions.Where(option => option.Id == attributeOptionId),
(attribute, option) => new [] {attribute.DisplayName, option.DisplayName}).Single());
}

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductSkuEto.cs

@ -23,6 +23,8 @@ namespace EasyAbp.EShop.Products.Products
public int OrderMaxQuantity { get; set; }
public TimeSpan? PaymentExpireIn { get; }
public string MediaResources { get; set; }
public Guid? ProductDetailId { get; set; }

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Options/ProductGroups/IProductGroup.cs

@ -1,7 +0,0 @@
namespace EasyAbp.EShop.Products.Options.ProductGroups
{
public interface IProductGroup
{
}
}

8
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/Product.cs

@ -14,21 +14,14 @@ namespace EasyAbp.EShop.Products.Products
public virtual Guid StoreId { get; protected set; }
[NotNull]
public virtual string ProductGroupName { get; protected set; }
public virtual Guid? ProductDetailId { get; protected set; }
[CanBeNull]
public virtual string UniqueName { get; protected set; }
[NotNull]
public virtual string DisplayName { get; protected set; }
/// <summary>
/// Tell your customer what the product is. It is usually shown in the product list.
/// </summary>
[CanBeNull]
public virtual string Overview { get; protected set; }
public virtual InventoryStrategy InventoryStrategy { get; protected set; }
@ -39,7 +32,6 @@ namespace EasyAbp.EShop.Products.Products
/// </summary>
public virtual string InventoryProviderName { get; protected set; }
[CanBeNull]
public virtual string MediaResources { get; protected set; }
public virtual int DisplayOrder { get; protected set; }

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductView.cs

@ -4,7 +4,8 @@ using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Products.Products
{
public class ProductView : CreationAuditedAggregateRoot<Guid>, IProductBase, IMultiTenant
public class ProductView : CreationAuditedAggregateRoot<Guid>,
IProductBase, IHasProductGroupDisplayName, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
@ -36,6 +37,8 @@ namespace EasyAbp.EShop.Products.Products
public virtual bool IsHidden { get; protected set; }
public virtual TimeSpan? PaymentExpireIn { get; protected set; }
#endregion
public virtual string ProductGroupDisplayName { get; protected set; }
@ -64,6 +67,7 @@ namespace EasyAbp.EShop.Products.Products
bool isPublished,
bool isStatic,
bool isHidden,
TimeSpan? paymentExpireIn,
string mediaResources,
int displayOrder,
string productGroupDisplayName,
@ -84,6 +88,7 @@ namespace EasyAbp.EShop.Products.Products
IsPublished = isPublished;
IsStatic = isStatic;
IsHidden = isHidden;
PaymentExpireIn = paymentExpireIn;
MediaResources = mediaResources;
DisplayOrder = displayOrder;

2
plugins/Baskets/src/EasyAbp.EShop.Plugins.Baskets.Application/EasyAbp/EShop/Plugins/Baskets/BasketItems/BasicBasketItemProductInfoUpdater.cs

@ -27,7 +27,7 @@ public class BasicBasketItemProductInfoUpdater : IBasketItemProductInfoUpdater,
protected virtual async Task InternalUpdateAsync(int targetQuantity, IBasketItem item, ProductDto productDto)
{
var productSkuDto = productDto.FindSkuById(item.ProductSkuId);
var productSkuDto = (ProductSkuDto)productDto.FindSkuById(item.ProductSkuId);
if (productSkuDto == null)
{

10
plugins/Booking/src/EasyAbp.EShop.Orders.Booking.Application/EasyAbp/EShop/Orders/Booking/Authorization/BookingOrderCreationAuthorizationHandler.cs

@ -116,7 +116,7 @@ namespace EasyAbp.EShop.Orders.Booking.Authorization
}
}
protected virtual OccupyAssetInfoModel CreateOccupyAssetInfoModel(Guid assetId, CreateOrderLineDto orderLine)
protected virtual OccupyAssetInfoModel CreateOccupyAssetInfoModel(Guid assetId, ICreateOrderLineInfo orderLine)
{
return new OccupyAssetInfoModel(
assetId,
@ -128,7 +128,7 @@ namespace EasyAbp.EShop.Orders.Booking.Authorization
}
protected virtual OccupyAssetByCategoryInfoModel CreateOccupyAssetByCategoryInfoModel(Guid assetCategoryId,
CreateOrderLineDto orderLine)
ICreateOrderLineInfo orderLine)
{
return new OccupyAssetByCategoryInfoModel(
assetCategoryId,
@ -140,7 +140,7 @@ namespace EasyAbp.EShop.Orders.Booking.Authorization
);
}
protected virtual async Task<bool> IsAssetInfoValidAsync(CreateOrderLineDto orderLine,
protected virtual async Task<bool> IsAssetInfoValidAsync(ICreateOrderLineInfo orderLine,
OrderCreationResource resource)
{
var mapping = (await _grantedStoreAppService.GetListAsync(new GetGrantedStoreListDto
@ -179,7 +179,7 @@ namespace EasyAbp.EShop.Orders.Booking.Authorization
return productAsset is not null;
}
protected virtual async Task<bool> IsAssetCategoryInfoValidAsync(CreateOrderLineDto orderLine,
protected virtual async Task<bool> IsAssetCategoryInfoValidAsync(ICreateOrderLineInfo orderLine,
OrderCreationResource resource)
{
var mapping = (await _grantedStoreAppService.GetListAsync(new GetGrantedStoreListDto
@ -218,7 +218,7 @@ namespace EasyAbp.EShop.Orders.Booking.Authorization
return productAssetCategory is not null;
}
protected virtual async Task<bool> IsPeriodInfoValidAsync(CreateOrderLineDto orderLine)
protected virtual async Task<bool> IsPeriodInfoValidAsync(ICreateOrderLineInfo orderLine)
{
var periodSchemeId = orderLine.GetBookingPeriodSchemeId();
var periodId = orderLine.GetBookingPeriodId();

13
plugins/Booking/src/EasyAbp.EShop.Orders.Booking.Application/EasyAbp/EShop/Orders/Booking/BookingOrderLinePriceOverrider.cs

@ -6,6 +6,7 @@ using EasyAbp.EShop.Plugins.Booking.ProductAssetCategories;
using EasyAbp.EShop.Plugins.Booking.ProductAssetCategories.Dtos;
using EasyAbp.EShop.Plugins.Booking.ProductAssets;
using EasyAbp.EShop.Plugins.Booking.ProductAssets.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using NodaMoney;
using Volo.Abp.DependencyInjection;
@ -25,8 +26,8 @@ public class BookingOrderLinePriceOverrider : IOrderLinePriceOverrider, ITransie
_productAssetCategoryAppService = productAssetCategoryAppService;
}
public virtual async Task<Money?> GetUnitPriceOrNullAsync(CreateOrderDto input, CreateOrderLineDto inputOrderLine,
ProductDto product, ProductSkuDto productSku, Currency effectiveCurrency)
public virtual async Task<Money?> GetUnitPriceOrNullAsync(ICreateOrderInfo input,
ICreateOrderLineInfo inputOrderLine, IProduct product, IProductSku productSku, Currency effectiveCurrency)
{
if (inputOrderLine.FindBookingAssetId() is not null)
{
@ -41,8 +42,8 @@ public class BookingOrderLinePriceOverrider : IOrderLinePriceOverrider, ITransie
return null;
}
public virtual async Task<Money?> GetAssetBookingUnitPriceAsync(CreateOrderDto input,
CreateOrderLineDto inputOrderLine, Currency effectiveCurrency)
public virtual async Task<Money?> GetAssetBookingUnitPriceAsync(ICreateOrderInfo input,
ICreateOrderLineInfo inputOrderLine, Currency effectiveCurrency)
{
var productAsset = (await _productAssetAppService.GetListAsync(
new GetProductAssetListDto
@ -76,8 +77,8 @@ public class BookingOrderLinePriceOverrider : IOrderLinePriceOverrider, ITransie
return null;
}
public virtual async Task<Money?> GetAssetCategoryBookingUnitPriceAsync(CreateOrderDto input,
CreateOrderLineDto inputOrderLine, Currency effectiveCurrency)
public virtual async Task<Money?> GetAssetCategoryBookingUnitPriceAsync(ICreateOrderInfo input,
ICreateOrderLineInfo inputOrderLine, Currency effectiveCurrency)
{
var productAssetCategory = (await _productAssetCategoryAppService.GetListAsync(
new GetProductAssetCategoryListDto

35
plugins/Booking/src/EasyAbp.EShop.Plugins.Booking.Application.Contracts/EasyAbp/EShop/Orders/CreateOrderLineDtoExtensions.cs → plugins/Booking/src/EasyAbp.EShop.Plugins.Booking.Application.Contracts/EasyAbp/EShop/Orders/CreateOrderLineInfoExtensions.cs

@ -1,94 +1,95 @@
using System;
using EasyAbp.EShop.Orders.Orders;
using EasyAbp.EShop.Orders.Orders.Dtos;
using Volo.Abp;
using Volo.Abp.Data;
namespace EasyAbp.EShop.Orders;
public static class CreateOrderLineDtoExtensions
public static class CreateOrderLineInfoExtensions
{
public static Guid? FindBookingAssetId(this CreateOrderLineDto orderLine)
public static Guid? FindBookingAssetId(this ICreateOrderLineInfo orderLine)
{
return orderLine.GetProperty<Guid?>(BookingOrderProperties.OrderLineBookingAssetId);
}
public static Guid GetBookingAssetId(this CreateOrderLineDto orderLine)
public static Guid GetBookingAssetId(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingAssetId(orderLine),
BookingOrderProperties.OrderLineBookingAssetId)!.Value;
}
public static Guid? FindBookingAssetCategoryId(this CreateOrderLineDto orderLine)
public static Guid? FindBookingAssetCategoryId(this ICreateOrderLineInfo orderLine)
{
return orderLine.GetProperty<Guid?>(BookingOrderProperties.OrderLineBookingAssetCategoryId);
}
public static Guid GetBookingAssetCategoryId(this CreateOrderLineDto orderLine)
public static Guid GetBookingAssetCategoryId(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingAssetCategoryId(orderLine),
BookingOrderProperties.OrderLineBookingAssetCategoryId)!.Value;
}
public static Guid? FindBookingPeriodSchemeId(this CreateOrderLineDto orderLine)
public static Guid? FindBookingPeriodSchemeId(this ICreateOrderLineInfo orderLine)
{
return orderLine.GetProperty<Guid?>(BookingOrderProperties.OrderLineBookingPeriodSchemeId);
}
public static Guid GetBookingPeriodSchemeId(this CreateOrderLineDto orderLine)
public static Guid GetBookingPeriodSchemeId(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingPeriodSchemeId(orderLine),
BookingOrderProperties.OrderLineBookingPeriodSchemeId)!.Value;
}
public static Guid? FindBookingPeriodId(this CreateOrderLineDto orderLine)
public static Guid? FindBookingPeriodId(this ICreateOrderLineInfo orderLine)
{
return orderLine.GetProperty<Guid?>(BookingOrderProperties.OrderLineBookingPeriodId);
}
public static Guid GetBookingPeriodId(this CreateOrderLineDto orderLine)
public static Guid GetBookingPeriodId(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingPeriodId(orderLine),
BookingOrderProperties.OrderLineBookingPeriodId)!.Value;
}
public static int? FindBookingVolume(this CreateOrderLineDto orderLine)
public static int? FindBookingVolume(this ICreateOrderLineInfo orderLine)
{
return orderLine.Quantity;
}
public static int GetBookingVolume(this CreateOrderLineDto orderLine)
public static int GetBookingVolume(this ICreateOrderLineInfo orderLine)
{
return FindBookingVolume(orderLine)!.Value;
}
public static DateTime? FindBookingDate(this CreateOrderLineDto orderLine)
public static DateTime? FindBookingDate(this ICreateOrderLineInfo orderLine)
{
return orderLine.FindDateTimeProperty(BookingOrderProperties.OrderLineBookingDate);
}
public static DateTime GetBookingDate(this CreateOrderLineDto orderLine)
public static DateTime GetBookingDate(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingDate(orderLine),
BookingOrderProperties.OrderLineBookingDate)!.Value;
}
public static TimeSpan? FindBookingStartingTime(this CreateOrderLineDto orderLine)
public static TimeSpan? FindBookingStartingTime(this ICreateOrderLineInfo orderLine)
{
return orderLine.FindTimeSpanProperty(BookingOrderProperties.OrderLineBookingStartingTime);
}
public static TimeSpan GetBookingStartingTime(this CreateOrderLineDto orderLine)
public static TimeSpan GetBookingStartingTime(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingStartingTime(orderLine),
BookingOrderProperties.OrderLineBookingStartingTime)!.Value;
}
public static TimeSpan? FindBookingDuration(this CreateOrderLineDto orderLine)
public static TimeSpan? FindBookingDuration(this ICreateOrderLineInfo orderLine)
{
return orderLine.FindTimeSpanProperty(BookingOrderProperties.OrderLineBookingDuration);
}
public static TimeSpan GetBookingDuration(this CreateOrderLineDto orderLine)
public static TimeSpan GetBookingDuration(this ICreateOrderLineInfo orderLine)
{
return Check.NotNull(FindBookingDuration(orderLine),
BookingOrderProperties.OrderLineBookingDuration)!.Value;

85
plugins/Coupons/src/EasyAbp.EShop.Orders.Plugins.Coupons/EasyAbp/EShop/Orders/Plugins/Coupons/OrderDiscount/CouponOrderDiscountProvider.cs

@ -7,7 +7,8 @@ using EasyAbp.EShop.Plugins.Coupons;
using EasyAbp.EShop.Plugins.Coupons.Coupons;
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos;
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.Products;
using NodaMoney;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
@ -16,6 +17,8 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
{
public class CouponOrderDiscountProvider : IOrderDiscountProvider, ITransientDependency
{
public static string OrderDiscountName { get; set; } = "Coupon";
private readonly IClock _clock;
private readonly ICouponAppService _couponAppService;
private readonly ICouponLookupService _couponLookupService;
@ -32,13 +35,14 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
_couponLookupService = couponLookupService;
_couponTemplateLookupService = couponTemplateLookupService;
}
public virtual async Task<Order> DiscountAsync(Order order, Dictionary<Guid, ProductDto> productDict)
public virtual async Task<List<OrderDiscountInfoModel>> GetAllAsync(Order order,
Dictionary<Guid, IProduct> productDict)
{
var couponId = order.GetProperty<Guid?>(CouponsConsts.OrderCouponIdPropertyName);
if (couponId is null)
{
return order;
return new List<OrderDiscountInfoModel>();
}
var now = _clock.Now;
@ -54,7 +58,7 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
{
throw new CouponHasBeenOccupiedException();
}
var couponTemplate = await _couponTemplateLookupService.FindByIdAsync(coupon.CouponTemplateId);
if (couponTemplate == null ||
@ -65,12 +69,12 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
}
var orderLinesInScope = GetOrderLinesInScope(couponTemplate, order, productDict);
DiscountOrderLines(couponTemplate, order, orderLinesInScope);
await _couponAppService.OccupyAsync(coupon.Id, new OccupyCouponInput {OrderId = order.Id});
return order;
var models = await DiscountOrderLinesAsync(couponTemplate, coupon, order, orderLinesInScope);
await _couponAppService.OccupyAsync(coupon.Id, new OccupyCouponInput { OrderId = order.Id });
return models;
}
protected virtual bool IsCurrencyExpected(CouponTemplateData couponTemplate, Order order)
@ -78,21 +82,25 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
return couponTemplate.Currency == order.Currency;
}
protected virtual void DiscountOrderLines(CouponTemplateData couponTemplate, Order order,
List<OrderLine> orderLinesInScope)
protected virtual Task<List<OrderDiscountInfoModel>> DiscountOrderLinesAsync(CouponTemplateData couponTemplate,
CouponData coupon, Order order, List<OrderLine> orderLinesInScope)
{
// Todo: support Custom coupon.
if (couponTemplate.CouponType == CouponType.Custom)
{
throw new NotSupportedException();
}
var totalOrderLineActualTotalPrice = orderLinesInScope.Sum(x => x.ActualTotalPrice);
var totalDiscountedAmount = couponTemplate.CouponType == CouponType.PerMeet
? couponTemplate.DiscountAmount *
Math.Floor(totalOrderLineActualTotalPrice / couponTemplate.ConditionAmount)
: couponTemplate.DiscountAmount;
var nodaCurrency = Currency.FromCode(order.Currency);
var totalOrderLineActualTotalPrice =
new Money(orderLinesInScope.Sum(x => x.ActualTotalPrice), nodaCurrency);
var totalDiscountedAmount = new Money(
couponTemplate.CouponType == CouponType.PerMeet
? couponTemplate.DiscountAmount *
Math.Floor(totalOrderLineActualTotalPrice.Amount / couponTemplate.ConditionAmount)
: couponTemplate.DiscountAmount,
nodaCurrency);
if (totalDiscountedAmount > totalOrderLineActualTotalPrice)
{
@ -101,21 +109,21 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
var remainingDiscountedAmount = totalDiscountedAmount;
// Todo: https://github.com/EasyAbp/EShop/issues/104
const int accuracy = 2;
var orderLineDiscounts = new Dictionary<OrderLine, Money>();
foreach (var orderLine in orderLinesInScope)
{
var orderLineActualTotalPrice = new Money(orderLine.ActualTotalPrice, nodaCurrency);
var maxDiscountAmount =
Math.Round(orderLine.ActualTotalPrice / totalOrderLineActualTotalPrice * totalDiscountedAmount,
accuracy, MidpointRounding.ToZero);
new Money(
orderLineActualTotalPrice.Amount / totalOrderLineActualTotalPrice.Amount *
totalDiscountedAmount.Amount, nodaCurrency, MidpointRounding.ToZero);
var discountAmount = maxDiscountAmount > orderLine.ActualTotalPrice
? orderLine.ActualTotalPrice
var discountAmount = maxDiscountAmount > totalOrderLineActualTotalPrice
? orderLineActualTotalPrice
: maxDiscountAmount;
order.AddDiscount(orderLine.Id, discountAmount);
orderLineDiscounts[orderLine] = discountAmount;
remainingDiscountedAmount -= discountAmount;
}
@ -125,13 +133,12 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
{
break;
}
var discountAmount = remainingDiscountedAmount > orderLine.ActualTotalPrice
? orderLine.ActualTotalPrice
var discountAmount = remainingDiscountedAmount > totalOrderLineActualTotalPrice
? totalOrderLineActualTotalPrice
: remainingDiscountedAmount;
order.AddDiscount(orderLine.Id, discountAmount);
orderLineDiscounts[orderLine] += discountAmount;
remainingDiscountedAmount -= discountAmount;
}
@ -139,12 +146,19 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
{
throw new ApplicationException();
}
order.SetProperty(CouponsConsts.OrderCouponDiscountAmountPropertyName, totalDiscountedAmount);
var models = orderLinesInScope.Select(orderLine =>
new OrderDiscountInfoModel(orderLine.Id, OrderDiscountName, coupon.Id.ToString(),
couponTemplate.DisplayName, orderLineDiscounts[orderLine].Amount)
).ToList();
return Task.FromResult(models);
}
protected virtual List<OrderLine> GetOrderLinesInScope(CouponTemplateData couponTemplate, Order order,
Dictionary<Guid, ProductDto> productDict)
Dictionary<Guid, IProduct> productDict)
{
if (couponTemplate.IsUnscoped)
{
@ -176,7 +190,8 @@ namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount
return expectedOrderLines;
}
protected virtual decimal GetOrderLineProductPrice(OrderLine orderLine, Dictionary<Guid, ProductDto> productDict)
protected virtual decimal GetOrderLineProductPrice(OrderLine orderLine,
Dictionary<Guid, IProduct> productDict)
{
return productDict[orderLine.ProductId].GetSkuById(orderLine.ProductSkuId).Price;
}

10
plugins/Coupons/src/EasyAbp.EShop.Plugins.Coupons.Domain.Shared/EasyAbp/EShop/Plugins/Coupons/Coupons/ICoupon.cs

@ -4,16 +4,18 @@ namespace EasyAbp.EShop.Plugins.Coupons.Coupons
{
public interface ICoupon
{
Guid Id { get; }
Guid CouponTemplateId { get; }
Guid UserId { get; }
Guid? OrderId { get; }
DateTime? ExpirationTime { get; }
DateTime? UsedTime { get; }
decimal? DiscountedAmount { get; }
}
}

48
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Orders/CreateFlashSaleOrderEventHandler.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders.Dtos;
using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans;
@ -58,7 +59,7 @@ public class CreateFlashSaleOrderEventHandler : IDistributedEventHandler<CreateF
public virtual async Task HandleEventAsync(CreateFlashSaleOrderEto eventData)
{
var product = await ProductAppService.GetAsync(eventData.Plan.ProductId);
var productSku = product.GetSkuById(eventData.Plan.ProductSkuId);
var productSku = (ProductSkuDto)product.GetSkuById(eventData.Plan.ProductSkuId);
if (!await ValidateHashTokenAsync(eventData.Plan, product, productSku, eventData.HashToken))
{
@ -84,9 +85,11 @@ public class CreateFlashSaleOrderEventHandler : IDistributedEventHandler<CreateF
var productDict = await GetProductDictionaryAsync(product);
var productDetailDict = await GetProductDetailDictionaryAsync(product, productSku);
var productDetailModificationTimeDict =
await GetProductDetailModificationTimeDictionaryAsync(input, productDict);
var order = await NewOrderGenerator.GenerateAsync(eventData.UserId, input, productDict, productDetailDict);
var order = await NewOrderGenerator.GenerateAsync(eventData.UserId, input, productDict,
productDetailModificationTimeDict);
await OrderRepository.InsertAsync(order, autoSave: true);
@ -107,25 +110,30 @@ public class CreateFlashSaleOrderEventHandler : IDistributedEventHandler<CreateF
});
}
protected virtual Task<Dictionary<Guid, ProductDto>> GetProductDictionaryAsync(ProductDto product)
protected virtual Task<Dictionary<Guid, IProduct>> GetProductDictionaryAsync(ProductDto product)
{
var productDict = new Dictionary<Guid, ProductDto>()
{
{product.Id, product}
};
var productDict = new Dictionary<Guid, IProduct>() { { product.Id, product } };
return Task.FromResult(productDict);
}
protected virtual async Task<Dictionary<Guid, ProductDetailDto>> GetProductDetailDictionaryAsync(ProductDto product, ProductSkuDto productSku)
protected virtual async Task<Dictionary<Guid, DateTime>> GetProductDetailModificationTimeDictionaryAsync(
ICreateOrderInfo input, Dictionary<Guid, IProduct> productDict)
{
var dict = new Dictionary<Guid, ProductDetailDto>();
var productDetailIds = input.OrderLines
.Select(dto =>
productDict[dto.ProductId].GetSkuById(dto.ProductSkuId).ProductDetailId ??
productDict[dto.ProductId].ProductDetailId)
.Where(x => x.HasValue)
.Select(x => x.Value)
.ToList();
var productDetailId = productSku.ProductDetailId ?? product.ProductDetailId;
var dict = new Dictionary<Guid, DateTime>();
if (productDetailId.HasValue)
foreach (var productDetailId in productDetailIds.Distinct())
{
dict.Add(productDetailId.Value, await ProductDetailAppService.GetAsync(productDetailId.Value));
var product = await ProductDetailAppService.GetAsync(productDetailId);
dict.Add(productDetailId, product.LastModificationTime ?? product.CreationTime);
}
return dict;
@ -133,13 +141,13 @@ public class CreateFlashSaleOrderEventHandler : IDistributedEventHandler<CreateF
protected virtual Task<CreateOrderDto> ConvertToCreateOrderDtoAsync(CreateFlashSaleOrderEto eventData)
{
var input = new CreateOrderDto()
var input = new CreateOrderDto
{
StoreId = eventData.Plan.StoreId,
CustomerRemark = eventData.CustomerRemark,
OrderLines = new List<CreateOrderLineDto>()
OrderLines = new List<CreateOrderLineDto>
{
new CreateOrderLineDto()
new()
{
ProductId = eventData.Plan.ProductId,
ProductSkuId = eventData.Plan.ProductSkuId,
@ -153,10 +161,12 @@ public class CreateFlashSaleOrderEventHandler : IDistributedEventHandler<CreateF
return Task.FromResult(input);
}
protected virtual async Task<bool> ValidateHashTokenAsync(FlashSalePlanEto plan, ProductDto product, ProductSkuDto productSku, string originHashToken)
protected virtual async Task<bool> ValidateHashTokenAsync(FlashSalePlanEto plan, ProductDto product,
ProductSkuDto productSku, string originHashToken)
{
var hashToken = await FlashSalePlanHasher.HashAsync(plan.LastModificationTime, product.LastModificationTime, productSku.LastModificationTime);
var hashToken = await FlashSalePlanHasher.HashAsync(plan.LastModificationTime, product.LastModificationTime,
productSku.LastModificationTime);
return string.Equals(hashToken, originHashToken, StringComparison.InvariantCulture);
}
}
}

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs

@ -207,7 +207,7 @@ public class FlashSalePlanAppService :
var plan = await GetFlashSalePlanCacheAsync(id);
var product = await ProductCache.GetAsync(plan.ProductId);
var productSku = product.GetSkuById(plan.ProductSkuId);
var productSku = (ProductSkuDto)product.GetSkuById(plan.ProductSkuId);
var expiresTime = DateTimeOffset.Now.Add(Options.PreOrderExpires);
await ValidatePreOrderAsync(plan, product, productSku);

6
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs

@ -309,7 +309,8 @@ public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase
var plan = await CreateFlashSalePlanAsync();
var preOrderCacheKey = string.Format(FlashSalePlanAppService.PreOrderCacheKeyFormat, plan.Id, CurrentUser.Id);
var hashToken = await GetRequiredService<IFlashSalePlanHasher>()
.HashAsync(plan.LastModificationTime, Product1.LastModificationTime, Product1.GetSkuById(plan.ProductSkuId).LastModificationTime);
.HashAsync(plan.LastModificationTime, Product1.LastModificationTime,
((ProductSkuDto)Product1.GetSkuById(plan.ProductSkuId)).LastModificationTime);
var dto = await AppService.PreOrderAsync(plan.Id);
@ -358,7 +359,8 @@ public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase
{
var plan = await CreateFlashSalePlanAsync();
var hashToken = await GetRequiredService<IFlashSalePlanHasher>()
.HashAsync(plan.LastModificationTime, Product1.LastModificationTime, Product1.GetSkuById(plan.ProductSkuId).LastModificationTime);
.HashAsync(plan.LastModificationTime, Product1.LastModificationTime,
((ProductSkuDto)Product1.GetSkuById(plan.ProductSkuId)).LastModificationTime);
var orderFlashSalePlanInput = new OrderFlashSalePlanInput
{
CustomerRemark = "remark1"

6406
samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/20230329111403_RefactordOrderAndSomeOthers.Designer.cs

File diff suppressed because it is too large

74
samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/20230329111403_RefactordOrderAndSomeOthers.cs

@ -0,0 +1,74 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace EShopSample.Migrations
{
/// <inheritdoc />
public partial class RefactordOrderAndSomeOthers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeSpan>(
name: "PaymentExpireIn",
table: "EasyAbpEShopProductsProductViews",
type: "time",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "DisplayName",
table: "EasyAbpEShopPaymentsRefundItemOrderExtraFees",
type: "nvarchar(max)",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "DisplayName",
table: "EasyAbpEShopOrdersOrderExtraFees",
type: "nvarchar(max)",
nullable: true);
migrationBuilder.CreateTable(
name: "EasyAbpEShopOrdersOrderDiscounts",
columns: table => new
{
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
OrderLineId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(450)", nullable: false),
Key = table.Column<string>(type: "nvarchar(450)", nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
DiscountedAmount = table.Column<decimal>(type: "decimal(20,8)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EasyAbpEShopOrdersOrderDiscounts", x => new { x.OrderId, x.OrderLineId, x.Name, x.Key });
table.ForeignKey(
name: "FK_EasyAbpEShopOrdersOrderDiscounts_EasyAbpEShopOrdersOrders_OrderId",
column: x => x.OrderId,
principalTable: "EasyAbpEShopOrdersOrders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "EasyAbpEShopOrdersOrderDiscounts");
migrationBuilder.DropColumn(
name: "PaymentExpireIn",
table: "EasyAbpEShopProductsProductViews");
migrationBuilder.DropColumn(
name: "DisplayName",
table: "EasyAbpEShopPaymentsRefundItemOrderExtraFees");
migrationBuilder.DropColumn(
name: "DisplayName",
table: "EasyAbpEShopOrdersOrderExtraFees");
}
}
}

57
samples/EShopSample/aspnet-core/src/EShopSample.EntityFrameworkCore/Migrations/EShopSampleDbContextModelSnapshot.cs

@ -607,6 +607,31 @@ namespace EShopSample.Migrations
b.ToTable("EasyAbpEShopOrdersOrders", (string)null);
});
modelBuilder.Entity("EasyAbp.EShop.Orders.Orders.OrderDiscount", b =>
{
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("OrderLineId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.HasColumnType("nvarchar(450)");
b.Property<string>("Key")
.HasColumnType("nvarchar(450)");
b.Property<decimal>("DiscountedAmount")
.HasColumnType("decimal(20,8)");
b.Property<string>("DisplayName")
.HasColumnType("nvarchar(max)");
b.HasKey("OrderId", "OrderLineId", "Name", "Key");
b.ToTable("EasyAbpEShopOrdersOrderDiscounts", (string)null);
});
modelBuilder.Entity("EasyAbp.EShop.Orders.Orders.OrderExtraFee", b =>
{
b.Property<Guid>("OrderId")
@ -618,6 +643,9 @@ namespace EShopSample.Migrations
b.Property<string>("Key")
.HasColumnType("nvarchar(450)");
b.Property<string>("DisplayName")
.HasColumnType("nvarchar(max)");
b.Property<decimal>("Fee")
.HasColumnType("decimal(20,8)");
@ -1066,6 +1094,9 @@ namespace EShopSample.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("DisplayName")
.HasColumnType("nvarchar(max)");
b.Property<string>("Key")
.HasColumnType("nvarchar(max)");
@ -2568,6 +2599,9 @@ namespace EShopSample.Migrations
b.Property<string>("Overview")
.HasColumnType("nvarchar(max)");
b.Property<TimeSpan?>("PaymentExpireIn")
.HasColumnType("time");
b.Property<Guid?>("ProductDetailId")
.HasColumnType("uniqueidentifier");
@ -5708,7 +5742,7 @@ namespace EShopSample.Migrations
.WithMany("Children")
.HasForeignKey("ParentId");
b.OwnsOne("EasyAbp.BookingService.AssetCategories.AssetCategory.TimeInAdvance#EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
b.OwnsOne("EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
{
b1.Property<Guid>("AssetCategoryId")
.HasColumnType("uniqueidentifier");
@ -5727,7 +5761,7 @@ namespace EShopSample.Migrations
b1.HasKey("AssetCategoryId");
b1.ToTable("EasyAbpBookingServiceAssetCategories", (string)null);
b1.ToTable("EasyAbpBookingServiceAssetCategories");
b1.WithOwner()
.HasForeignKey("AssetCategoryId");
@ -5740,7 +5774,7 @@ namespace EShopSample.Migrations
modelBuilder.Entity("EasyAbp.BookingService.AssetSchedules.AssetSchedule", b =>
{
b.OwnsOne("EasyAbp.BookingService.AssetSchedules.AssetSchedule.TimeInAdvance#EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
b.OwnsOne("EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
{
b1.Property<Guid>("AssetScheduleId")
.HasColumnType("uniqueidentifier");
@ -5759,7 +5793,7 @@ namespace EShopSample.Migrations
b1.HasKey("AssetScheduleId");
b1.ToTable("EasyAbpBookingServiceAssetSchedules", (string)null);
b1.ToTable("EasyAbpBookingServiceAssetSchedules");
b1.WithOwner()
.HasForeignKey("AssetScheduleId");
@ -5770,7 +5804,7 @@ namespace EShopSample.Migrations
modelBuilder.Entity("EasyAbp.BookingService.Assets.Asset", b =>
{
b.OwnsOne("EasyAbp.BookingService.Assets.Asset.TimeInAdvance#EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
b.OwnsOne("EasyAbp.BookingService.TimeInAdvance", "TimeInAdvance", b1 =>
{
b1.Property<Guid>("AssetId")
.HasColumnType("uniqueidentifier");
@ -5789,7 +5823,7 @@ namespace EShopSample.Migrations
b1.HasKey("AssetId");
b1.ToTable("EasyAbpBookingServiceAssets", (string)null);
b1.ToTable("EasyAbpBookingServiceAssets");
b1.WithOwner()
.HasForeignKey("AssetId");
@ -5805,6 +5839,15 @@ namespace EShopSample.Migrations
.HasForeignKey("PeriodSchemeId");
});
modelBuilder.Entity("EasyAbp.EShop.Orders.Orders.OrderDiscount", b =>
{
b.HasOne("EasyAbp.EShop.Orders.Orders.Order", null)
.WithMany("OrderDiscounts")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("EasyAbp.EShop.Orders.Orders.OrderExtraFee", b =>
{
b.HasOne("EasyAbp.EShop.Orders.Orders.Order", null)
@ -6203,6 +6246,8 @@ namespace EShopSample.Migrations
modelBuilder.Entity("EasyAbp.EShop.Orders.Orders.Order", b =>
{
b.Navigation("OrderDiscounts");
b.Navigation("OrderExtraFees");
b.Navigation("OrderLines");

Loading…
Cancel
Save