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.Collections.Generic; |
||||
using System.Threading.Tasks; |
|
||||
using EasyAbp.EShop.Orders.Orders.Dtos; |
using EasyAbp.EShop.Orders.Orders.Dtos; |
||||
using EasyAbp.EShop.Payments.Payments.Dtos; |
using EasyAbp.EShop.Payments.Payments.Dtos; |
||||
using EasyAbp.PaymentService.Payments; |
using EasyAbp.PaymentService.Payments; |
||||
|
|
||||
namespace EasyAbp.EShop.Payments.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