Browse Source

removed payment bypass service

Introduced IPaymentStrategy
pull/57/head
Galip Tolga Erdem 5 years ago
parent
commit
4d5bc063c2
  1. 9
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs
  2. 10
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCompleteInputDto.cs
  3. 1
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs
  4. 1
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs
  5. 137
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
  6. 38
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs
  7. 12
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs
  8. 25
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/DemoService.cs
  9. 10
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/IPaymentStrategy.cs
  10. 41
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaymentServiceFactory.cs
  11. 94
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaypalService.cs
  12. 2
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PayPalConsts.cs
  13. 39
      services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestDomainService.cs
  14. 6
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs

9
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs

@ -9,8 +9,15 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input); Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input);
Task<PaymentRequestDto> CompleteAsync(string token); Task<PaymentRequestDto> CompleteAsync(PaymentRequestCompleteInputDto input);
Task<bool> HandleWebhookAsync(string payload); Task<bool> HandleWebhookAsync(string payload);
// /// <summary>
// /// 0 - Demo
// /// 1 - Paypal
// /// </summary>
// /// <param name="paymentTypeId"></param>
// /// <returns></returns>
// Task SetPaymentServiceAsync(int paymentTypeId);
} }
} }

10
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCompleteInputDto.cs

@ -0,0 +1,10 @@
using System;
namespace EShopOnAbp.PaymentService.PaymentRequests;
[Serializable]
public class PaymentRequestCompleteInputDto
{
public string Token { get; set; }
public int PaymentTypeId { get; set; }
}

1
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs

@ -6,6 +6,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
[Serializable] [Serializable]
public class PaymentRequestStartDto public class PaymentRequestStartDto
{ {
public int PaymentTypeId { get; set; }
public Guid PaymentRequestId { get; set; } public Guid PaymentRequestId { get; set; }
[Required] [Required]

1
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs

@ -2,6 +2,5 @@
{ {
public static class PaymentServiceConsts public static class PaymentServiceConsts
{ {
public static bool ByPassPaymentProvider { get; set; }
} }
} }

137
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs

@ -1,44 +1,49 @@
using EShopOnAbp.PaymentService.PayPal; using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
using PayPalCheckoutSdk.Core; using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders; using PayPalCheckoutSdk.Orders;
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using EShopOnAbp.PaymentService.PaymentServices;
using Microsoft.Extensions.Logging;
namespace EShopOnAbp.PaymentService.PaymentRequests namespace EShopOnAbp.PaymentService.PaymentRequests
{ {
[ExposeServices(typeof(PaymentRequestAppService))]
public class PaymentRequestAppService : PaymentServiceAppService, IPaymentRequestAppService public class PaymentRequestAppService : PaymentServiceAppService, IPaymentRequestAppService
{ {
private readonly PaymentServiceFactory _paymentServiceFactory;
private readonly PaymentRequestDomainService _paymentRequestDomainService;
protected IPaymentRequestRepository PaymentRequestRepository { get; } protected IPaymentRequestRepository PaymentRequestRepository { get; }
protected PayPalHttpClient PayPalHttpClient { get; } protected PayPalHttpClient PayPalHttpClient { get; }
public PaymentRequestAppService( public PaymentRequestAppService(
IPaymentRequestRepository paymentRequestRepository, IPaymentRequestRepository paymentRequestRepository,
PayPalHttpClient payPalHttpClient) PayPalHttpClient payPalHttpClient,
PaymentServiceFactory paymentServiceFactory,
PaymentRequestDomainService paymentRequestDomainService)
{ {
PaymentRequestRepository = paymentRequestRepository; PaymentRequestRepository = paymentRequestRepository;
PayPalHttpClient = payPalHttpClient; PayPalHttpClient = payPalHttpClient;
_paymentServiceFactory = paymentServiceFactory;
_paymentRequestDomainService = paymentRequestDomainService;
} }
public virtual async Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input) public virtual async Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input)
{ {
var paymentRequest = new PaymentRequest(id: GuidGenerator.Create(), orderId: input.OrderId, orderNo:input.OrderNo, currency: input.Currency, buyerId: input.BuyerId); var paymentRequest = new PaymentRequest(id: GuidGenerator.Create(), orderId: input.OrderId,
orderNo: input.OrderNo, currency: input.Currency, buyerId: input.BuyerId);
foreach (var paymentRequestProduct in input.Products foreach (var paymentRequestProduct in input.Products
.Select(s => new PaymentRequestProduct( .Select(s => new PaymentRequestProduct(
GuidGenerator.Create(), GuidGenerator.Create(),
paymentRequestId: paymentRequest.Id, paymentRequestId: paymentRequest.Id,
code: s.Code, code: s.Code,
name: s.Name, name: s.Name,
unitPrice: s.UnitPrice, unitPrice: s.UnitPrice,
quantity: s.Quantity, quantity: s.Quantity,
totalPrice: s.TotalPrice, totalPrice: s.TotalPrice,
referenceId: s.ReferenceId))) referenceId: s.ReferenceId)))
{ {
paymentRequest.Products.Add(paymentRequestProduct); paymentRequest.Products.Add(paymentRequestProduct);
} }
@ -50,71 +55,17 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public virtual async Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input) public virtual async Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input)
{ {
var paymentRequest = await PaymentRequestRepository.GetAsync(input.PaymentRequestId, includeDetails: true); PaymentRequest paymentRequest = await PaymentRequestRepository.GetAsync(input.PaymentRequestId, includeDetails: true);
var totalCheckoutPrice = paymentRequest.Products.Sum(s => s.TotalPrice); var paymentService = _paymentServiceFactory.Create(input.PaymentTypeId);
return await paymentService.StartAsync(paymentRequest, input);
var order = new OrderRequest
{
CheckoutPaymentIntent = "CAPTURE",
ApplicationContext = new ApplicationContext
{
ReturnUrl = input.ReturnUrl,
CancelUrl = input.CancelUrl,
},
PurchaseUnits = new List<PurchaseUnitRequest>
{
new PurchaseUnitRequest
{
AmountWithBreakdown = new AmountWithBreakdown
{
AmountBreakdown = new AmountBreakdown
{
ItemTotal = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = totalCheckoutPrice.ToString($"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00")
}
},
CurrencyCode = paymentRequest.Currency,
Value = totalCheckoutPrice.ToString($"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00"),
},
Items = paymentRequest.Products.Select(p => new Item
{
Quantity = p.Quantity.ToString(),
Name = p.Name,
UnitAmount = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = p.UnitPrice.ToString($"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00")
}
}).ToList(),
ReferenceId = paymentRequest.Id.ToString()
}
}
};
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
var result = (await PayPalHttpClient.Execute(request)).Result<Order>();
return new PaymentRequestStartResultDto
{
CheckoutLink = result.Links.First(x => x.Rel == "approve").Href
};
} }
public virtual async Task<PaymentRequestDto> CompleteAsync(string token) public virtual async Task<PaymentRequestDto> CompleteAsync(PaymentRequestCompleteInputDto input)
{ {
var request = new OrdersCaptureRequest(token); var paymentService = _paymentServiceFactory.Create(input.PaymentTypeId);
request.RequestBody(new OrderActionRequest());
var paymentRequest = await paymentService.CompleteAsync(PaymentRequestRepository, input.Token);
var order = (await PayPalHttpClient.Execute(request)).Result<Order>();
var paymentRequest = await UpdatePaymentRequestStateAsync(order);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest); return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
} }
@ -130,34 +81,12 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
var response = await PayPalHttpClient.Execute(request); var response = await PayPalHttpClient.Execute(request);
order = response.Result<Order>(); order = response.Result<Order>();
await UpdatePaymentRequestStateAsync(order); var paymentRequestId = Guid.Parse(order.PurchaseUnits.First().ReferenceId);
await _paymentRequestDomainService.UpdatePaymentRequestStateAsync(paymentRequestId, order.Status, order.Id);
// PayPal doesn't accept Http 204 (NoContent) result and tries to execute webhook again. // PayPal doesn't accept Http 204 (NoContent) result and tries to execute webhook again.
// So with following value, API returns Http 200 (OK) result. // So with following value, API returns Http 200 (OK) result.
return true; return true;
} }
protected async Task<PaymentRequest> UpdatePaymentRequestStateAsync(Order order)
{
var paymentRequestId = Guid.Parse(order.PurchaseUnits.First().ReferenceId);
var paymentRequest = await PaymentRequestRepository.GetAsync(paymentRequestId);
if (order.Status == PayPalConsts.OrderStatus.Completed || order.Status == PayPalConsts.OrderStatus.Approved)
{
paymentRequest.SetAsCompleted();
}
else
{
paymentRequest.SetAsFailed(order.Status);
}
paymentRequest.ExtraProperties[PayPalConsts.OrderIdPropertyName] = order.Id;
paymentRequest.ExtraProperties[nameof(order.Status)] = order.Status;
await PaymentRequestRepository.UpdateAsync(paymentRequest);
return paymentRequest;
}
} }
} }

38
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs

@ -1,38 +0,0 @@
using PayPalCheckoutSdk.Core;
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.PaymentService.PaymentRequests
{
[ExposeServices(typeof(PaymentRequestByPassAppService))]
public class PaymentRequestByPassAppService : PaymentRequestAppService
{
public PaymentRequestByPassAppService(
IPaymentRequestRepository paymentRequestRepository,
PayPalHttpClient payPalHttpClient)
: base(paymentRequestRepository,
payPalHttpClient)
{
}
public override Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input)
{
return Task.FromResult(new PaymentRequestStartResultDto
{
CheckoutLink = input.ReturnUrl + "?token=" + input.PaymentRequestId
});
}
public override async Task<PaymentRequestDto> CompleteAsync(string token)
{
var paymentRequest = await PaymentRequestRepository.GetAsync(Guid.Parse(token));
paymentRequest.SetAsCompleted();
await PaymentRequestRepository.UpdateAsync(paymentRequest);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
}
}

12
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs

@ -39,18 +39,6 @@ namespace EShopOnAbp.PaymentService
return new PayPalHttpClient(new LiveEnvironment(options.ClientId, options.Secret)); return new PayPalHttpClient(new LiveEnvironment(options.ClientId, options.Secret));
}); });
context.Services.AddTransient<IPaymentRequestAppService>(provider =>
{
if (PaymentServiceConsts.ByPassPaymentProvider)
{
return provider.GetRequiredService<PaymentRequestByPassAppService>();
}
else
{
return provider.GetRequiredService<PaymentRequestAppService>();
}
});
} }
} }
} }

25
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/DemoService.cs

@ -0,0 +1,25 @@
using System;
using System.Threading.Tasks;
using EShopOnAbp.PaymentService.PaymentRequests;
namespace EShopOnAbp.PaymentService.PaymentServices;
public class DemoService : IPaymentStrategy
{
public Task<PaymentRequestStartResultDto> StartAsync(PaymentRequest paymentRequest, PaymentRequestStartDto input)
{
return Task.FromResult(new PaymentRequestStartResultDto
{
CheckoutLink = input.ReturnUrl + "?token=" + input.PaymentRequestId
});
}
public async Task<PaymentRequest> CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token)
{
var paymentRequest = await paymentRequestRepository.GetAsync(Guid.Parse(token));
paymentRequest.SetAsCompleted();
return await paymentRequestRepository.UpdateAsync(paymentRequest);
}
}

10
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/IPaymentStrategy.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using EShopOnAbp.PaymentService.PaymentRequests;
namespace EShopOnAbp.PaymentService.PaymentServices;
public interface IPaymentStrategy
{
public Task<PaymentRequestStartResultDto> StartAsync(PaymentRequest paymentRequest, PaymentRequestStartDto input);
public Task<PaymentRequest> CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token);
}

41
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaymentServiceFactory.cs

@ -0,0 +1,41 @@
using System;
using EShopOnAbp.PaymentService.PaymentRequests;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PayPalCheckoutSdk.Core;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.PaymentService.PaymentServices;
public class PaymentServiceFactory : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<PaymentServiceFactory> _logger;
public PaymentServiceFactory(IServiceProvider serviceProvider, ILogger<PaymentServiceFactory> logger)
{
logger.LogInformation("== Payment SErvice Factory == ");
_serviceProvider = serviceProvider;
_logger = logger;
}
public IPaymentStrategy Create(int paymentTypeId)
{
if (paymentTypeId == 0)
{
return new DemoService();
}
if (paymentTypeId == 1)
{
var paypalService = _serviceProvider.GetRequiredService<PayPalHttpClient>();
_logger.LogInformation($"=== Resolved PaypalService {paypalService} ===");
var requestDomainService = _serviceProvider.GetRequiredService<PaymentRequestDomainService>();
_logger.LogInformation($"=== Resolved PaymentRequestDomainService {requestDomainService} ===");
return new PaypalService(paypalService, requestDomainService);
}
return new DemoService();
}
}

94
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaypalService.cs

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using EShopOnAbp.PaymentService.PaymentRequests;
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;
namespace EShopOnAbp.PaymentService.PaymentServices;
public class PaypalService : IPaymentStrategy
{
private readonly PayPalHttpClient _payPalHttpClient;
private readonly PaymentRequestDomainService _paymentRequestDomainService;
public PaypalService(PayPalHttpClient payPalHttpClient, PaymentRequestDomainService paymentRequestDomainService)
{
_payPalHttpClient = payPalHttpClient;
_paymentRequestDomainService = paymentRequestDomainService;
}
public async Task<PaymentRequestStartResultDto> StartAsync(PaymentRequest paymentRequest,
PaymentRequestStartDto input)
{
var totalCheckoutPrice = paymentRequest.Products.Sum(s => s.TotalPrice);
var order = new OrderRequest
{
CheckoutPaymentIntent = "CAPTURE",
ApplicationContext = new ApplicationContext
{
ReturnUrl = input.ReturnUrl,
CancelUrl = input.CancelUrl,
},
PurchaseUnits = new List<PurchaseUnitRequest>
{
new PurchaseUnitRequest
{
AmountWithBreakdown = new AmountWithBreakdown
{
AmountBreakdown = new AmountBreakdown
{
ItemTotal = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = totalCheckoutPrice.ToString(
$"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00")
}
},
CurrencyCode = paymentRequest.Currency,
Value = totalCheckoutPrice.ToString(
$"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00"),
},
Items = paymentRequest.Products.Select(p => new Item
{
Quantity = p.Quantity.ToString(),
Name = p.Name,
UnitAmount = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = p.UnitPrice.ToString(
$"{CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator}00")
}
}).ToList(),
ReferenceId = paymentRequest.Id.ToString()
}
}
};
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
Order result = (await _payPalHttpClient.Execute(request)).Result<Order>();
return new PaymentRequestStartResultDto
{
CheckoutLink = result.Links.First(x => x.Rel == "approve").Href
};
}
public async Task<PaymentRequest> CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token)
{
var request = new OrdersCaptureRequest(token);
request.RequestBody(new OrderActionRequest());
var order = (await _payPalHttpClient.Execute(request)).Result<Order>();
var paymentRequestId = Guid.Parse(order.PurchaseUnits.First().ReferenceId);
return await _paymentRequestDomainService.UpdatePaymentRequestStateAsync(paymentRequestId, order.Status,
order.Id);
}
}

2
services/payment/src/EShopOnAbp.PaymentService.Application/PayPal/PayPalConsts.cs → services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PayPalConsts.cs

@ -1,4 +1,4 @@
namespace EShopOnAbp.PaymentService.PayPal namespace EShopOnAbp.PaymentService
{ {
public static class PayPalConsts public static class PayPalConsts
{ {

39
services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestDomainService.cs

@ -0,0 +1,39 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
namespace EShopOnAbp.PaymentService.PaymentRequests;
public class PaymentRequestDomainService : DomainService
{
private readonly IPaymentRequestRepository _paymentRequestRepository;
public PaymentRequestDomainService(IPaymentRequestRepository paymentRequestRepository)
{
_paymentRequestRepository = paymentRequestRepository;
}
public async Task<PaymentRequest> UpdatePaymentRequestStateAsync(
Guid paymentRequestId,
string orderStatus,
string orderId)
{
var paymentRequest = await _paymentRequestRepository.GetAsync(paymentRequestId);
if (orderStatus == PayPalConsts.OrderStatus.Completed || orderStatus == PayPalConsts.OrderStatus.Approved)
{
paymentRequest.SetAsCompleted();
}
else
{
paymentRequest.SetAsFailed(orderStatus);
}
paymentRequest.ExtraProperties[PayPalConsts.OrderIdPropertyName] = orderId;
paymentRequest.ExtraProperties[nameof(orderStatus)] = orderStatus;
await _paymentRequestRepository.UpdateAsync(paymentRequest);
return paymentRequest;
}
}

6
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs

@ -30,11 +30,7 @@ namespace EShopOnAbp.PaymentService
var hostingEnvironment = context.Services.GetHostingEnvironment(); var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
/// Enable bypassing payment provider via uncommenting code line below.
/// If bypassing is enabled, all payments will be completed immediately.
// PaymentServiceConsts.ByPassPaymentProvider = true;
JwtBearerConfigurationHelper.Configure(context, "PaymentService"); JwtBearerConfigurationHelper.Configure(context, "PaymentService");
// SwaggerConfigurationHelper.Configure(context, "Payment Service API"); // SwaggerConfigurationHelper.Configure(context, "Payment Service API");

Loading…
Cancel
Save