mirror of https://github.com/EasyAbp/EShop.git
38 changed files with 632 additions and 440 deletions
@ -1,36 +0,0 @@ |
|||
using AutoMapper; |
|||
using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
using EasyAbp.EShop.Products.ProductDetails.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Plugins.FlashSales |
|||
{ |
|||
public class EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile : Profile |
|||
{ |
|||
public EShopOrdersPluginsFlashSalesApplicationAutoMapperProfile() |
|||
{ |
|||
/* You can configure your AutoMapper mapping configuration here. |
|||
* Alternatively, you can split your mapping configurations |
|||
* into multiple profile classes for a better organization. */ |
|||
CreateMap<FlashSaleProductEto, ProductDto>(MemberList.Destination) |
|||
.Ignore(dto => dto.Sold) |
|||
.Ignore(dto => dto.MinimumPrice) |
|||
.Ignore(dto => dto.MaximumPrice) |
|||
.MapExtraProperties(); |
|||
CreateMap<FlashSaleProductSkuEto, ProductSkuDto>(MemberList.Destination) |
|||
.ForSourceMember(entity => entity.SerializedAttributeOptionIds, opt => opt.DoNotValidate()) |
|||
.Ignore(dto => dto.DiscountedPrice) |
|||
.Ignore(dto => dto.Inventory) |
|||
.Ignore(dto => dto.Sold) |
|||
.MapExtraProperties(); |
|||
CreateMap<FlashSaleProductAttributeEto, ProductAttributeDto>(MemberList.Destination) |
|||
.MapExtraProperties(); |
|||
CreateMap<FlashSaleProductAttributeOptionEto, ProductAttributeOptionDto>(MemberList.Destination) |
|||
.MapExtraProperties(); |
|||
CreateMap<FlashSaleProductDetailEto, ProductDetailDto>(MemberList.Destination) |
|||
.MapExtraProperties(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSalePlanPreOrderCacheItem |
|||
{ |
|||
public string HashToken { get; set; } |
|||
|
|||
public Guid PlanId { get; set; } |
|||
|
|||
public Guid ProductId { get; set; } |
|||
|
|||
public Guid ProductSkuId { get; set; } |
|||
|
|||
public string InventoryProviderName { get; set; } |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.Eshop.Products.Products; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
[ExposeServices(typeof(IFlashSaleInventoryManager), IncludeSelf = true)] |
|||
[Dependency(TryRegister = true)] |
|||
public class FlashSaleInventoryManager : IFlashSaleInventoryManager, ITransientDependency |
|||
{ |
|||
protected IFlashSaleInventoryAppService FlashSaleInventoryReducerAppService { get; } |
|||
|
|||
public FlashSaleInventoryManager(IFlashSaleInventoryAppService flashSaleInventoryReducerAppService) |
|||
{ |
|||
FlashSaleInventoryReducerAppService = flashSaleInventoryReducerAppService; |
|||
} |
|||
|
|||
public virtual async Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, |
|||
Guid productSkuId, int quantity, bool increaseSold) |
|||
{ |
|||
return await FlashSaleInventoryReducerAppService.TryReduceInventoryAsync( |
|||
new ReduceInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, increaseSold)); |
|||
} |
|||
|
|||
public virtual async Task<bool> TryIncreaseInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, |
|||
Guid productSkuId, int quantity, bool decreaseSold) |
|||
{ |
|||
return await FlashSaleInventoryReducerAppService.TryIncreaseInventoryAsync |
|||
(new IncreaseInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, decreaseSold)); |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using EasyAbp.EShop.Products.Products; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleProductAttributeEto : FullAuditedEntityEto<Guid>, IProductAttribute |
|||
{ |
|||
public string DisplayName { get; set; } |
|||
|
|||
public string Description { get; set; } |
|||
|
|||
public int DisplayOrder { get; set; } |
|||
|
|||
public List<FlashSaleProductAttributeOptionEto> ProductAttributeOptions { get; set; } |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using EasyAbp.EShop.Products.Products; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleProductAttributeOptionEto : FullAuditedEntityEto<Guid>, IProductAttributeOption |
|||
{ |
|||
public string DisplayName { get; set; } |
|||
|
|||
public string Description { get; set; } |
|||
|
|||
public int DisplayOrder { get; set; } |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleProductDetailEto : FullAuditedEntityEto<Guid>, IMultiTenant |
|||
{ |
|||
public Guid? TenantId { get; set; } |
|||
|
|||
public Guid? StoreId { get; set; } |
|||
|
|||
public string Description { get; set; } |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using EasyAbp.EShop.Products.Products; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleProductEto : FullAuditedEntityEto<Guid>, IProduct, IMultiTenant |
|||
{ |
|||
public Guid? TenantId { get; set; } |
|||
|
|||
public Guid StoreId { get; set; } |
|||
|
|||
public string ProductGroupName { get; set; } |
|||
|
|||
public string ProductGroupDisplayName { get; set; } |
|||
|
|||
public Guid? ProductDetailId { get; set; } |
|||
|
|||
public string UniqueName { get; set; } |
|||
|
|||
public string DisplayName { get; set; } |
|||
|
|||
public InventoryStrategy InventoryStrategy { get; set; } |
|||
|
|||
public string InventoryProviderName { get; set; } |
|||
|
|||
public string MediaResources { get; set; } |
|||
|
|||
public int DisplayOrder { get; set; } |
|||
|
|||
public bool IsPublished { get; set; } |
|||
|
|||
public bool IsStatic { get; set; } |
|||
|
|||
public bool IsHidden { get; set; } |
|||
|
|||
public TimeSpan? PaymentExpireIn { get; set; } |
|||
|
|||
public List<FlashSaleProductAttributeEto> ProductAttributes { get; set; } |
|||
|
|||
public List<FlashSaleProductSkuEto> ProductSkus { get; set; } |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using EasyAbp.EShop.Products.Products; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleProductSkuEto : FullAuditedEntityEto<Guid>, IProductSku |
|||
{ |
|||
public List<Guid> AttributeOptionIds { get; set; } |
|||
|
|||
public string SerializedAttributeOptionIds { get; set; } |
|||
|
|||
public string Name { get; set; } |
|||
|
|||
public string Currency { get; set; } |
|||
|
|||
public decimal? OriginalPrice { get; set; } |
|||
|
|||
public decimal Price { get; set; } |
|||
|
|||
public int OrderMinQuantity { get; set; } |
|||
|
|||
public int OrderMaxQuantity { get; set; } |
|||
|
|||
public TimeSpan? PaymentExpireIn { get; set; } |
|||
|
|||
public string MediaResources { get; set; } |
|||
|
|||
public Guid? ProductDetailId { get; set; } |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.ObjectExtending; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
|
|||
[Serializable] |
|||
public class FlashSaleReduceInventoryEto : ExtensibleObject, IMultiTenant |
|||
{ |
|||
public Guid? TenantId { get; set; } |
|||
|
|||
public Guid StoreId { get; set; } |
|||
|
|||
public Guid PlanId { get; set; } |
|||
|
|||
public Guid UserId { get; set; } |
|||
|
|||
public Guid PendingResultId { get; set; } |
|||
|
|||
public DateTime CreateTime { get; set; } |
|||
|
|||
public string CustomerRemark { get; set; } |
|||
|
|||
public FlashSalePlanEto Plan { get; set; } |
|||
|
|||
public string HashToken { get; set; } |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,11 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace EasyAbp.EShop.Products.Plugins.FlashSales; |
|||
|
|||
[DependsOn( |
|||
typeof(EShopProductsApplicationContractsModule) |
|||
)] |
|||
public class EShopProductsPluginsFlashSalesAbstractionsModule : AbpModule |
|||
{ |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace EasyAbp.Eshop.Products.Products; |
|||
|
|||
public interface IFlashSaleInventoryManager |
|||
{ |
|||
Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold); |
|||
|
|||
Task<bool> TryIncreaseInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold); |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,14 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,10 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace EasyAbp.EShop.Products.Plugins.FlashSales; |
|||
|
|||
[DependsOn( |
|||
typeof(EShopProductsApplicationContractsModule) |
|||
)] |
|||
public class EShopProductsPluginsFlashSalesApplicationContractsModule : AbpModule |
|||
{ |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using EasyAbp.EShop.Products.Localization; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace EasyAbp.EShop.Products.Permissions |
|||
{ |
|||
public class ProductsPluginsFlashSalesPermissionDefinitionProvider : PermissionDefinitionProvider |
|||
{ |
|||
public override void Define(IPermissionDefinitionContext context) |
|||
{ |
|||
var moduleGroup = context.AddGroup(ProductsPluginsFlashSalesPermissions.GroupName, L("Permission:Products")); |
|||
|
|||
var flashSaleInventoryPermission = moduleGroup.AddPermission(ProductsPluginsFlashSalesPermissions.FlashSaleInventory.Default, L("Permission:FlashSaleInventory")) |
|||
.WithProviders(ClientPermissionValueProvider.ProviderName); |
|||
flashSaleInventoryPermission.AddChild(ProductsPluginsFlashSalesPermissions.FlashSaleInventory.Increase, L("Permission:InventoryIncrease")) |
|||
.WithProviders(ClientPermissionValueProvider.ProviderName); |
|||
flashSaleInventoryPermission.AddChild(ProductsPluginsFlashSalesPermissions.FlashSaleInventory.Reduce, L("Permission:InventoryReduce")) |
|||
.WithProviders(ClientPermissionValueProvider.ProviderName); |
|||
} |
|||
|
|||
private static LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<ProductsResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace EasyAbp.EShop.Products.Permissions |
|||
{ |
|||
public class ProductsPluginsFlashSalesPermissions |
|||
{ |
|||
public const string GroupName = "EasyAbp.EShop.Products.Plugins.FlashSales"; |
|||
|
|||
public class FlashSaleInventory |
|||
{ |
|||
public const string Default = GroupName + ".FlashSaleInventory"; |
|||
public const string Reduce = Default + ".Reduce"; |
|||
public const string Increase = Default + ".Increase"; |
|||
} |
|||
|
|||
public static string[] GetAll() |
|||
{ |
|||
return ReflectionHelper.GetPublicConstantsRecursively(typeof(ProductsPluginsFlashSalesPermissions)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System; |
|||
using EasyAbp.EShop.Stores.Stores; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
public class IncreaseInventoryInput : IMultiTenant, IMultiStore |
|||
{ |
|||
public Guid? TenantId { get; set; } |
|||
|
|||
public string ProviderName { get; set; } |
|||
|
|||
public Guid StoreId { get; set; } |
|||
|
|||
public Guid ProductId { get; set; } |
|||
|
|||
public Guid ProductSkuId { get; set; } |
|||
|
|||
public int Quantity { get; set; } |
|||
|
|||
public bool ReduceSold { get; set; } |
|||
|
|||
public IncreaseInventoryInput() |
|||
{ |
|||
} |
|||
|
|||
public IncreaseInventoryInput(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool reduceSold) |
|||
{ |
|||
TenantId = tenantId; |
|||
ProviderName = providerName; |
|||
StoreId = storeId; |
|||
ProductId = productId; |
|||
ProductSkuId = productSkuId; |
|||
Quantity = quantity; |
|||
ReduceSold = reduceSold; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System; |
|||
using EasyAbp.EShop.Stores.Stores; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
public class ReduceInventoryInput : IMultiTenant, IMultiStore |
|||
{ |
|||
public Guid? TenantId { get; set; } |
|||
|
|||
public string ProviderName { get; set; } |
|||
|
|||
public Guid StoreId { get; set; } |
|||
|
|||
public Guid ProductId { get; set; } |
|||
|
|||
public Guid ProductSkuId { get; set; } |
|||
|
|||
public int Quantity { get; set; } |
|||
|
|||
public bool IncreaseSold { get; set; } |
|||
|
|||
public ReduceInventoryInput() |
|||
{ |
|||
} |
|||
|
|||
public ReduceInventoryInput(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold) |
|||
{ |
|||
TenantId = tenantId; |
|||
ProviderName = providerName; |
|||
StoreId = storeId; |
|||
ProductId = productId; |
|||
ProductSkuId = productSkuId; |
|||
Quantity = quantity; |
|||
IncreaseSold = increaseSold; |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
public interface IFlashSaleInventoryAppService : IApplicationService |
|||
{ |
|||
Task<bool> TryReduceInventoryAsync(ReduceInventoryInput input); |
|||
|
|||
Task<bool> TryIncreaseInventoryAsync(IncreaseInventoryInput input); |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -1,37 +0,0 @@ |
|||
using System.Linq; |
|||
using AutoMapper; |
|||
using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
using EasyAbp.EShop.Products.Options; |
|||
using EasyAbp.EShop.Products.ProductDetails; |
|||
using EasyAbp.EShop.Products.Products; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.FlashSales; |
|||
|
|||
public class EShopProductsPluginsFlashSalesApplicationAutoMapperProfile : Profile, ISingletonDependency |
|||
{ |
|||
public EShopProductsPluginsFlashSalesApplicationAutoMapperProfile( |
|||
IAttributeOptionIdsSerializer attributeOptionIdsSerializer, |
|||
IOptionsMonitor<EShopProductsOptions> options) |
|||
{ |
|||
CreateMap<Product, FlashSaleProductEto>() |
|||
.ForMember(x => x.ProductGroupDisplayName, opt => opt.Ignore()) |
|||
.AfterMap((src, dest) => |
|||
{ |
|||
var dict = options.CurrentValue.Groups.GetConfigurationsDictionary(); |
|||
dest.ProductGroupDisplayName = dict[src.ProductGroupName].DisplayName; |
|||
}) |
|||
.MapExtraProperties(); |
|||
CreateMap<ProductSku, FlashSaleProductSkuEto>() |
|||
.ForMember(x => x.AttributeOptionIds, opt => opt.Ignore()) |
|||
.AfterMap(async (src, dest) => dest.AttributeOptionIds = (await attributeOptionIdsSerializer.DeserializeAsync(src.SerializedAttributeOptionIds)).ToList()) |
|||
.MapExtraProperties(); |
|||
CreateMap<ProductAttribute, FlashSaleProductAttributeEto>() |
|||
.MapExtraProperties(); |
|||
CreateMap<ProductAttributeOption, FlashSaleProductAttributeOptionEto>() |
|||
.MapExtraProperties(); |
|||
CreateMap<ProductDetail, FlashSaleProductDetailEto>() |
|||
.MapExtraProperties(); |
|||
} |
|||
} |
|||
@ -1,28 +1,14 @@ |
|||
using EasyAbp.EShop.Plugins.FlashSales; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace EasyAbp.EShop.Products.Plugins.FlashSales; |
|||
|
|||
[DependsOn( |
|||
typeof(EShopProductsApplicationModule), |
|||
typeof(EShopPluginsFlashSalesApplicationContractsModule) |
|||
typeof(EShopPluginsFlashSalesApplicationContractsModule), |
|||
typeof(EShopProductsPluginsFlashSalesApplicationContractsModule), |
|||
typeof(EShopProductsPluginsFlashSalesAbstractionsModule) |
|||
)] |
|||
public class EShopProductsPluginsFlashSalesApplicationModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAutoMapperObjectMapper<EShopProductsPluginsFlashSalesApplicationModule>(); |
|||
Configure<AbpAutoMapperOptions>(options => |
|||
{ |
|||
options.Configurators.Add(abpAutoMapperConfigurationContext => |
|||
{ |
|||
var profile = abpAutoMapperConfigurationContext.ServiceProvider |
|||
.GetRequiredService<EShopProductsPluginsFlashSalesApplicationAutoMapperProfile>(); |
|||
|
|||
abpAutoMapperConfigurationContext.MapperConfiguration.AddProfile(profile); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,45 @@ |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Products.Permissions; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
public class FlashSaleInventoryAppService : ProductsAppService, IFlashSaleInventoryAppService |
|||
{ |
|||
protected ILocalFlashSaleInventoryManager LocalFlashSaleInventoryReducer { get; } |
|||
|
|||
public FlashSaleInventoryAppService(ILocalFlashSaleInventoryManager localFlashSaleInventoryReducer) |
|||
{ |
|||
LocalFlashSaleInventoryReducer = localFlashSaleInventoryReducer; |
|||
} |
|||
|
|||
public virtual async Task<bool> TryReduceInventoryAsync(ReduceInventoryInput input) |
|||
{ |
|||
await CheckPolicyAsync(ProductsPluginsFlashSalesPermissions.FlashSaleInventory.Reduce); |
|||
|
|||
return await LocalFlashSaleInventoryReducer.TryReduceInventoryAsync( |
|||
input.TenantId, |
|||
input.ProviderName, |
|||
input.StoreId, |
|||
input.ProductId, |
|||
input.ProductSkuId, |
|||
input.Quantity, |
|||
input.IncreaseSold |
|||
); |
|||
} |
|||
|
|||
public virtual async Task<bool> TryIncreaseInventoryAsync(IncreaseInventoryInput input) |
|||
{ |
|||
await CheckPolicyAsync(ProductsPluginsFlashSalesPermissions.FlashSaleInventory.Increase); |
|||
|
|||
return await LocalFlashSaleInventoryReducer.TryIncreaseInventoryAsync( |
|||
input.TenantId, |
|||
input.ProviderName, |
|||
input.StoreId, |
|||
input.ProductId, |
|||
input.ProductSkuId, |
|||
input.Quantity, |
|||
input.ReduceSold |
|||
); |
|||
} |
|||
} |
|||
@ -1,112 +0,0 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; |
|||
using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; |
|||
using EasyAbp.EShop.Products.ProductDetails; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.ObjectMapping; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
public class FlashSaleReduceInventoryEventHandler : IDistributedEventHandler<FlashSaleReduceInventoryEto>, ITransientDependency |
|||
{ |
|||
protected IProductRepository ProductRepository { get; } |
|||
|
|||
protected IProductDetailRepository ProductDetailRepository { get; } |
|||
|
|||
protected ProductManager ProductManager { get; } |
|||
|
|||
protected IDistributedEventBus DistributedEventBus { get; } |
|||
|
|||
protected IObjectMapper ObjectMapper { get; } |
|||
|
|||
protected IFlashSalePlanHasher FlashSalePlanHasher { get; } |
|||
|
|||
public FlashSaleReduceInventoryEventHandler( |
|||
IProductRepository productRepository, |
|||
IProductDetailRepository productDetailRepository, |
|||
ProductManager productManager, |
|||
IDistributedEventBus distributedEventBus, |
|||
IObjectMapper objectMapper, |
|||
IFlashSalePlanHasher flashSalePlanHasher) |
|||
{ |
|||
ProductRepository = productRepository; |
|||
ProductDetailRepository = productDetailRepository; |
|||
ProductManager = productManager; |
|||
DistributedEventBus = distributedEventBus; |
|||
ObjectMapper = objectMapper; |
|||
FlashSalePlanHasher = flashSalePlanHasher; |
|||
} |
|||
|
|||
[UnitOfWork] |
|||
public virtual async Task HandleEventAsync(FlashSaleReduceInventoryEto eventData) |
|||
{ |
|||
var product = await ProductRepository.GetAsync(eventData.Plan.ProductId); |
|||
var productSku = product.ProductSkus.Single(x => x.Id == eventData.Plan.ProductSkuId); |
|||
|
|||
var hashToken = await FlashSalePlanHasher.HashAsync(eventData.Plan.LastModificationTime, product.LastModificationTime, productSku.LastModificationTime); |
|||
|
|||
if (hashToken != eventData.HashToken) |
|||
{ |
|||
await DistributedEventBus.PublishAsync(new CreateFlashSaleOrderCompleteEto() |
|||
{ |
|||
TenantId = eventData.TenantId, |
|||
PlanId = eventData.PlanId, |
|||
OrderId = null, |
|||
UserId = eventData.UserId, |
|||
StoreId = eventData.StoreId, |
|||
PendingResultId = eventData.PendingResultId, |
|||
Success = false, |
|||
Reason = FlashSaleResultFailedReason.PreOrderExipred |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
if (!await ProductManager.TryReduceInventoryAsync(product, productSku, 1, true)) |
|||
{ |
|||
await DistributedEventBus.PublishAsync(new CreateFlashSaleOrderCompleteEto() |
|||
{ |
|||
TenantId = eventData.TenantId, |
|||
PlanId = eventData.PlanId, |
|||
OrderId = null, |
|||
UserId = eventData.UserId, |
|||
StoreId = eventData.StoreId, |
|||
PendingResultId = eventData.PendingResultId, |
|||
Success = false, |
|||
Reason = FlashSaleResultFailedReason.InsufficientInventory |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
var productDetailId = productSku.ProductDetailId ?? product.ProductDetailId; |
|||
|
|||
var productDetailEto = productDetailId.HasValue ? |
|||
ObjectMapper.Map<ProductDetail, FlashSaleProductDetailEto>(await ProductDetailRepository.GetAsync(productDetailId.Value)) : |
|||
null; |
|||
|
|||
var productEto = ObjectMapper.Map<Product, FlashSaleProductEto>(product); |
|||
|
|||
var createFlashSalesOrderEto = new CreateFlashSaleOrderEto() |
|||
{ |
|||
TenantId = eventData.TenantId, |
|||
PlanId = eventData.PlanId, |
|||
UserId = eventData.UserId, |
|||
PendingResultId = eventData.PendingResultId, |
|||
StoreId = eventData.StoreId, |
|||
CreateTime = eventData.CreateTime, |
|||
CustomerRemark = eventData.CustomerRemark, |
|||
Product = productEto, |
|||
ProductDetail = productDetailEto, |
|||
Plan = eventData.Plan |
|||
}; |
|||
|
|||
foreach (var item in eventData.ExtraProperties) |
|||
{ |
|||
createFlashSalesOrderEto.ExtraProperties.Add(item.Key, item.Value); |
|||
} |
|||
|
|||
await DistributedEventBus.PublishAsync(createFlashSalesOrderEto); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.Eshop.Products.Products; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
public interface ILocalFlashSaleInventoryManager : IFlashSaleInventoryManager |
|||
{ |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Products.ProductInventories; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products; |
|||
|
|||
public class LocalFlashSaleInventoryManager : ILocalFlashSaleInventoryManager, ITransientDependency |
|||
{ |
|||
protected IProductInventoryProviderResolver ProductInventoryProviderResolver { get; } |
|||
|
|||
public LocalFlashSaleInventoryManager(IProductInventoryProviderResolver productInventoryProviderResolver) |
|||
{ |
|||
ProductInventoryProviderResolver = productInventoryProviderResolver; |
|||
} |
|||
|
|||
public virtual async Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, |
|||
Guid productSkuId, int quantity, bool increaseSold) |
|||
{ |
|||
var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId); |
|||
return await (await ProductInventoryProviderResolver.GetAsync(providerName)) |
|||
.TryReduceInventoryAsync(model, quantity, increaseSold); |
|||
} |
|||
|
|||
public virtual async Task<bool> TryIncreaseInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, |
|||
Guid productSkuId, int quantity, bool decreaseSold) |
|||
{ |
|||
var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId); |
|||
return await (await ProductInventoryProviderResolver.GetAsync(providerName)) |
|||
.TryIncreaseInventoryAsync(model, quantity, decreaseSold); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue