Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce CurrencyCode setting in the Orders module #178

Merged
merged 2 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
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
Expand All @@ -20,6 +23,7 @@ public class NewOrderGenerator : 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;
Expand All @@ -29,6 +33,7 @@ public NewOrderGenerator(
IClock clock,
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant,
ISettingProvider settingProvider,
IServiceProvider serviceProvider,
IOrderNumberGenerator orderNumberGenerator,
IProductSkuDescriptionProvider productSkuDescriptionProvider,
Expand All @@ -37,6 +42,7 @@ public NewOrderGenerator(
_clock = clock;
_guidGenerator = guidGenerator;
_currentTenant = currentTenant;
_settingProvider = settingProvider;
_serviceProvider = serviceProvider;
_orderNumberGenerator = orderNumberGenerator;
_productSkuDescriptionProvider = productSkuDescriptionProvider;
Expand All @@ -53,16 +59,17 @@ public virtual async Task<Order> GenerateAsync(Guid customerUserId, CreateOrderD
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();
Expand All @@ -72,7 +79,7 @@ public virtual async Task<Order> GenerateAsync(Guid customerUserId, CreateOrderD
tenantId: _currentTenant.Id,
storeId: input.StoreId,
customerUserId: customerUserId,
currency: storeCurrency,
currency: effectiveCurrency,
productTotalPrice: productTotalPrice,
totalDiscount: totalDiscount,
totalPrice: totalPrice,
Expand Down Expand Up @@ -124,7 +131,7 @@ protected virtual async Task<OrderLine> GenerateOrderLineAsync(CreateOrderDto in
}

var unitPrice = await GetUnitPriceAsync(input, inputOrderLine, product, productSku);

var totalPrice = unitPrice * inputOrderLine.Quantity;

var orderLine = new OrderLine(
Expand All @@ -148,7 +155,7 @@ protected virtual async Task<OrderLine> GenerateOrderLineAsync(CreateOrderDto in
actualTotalPrice: totalPrice,
quantity: inputOrderLine.Quantity
);

inputOrderLine.MapExtraPropertiesTo(orderLine, MappingPropertyDefinitionChecks.Destination);

return orderLine;
Expand All @@ -171,10 +178,14 @@ protected virtual async Task<decimal> GetUnitPriceAsync(CreateOrderDto input, Cr
return productSku.Price;
}

protected virtual Task<string> GetStoreCurrencyAsync(Guid storeId)
protected virtual async Task<string> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
}
}
Original file line number Diff line number Diff line change
@@ -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<OrdersResource>(name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public static class OrdersSettings
/* Add constants for setting names. Example:
* public const string MySettingName = GroupName + ".MySettingName";
*/

public const string CurrencyCode = GroupName + ".CurrencyCode";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand All @@ -12,6 +13,7 @@
using NSubstitute;
using Shouldly;
using Volo.Abp;
using Volo.Abp.Settings;
using Volo.Abp.Timing;
using Xunit;

Expand Down Expand Up @@ -532,17 +534,62 @@ public async Task Should_Not_Create_Order_With_Flash_Sales_Products()
}
};

Product1.InventoryStrategy = InventoryStrategy.FlashSales;
try
{
Product1.InventoryStrategy = InventoryStrategy.FlashSales;

await WithUnitOfWorkAsync(async () =>
await WithUnitOfWorkAsync(async () =>
{
var exception =
await Should.ThrowAsync<BusinessException>(() => _orderAppService.CreateAsync(createOrderDto));

exception.Code.ShouldBe(OrdersErrorCodes.ExistFlashSalesProduct);
});

Product1.InventoryStrategy = InventoryStrategy.NoNeed;
}
catch
{
var exception =
await Should.ThrowAsync<BusinessException>(() => _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<CreateOrderLineDto>
{
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<BusinessException>(() => _orderAppService.CreateAsync(createOrderDto));

Product1.InventoryStrategy = InventoryStrategy.NoNeed;
exception.Code.ShouldBe(OrdersErrorCodes.UnexpectedCurrency);
});

OrdersSettingDefinitionProvider.DefaultCurrency = "USD";
}
catch
{
OrdersSettingDefinitionProvider.DefaultCurrency = "USD";
throw;
}
}
}
}