mirror of https://github.com/EasyAbp/EShop.git
42 changed files with 546 additions and 56 deletions
@ -1,15 +1,52 @@ |
|||||
using System.Collections.Generic; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using EasyAbp.EShop.Orders.Orders; |
using EasyAbp.EShop.Orders.Orders; |
||||
|
using EasyAbp.EShop.Plugins.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using Volo.Abp.Data; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
{ |
{ |
||||
public class CouponOrderDiscountProvider : IOrderDiscountProvider, ITransientDependency |
public class CouponOrderDiscountProvider : IOrderDiscountProvider, ITransientDependency |
||||
{ |
{ |
||||
public async Task<Order> DiscountAsync(Order order, Dictionary<string, object> inputExtraProperties) |
private readonly IOrderRepository _orderRepository; |
||||
|
private readonly ICouponLookupService _couponLookupService; |
||||
|
private readonly ICouponTemplateLookupService _couponTemplateLookupService; |
||||
|
|
||||
|
public CouponOrderDiscountProvider( |
||||
|
IOrderRepository orderRepository, |
||||
|
ICouponLookupService couponLookupService, |
||||
|
ICouponTemplateLookupService couponTemplateLookupService) |
||||
|
{ |
||||
|
_orderRepository = orderRepository; |
||||
|
_couponLookupService = couponLookupService; |
||||
|
_couponTemplateLookupService = couponTemplateLookupService; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Order> DiscountAsync(Order order) |
||||
{ |
{ |
||||
throw new System.NotImplementedException(); |
if (!Guid.TryParse(order.GetProperty<string>(CouponsConsts.OrderCouponIdPropertyName), |
||||
|
out var couponId)) |
||||
|
{ |
||||
|
return order; |
||||
|
} |
||||
|
|
||||
|
var coupon = await _couponLookupService.FindByIdAsync(couponId); |
||||
|
|
||||
|
var couponTemplate = await _couponTemplateLookupService.FindByIdAsync(coupon.CouponTemplateId); |
||||
|
|
||||
|
// Todo: consume the coupon!!!
|
||||
|
|
||||
|
// Todo: get discounted order lines
|
||||
|
var discountedAmount = order.AddDiscountGetRealDiscountedAmount(couponTemplate.DiscountAmount); |
||||
|
|
||||
|
order.SetProperty(CouponsConsts.OrderCouponDiscountAmountPropertyName, discountedAmount); |
||||
|
|
||||
|
await _orderRepository.UpdateAsync(order, true); |
||||
|
|
||||
|
return order; |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -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,25 +0,0 @@ |
|||||
using System; |
|
||||
using EasyAbp.EShop.Plugins.Coupons.Permissions; |
|
||||
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
|
||||
using Volo.Abp.Application.Dtos; |
|
||||
using Volo.Abp.Application.Services; |
|
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
|
||||
{ |
|
||||
public class CouponTemplateAppService : CrudAppService<CouponTemplate, CouponTemplateDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateCouponTemplateDto, CreateUpdateCouponTemplateDto>, |
|
||||
ICouponTemplateAppService |
|
||||
{ |
|
||||
protected override string GetPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
|
||||
protected override string GetListPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
|
||||
protected override string CreatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Create; |
|
||||
protected override string UpdatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Update; |
|
||||
protected override string DeletePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Delete; |
|
||||
|
|
||||
private readonly ICouponTemplateRepository _repository; |
|
||||
|
|
||||
public CouponTemplateAppService(ICouponTemplateRepository repository) : base(repository) |
|
||||
{ |
|
||||
_repository = repository; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,88 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Permissions; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateAppService : CrudAppService<CouponTemplate, CouponTemplateDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateCouponTemplateDto, CreateUpdateCouponTemplateDto>, |
||||
|
ICouponTemplateAppService |
||||
|
{ |
||||
|
protected override string GetPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
||||
|
protected override string GetListPolicyName { get; set; } = CouponsPermissions.CouponTemplate.Default; |
||||
|
protected override string CreatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Create; |
||||
|
protected override string UpdatePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Update; |
||||
|
protected override string DeletePolicyName { get; set; } = CouponsPermissions.CouponTemplate.Delete; |
||||
|
|
||||
|
private readonly ICouponTemplateRepository _repository; |
||||
|
|
||||
|
public CouponTemplateAppService(ICouponTemplateRepository repository) : base(repository) |
||||
|
{ |
||||
|
_repository = repository; |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponTemplateDto> CreateAsync(CreateUpdateCouponTemplateDto input) |
||||
|
{ |
||||
|
await CheckCreatePolicyAsync(); |
||||
|
|
||||
|
var entity = await MapToEntityAsync(input); |
||||
|
|
||||
|
TryToSetTenantId(entity); |
||||
|
|
||||
|
foreach (var inputScoreDto in input.Scopes) |
||||
|
{ |
||||
|
entity.Scopes.Add(new CouponTemplateScope(GuidGenerator.Create(), inputScoreDto.StoreId, |
||||
|
inputScoreDto.ProductGroupName, inputScoreDto.ProductId, inputScoreDto.ProductSkuId)); |
||||
|
} |
||||
|
|
||||
|
await Repository.InsertAsync(entity, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(entity); |
||||
|
} |
||||
|
|
||||
|
public override async Task<CouponTemplateDto> UpdateAsync(Guid id, CreateUpdateCouponTemplateDto input) |
||||
|
{ |
||||
|
await CheckUpdatePolicyAsync(); |
||||
|
|
||||
|
var entity = await GetEntityByIdAsync(id); |
||||
|
|
||||
|
await MapToEntityAsync(input, entity); |
||||
|
|
||||
|
foreach (var inputScoreDto in input.Scopes.Where(dto => !ExistScope(entity.Scopes, dto))) |
||||
|
{ |
||||
|
entity.Scopes.Add(new CouponTemplateScope(GuidGenerator.Create(), inputScoreDto.StoreId, |
||||
|
inputScoreDto.ProductGroupName, inputScoreDto.ProductId, inputScoreDto.ProductSkuId)); |
||||
|
} |
||||
|
|
||||
|
foreach (var scope in entity.Scopes.Where(scope => !ExistScope(input.Scopes, scope))) |
||||
|
{ |
||||
|
entity.Scopes.Remove(scope); |
||||
|
} |
||||
|
|
||||
|
await Repository.UpdateAsync(entity, autoSave: true); |
||||
|
|
||||
|
return await MapToGetOutputDtoAsync(entity); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ExistScope(IEnumerable<CreateUpdateCouponTemplateScopeDto> scopes, ICouponTemplateScope need) |
||||
|
{ |
||||
|
return scopes.Any(x => x.StoreId == need.StoreId && |
||||
|
x.ProductGroupName == need.ProductGroupName && |
||||
|
x.ProductId == need.ProductId && |
||||
|
x.ProductSkuId == need.ProductSkuId); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ExistScope(IEnumerable<ICouponTemplateScope> scopes, CreateUpdateCouponTemplateScopeDto dto) |
||||
|
{ |
||||
|
return scopes.Any(x => x.StoreId == dto.StoreId && |
||||
|
x.ProductGroupName == dto.ProductGroupName && |
||||
|
x.ProductId == dto.ProductId && |
||||
|
x.ProductSkuId == dto.ProductSkuId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateData : ICouponTemplate, IHasCouponTemplateScopes<CouponTemplateScopeData> |
||||
|
{ |
||||
|
public Guid? StoreId { get; set; } |
||||
|
|
||||
|
public CouponType CouponType { get; set; } |
||||
|
|
||||
|
public string UniqueName { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public TimeSpan? UsableDuration { get; set; } |
||||
|
|
||||
|
public DateTime? UsableBeginTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsableEndTime { get; set; } |
||||
|
|
||||
|
public decimal ConditionAmount { get; set; } |
||||
|
|
||||
|
public decimal DiscountAmount { get; set; } |
||||
|
|
||||
|
public bool IsCrossProductAllowed { get; set; } |
||||
|
|
||||
|
public bool IsUnscoped { get; set; } |
||||
|
|
||||
|
public List<CouponTemplateScopeData> Scopes { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class CouponTemplateScopeData : ICouponTemplateScope |
||||
|
{ |
||||
|
public Guid StoreId { get; set; } |
||||
|
|
||||
|
public string ProductGroupName { get; set; } |
||||
|
|
||||
|
public Guid? ProductId { get; set; } |
||||
|
|
||||
|
public Guid? ProductSkuId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public interface IHasCouponTemplateScopes<T> where T : ICouponTemplateScope |
||||
|
{ |
||||
|
List<T> Scopes { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponData : ICoupon |
||||
|
{ |
||||
|
public Guid CouponTemplateId { get; set; } |
||||
|
|
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public Guid? OrderId { get; set; } |
||||
|
|
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
|
||||
|
public DateTime? UsedTime { get; set; } |
||||
|
|
||||
|
public decimal? DiscountedAmount { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
public class RepositoryCouponTemplateLookupService : ICouponTemplateLookupService, ITransientDependency |
||||
|
{ |
||||
|
private readonly IObjectMapper _objectMapper; |
||||
|
private readonly ICouponTemplateRepository _couponTemplateRepository; |
||||
|
|
||||
|
public RepositoryCouponTemplateLookupService( |
||||
|
IObjectMapper objectMapper, |
||||
|
ICouponTemplateRepository couponTemplateRepository) |
||||
|
{ |
||||
|
// Todo: use ICouponTemplateStore
|
||||
|
_objectMapper = objectMapper; |
||||
|
_couponTemplateRepository = couponTemplateRepository; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<CouponTemplateData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return _objectMapper.Map<CouponTemplate, CouponTemplateData>( |
||||
|
await _couponTemplateRepository.FindAsync(id, true, cancellationToken)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class RepositoryCouponLookupService : ICouponLookupService, ITransientDependency |
||||
|
{ |
||||
|
private readonly ICouponRepository _couponRepository; |
||||
|
|
||||
|
public RepositoryCouponLookupService( |
||||
|
ICouponRepository couponRepository) |
||||
|
{ |
||||
|
_couponRepository = couponRepository; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ICoupon> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await _couponRepository.FindAsync(id, true, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using AutoMapper; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
public class CouponsDomainAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public CouponsDomainAutoMapperProfile() |
||||
|
{ |
||||
|
/* You can configure your AutoMapper mapping configuration here. |
||||
|
* Alternatively, you can split your mapping configurations |
||||
|
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<Coupon, CouponData>(MemberList.Destination); |
||||
|
|
||||
|
CreateMap<CouponTemplate, CouponTemplateData>(MemberList.Destination); |
||||
|
CreateMap<CouponTemplateScope, CouponTemplateScopeData>(MemberList.Destination); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,24 @@ |
|||||
using Volo.Abp.Domain; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Domain; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.Coupons |
namespace EasyAbp.EShop.Plugins.Coupons |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
|
typeof(AbpAutoMapperModule), |
||||
typeof(AbpDddDomainModule), |
typeof(AbpDddDomainModule), |
||||
typeof(EShopPluginsCouponsDomainSharedModule) |
typeof(EShopPluginsCouponsDomainSharedModule) |
||||
)] |
)] |
||||
public class EShopPluginsCouponsDomainModule : AbpModule |
public class EShopPluginsCouponsDomainModule : AbpModule |
||||
{ |
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<EShopPluginsCouponsDomainModule>(); |
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddMaps<EShopPluginsCouponsDomainModule>(validate: true); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.CouponTemplates |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class HttpClientCouponTemplateLookupService : ICouponTemplateLookupService, ITransientDependency |
||||
|
{ |
||||
|
private readonly IObjectMapper _objectMapper; |
||||
|
private readonly ICouponTemplateAppService _couponTemplateAppService; |
||||
|
|
||||
|
public HttpClientCouponTemplateLookupService( |
||||
|
IObjectMapper objectMapper, |
||||
|
ICouponTemplateAppService couponTemplateAppService) |
||||
|
{ |
||||
|
_objectMapper = objectMapper; |
||||
|
_couponTemplateAppService = couponTemplateAppService; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<CouponTemplateData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return _objectMapper.Map<CouponTemplateDto, CouponTemplateData>( |
||||
|
await _couponTemplateAppService.GetAsync(id)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class HttpClientCouponLookupService : ICouponLookupService, ITransientDependency |
||||
|
{ |
||||
|
private readonly ICouponAppService _couponAppService; |
||||
|
|
||||
|
public HttpClientCouponLookupService( |
||||
|
ICouponAppService couponAppService) |
||||
|
{ |
||||
|
_couponAppService = couponAppService; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ICoupon> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await _couponAppService.GetAsync(id); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates.Dtos; |
||||
|
using AutoMapper; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons |
||||
|
{ |
||||
|
public class CouponsHttpApiClientAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public CouponsHttpApiClientAutoMapperProfile() |
||||
|
{ |
||||
|
/* You can configure your AutoMapper mapping configuration here. |
||||
|
* Alternatively, you can split your mapping configurations |
||||
|
* into multiple profile classes for a better organization. */ |
||||
|
CreateMap<CouponDto, CouponData>(MemberList.Destination); |
||||
|
|
||||
|
CreateMap<CouponTemplateDto, CouponTemplateData>(MemberList.Destination); |
||||
|
CreateMap<CouponTemplateScopeDto, CouponTemplateScopeData>(MemberList.Destination); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue