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 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; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
|||
{ |
|||
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; |
|||
|
|||
namespace EasyAbp.EShop.Plugins.Coupons |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAutoMapperModule), |
|||
typeof(AbpDddDomainModule), |
|||
typeof(EShopPluginsCouponsDomainSharedModule) |
|||
)] |
|||
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