Browse Source

Improve FlashSales

pull/184/head
Jadyn 4 years ago
parent
commit
50b59e6de2
  1. 4
      plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationModule.cs
  2. 66
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppService.cs
  3. 5
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanTokenCacheItem.cs
  4. 7
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/RollBackInventoryCreateFlashSaleOrderCompleteEventHandler.cs
  5. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanHasher.cs
  6. 2
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesErrorCodes.cs
  7. 1
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/en.json
  8. 1
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hans.json
  9. 1
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hant.json
  10. 14
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs
  11. 12
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultStatusNotPendingException.cs

4
plugins/FlashSales/src/EasyAbp.EShop.Orders.Plugins.FlashSales.Application/EasyAbp/EShop/Orders/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationModule.cs

@ -1,7 +1,5 @@
using EasyAbp.EShop.Orders.Orders;
using EasyAbp.EShop.Plugins.FlashSales;
using EasyAbp.EShop.Plugins.FlashSales;
using EasyAbp.EShop.Products;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;

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

@ -29,6 +29,21 @@ public class FlashSalePlanAppService :
MultiStoreCrudAppService<FlashSalePlan, FlashSalePlanDto, Guid, FlashSalePlanGetListInput, FlashSalePlanCreateDto, FlashSalePlanUpdateDto>,
IFlashSalePlanAppService
{
/// <summary>
/// The <see cref="GetPreOrderCacheKeyAsync(FlashSalePlanCacheItem)"/> cache key format.
/// <para>{0}: FlashSalePlan ID</para>
/// <para>{1}: User ID</para>
/// </summary>
public const string PreOrderCacheKeyFormat = "eshopflashsales_{0}_{1}";
/// <summary>
/// The <see cref="GetUserFlashSaleResultCacheKeyAsync(FlashSalePlanCacheItem,Guid)"/> cache key format.
/// <para>{0}: Tenant ID</para>
/// <para>{1}: FlashSalePlan ID</para>
/// <para>{2}: User ID</para>
/// </summary>
public const string UserFlashSaleResultCacheKeyFormat = "eshopflashsales-result_{0}_{1}_{2}";
protected override string CrossStorePolicyName { get; set; } = FlashSalesPermissions.FlashSalePlan.CrossStore;
protected override string GetPolicyName { get; set; }
protected override string GetListPolicyName { get; set; }
@ -203,6 +218,12 @@ public class FlashSalePlanAppService :
public virtual async Task<bool> OrderAsync(Guid id, CreateOrderInput input)
{
var preOrderCache = await GetPreOrderCacheAsync(id);
if (preOrderCache == null)
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExpired);
}
var plan = await GetFlashSalePlanCacheAsync(id);
var now = Clock.Now;
if (plan.BeginTime > now)
@ -215,13 +236,7 @@ public class FlashSalePlanAppService :
throw new BusinessException(FlashSalesErrorCodes.FlashSaleIsOver);
}
var preOrderCache = await GetPreOrderCacheAsync(plan);
if (preOrderCache == null)
{
throw new BusinessException(FlashSalesErrorCodes.PreOrderExpired);
}
await RemovePreOrderCacheAsync(plan);
await RemovePreOrderCacheAsync(id);
var userId = CurrentUser.GetId();
@ -234,7 +249,7 @@ public class FlashSalePlanAppService :
throw new BusinessException(FlashSalesErrorCodes.BusyToCreateFlashSaleOrder);
}
var userFlashSaleResultCache = await GetUserFlashSaleResultCacheAsync(plan, userId);
var userFlashSaleResultCache = await GetUserFlashSaleResultCacheAsync(plan.Id);
if (!userFlashSaleResultCache.IsNullOrWhiteSpace())
{
throw new BusinessException(FlashSalesErrorCodes.DuplicateFlashSalesOrder);
@ -249,7 +264,7 @@ public class FlashSalePlanAppService :
var result = await CreatePendingFlashSaleResultAsync(plan, userId, async (existsResultId) =>
{
await SetUserFlashSaleResultCacheAsync(plan, userId, existsResultId);
await SetUserFlashSaleResultCacheAsync(plan.Id, existsResultId);
await FlashSaleInventoryManager.TryRollBackInventoryAsync(
plan.TenantId, preOrderCache.InventoryProviderName,
@ -257,7 +272,7 @@ public class FlashSalePlanAppService :
);
});
await SetUserFlashSaleResultCacheAsync(plan, userId, result.Id);
await SetUserFlashSaleResultCacheAsync(plan.Id, result.Id);
var createFlashSaleOrderEto = await PrepareCreateFlashSaleOrderEtoAsync(plan, result.Id, input, userId, now, preOrderCache.HashToken);
@ -277,26 +292,26 @@ public class FlashSalePlanAppService :
});
}
protected virtual Task<string> GetPreOrderCacheKeyAsync(FlashSalePlanCacheItem plan)
protected virtual Task<string> GetPreOrderCacheKeyAsync(Guid planId)
{
return Task.FromResult($"eshopflashsales_{CurrentTenant.Id}_{CurrentUser.Id}_{plan.ProductSkuId}");
return Task.FromResult(string.Format(PreOrderCacheKeyFormat, planId, CurrentUser.Id));
}
protected virtual async Task<FlashSalePlanPreOrderCacheItem> GetPreOrderCacheAsync(FlashSalePlanCacheItem plan)
protected virtual async Task<FlashSalePlanPreOrderCacheItem> GetPreOrderCacheAsync(Guid planId)
{
return await PreOrderDistributedCache.GetAsync(await GetPreOrderCacheKeyAsync(plan));
return await PreOrderDistributedCache.GetAsync(await GetPreOrderCacheKeyAsync(planId));
}
protected virtual async Task RemovePreOrderCacheAsync(FlashSalePlanCacheItem plan)
protected virtual async Task RemovePreOrderCacheAsync(Guid planId)
{
await PreOrderDistributedCache.RemoveAsync(await GetPreOrderCacheKeyAsync(plan));
await PreOrderDistributedCache.RemoveAsync(await GetPreOrderCacheKeyAsync(planId));
}
protected virtual async Task SetPreOrderCacheAsync(FlashSalePlanCacheItem plan, ProductDto product, ProductSkuDto productSku, DateTimeOffset expirationTime)
{
var hashToken = await FlashSalePlanHasher.HashAsync(plan.LastModificationTime, product.LastModificationTime, productSku.LastModificationTime);
await PreOrderDistributedCache.SetAsync(await GetPreOrderCacheKeyAsync(plan), new FlashSalePlanPreOrderCacheItem()
await PreOrderDistributedCache.SetAsync(await GetPreOrderCacheKeyAsync(plan.Id), new FlashSalePlanPreOrderCacheItem()
{
HashToken = hashToken,
PlanId = plan.Id,
@ -313,20 +328,20 @@ public class FlashSalePlanAppService :
#region UserFlashSaleResultCache
protected virtual Task<string> GetUserFlashSaleResultCacheKeyAsync(FlashSalePlanCacheItem plan, Guid userId)
protected virtual Task<string> GetUserFlashSaleResultCacheKeyAsync(Guid planId)
{
return Task.FromResult($"flash-sale-result-{plan.Id}-{userId}");
return Task.FromResult(string.Format(UserFlashSaleResultCacheKeyFormat, CurrentTenant.Id, planId, CurrentUser.GetId()));
}
protected virtual async Task<string> GetUserFlashSaleResultCacheAsync(FlashSalePlanCacheItem plan, Guid userId)
protected virtual async Task<string> GetUserFlashSaleResultCacheAsync(Guid planId)
{
var userFlashSaleResultCacheKey = await GetUserFlashSaleResultCacheKeyAsync(plan, userId);
var userFlashSaleResultCacheKey = await GetUserFlashSaleResultCacheKeyAsync(planId);
return await DistributedCache.GetStringAsync(userFlashSaleResultCacheKey);
}
protected virtual async Task SetUserFlashSaleResultCacheAsync(FlashSalePlanCacheItem plan, Guid userId, Guid resultId)
protected virtual async Task SetUserFlashSaleResultCacheAsync(Guid planId, Guid resultId)
{
var userFlashSaleResultCacheKey = await GetUserFlashSaleResultCacheKeyAsync(plan, userId);
var userFlashSaleResultCacheKey = await GetUserFlashSaleResultCacheKeyAsync(planId);
await DistributedCache.SetStringAsync(userFlashSaleResultCacheKey, resultId.ToString());
}
@ -427,10 +442,7 @@ public class FlashSalePlanAppService :
tenantId: CurrentTenant.Id,
storeId: plan.StoreId,
planId: plan.Id,
status: FlashSaleResultStatus.Pending,
reason: null,
userId: userId,
orderId: null
userId: userId
);
return await FlashSaleResultRepository.InsertAsync(result, autoSave: true);

5
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanTokenCacheItem.cs

@ -1,10 +1,13 @@
using System;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans;
[Serializable]
public class FlashSalePlanPreOrderCacheItem
public class FlashSalePlanPreOrderCacheItem : IMultiTenant
{
public Guid? TenantId { get; set; }
public string HashToken { get; set; }
public Guid PlanId { get; set; }

7
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/RollBackInventoryCreateFlashSaleOrderCompleteEventHandler.cs

@ -7,7 +7,6 @@ using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans;
@ -23,12 +22,14 @@ public class RollBackInventoryCreateFlashSaleOrderCompleteEventHandler : IDistri
IFlashSaleInventoryManager flashSaleInventoryManager,
IDistributedCache distributedCache,
IFlashSalePlanRepository flashSalePlanRepository,
IProductAppService productAppService)
IProductAppService productAppService,
ILogger<RollBackInventoryCreateFlashSaleOrderCompleteEventHandler> logger)
{
FlashSaleInventoryManager = flashSaleInventoryManager;
DistributedCache = distributedCache;
FlashSalePlanRepository = flashSalePlanRepository;
ProductAppService = productAppService;
Logger = logger;
}
public virtual async Task HandleEventAsync(CreateFlashSaleOrderCompleteEto eventData)
@ -60,7 +61,7 @@ public class RollBackInventoryCreateFlashSaleOrderCompleteEventHandler : IDistri
protected virtual Task<string> GetUserFlashSaleResultCacheKeyAsync(FlashSalePlan plan, Guid userId)
{
return Task.FromResult($"flash-sale-result-{plan.Id}-{userId}");
return Task.FromResult(string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, userId));
}
protected virtual async Task RemoveUserFlashSaleResultCacheAsync(FlashSalePlan plan, Guid userId)

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanHasher.cs

@ -10,7 +10,7 @@ public class FlashSalePlanHasher : IFlashSalePlanHasher, ITransientDependency
{
public virtual Task<string> HashAsync(DateTime? planLastModificationTime, DateTime? productLastModificationTime, DateTime? productSkuLastModificationTime)
{
var input = $"{planLastModificationTime}|{productLastModificationTime}|{productSkuLastModificationTime}";
var input = $"{planLastModificationTime?.Ticks}|{productLastModificationTime?.Ticks}|{productSkuLastModificationTime?.Ticks}";
return Task.FromResult(CreateMd5(input));
}

2
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/FlashSalesErrorCodes.cs

@ -27,4 +27,6 @@ public static class FlashSalesErrorCodes
public const string DuplicateFlashSalesOrder = $"{Namespace}:{nameof(DuplicateFlashSalesOrder)}";
public const string RelatedFlashSaleResultsExist = $"{Namespace}:{nameof(RelatedFlashSaleResultsExist)}";
public const string FlashSaleResultStatusNotPending = $"{Namespace}:{nameof(FlashSaleResultStatusNotPending)}";
}

1
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/en.json

@ -13,6 +13,7 @@
"EasyAbp.EShop.Plugins.FlashSales:BusyToCreateFlashSaleOrder": "Busy to create flash-sale order",
"EasyAbp.EShop.Plugins.FlashSales:DuplicateFlashSalesOrder": "Duplicate flash-sales order",
"EasyAbp.EShop.Plugins.FlashSales:RelatedFlashSaleResultsExist": "Related flash-sales results exist",
"EasyAbp.EShop.Plugins.FlashSales:FlashSaleResultStatusNotPending": "The status of flash-sale result has been changed",
"Menu:FlashSalesManagement": "Flash-Sales Management",
"Permission:FlashSalePlan": "FlashSale Plan",
"Permission:Manage": "Manage",

1
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hans.json

@ -13,6 +13,7 @@
"EasyAbp.EShop.Plugins.FlashSales:BusyToCreateFlashSaleOrder": "闪购下单繁忙",
"EasyAbp.EShop.Plugins.FlashSales:DuplicateFlashSalesOrder": "重复闪购下单",
"EasyAbp.EShop.Plugins.FlashSales:RelatedFlashSaleResultsExist": "已存在关联的闪购结果",
"EasyAbp.EShop.Plugins.FlashSales:FlashSaleResultStatusNotPending": "闪购结果的状态已经变更",
"Menu:FlashSalesManagement": "闪购",
"Permission:FlashSalePlan": "闪购计划",
"Permission:Manage": "管理",

1
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain.Shared/EasyAbp/EShop/Plugins/FlashSales/Localization/zh-Hant.json

@ -13,6 +13,7 @@
"EasyAbp.EShop.Plugins.FlashSales:BusyToCreateFlashSaleOrder": "閃購下單繁忙",
"EasyAbp.EShop.Plugins.FlashSales:DuplicateFlashSalesOrder": "重複閃購下單",
"EasyAbp.EShop.Plugins.FlashSales:RelatedFlashSaleResultsExist": "已存在關聯的閃購結果",
"EasyAbp.EShop.Plugins.FlashSales:FlashSaleResultStatusNotPending": "閃購結果的状态已經變更",
"Menu:FlashSalesManagement": "閃購管理",
"Permission:FlashSalePlan": "閃購計畫",
"Permission:Manage": "管理",

14
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResult.cs

@ -24,26 +24,32 @@ public class FlashSaleResult : FullAuditedAggregateRoot<Guid>, IMultiTenant, IMu
protected FlashSaleResult() { }
public FlashSaleResult(Guid id, Guid? tenantId, Guid storeId, Guid planId, FlashSaleResultStatus status, string reason, Guid userId, Guid? orderId)
public FlashSaleResult(Guid id, Guid? tenantId, Guid storeId, Guid planId, Guid userId)
: base(id)
{
TenantId = tenantId;
StoreId = storeId;
PlanId = planId;
Status = status;
Reason = reason;
Status = FlashSaleResultStatus.Pending;
UserId = userId;
OrderId = orderId;
}
public void MarkAsSuccessful(Guid orderId)
{
if (Status != FlashSaleResultStatus.Pending)
{
throw new FlashSaleResultStatusNotPendingException(Id);
}
Status = FlashSaleResultStatus.Successful;
OrderId = orderId;
}
public void MarkAsFailed(string reason)
{
if (Status != FlashSaleResultStatus.Pending)
{
throw new FlashSaleResultStatusNotPendingException(Id);
}
Status = FlashSaleResultStatus.Failed;
Reason = Check.NotNullOrEmpty(reason, nameof(reason));
}

12
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Domain/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultStatusNotPendingException.cs

@ -0,0 +1,12 @@
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults;
public class FlashSaleResultStatusNotPendingException : BusinessException
{
public FlashSaleResultStatusNotPendingException(Guid resultId) : base(FlashSalesErrorCodes.FlashSaleResultStatusNotPending)
{
WithData(nameof(resultId), resultId);
}
}
Loading…
Cancel
Save