mirror of https://github.com/EasyAbp/EShop.git
committed by
GitHub
29 changed files with 274 additions and 275 deletions
@ -0,0 +1,53 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class BasicOrderCreationAuthorizationHandler : OrderCreationAuthorizationHandler |
|||
{ |
|||
protected override async Task HandleOrderCreationAsync(AuthorizationHandlerContext context, |
|||
OrderOperationAuthorizationRequirement requirement, OrderCreationResource resource) |
|||
{ |
|||
if (!await IsProductsPublishedAsync(resource.Input, resource.ProductDictionary)) |
|||
{ |
|||
context.Fail(); |
|||
return; |
|||
} |
|||
|
|||
if (!await IsInventoriesSufficientAsync(resource.Input, resource.ProductDictionary)) |
|||
{ |
|||
context.Fail(); |
|||
return; |
|||
} |
|||
|
|||
context.Succeed(requirement); |
|||
} |
|||
|
|||
protected virtual Task<bool> IsProductsPublishedAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDictionary) |
|||
{ |
|||
return Task.FromResult( |
|||
input.OrderLines.Select(dto => dto.ProductId).Distinct().ToArray() |
|||
.All(productId => productDictionary[productId].IsPublished) |
|||
); |
|||
} |
|||
|
|||
protected virtual Task<bool> IsInventoriesSufficientAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDictionary) |
|||
{ |
|||
return Task.FromResult( |
|||
!(from orderLine in input.OrderLines |
|||
let product = productDictionary[orderLine.ProductId] |
|||
let inventory = product.ProductSkus.Single(sku => sku.Id == orderLine.ProductSkuId).Inventory |
|||
where product.InventoryStrategy != InventoryStrategy.NoNeed && inventory < orderLine.Quantity |
|||
select orderLine).Any() |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class BasicPurchasableCheckProvider : IPurchasableCheckProvider, ITransientDependency |
|||
{ |
|||
public virtual async Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict, |
|||
Dictionary<string, object> orderExtraProperties) |
|||
{ |
|||
await CheckProductsPublishedAsync(input, productDict); |
|||
|
|||
await CheckInventoriesSufficientAsync(input, productDict); |
|||
} |
|||
|
|||
protected virtual Task CheckProductsPublishedAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
foreach (var productId in input.OrderLines.Select(dto => dto.ProductId).Distinct().ToArray()) |
|||
{ |
|||
if (!productDict[productId].IsPublished) |
|||
{ |
|||
throw new NotPurchasableException(productId, null, "Unpublished project"); |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task CheckInventoriesSufficientAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
foreach (var orderLine in input.OrderLines) |
|||
{ |
|||
var product = productDict[orderLine.ProductId]; |
|||
var inventory = product.ProductSkus |
|||
.Single(sku => sku.Id == orderLine.ProductSkuId).Inventory; |
|||
|
|||
if (product.InventoryStrategy != InventoryStrategy.NoNeed && inventory < orderLine.Quantity) |
|||
{ |
|||
throw new NotPurchasableException(orderLine.ProductId, orderLine.ProductSkuId, |
|||
"Insufficient inventory"); |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class CurrencyIsLimitException : BusinessException |
|||
{ |
|||
public CurrencyIsLimitException(string expectedCurrency) : base( |
|||
"CurrencyIsLimit", |
|||
$"Only the specified currency {expectedCurrency} is allowed.") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public interface IPurchasableCheckProvider |
|||
{ |
|||
Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict, |
|||
Dictionary<string, object> orderExtraProperties); |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public interface IPurchasableChecker |
|||
{ |
|||
Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict, |
|||
Dictionary<string, object> orderExtraProperties); |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class NotPurchasableException : BusinessException |
|||
{ |
|||
public NotPurchasableException(Guid productId, Guid? productSkuId, string reason) : base( |
|||
message: $"Product {productId} (SKU: {productSkuId}) cannot be purchased, the reason is: {reason}") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public abstract class OrderCreationAuthorizationHandler : AuthorizationHandler<OrderOperationAuthorizationRequirement, OrderCreationResource> |
|||
{ |
|||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OrderOperationAuthorizationRequirement requirement, |
|||
OrderCreationResource resource) |
|||
{ |
|||
if (requirement.OrderOperation != OrderOperation.Creation) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
await HandleOrderCreationAsync(context, requirement, resource); |
|||
} |
|||
|
|||
protected abstract Task HandleOrderCreationAsync(AuthorizationHandlerContext context, |
|||
OrderOperationAuthorizationRequirement requirement, OrderCreationResource resource); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class OrderCreationResource |
|||
{ |
|||
public CreateOrderDto Input { get; set; } |
|||
|
|||
public Dictionary<Guid, ProductDto> ProductDictionary { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
[Flags] |
|||
public enum OrderOperation |
|||
{ |
|||
Creation = 0 |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class OrderOperationAuthorizationRequirement : IAuthorizationRequirement |
|||
{ |
|||
public OrderOperation OrderOperation { get; } |
|||
|
|||
public OrderOperationAuthorizationRequirement(OrderOperation orderOperation) |
|||
{ |
|||
OrderOperation = orderOperation; |
|||
} |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class PurchasableChecker : IPurchasableChecker, ITransientDependency |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public PurchasableChecker(IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
} |
|||
|
|||
public virtual async Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict, |
|||
Dictionary<string, object> orderExtraProperties) |
|||
{ |
|||
var providers = _serviceProvider.GetServices<IPurchasableCheckProvider>(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
await provider.CheckAsync(input, productDict, orderExtraProperties); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class PaymentAlreadyExistsException : BusinessException |
|||
{ |
|||
public PaymentAlreadyExistsException(Guid orderId) |
|||
: base(message: $"The order {orderId}'s payment is already exists.") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Payments.Payments.Dtos; |
|||
using EasyAbp.PaymentService.Payments; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class BasicPayableCheckProvider : IPayableCheckProvider, ITransientDependency |
|||
{ |
|||
public virtual Task CheckAsync(CreatePaymentDto input, List<OrderDto> orders, CreatePaymentEto createPaymentEto) |
|||
{ |
|||
foreach (var order in orders.Where(order => order.PaymentId.HasValue || order.PaidTime.HasValue)) |
|||
{ |
|||
throw new PaymentAlreadyExistsException(order.Id); |
|||
} |
|||
|
|||
if (orders.Select(order => order.Currency).Distinct().Count() != 1) |
|||
{ |
|||
// Todo: convert to a single currency.
|
|||
throw new MultiCurrencyNotSupportedException(); |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class BasicPaymentCreationAuthorizationHandler : PaymentCreationAuthorizationHandler |
|||
{ |
|||
|
|||
public BasicPaymentCreationAuthorizationHandler() |
|||
{ |
|||
} |
|||
|
|||
protected override Task HandlePaymentCreationAsync(AuthorizationHandlerContext context, |
|||
PaymentOperationAuthorizationRequirement requirement, PaymentCreationResource resource) |
|||
{ |
|||
if (resource.Orders.Any(order => order.PaymentId.HasValue || order.PaidTime.HasValue)) |
|||
{ |
|||
context.Fail(); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
if (resource.Orders.Select(order => order.Currency).Distinct().Count() != 1) |
|||
{ |
|||
// Todo: convert to a single currency.
|
|||
context.Fail(); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
context.Succeed(requirement); |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Payments.Payments.Dtos; |
|||
using EasyAbp.PaymentService.Payments; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public interface IPayableChecker |
|||
{ |
|||
Task CheckAsync(CreatePaymentDto input, List<OrderDto> orders, CreatePaymentEto createPaymentEto); |
|||
} |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class MultiCurrencyNotSupportedException : BusinessException |
|||
{ |
|||
public MultiCurrencyNotSupportedException() : base(message: $"The currency of all orders should be the same.") |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Payments.Payments.Dtos; |
|||
using EasyAbp.PaymentService.Payments; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class PayableChecker : IPayableChecker, ITransientDependency |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public PayableChecker(IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
} |
|||
|
|||
|
|||
public virtual async Task CheckAsync(CreatePaymentDto input, List<OrderDto> orders, CreatePaymentEto createPaymentEto) |
|||
{ |
|||
var providers = _serviceProvider.GetServices<IPayableCheckProvider>(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
await provider.CheckAsync(input, orders, createPaymentEto); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public abstract class PaymentCreationAuthorizationHandler : AuthorizationHandler<PaymentOperationAuthorizationRequirement, PaymentCreationResource> |
|||
{ |
|||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PaymentOperationAuthorizationRequirement requirement, |
|||
PaymentCreationResource resource) |
|||
{ |
|||
if (requirement.PaymentOperation != PaymentOperation.Creation) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
await HandlePaymentCreationAsync(context, requirement, resource); |
|||
} |
|||
|
|||
protected abstract Task HandlePaymentCreationAsync(AuthorizationHandlerContext context, |
|||
PaymentOperationAuthorizationRequirement requirement, PaymentCreationResource resource); |
|||
} |
|||
} |
|||
@ -1,13 +1,14 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Payments.Payments.Dtos; |
|||
using EasyAbp.PaymentService.Payments; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public interface IPayableCheckProvider |
|||
public class PaymentCreationResource |
|||
{ |
|||
Task CheckAsync(CreatePaymentDto input, List<OrderDto> orders, CreatePaymentEto createPaymentEto); |
|||
public CreatePaymentDto Input { get; set; } |
|||
|
|||
public List<OrderDto> Orders { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
[Flags] |
|||
public enum PaymentOperation |
|||
{ |
|||
Creation = 0 |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace EasyAbp.EShop.Payments.Payments |
|||
{ |
|||
public class PaymentOperationAuthorizationRequirement : IAuthorizationRequirement |
|||
{ |
|||
public PaymentOperation PaymentOperation { get; } |
|||
|
|||
public PaymentOperationAuthorizationRequirement(PaymentOperation paymentOperation) |
|||
{ |
|||
PaymentOperation = paymentOperation; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue