mirror of https://github.com/EasyAbp/EShop.git
81 changed files with 5470 additions and 474 deletions
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Products.Products.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders |
||||
|
{ |
||||
|
public interface IOrderDiscountProvider |
||||
|
{ |
||||
|
Task<Order> DiscountAsync(Order order, Dictionary<Guid, ProductDto> productDict); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Orders |
||||
|
{ |
||||
|
public class DiscountAmountOverflowException : BusinessException |
||||
|
{ |
||||
|
public DiscountAmountOverflowException() |
||||
|
: base("DiscountAmountOverflow", $"The discount amount overflow.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,10 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace EasyAbp.EShop.Orders.Orders |
|
||||
{ |
|
||||
public interface IOrderDiscountProvider |
|
||||
{ |
|
||||
Task<Order> DiscountAsync(Order order); |
|
||||
} |
|
||||
} |
|
||||
@ -1,100 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using EasyAbp.EShop.Orders.Orders; |
|
||||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|
||||
using EasyAbp.EShop.Plugins.Coupons; |
|
||||
using EasyAbp.EShop.Plugins.Coupons.Coupons; |
|
||||
using EasyAbp.EShop.Plugins.Coupons.CouponTemplates; |
|
||||
using Microsoft.AspNetCore.Authorization; |
|
||||
using Volo.Abp.Data; |
|
||||
using Volo.Abp.Timing; |
|
||||
|
|
||||
namespace EasyAbp.EShop.Orders.Plugins.Coupons.Authorization |
|
||||
{ |
|
||||
public class CouponOrderCreationAuthorizationHandler : OrderCreationAuthorizationHandler |
|
||||
{ |
|
||||
private readonly IClock _clock; |
|
||||
private readonly ICouponLookupService _couponLookupService; |
|
||||
private readonly ICouponTemplateLookupService _couponTemplateLookupService; |
|
||||
|
|
||||
public CouponOrderCreationAuthorizationHandler( |
|
||||
IClock clock, |
|
||||
ICouponLookupService couponLookupService, |
|
||||
ICouponTemplateLookupService couponTemplateLookupService) |
|
||||
{ |
|
||||
_clock = clock; |
|
||||
_couponLookupService = couponLookupService; |
|
||||
_couponTemplateLookupService = couponTemplateLookupService; |
|
||||
} |
|
||||
|
|
||||
protected override async Task HandleOrderCreationAsync(AuthorizationHandlerContext context, |
|
||||
OrderOperationAuthorizationRequirement requirement, OrderCreationResource resource) |
|
||||
{ |
|
||||
if (!Guid.TryParse(resource.Input.GetProperty<string>(CouponsConsts.OrderCouponIdPropertyName), |
|
||||
out var couponId)) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var now = _clock.Now; |
|
||||
|
|
||||
var coupon = await _couponLookupService.FindByIdAsync(couponId); |
|
||||
|
|
||||
if (coupon == null || coupon.ExpirationTime < now) |
|
||||
{ |
|
||||
context.Fail(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var couponTemplate = await _couponTemplateLookupService.FindByIdAsync(coupon.CouponTemplateId); |
|
||||
|
|
||||
if (couponTemplate == null || |
|
||||
!IsInUsableTime(couponTemplate, now) || |
|
||||
!IsOrderInScope(couponTemplate, resource)) |
|
||||
{ |
|
||||
context.Fail(); |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual bool IsOrderInScope(CouponTemplateData couponTemplate, OrderCreationResource resource) |
|
||||
{ |
|
||||
if (couponTemplate.IsUnscoped) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
var expectedOrderLines = new List<CreateOrderLineDto>(); |
|
||||
|
|
||||
foreach (var scope in couponTemplate.Scopes) |
|
||||
{ |
|
||||
expectedOrderLines.AddRange(resource.Input.OrderLines |
|
||||
.WhereIf(scope.ProductGroupName != null, |
|
||||
x => resource.ProductDictionary[x.ProductId].ProductGroupName == scope.ProductGroupName) |
|
||||
.WhereIf(scope.ProductId.HasValue, x => x.ProductId == scope.ProductId) |
|
||||
.WhereIf(scope.ProductSkuId.HasValue, x => x.ProductSkuId == scope.ProductSkuId)); |
|
||||
} |
|
||||
|
|
||||
if (couponTemplate.IsCrossProductAllowed) |
|
||||
{ |
|
||||
return expectedOrderLines.Sum(x => GetOrderLineProductPrice(x, resource) * x.Quantity) >= |
|
||||
couponTemplate.ConditionAmount; |
|
||||
} |
|
||||
|
|
||||
return expectedOrderLines.Any(orderLine => |
|
||||
GetOrderLineProductPrice(orderLine, resource) >= couponTemplate.ConditionAmount); |
|
||||
} |
|
||||
|
|
||||
protected virtual decimal GetOrderLineProductPrice(CreateOrderLineDto createOrderLineDto, OrderCreationResource resource) |
|
||||
{ |
|
||||
return resource.ProductDictionary[createOrderLineDto.ProductId].GetSkuById(createOrderLineDto.ProductSkuId).Price; |
|
||||
} |
|
||||
|
|
||||
protected virtual bool IsInUsableTime(ICouponTemplate couponTemplate, DateTime now) |
|
||||
{ |
|
||||
return couponTemplate.UsableBeginTime <= now && couponTemplate.UsableEndTime > now; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +1,18 @@ |
|||||
using EasyAbp.EShop.Orders.Plugins.Coupons.Authorization; |
using EasyAbp.EShop.Orders.Plugins.Coupons.ObjectExtending; |
||||
using EasyAbp.EShop.Orders.Plugins.Coupons.ObjectExtending; |
|
||||
using EasyAbp.EShop.Plugins.Coupons; |
using EasyAbp.EShop.Plugins.Coupons; |
||||
using Microsoft.AspNetCore.Authorization; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace EasyAbp.EShop.Orders.Plugins.Coupons |
namespace EasyAbp.EShop.Orders.Plugins.Coupons |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(EShopOrdersDomainModule), |
typeof(EShopOrdersDomainModule), |
||||
typeof(EShopPluginsCouponsDomainSharedModule) |
typeof(EShopPluginsCouponsApplicationContractsModule) |
||||
)] |
)] |
||||
public class EShopOrdersPluginsCouponsModule : AbpModule |
public class EShopOrdersPluginsCouponsModule : AbpModule |
||||
{ |
{ |
||||
public override void PreConfigureServices(ServiceConfigurationContext context) |
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
EShopOrdersPluginsCouponsObjectExtensions.Configure(); |
EShopOrdersPluginsCouponsObjectExtensions.Configure(); |
||||
|
|
||||
context.Services.AddSingleton<IAuthorizationHandler, CouponOrderCreationAuthorizationHandler>(); |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class CouponNotFoundOrHasExpiredException : BusinessException |
||||
|
{ |
||||
|
public CouponNotFoundOrHasExpiredException() : base("CouponNotFoundOrHasExpired", |
||||
|
"Coupon not found or has expired.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class CouponTemplateNotFoundOrUnavailableException : BusinessException |
||||
|
{ |
||||
|
public CouponTemplateNotFoundOrUnavailableException() : base("CouponTemplateNotFoundOrUnavailable", |
||||
|
"Coupon template not found or unavailable.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Orders.Plugins.Coupons.OrderDiscount |
||||
|
{ |
||||
|
public class OrderDoesNotMeetCouponUsageConditionException : BusinessException |
||||
|
{ |
||||
|
public OrderDoesNotMeetCouponUsageConditionException() : base("OrderDoesNotMeetCouponUsageCondition", |
||||
|
"Order does not meet the coupon usage condition.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponHasBeenOccupiedException : BusinessException |
||||
|
{ |
||||
|
public CouponHasBeenOccupiedException() : base("CouponHasBeenOccupied", "Coupon has been occupied.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class GetCouponListInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public bool AvailableOnly { get; set; } |
||||
|
|
||||
|
public Guid? UserId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class OccupyCouponInput |
||||
|
{ |
||||
|
public Guid OrderId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class UpdateCouponDto |
||||
|
{ |
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,39 +1,41 @@ |
|||||
{ |
{ |
||||
"culture": "pl-PL", |
"culture": "pl-PL", |
||||
"texts": { |
"texts": { |
||||
"Permission:CouponTemplate": "CouponTemplate", |
"Permission:CouponTemplate": "Coupon template", |
||||
"Permission:Create": "Create", |
"Permission:Create": "Create", |
||||
"Permission:Update": "Update", |
"Permission:Update": "Update", |
||||
"Permission:Delete": "Delete", |
"Permission:Delete": "Delete", |
||||
"Menu:CouponTemplate": "MenuCouponTemplate", |
"Menu:CouponTemplate": "Coupon template", |
||||
"CouponTemplate": "CouponTemplate", |
"CouponTemplate": "Coupon template", |
||||
"CouponTemplateStoreId": "CouponTemplateStoreId", |
"CouponTemplateStoreId": "Store ID", |
||||
"CouponTemplateCouponType": "CouponTemplateCouponType", |
"CouponTemplateCouponType": "Coupon type", |
||||
"CouponTemplateUniqueName": "CouponTemplateUniqueName", |
"CouponTemplateUniqueName": "Unique name", |
||||
"CouponTemplateDisplayName": "CouponTemplateDisplayName", |
"CouponTemplateDisplayName": "Display name", |
||||
"CouponTemplateDescription": "CouponTemplateDescription", |
"CouponTemplateDescription": "Description", |
||||
"CouponTemplateUsableDuration": "CouponTemplateUsableDuration", |
"CouponTemplateUsableDuration": "Usable duration", |
||||
"CouponTemplateUsableBeginTime": "CouponTemplateUsableBeginTime", |
"CouponTemplateUsableBeginTime": "Usable begin time", |
||||
"CouponTemplateUsableEndTime": "CouponTemplateUsableEndTime", |
"CouponTemplateUsableEndTime": "Usable end time", |
||||
"CouponTemplateConditionAmount": "CouponTemplateConditionAmount", |
"CouponTemplateConditionAmount": "Condition amount", |
||||
"CouponTemplateDiscountAmount": "CouponTemplateDiscountAmount", |
"CouponTemplateDiscountAmount": "Discount amount", |
||||
"CouponTemplateIsCrossProductAllowed": "CouponTemplateIsCrossProductAllowed", |
"CouponTemplateIsUnscoped": "Unscoped", |
||||
"CouponTemplateIsUnscoped": "CouponTemplateIsUnscoped", |
"CreateCouponTemplate": "New", |
||||
"CreateCouponTemplate": "CreateCouponTemplate", |
"EditCouponTemplate": "Edit", |
||||
"EditCouponTemplate": "EditCouponTemplate", |
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the coupon template {0}?", |
||||
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the couponTemplate {0}?", |
|
||||
"SuccessfullyDeleted": "Successfully deleted", |
"SuccessfullyDeleted": "Successfully deleted", |
||||
|
"CouponType.Normal": "X discount", |
||||
|
"CouponType.PerMeet": "X discount for every Y", |
||||
|
"CouponType.Custom": "Custom", |
||||
"Permission:Coupon": "Coupon", |
"Permission:Coupon": "Coupon", |
||||
"Menu:Coupon": "MenuCoupon", |
"Menu:Coupon": "Coupon", |
||||
"Coupon": "Coupon", |
"Coupon": "Coupon", |
||||
"CouponCouponTemplateId": "CouponCouponTemplateId", |
"CouponCouponTemplateId": "Coupon template ID", |
||||
"CouponUserId": "CouponUserId", |
"CouponUserId": "User ID", |
||||
"CouponOrderId": "CouponOrderId", |
"CouponOrderId": "Order ID", |
||||
"CouponExpirationTime": "CouponExpirationTime", |
"CouponExpirationTime": "Expiration time", |
||||
"CouponUsedTime": "CouponUsedTime", |
"CouponUsedTime": "Used time", |
||||
"CouponDiscountedAmount": "CouponDiscountedAmount", |
"CouponDiscountedAmount": "Discounted amount", |
||||
"CreateCoupon": "CreateCoupon", |
"CreateCoupon": "New", |
||||
"EditCoupon": "EditCoupon", |
"EditCoupon": "Edit", |
||||
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
||||
} |
} |
||||
} |
} |
||||
@ -1,39 +1,41 @@ |
|||||
{ |
{ |
||||
"culture": "pt-BR", |
"culture": "pt-BR", |
||||
"texts": { |
"texts": { |
||||
"Permission:CouponTemplate": "CouponTemplate", |
"Permission:CouponTemplate": "Coupon template", |
||||
"Permission:Create": "Create", |
"Permission:Create": "Create", |
||||
"Permission:Update": "Update", |
"Permission:Update": "Update", |
||||
"Permission:Delete": "Delete", |
"Permission:Delete": "Delete", |
||||
"Menu:CouponTemplate": "MenuCouponTemplate", |
"Menu:CouponTemplate": "Coupon template", |
||||
"CouponTemplate": "CouponTemplate", |
"CouponTemplate": "Coupon template", |
||||
"CouponTemplateStoreId": "CouponTemplateStoreId", |
"CouponTemplateStoreId": "Store ID", |
||||
"CouponTemplateCouponType": "CouponTemplateCouponType", |
"CouponTemplateCouponType": "Coupon type", |
||||
"CouponTemplateUniqueName": "CouponTemplateUniqueName", |
"CouponTemplateUniqueName": "Unique name", |
||||
"CouponTemplateDisplayName": "CouponTemplateDisplayName", |
"CouponTemplateDisplayName": "Display name", |
||||
"CouponTemplateDescription": "CouponTemplateDescription", |
"CouponTemplateDescription": "Description", |
||||
"CouponTemplateUsableDuration": "CouponTemplateUsableDuration", |
"CouponTemplateUsableDuration": "Usable duration", |
||||
"CouponTemplateUsableBeginTime": "CouponTemplateUsableBeginTime", |
"CouponTemplateUsableBeginTime": "Usable begin time", |
||||
"CouponTemplateUsableEndTime": "CouponTemplateUsableEndTime", |
"CouponTemplateUsableEndTime": "Usable end time", |
||||
"CouponTemplateConditionAmount": "CouponTemplateConditionAmount", |
"CouponTemplateConditionAmount": "Condition amount", |
||||
"CouponTemplateDiscountAmount": "CouponTemplateDiscountAmount", |
"CouponTemplateDiscountAmount": "Discount amount", |
||||
"CouponTemplateIsCrossProductAllowed": "CouponTemplateIsCrossProductAllowed", |
"CouponTemplateIsUnscoped": "Unscoped", |
||||
"CouponTemplateIsUnscoped": "CouponTemplateIsUnscoped", |
"CreateCouponTemplate": "New", |
||||
"CreateCouponTemplate": "CreateCouponTemplate", |
"EditCouponTemplate": "Edit", |
||||
"EditCouponTemplate": "EditCouponTemplate", |
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the coupon template {0}?", |
||||
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the couponTemplate {0}?", |
|
||||
"SuccessfullyDeleted": "Successfully deleted", |
"SuccessfullyDeleted": "Successfully deleted", |
||||
|
"CouponType.Normal": "X discount", |
||||
|
"CouponType.PerMeet": "X discount for every Y", |
||||
|
"CouponType.Custom": "Custom", |
||||
"Permission:Coupon": "Coupon", |
"Permission:Coupon": "Coupon", |
||||
"Menu:Coupon": "MenuCoupon", |
"Menu:Coupon": "Coupon", |
||||
"Coupon": "Coupon", |
"Coupon": "Coupon", |
||||
"CouponCouponTemplateId": "CouponCouponTemplateId", |
"CouponCouponTemplateId": "Coupon template ID", |
||||
"CouponUserId": "CouponUserId", |
"CouponUserId": "User ID", |
||||
"CouponOrderId": "CouponOrderId", |
"CouponOrderId": "Order ID", |
||||
"CouponExpirationTime": "CouponExpirationTime", |
"CouponExpirationTime": "Expiration time", |
||||
"CouponUsedTime": "CouponUsedTime", |
"CouponUsedTime": "Used time", |
||||
"CouponDiscountedAmount": "CouponDiscountedAmount", |
"CouponDiscountedAmount": "Discounted amount", |
||||
"CreateCoupon": "CreateCoupon", |
"CreateCoupon": "New", |
||||
"EditCoupon": "EditCoupon", |
"EditCoupon": "Edit", |
||||
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
||||
} |
} |
||||
} |
} |
||||
@ -1,39 +1,41 @@ |
|||||
{ |
{ |
||||
"culture": "vi", |
"culture": "vi", |
||||
"texts": { |
"texts": { |
||||
"Permission:CouponTemplate": "CouponTemplate", |
"Permission:CouponTemplate": "Coupon template", |
||||
"Permission:Create": "Create", |
"Permission:Create": "Create", |
||||
"Permission:Update": "Update", |
"Permission:Update": "Update", |
||||
"Permission:Delete": "Delete", |
"Permission:Delete": "Delete", |
||||
"Menu:CouponTemplate": "MenuCouponTemplate", |
"Menu:CouponTemplate": "Coupon template", |
||||
"CouponTemplate": "CouponTemplate", |
"CouponTemplate": "Coupon template", |
||||
"CouponTemplateStoreId": "CouponTemplateStoreId", |
"CouponTemplateStoreId": "Store ID", |
||||
"CouponTemplateCouponType": "CouponTemplateCouponType", |
"CouponTemplateCouponType": "Coupon type", |
||||
"CouponTemplateUniqueName": "CouponTemplateUniqueName", |
"CouponTemplateUniqueName": "Unique name", |
||||
"CouponTemplateDisplayName": "CouponTemplateDisplayName", |
"CouponTemplateDisplayName": "Display name", |
||||
"CouponTemplateDescription": "CouponTemplateDescription", |
"CouponTemplateDescription": "Description", |
||||
"CouponTemplateUsableDuration": "CouponTemplateUsableDuration", |
"CouponTemplateUsableDuration": "Usable duration", |
||||
"CouponTemplateUsableBeginTime": "CouponTemplateUsableBeginTime", |
"CouponTemplateUsableBeginTime": "Usable begin time", |
||||
"CouponTemplateUsableEndTime": "CouponTemplateUsableEndTime", |
"CouponTemplateUsableEndTime": "Usable end time", |
||||
"CouponTemplateConditionAmount": "CouponTemplateConditionAmount", |
"CouponTemplateConditionAmount": "Condition amount", |
||||
"CouponTemplateDiscountAmount": "CouponTemplateDiscountAmount", |
"CouponTemplateDiscountAmount": "Discount amount", |
||||
"CouponTemplateIsCrossProductAllowed": "CouponTemplateIsCrossProductAllowed", |
"CouponTemplateIsUnscoped": "Unscoped", |
||||
"CouponTemplateIsUnscoped": "CouponTemplateIsUnscoped", |
"CreateCouponTemplate": "New", |
||||
"CreateCouponTemplate": "CreateCouponTemplate", |
"EditCouponTemplate": "Edit", |
||||
"EditCouponTemplate": "EditCouponTemplate", |
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the coupon template {0}?", |
||||
"CouponTemplateDeletionConfirmationMessage": "Are you sure to delete the couponTemplate {0}?", |
|
||||
"SuccessfullyDeleted": "Successfully deleted", |
"SuccessfullyDeleted": "Successfully deleted", |
||||
|
"CouponType.Normal": "X discount", |
||||
|
"CouponType.PerMeet": "X discount for every Y", |
||||
|
"CouponType.Custom": "Custom", |
||||
"Permission:Coupon": "Coupon", |
"Permission:Coupon": "Coupon", |
||||
"Menu:Coupon": "MenuCoupon", |
"Menu:Coupon": "Coupon", |
||||
"Coupon": "Coupon", |
"Coupon": "Coupon", |
||||
"CouponCouponTemplateId": "CouponCouponTemplateId", |
"CouponCouponTemplateId": "Coupon template ID", |
||||
"CouponUserId": "CouponUserId", |
"CouponUserId": "User ID", |
||||
"CouponOrderId": "CouponOrderId", |
"CouponOrderId": "Order ID", |
||||
"CouponExpirationTime": "CouponExpirationTime", |
"CouponExpirationTime": "Expiration time", |
||||
"CouponUsedTime": "CouponUsedTime", |
"CouponUsedTime": "Used time", |
||||
"CouponDiscountedAmount": "CouponDiscountedAmount", |
"CouponDiscountedAmount": "Discounted amount", |
||||
"CreateCoupon": "CreateCoupon", |
"CreateCoupon": "New", |
||||
"EditCoupon": "EditCoupon", |
"EditCoupon": "Edit", |
||||
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
"CouponDeletionConfirmationMessage": "Are you sure to delete the coupon {0}?" |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponOrderCanceledEventHandler : IDistributedEventHandler<OrderCanceledEto>, ITransientDependency |
||||
|
{ |
||||
|
private readonly ICouponRepository _couponRepository; |
||||
|
|
||||
|
public CouponOrderCanceledEventHandler(ICouponRepository couponRepository) |
||||
|
{ |
||||
|
_couponRepository = couponRepository; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork(true)] |
||||
|
public virtual async Task HandleEventAsync(OrderCanceledEto eventData) |
||||
|
{ |
||||
|
if (!Guid.TryParse(eventData.Order.GetProperty<string>(CouponsConsts.OrderCouponIdPropertyName), |
||||
|
out var couponId)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var coupon = await _couponRepository.GetAsync(couponId); |
||||
|
|
||||
|
coupon.SetOrderId(null); |
||||
|
coupon.SetUsed(null, null); |
||||
|
|
||||
|
await _couponRepository.UpdateAsync(coupon, true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Orders.Orders; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Entities.Events.Distributed; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Timing; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class CouponOrderCreatedEventHandler : IDistributedEventHandler<EntityCreatedEto<OrderEto>>, ITransientDependency |
||||
|
{ |
||||
|
private readonly IClock _clock; |
||||
|
private readonly ICouponRepository _couponRepository; |
||||
|
|
||||
|
public CouponOrderCreatedEventHandler( |
||||
|
IClock clock, |
||||
|
ICouponRepository couponRepository) |
||||
|
{ |
||||
|
_clock = clock; |
||||
|
_couponRepository = couponRepository; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork(true)] |
||||
|
public virtual async Task HandleEventAsync(EntityCreatedEto<OrderEto> eventData) |
||||
|
{ |
||||
|
if (!Guid.TryParse(eventData.Entity.GetProperty<string>(CouponsConsts.OrderCouponIdPropertyName), |
||||
|
out var couponId)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var discountAmount = eventData.Entity.GetProperty<decimal>(CouponsConsts.OrderCouponDiscountAmountPropertyName); |
||||
|
|
||||
|
var coupon = await _couponRepository.GetAsync(couponId); |
||||
|
|
||||
|
if (coupon.OrderId != eventData.Entity.Id) |
||||
|
{ |
||||
|
throw new InvalidCouponOrderIdException(eventData.Entity.Id, coupon.OrderId); |
||||
|
} |
||||
|
|
||||
|
coupon.SetUsed(_clock.Now, discountAmount); |
||||
|
|
||||
|
await _couponRepository.UpdateAsync(coupon, true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,12 @@ |
|||||
using System; |
using System; |
||||
|
using System.Linq; |
||||
using Volo.Abp.Domain.Repositories; |
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
{ |
{ |
||||
public interface ICouponRepository : IRepository<Coupon, Guid> |
public interface ICouponRepository : IRepository<Coupon, Guid> |
||||
{ |
{ |
||||
|
IQueryable<Coupon> GetAvailableCouponQueryable(IClock clock); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
|
{ |
||||
|
public class InvalidCouponOrderIdException : BusinessException |
||||
|
{ |
||||
|
public InvalidCouponOrderIdException(Guid expectedOrderId, Guid? actualOrderId) : base("InvalidCouponOrderId", |
||||
|
$"The expected order ID is {expectedOrderId}, but the actual order ID is {actualOrderId}.") |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,24 +1,29 @@ |
|||||
using System; |
using System; |
||||
using System.Threading; |
using System.Threading; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using EasyAbp.EShop.Plugins.Coupons.Coupons.Dtos; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
namespace EasyAbp.EShop.Plugins.Coupons.Coupons |
||||
{ |
{ |
||||
[Dependency(TryRegister = true)] |
[Dependency(TryRegister = true)] |
||||
public class HttpClientCouponLookupService : ICouponLookupService, ITransientDependency |
public class HttpClientCouponLookupService : ICouponLookupService, ITransientDependency |
||||
{ |
{ |
||||
|
private readonly IObjectMapper _objectMapper; |
||||
private readonly ICouponAppService _couponAppService; |
private readonly ICouponAppService _couponAppService; |
||||
|
|
||||
public HttpClientCouponLookupService( |
public HttpClientCouponLookupService( |
||||
|
IObjectMapper objectMapper, |
||||
ICouponAppService couponAppService) |
ICouponAppService couponAppService) |
||||
{ |
{ |
||||
|
_objectMapper = objectMapper; |
||||
_couponAppService = couponAppService; |
_couponAppService = couponAppService; |
||||
} |
} |
||||
|
|
||||
public virtual async Task<ICoupon> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
public virtual async Task<CouponData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) |
||||
{ |
{ |
||||
return await _couponAppService.GetAsync(id); |
return _objectMapper.Map<CouponDto, CouponData>(await _couponAppService.GetAsync(id)); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -1,10 +1,9 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
using System.ComponentModel.DataAnnotations; |
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
namespace EasyAbp.EShop.Plugins.Coupons.Web.Pages.EShop.Plugins.Coupons.Coupons.Coupon.ViewModels |
namespace EasyAbp.EShop.Plugins.Coupons.Web.Pages.EShop.Plugins.Coupons.Coupons.Coupon.ViewModels |
||||
{ |
{ |
||||
public class CreateEditCouponViewModel |
public class CreateCouponViewModel |
||||
{ |
{ |
||||
[Display(Name = "CouponCouponTemplateId")] |
[Display(Name = "CouponCouponTemplateId")] |
||||
public Guid CouponTemplateId { get; set; } |
public Guid CouponTemplateId { get; set; } |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace EasyAbp.EShop.Plugins.Coupons.Web.Pages.EShop.Plugins.Coupons.Coupons.Coupon.ViewModels |
||||
|
{ |
||||
|
public class EditCouponViewModel |
||||
|
{ |
||||
|
[Display(Name = "CouponExpirationTime")] |
||||
|
public DateTime? ExpirationTime { get; set; } |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,24 @@ |
|||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
namespace EShopSample.Migrations |
||||
|
{ |
||||
|
public partial class RemovedIsCrossProductAllowed : Migration |
||||
|
{ |
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropColumn( |
||||
|
name: "IsCrossProductAllowed", |
||||
|
table: "EasyAbpEShopPluginsCouponsCouponTemplates"); |
||||
|
} |
||||
|
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.AddColumn<bool>( |
||||
|
name: "IsCrossProductAllowed", |
||||
|
table: "EasyAbpEShopPluginsCouponsCouponTemplates", |
||||
|
type: "bit", |
||||
|
nullable: false, |
||||
|
defaultValue: false); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue