- @*
@L["Payment"]
*@
@await Component.InvokeAsync(typeof(PaymentWidgetViewComponent))
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs
index d4191c8c..9ad48597 100644
--- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs
@@ -59,7 +59,7 @@ public class PaymentModel : AbpPageModel
var placedOrder = await _orderAppService.CreateAsync(new OrderCreateDto()
{
- PaymentTypeId = 1, // Paypal
+ PaymentTypeId = model.SelectedPaymentId,
Address = GetUserAddress(model.SelectedAddressId),
Products = productItems
});
@@ -75,9 +75,10 @@ public class PaymentModel : AbpPageModel
var response = await _paymentRequestAppService.StartAsync(new PaymentRequestStartDto
{
+ PaymentTypeId = model.SelectedPaymentId,
PaymentRequestId = paymentRequest.Id,
ReturnUrl = _publicWebPaymentOptions.PaymentSuccessfulCallbackUrl,
- CancelUrl = _publicWebPaymentOptions.PaymentFailureCallbackUrl,
+ CancelUrl = _publicWebPaymentOptions.PaymentFailureCallbackUrl
});
return Redirect(response.CheckoutLink);
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs
index e313939d..ffaa090e 100644
--- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs
@@ -24,12 +24,23 @@ public class PaymentCompletedModel : AbpPageModel
public async Task
OnGetAsync()
{
- PaymentRequest = await _paymentRequestAppService.CompleteAsync(Token);
+ int selectedPaymentId = 0;
+ if (HttpContext.Request.Cookies.TryGetValue(EShopOnAbpPaymentConsts.PaymentIdCookie,
+ out var selectedPaymentIdString))
+ {
+ selectedPaymentId = string.IsNullOrEmpty(selectedPaymentIdString) ? 0 : int.Parse(selectedPaymentIdString);
+ }
+
+ PaymentRequest = await _paymentRequestAppService.CompleteAsync(
+ new PaymentRequestCompleteInputDto() {Token = Token, PaymentTypeId = selectedPaymentId});
IsSuccessful = PaymentRequest.State == PaymentRequestState.Completed;
+
if (IsSuccessful)
{
- return RedirectToPage("OrderReceived", new { orderNo = PaymentRequest.OrderNo });
+ // Remove cookie so that can be set again when default payment type is set
+ HttpContext.Response.Cookies.Delete(EShopOnAbpPaymentConsts.PaymentIdCookie);
+ return RedirectToPage("OrderReceived", new {orderNo = PaymentRequest.OrderNo});
}
return Page();
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/PaymentTypeProvider.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/PaymentTypeProvider.cs
new file mode 100644
index 00000000..a2b9d755
--- /dev/null
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/PaymentTypeProvider.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using Volo.Abp.DependencyInjection;
+
+namespace EShopOnAbp.PublicWeb.ServiceProviders;
+
+public class PaymentTypeProvider : ITransientDependency
+{
+ public List GetPaymentTypes()
+ {
+ return new List
+ {
+ new() {Id = 0, Name = "Demo", IconCss = "fa-credit-card demo", IsDefault = true},
+ new() {Id = 1, Name = "Paypal", IconCss = "fa-cc-paypal paypal"}
+ };
+ }
+}
+
+public class PaymentType
+{
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string IconCss { get; set; }
+ public bool IsDefault { get; set; } = false;
+}
\ No newline at end of file
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs
index 6e343752..9c69caa0 100644
--- a/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs
@@ -26,8 +26,7 @@ public class UserAddressProvider : ITransientDependency
Street = "Yeşilköy Serbest Bölge Mah. E-Blok Sk. Bakırköy",
City = "İstanbul",
Country = "Turkey",
- ZipCode = "34149",
- Description = "Near Ataturk Airport"
+ ZipCode = "34149"
}
};
}
@@ -38,7 +37,6 @@ public class AddressDto
public int Id { get; set; }
public string Type { get; set; }
public bool IsDefault { get; set; } = false;
- public string Description { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css
index 1b38f784..90e9a095 100644
--- a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css
@@ -17,4 +17,16 @@
.is-selected {
border: solid #bfbfe3;
+}
+
+.payment-type-header {
+ font-weight: 500;
+}
+
+.paypal {
+ color: #6c84fa;
+}
+
+.demo {
+ color: darkgray;
}
\ No newline at end of file
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js
index b246c5f1..0632b47c 100644
--- a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js
+++ b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js
@@ -1,4 +1,8 @@
(function () {
+ // Write selected payment type to cookie anyways
+ const paymentTypeId = $(".payment-list").find(".is-selected").attr('data-payment-id');
+ abp.utils.setCookieValue("selected_payment_id", paymentTypeId);
+
abp.widgets.PaymentWidget = function ($wrapper) {
var widgetManager = $wrapper.data('abp-widget-manager');
@@ -6,12 +10,20 @@
$wrapper
.find('.address-list .card')
.click(function () {
- var $this = $(this);
- var addressId = $this.attr('data-address-id');
- abp.utils.setCookieValue("selected-address", addressId);
+ const $this = $(this);
$this.parents(".address-list").find('.card').removeClass("is-selected");
$this.addClass("is-selected");
});
+
+ $wrapper
+ .find('.payment-list .card')
+ .click(el => {
+ const $this = $(el.currentTarget);
+ const paymentTypeId = $this.attr('data-payment-id');
+ abp.utils.setCookieValue("selected_payment_id", paymentTypeId);
+ $this.parents(".payment-list").find('.card').removeClass("is-selected");
+ $this.addClass("is-selected");
+ });
};
return {
diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs
index 2e556acd..ec3a0e35 100644
--- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs
+++ b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs
@@ -7,16 +7,16 @@ namespace EShopOnAbp.OrderingService.Orders;
public class PaymentType : Enumeration
{
+ public static PaymentType Demo = new PaymentType(0, nameof(Demo).ToLowerInvariant());
public static PaymentType Paypal = new PaymentType(1, nameof(Paypal).ToLowerInvariant());
- public static PaymentType Demo = new PaymentType(2, nameof(Paypal).ToLowerInvariant());
public PaymentType(int id, string name) : base(id, name)
{
}
public static IEnumerable List() =>
- new[] {Paypal, Demo};
-
+ new[] {Demo, Paypal};
+
public static PaymentType FromName(string name)
{
var state = List()
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs
index cf3e8f40..366c3413 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs
@@ -9,7 +9,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
Task StartAsync(PaymentRequestStartDto input);
- Task CompleteAsync(string token);
+ Task CompleteAsync(PaymentRequestCompleteInputDto input);
Task HandleWebhookAsync(string payload);
}
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCompleteInputDto.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCompleteInputDto.cs
new file mode 100644
index 00000000..2c154610
--- /dev/null
+++ b/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; }
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs
index 44b39fdb..d5b06af4 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestStartDto.cs
@@ -6,6 +6,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
[Serializable]
public class PaymentRequestStartDto
{
+ public int PaymentTypeId { get; set; }
public Guid PaymentRequestId { get; set; }
[Required]
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs
index 1b805927..6bfa585d 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentServiceConsts.cs
@@ -2,6 +2,5 @@
{
public static class PaymentServiceConsts
{
- public static bool ByPassPaymentProvider { get; set; }
}
}
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
index 28bac790..15b62860 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
@@ -1,44 +1,47 @@
-using EShopOnAbp.PaymentService.PayPal;
-using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Linq;
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;
using System;
-using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
-using Volo.Abp.DependencyInjection;
+using EShopOnAbp.PaymentService.PaymentServices;
namespace EShopOnAbp.PaymentService.PaymentRequests
{
- [ExposeServices(typeof(PaymentRequestAppService))]
public class PaymentRequestAppService : PaymentServiceAppService, IPaymentRequestAppService
{
+ private readonly PaymentMethodResolver _paymentMethodResolver;
+ private readonly PaymentRequestDomainService _paymentRequestDomainService;
protected IPaymentRequestRepository PaymentRequestRepository { get; }
protected PayPalHttpClient PayPalHttpClient { get; }
public PaymentRequestAppService(
IPaymentRequestRepository paymentRequestRepository,
- PayPalHttpClient payPalHttpClient)
+ PayPalHttpClient payPalHttpClient,
+ PaymentMethodResolver paymentMethodResolver,
+ PaymentRequestDomainService paymentRequestDomainService)
{
PaymentRequestRepository = paymentRequestRepository;
PayPalHttpClient = payPalHttpClient;
+ _paymentMethodResolver = paymentMethodResolver;
+ _paymentRequestDomainService = paymentRequestDomainService;
}
public virtual async Task 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
- .Select(s => new PaymentRequestProduct(
- GuidGenerator.Create(),
- paymentRequestId: paymentRequest.Id,
- code: s.Code,
- name: s.Name,
- unitPrice: s.UnitPrice,
- quantity: s.Quantity,
- totalPrice: s.TotalPrice,
- referenceId: s.ReferenceId)))
+ .Select(s => new PaymentRequestProduct(
+ GuidGenerator.Create(),
+ paymentRequestId: paymentRequest.Id,
+ code: s.Code,
+ name: s.Name,
+ unitPrice: s.UnitPrice,
+ quantity: s.Quantity,
+ totalPrice: s.TotalPrice,
+ referenceId: s.ReferenceId)))
{
paymentRequest.Products.Add(paymentRequestProduct);
}
@@ -50,71 +53,18 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public virtual async Task 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 order = new OrderRequest
- {
- CheckoutPaymentIntent = "CAPTURE",
- ApplicationContext = new ApplicationContext
- {
- ReturnUrl = input.ReturnUrl,
- CancelUrl = input.CancelUrl,
- },
- PurchaseUnits = new List
- {
- 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();
-
- return new PaymentRequestStartResultDto
- {
- CheckoutLink = result.Links.First(x => x.Rel == "approve").Href
- };
+ var paymentService = _paymentMethodResolver.Resolve(input.PaymentTypeId);
+ return await paymentService.StartAsync(paymentRequest, input);
}
- public virtual async Task CompleteAsync(string token)
+ public virtual async Task CompleteAsync(PaymentRequestCompleteInputDto input)
{
- var request = new OrdersCaptureRequest(token);
- request.RequestBody(new OrderActionRequest());
-
- var order = (await PayPalHttpClient.Execute(request)).Result();
-
- var paymentRequest = await UpdatePaymentRequestStateAsync(order);
+ var paymentService = _paymentMethodResolver.Resolve(input.PaymentTypeId);
+ var paymentRequest = await paymentService.CompleteAsync(PaymentRequestRepository, input.Token);
return ObjectMapper.Map(paymentRequest);
}
@@ -130,34 +80,12 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
var response = await PayPalHttpClient.Execute(request);
order = response.Result();
- 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.
// So with following value, API returns Http 200 (OK) result.
return true;
}
-
- protected async Task 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;
- }
}
-}
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs
deleted file mode 100644
index 1c032844..00000000
--- a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs
+++ /dev/null
@@ -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 StartAsync(PaymentRequestStartDto input)
- {
- return Task.FromResult(new PaymentRequestStartResultDto
- {
- CheckoutLink = input.ReturnUrl + "?token=" + input.PaymentRequestId
- });
- }
-
- public override async Task CompleteAsync(string token)
- {
- var paymentRequest = await PaymentRequestRepository.GetAsync(Guid.Parse(token));
-
- paymentRequest.SetAsCompleted();
-
- await PaymentRequestRepository.UpdateAsync(paymentRequest);
-
- return ObjectMapper.Map(paymentRequest);
- }
- }
-}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs
index 158e6fb1..f0b21e0f 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs
@@ -7,6 +7,8 @@ using EShopOnAbp.PaymentService.PayPal;
using PayPalCheckoutSdk.Core;
using System;
using EShopOnAbp.PaymentService.PaymentRequests;
+using EShopOnAbp.PaymentService.PaymentServices;
+using Microsoft.Extensions.Logging;
namespace EShopOnAbp.PaymentService
{
@@ -15,7 +17,7 @@ namespace EShopOnAbp.PaymentService
typeof(PaymentServiceApplicationContractsModule),
typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule)
- )]
+ )]
public class PaymentServiceApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@@ -40,17 +42,10 @@ namespace EShopOnAbp.PaymentService
return new PayPalHttpClient(new LiveEnvironment(options.ClientId, options.Secret));
});
- context.Services.AddTransient(provider =>
- {
- if (PaymentServiceConsts.ByPassPaymentProvider)
- {
- return provider.GetRequiredService();
- }
- else
- {
- return provider.GetRequiredService();
- }
- });
+ context.Services.AddTransient(provider => new PaymentMethodResolver(
+ provider.GetServices(),
+ provider.GetRequiredService>()
+ ));
}
}
-}
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/DemoPaymentMethod.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/DemoPaymentMethod.cs
new file mode 100644
index 00000000..46c8e24d
--- /dev/null
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/DemoPaymentMethod.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Threading.Tasks;
+using EShopOnAbp.PaymentService.PaymentRequests;
+using Volo.Abp.DependencyInjection;
+
+namespace EShopOnAbp.PaymentService.PaymentServices;
+
+[ExposeServices(typeof(IPaymentMethod), typeof(DemoPaymentMethod))]
+public class DemoPaymentMethod : IPaymentMethod
+{
+ public int PaymentTypeId { get; }
+
+ public DemoPaymentMethod()
+ {
+ PaymentTypeId = 0;
+ }
+
+ public Task StartAsync(PaymentRequest paymentRequest, PaymentRequestStartDto input)
+ {
+ return Task.FromResult(new PaymentRequestStartResultDto
+ {
+ CheckoutLink = input.ReturnUrl + "?token=" + input.PaymentRequestId
+ });
+ }
+
+ public async Task CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token)
+ {
+ var paymentRequest = await paymentRequestRepository.GetAsync(Guid.Parse(token));
+
+ paymentRequest.SetAsCompleted();
+
+ return await paymentRequestRepository.UpdateAsync(paymentRequest);
+ }
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/IPaymentMethod.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/IPaymentMethod.cs
new file mode 100644
index 00000000..16d1ed6c
--- /dev/null
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/IPaymentMethod.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+using EShopOnAbp.PaymentService.PaymentRequests;
+using Volo.Abp.DependencyInjection;
+
+namespace EShopOnAbp.PaymentService.PaymentServices;
+
+public interface IPaymentMethod : ITransientDependency
+{
+ public int PaymentTypeId { get; }
+ public Task StartAsync(PaymentRequest paymentRequest, PaymentRequestStartDto input);
+ public Task CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token);
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaymentMethodResolver.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaymentMethodResolver.cs
new file mode 100644
index 00000000..7973da79
--- /dev/null
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaymentMethodResolver.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Logging;
+using Volo.Abp.DependencyInjection;
+
+namespace EShopOnAbp.PaymentService.PaymentServices;
+
+public class PaymentMethodResolver : ITransientDependency
+{
+ private readonly IEnumerable _paymentMethods;
+ private readonly ILogger _logger;
+
+ public PaymentMethodResolver(IEnumerable paymentMethods, ILogger logger)
+ {
+ _paymentMethods = paymentMethods;
+ _logger = logger;
+ }
+
+ public IPaymentMethod Resolve(int paymentTypeId)
+ {
+ IPaymentMethod paymentMethod = _paymentMethods.FirstOrDefault(q => q.PaymentTypeId == paymentTypeId);
+ if (paymentMethod == null)
+ {
+ _logger.LogError($"Couldn't find Payment method with id:{paymentTypeId}");
+ throw new ArgumentException("Payment method not found", paymentTypeId.ToString());
+ }
+
+ return paymentMethod;
+ }
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaypalMethod.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaypalMethod.cs
new file mode 100644
index 00000000..c660f112
--- /dev/null
+++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServices/PaypalMethod.cs
@@ -0,0 +1,98 @@
+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;
+using Volo.Abp.DependencyInjection;
+
+namespace EShopOnAbp.PaymentService.PaymentServices;
+
+[ExposeServices(typeof(IPaymentMethod), typeof(PaypalMethod))]
+public class PaypalMethod : IPaymentMethod
+{
+ private readonly PayPalHttpClient _payPalHttpClient;
+ private readonly PaymentRequestDomainService _paymentRequestDomainService;
+ public int PaymentTypeId { get; }
+
+ public PaypalMethod(PayPalHttpClient payPalHttpClient, PaymentRequestDomainService paymentRequestDomainService)
+ {
+ _payPalHttpClient = payPalHttpClient;
+ _paymentRequestDomainService = paymentRequestDomainService;
+ PaymentTypeId = 1;
+ }
+
+ public async Task 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
+ {
+ 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();
+
+ return new PaymentRequestStartResultDto
+ {
+ CheckoutLink = result.Links.First(x => x.Rel == "approve").Href
+ };
+ }
+
+ public async Task CompleteAsync(IPaymentRequestRepository paymentRequestRepository, string token)
+ {
+ var request = new OrdersCaptureRequest(token);
+ request.RequestBody(new OrderActionRequest());
+
+ var order = (await _payPalHttpClient.Execute(request)).Result();
+
+ var paymentRequestId = Guid.Parse(order.PurchaseUnits.First().ReferenceId);
+ return await _paymentRequestDomainService.UpdatePaymentRequestStateAsync(paymentRequestId, order.Status,
+ order.Id);
+ }
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PayPal/PayPalConsts.cs b/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PayPalConsts.cs
similarity index 97%
rename from services/payment/src/EShopOnAbp.PaymentService.Application/PayPal/PayPalConsts.cs
rename to services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PayPalConsts.cs
index 0e83292c..d13ad8c0 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.Application/PayPal/PayPalConsts.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PayPalConsts.cs
@@ -1,4 +1,4 @@
-namespace EShopOnAbp.PaymentService.PayPal
+namespace EShopOnAbp.PaymentService
{
public static class PayPalConsts
{
diff --git a/services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestDomainService.cs b/services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestDomainService.cs
new file mode 100644
index 00000000..6ea3542a
--- /dev/null
+++ b/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 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;
+ }
+}
\ No newline at end of file
diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs
index c59692b4..5295d312 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs
@@ -15,11 +15,11 @@ namespace EShopOnAbp.PaymentService.Controllers.ClientProxies
[ExposeServices(typeof(IPaymentRequestAppService), typeof(PaymentRequestClientProxy))]
public partial class PaymentRequestClientProxy : ClientProxyBase, IPaymentRequestAppService
{
- public virtual async Task CompleteAsync(string token)
+ public virtual async Task CompleteAsync(PaymentRequestCompleteInputDto input)
{
return await RequestAsync(nameof(CompleteAsync), new ClientProxyRequestTypeValue
{
- { typeof(string), token }
+ { typeof(PaymentRequestCompleteInputDto), input }
});
}
diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json
index 7f45f280..ad90fbc0 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json
+++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json
@@ -14,33 +14,33 @@
}
],
"actions": {
- "CompleteAsyncByToken": {
- "uniqueName": "CompleteAsyncByToken",
+ "CompleteAsyncByInput": {
+ "uniqueName": "CompleteAsyncByInput",
"name": "CompleteAsync",
"httpMethod": "POST",
"url": "api/payment/requests/complete",
"supportedVersions": [],
"parametersOnMethod": [
{
- "name": "token",
- "typeAsString": "System.String, System.Private.CoreLib",
- "type": "System.String",
- "typeSimple": "string",
+ "name": "input",
+ "typeAsString": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCompleteInputDto, EShopOnAbp.PaymentService.Application.Contracts",
+ "type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCompleteInputDto",
+ "typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCompleteInputDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
- "nameOnMethod": "token",
- "name": "token",
+ "nameOnMethod": "input",
+ "name": "input",
"jsonName": null,
- "type": "System.String",
- "typeSimple": "string",
+ "type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCompleteInputDto",
+ "typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCompleteInputDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
- "bindingSourceId": "ModelBinding",
+ "bindingSourceId": "Body",
"descriptorName": ""
}
],
diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs
index 23af9ecd..9eed0e02 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs
@@ -30,11 +30,7 @@ namespace EShopOnAbp.PaymentService
var hostingEnvironment = context.Services.GetHostingEnvironment();
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");
// SwaggerConfigurationHelper.Configure(context, "Payment Service API");
diff --git a/services/payment/src/EShopOnAbp.PaymentService.HttpApi/Controllers/PaymentRequestController.cs b/services/payment/src/EShopOnAbp.PaymentService.HttpApi/Controllers/PaymentRequestController.cs
index 7325ed28..4c73bf1c 100644
--- a/services/payment/src/EShopOnAbp.PaymentService.HttpApi/Controllers/PaymentRequestController.cs
+++ b/services/payment/src/EShopOnAbp.PaymentService.HttpApi/Controllers/PaymentRequestController.cs
@@ -20,9 +20,9 @@ namespace EShopOnAbp.PaymentService.Controllers
}
[HttpPost("complete")]
- public Task CompleteAsync(string token)
+ public Task CompleteAsync(PaymentRequestCompleteInputDto input)
{
- return PaymentRequestAppService.CompleteAsync(token);
+ return PaymentRequestAppService.CompleteAsync(input);
}
[HttpPost]
@@ -47,4 +47,4 @@ namespace EShopOnAbp.PaymentService.Controllers
return PaymentRequestAppService.StartAsync(input);
}
}
-}
+}
\ No newline at end of file
diff --git a/services/payment/test/EShopOnAbp.PaymentService.EntityFrameworkCore.Tests/PaymentRequests/PaymentRequestRepository_Tests.cs b/services/payment/test/EShopOnAbp.PaymentService.EntityFrameworkCore.Tests/PaymentRequests/PaymentRequestRepository_Tests.cs
index 406f5e10..f21634a0 100644
--- a/services/payment/test/EShopOnAbp.PaymentService.EntityFrameworkCore.Tests/PaymentRequests/PaymentRequestRepository_Tests.cs
+++ b/services/payment/test/EShopOnAbp.PaymentService.EntityFrameworkCore.Tests/PaymentRequests/PaymentRequestRepository_Tests.cs
@@ -18,12 +18,12 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public async Task Should_Insert_Payment_Request()
{
var id = Guid.NewGuid();
- var paymentRequest = new PaymentRequest(id, "USD");
-
+ var paymentRequest = new PaymentRequest(id, "123",456,"USD");
+
await _paymentRequestRepository.InsertAsync(paymentRequest, autoSave: true);
-
+
var inserted = await _paymentRequestRepository.GetAsync(id);
-
+
inserted.Id.ShouldNotBe(Guid.Empty);
}
}