From 29cf960a5ebe9fea205a54580907a331e1578516 Mon Sep 17 00:00:00 2001 From: gdlcf88 Date: Wed, 15 Jun 2022 00:41:51 +0800 Subject: [PATCH] Introduce CurrencyCode setting in the Orders module Resolve #22 --- .../EShop/Orders/Orders/NewOrderGenerator.cs | 33 ++++++---- .../EShop/Orders/Localization/Orders/en.json | 4 +- .../Orders/Localization/Orders/zh-Hans.json | 4 +- .../Orders/Localization/Orders/zh-Hant.json | 4 +- .../OrdersSettingDefinitionProvider.cs | 21 ++++++- .../EShop/Orders/Settings/OrdersSettings.cs | 2 + .../Orders/OrderAppServiceTests.cs | 61 ++++++++++++++++--- 7 files changed, 107 insertions(+), 22 deletions(-) diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs index 102695f6..2ab9a54c 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/NewOrderGenerator.cs @@ -3,14 +3,17 @@ 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 Volo.Abp; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectExtending; +using Volo.Abp.Settings; using Volo.Abp.Timing; namespace EasyAbp.EShop.Orders.Orders @@ -20,6 +23,7 @@ namespace EasyAbp.EShop.Orders.Orders 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; @@ -29,6 +33,7 @@ namespace EasyAbp.EShop.Orders.Orders IClock clock, IGuidGenerator guidGenerator, ICurrentTenant currentTenant, + ISettingProvider settingProvider, IServiceProvider serviceProvider, IOrderNumberGenerator orderNumberGenerator, IProductSkuDescriptionProvider productSkuDescriptionProvider, @@ -37,6 +42,7 @@ namespace EasyAbp.EShop.Orders.Orders _clock = clock; _guidGenerator = guidGenerator; _currentTenant = currentTenant; + _settingProvider = settingProvider; _serviceProvider = serviceProvider; _orderNumberGenerator = orderNumberGenerator; _productSkuDescriptionProvider = productSkuDescriptionProvider; @@ -53,16 +59,17 @@ namespace EasyAbp.EShop.Orders.Orders orderLines.Add(await GenerateOrderLineAsync(input, inputOrderLine, productDict, productDetailDict)); } - var storeCurrency = await GetStoreCurrencyAsync(input.StoreId); + var effectiveCurrency = await GetEffectiveCurrencyAsync(); - if (orderLines.Any(x => x.Currency != storeCurrency)) + if (orderLines.Any(x => x.Currency != effectiveCurrency)) { - throw new UnexpectedCurrencyException(storeCurrency); + throw new UnexpectedCurrencyException(effectiveCurrency); } var productTotalPrice = orderLines.Select(x => x.TotalPrice).Sum(); - - var paymentExpireIn = orderLines.Select(x => productDict[x.ProductId].GetSkuPaymentExpireIn(x.ProductSkuId)).Min(); + + var paymentExpireIn = orderLines.Select(x => productDict[x.ProductId].GetSkuPaymentExpireIn(x.ProductSkuId)) + .Min(); var totalPrice = productTotalPrice; var totalDiscount = orderLines.Select(x => x.TotalDiscount).Sum(); @@ -72,7 +79,7 @@ namespace EasyAbp.EShop.Orders.Orders tenantId: _currentTenant.Id, storeId: input.StoreId, customerUserId: customerUserId, - currency: storeCurrency, + currency: effectiveCurrency, productTotalPrice: productTotalPrice, totalDiscount: totalDiscount, totalPrice: totalPrice, @@ -124,7 +131,7 @@ namespace EasyAbp.EShop.Orders.Orders } var unitPrice = await GetUnitPriceAsync(input, inputOrderLine, product, productSku); - + var totalPrice = unitPrice * inputOrderLine.Quantity; var orderLine = new OrderLine( @@ -148,7 +155,7 @@ namespace EasyAbp.EShop.Orders.Orders actualTotalPrice: totalPrice, quantity: inputOrderLine.Quantity ); - + inputOrderLine.MapExtraPropertiesTo(orderLine, MappingPropertyDefinitionChecks.Destination); return orderLine; @@ -171,10 +178,14 @@ namespace EasyAbp.EShop.Orders.Orders return productSku.Price; } - protected virtual Task GetStoreCurrencyAsync(Guid storeId) + protected virtual async Task GetEffectiveCurrencyAsync() { - // Todo: Get real store currency configuration. - return Task.FromResult("USD"); + var currencyCode = Check.NotNullOrWhiteSpace( + await _settingProvider.GetOrNullAsync(OrdersSettings.CurrencyCode), + nameof(OrdersSettings.CurrencyCode) + ); + + return currencyCode; } } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json index 55b6b7c6..67aa9901 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/en.json @@ -53,6 +53,8 @@ "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", + "DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "Currency code", + "Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 code (see https://en.wikipedia.org/wiki/ISO_4217)" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json index 515b4ce9..00245f2f 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hans.json @@ -53,6 +53,8 @@ "EasyAbp.EShop.Orders:InvalidRefundAmount": "退款金额({amount})无效", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款数量({quantity})无效", "EasyAbp.EShop.Orders:OrderIsInWrongStage": "订单{orderId}处于错误的阶段", - "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清单中不允许存在闪购产品" + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清单中不允许存在闪购产品", + "DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "货币代码", + "Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 货币代码 (详见 https://en.wikipedia.org/wiki/ISO_4217)" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json index 63e4fc76..6529af18 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain.Shared/EasyAbp/EShop/Orders/Localization/Orders/zh-Hant.json @@ -53,6 +53,8 @@ "EasyAbp.EShop.Orders:InvalidRefundAmount": "退款金額({amount})無效", "EasyAbp.EShop.Orders:InvalidRefundQuantity": "退款數量({quantity})無效", "EasyAbp.EShop.Orders:OrderIsInWrongStage": "訂單{orderId}處於錯誤的階段", - "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清單中不允許存在閃購產品" + "EasyAbp.EShop.Orders:ExistFlashSalesProduct": "清單中不允許存在閃購產品", + "DisplayName:EasyAbp.EShop.Orders.CurrencyCode": "貨幣代碼", + "Description:EasyAbp.EShop.Orders.CurrencyCode": "ISO 4217 貨幣代碼 (詳見 https://en.wikipedia.org/wiki/ISO_4217)" } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettingDefinitionProvider.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettingDefinitionProvider.cs index 92d73790..3ae499ef 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettingDefinitionProvider.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettingDefinitionProvider.cs @@ -1,14 +1,33 @@ -using Volo.Abp.Settings; +using EasyAbp.EShop.Orders.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Settings; namespace EasyAbp.EShop.Orders.Settings { public class OrdersSettingDefinitionProvider : SettingDefinitionProvider { + public static string DefaultCurrency { get; set; } = "USD"; + public override void Define(ISettingDefinitionContext context) { /* Define module settings here. * Use names from OrdersSettings class. */ + + context.Add( + new SettingDefinition( + OrdersSettings.CurrencyCode, + DefaultCurrency, + L($"DisplayName:{OrdersSettings.CurrencyCode}"), + L($"Description:{OrdersSettings.CurrencyCode}"), + isVisibleToClients: true + ) + ); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); } } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettings.cs b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettings.cs index a37c170e..f6646bb1 100644 --- a/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettings.cs +++ b/modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Domain/EasyAbp/EShop/Orders/Settings/OrdersSettings.cs @@ -7,5 +7,7 @@ /* Add constants for setting names. Example: * public const string MySettingName = GroupName + ".MySettingName"; */ + + public const string CurrencyCode = GroupName + ".CurrencyCode"; } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs index 2d507b7b..bc99825f 100644 --- a/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs +++ b/modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs @@ -3,6 +3,7 @@ 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; using EasyAbp.EShop.Products.ProductDetails.Dtos; using EasyAbp.EShop.Products.Products; @@ -12,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; using Volo.Abp; +using Volo.Abp.Settings; using Volo.Abp.Timing; using Xunit; @@ -532,17 +534,62 @@ namespace EasyAbp.EShop.Orders.Orders } }; - Product1.InventoryStrategy = InventoryStrategy.FlashSales; + try + { + Product1.InventoryStrategy = InventoryStrategy.FlashSales; - await WithUnitOfWorkAsync(async () => + await WithUnitOfWorkAsync(async () => + { + var exception = + await Should.ThrowAsync(() => _orderAppService.CreateAsync(createOrderDto)); + + exception.Code.ShouldBe(OrdersErrorCodes.ExistFlashSalesProduct); + }); + + Product1.InventoryStrategy = InventoryStrategy.NoNeed; + } + catch { - var exception = - await Should.ThrowAsync(() => _orderAppService.CreateAsync(createOrderDto)); + Product1.InventoryStrategy = InventoryStrategy.NoNeed; + throw; + } + } - exception.Code.ShouldBe(OrdersErrorCodes.ExistFlashSalesProduct); - }); + [Fact] + public async Task Should_Throw_If_Product_Sku_Uses_Unexpected_Currency() + { + var createOrderDto = new CreateOrderDto + { + StoreId = OrderTestData.Store1Id, + OrderLines = new List + { + new() + { + ProductId = OrderTestData.Product1Id, + ProductSkuId = OrderTestData.ProductSku1Id, + Quantity = 1 + } + } + }; + + try + { + OrdersSettingDefinitionProvider.DefaultCurrency = "CNY"; // The effective value is "USD" + await WithUnitOfWorkAsync(async () => + { + var exception = + await Should.ThrowAsync(() => _orderAppService.CreateAsync(createOrderDto)); - Product1.InventoryStrategy = InventoryStrategy.NoNeed; + exception.Code.ShouldBe(OrdersErrorCodes.UnexpectedCurrency); + }); + + OrdersSettingDefinitionProvider.DefaultCurrency = "USD"; + } + catch + { + OrdersSettingDefinitionProvider.DefaultCurrency = "USD"; + throw; + } } } } \ No newline at end of file