632 lines
30 KiB
C#
632 lines
30 KiB
C#
using System.Globalization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
using Microsoft.AspNetCore.Mvc.Routing;
|
|
using Microsoft.Extensions.Primitives;
|
|
using Nop.Core;
|
|
using Nop.Core.Domain.Cms;
|
|
using Nop.Core.Domain.Directory;
|
|
using Nop.Core.Domain.Orders;
|
|
using Nop.Core.Domain.Payments;
|
|
using Nop.Core.Http.Extensions;
|
|
using Nop.Plugin.Payments.PayPalCommerce.Components;
|
|
using Nop.Plugin.Payments.PayPalCommerce.Domain;
|
|
using Nop.Plugin.Payments.PayPalCommerce.Models;
|
|
using Nop.Plugin.Payments.PayPalCommerce.Services;
|
|
using Nop.Services.Cms;
|
|
using Nop.Services.Common;
|
|
using Nop.Services.Configuration;
|
|
using Nop.Services.Directory;
|
|
using Nop.Services.Localization;
|
|
using Nop.Services.Payments;
|
|
using Nop.Services.Plugins;
|
|
using Nop.Services.Stores;
|
|
using Nop.Web.Framework.Infrastructure;
|
|
|
|
namespace Nop.Plugin.Payments.PayPalCommerce;
|
|
|
|
/// <summary>
|
|
/// Represents a payment method implementation
|
|
/// </summary>
|
|
public class PayPalCommercePaymentMethod : BasePlugin, IPaymentMethod, IWidgetPlugin
|
|
{
|
|
#region Fields
|
|
|
|
protected readonly CurrencySettings _currencySettings;
|
|
protected readonly IActionContextAccessor _actionContextAccessor;
|
|
protected readonly ICurrencyService _currencyService;
|
|
protected readonly IGenericAttributeService _genericAttributeService;
|
|
protected readonly ILocalizationService _localizationService;
|
|
protected readonly IPaymentService _paymentService;
|
|
protected readonly ISettingService _settingService;
|
|
protected readonly IStoreService _storeService;
|
|
protected readonly IUrlHelperFactory _urlHelperFactory;
|
|
protected readonly PaymentSettings _paymentSettings;
|
|
protected readonly PayPalCommerceSettings _settings;
|
|
protected readonly ServiceManager _serviceManager;
|
|
protected readonly WidgetSettings _widgetSettings;
|
|
|
|
#endregion
|
|
|
|
#region Ctor
|
|
|
|
public PayPalCommercePaymentMethod(CurrencySettings currencySettings,
|
|
IActionContextAccessor actionContextAccessor,
|
|
ICurrencyService currencyService,
|
|
IGenericAttributeService genericAttributeService,
|
|
ILocalizationService localizationService,
|
|
IPaymentService paymentService,
|
|
ISettingService settingService,
|
|
IStoreService storeService,
|
|
IUrlHelperFactory urlHelperFactory,
|
|
PaymentSettings paymentSettings,
|
|
PayPalCommerceSettings settings,
|
|
ServiceManager serviceManager,
|
|
WidgetSettings widgetSettings)
|
|
{
|
|
_currencySettings = currencySettings;
|
|
_actionContextAccessor = actionContextAccessor;
|
|
_currencyService = currencyService;
|
|
_genericAttributeService = genericAttributeService;
|
|
_localizationService = localizationService;
|
|
_paymentService = paymentService;
|
|
_settingService = settingService;
|
|
_storeService = storeService;
|
|
_urlHelperFactory = urlHelperFactory;
|
|
_paymentSettings = paymentSettings;
|
|
_settings = settings;
|
|
_serviceManager = serviceManager;
|
|
_widgetSettings = widgetSettings;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// Process a payment
|
|
/// </summary>
|
|
/// <param name="processPaymentRequest">Payment info required for an order processing</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the process payment result
|
|
/// </returns>
|
|
public async Task<ProcessPaymentResult> ProcessPaymentAsync(ProcessPaymentRequest processPaymentRequest)
|
|
{
|
|
//try to get an order id from custom values
|
|
var orderIdKey = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.OrderId");
|
|
if (!processPaymentRequest.CustomValues.TryGetValue(orderIdKey, out var orderId) || string.IsNullOrEmpty(orderId?.ToString()))
|
|
throw new NopException("Failed to get the PayPal order ID");
|
|
|
|
//authorize or capture the order
|
|
var (order, error) = _settings.PaymentType == PaymentType.Capture
|
|
? await _serviceManager.CaptureAsync(_settings, orderId.ToString())
|
|
: (_settings.PaymentType == PaymentType.Authorize
|
|
? await _serviceManager.AuthorizeAsync(_settings, orderId.ToString())
|
|
: (default, default));
|
|
|
|
if (!string.IsNullOrEmpty(error))
|
|
return new ProcessPaymentResult { Errors = new[] { error } };
|
|
|
|
//request succeeded
|
|
var result = new ProcessPaymentResult();
|
|
|
|
var purchaseUnit = order.PurchaseUnits
|
|
.FirstOrDefault(item => item.ReferenceId.Equals(processPaymentRequest.OrderGuid.ToString()));
|
|
var authorization = purchaseUnit.Payments?.Authorizations?.FirstOrDefault();
|
|
if (authorization != null)
|
|
{
|
|
result.AuthorizationTransactionId = authorization.Id;
|
|
result.AuthorizationTransactionResult = authorization.Status;
|
|
result.NewPaymentStatus = PaymentStatus.Authorized;
|
|
}
|
|
var capture = purchaseUnit.Payments?.Captures?.FirstOrDefault();
|
|
if (capture != null)
|
|
{
|
|
result.CaptureTransactionId = capture.Id;
|
|
result.CaptureTransactionResult = capture.Status;
|
|
result.NewPaymentStatus = PaymentStatus.Paid;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Post process payment (used by payment gateways that require redirecting to a third-party URL)
|
|
/// </summary>
|
|
/// <param name="postProcessPaymentRequest">Payment info required for an order processing</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public Task PostProcessPaymentAsync(PostProcessPaymentRequest postProcessPaymentRequest)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Captures payment
|
|
/// </summary>
|
|
/// <param name="capturePaymentRequest">Capture payment request</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the capture payment result
|
|
/// </returns>
|
|
public async Task<CapturePaymentResult> CaptureAsync(CapturePaymentRequest capturePaymentRequest)
|
|
{
|
|
//capture a previously approved but not completed order
|
|
if (capturePaymentRequest.Order.AuthorizationTransactionResult == "approved")
|
|
{
|
|
//try to get an order id from custom values
|
|
var orderIdKey = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.OrderId");
|
|
var customValues = _paymentService.DeserializeCustomValues(capturePaymentRequest.Order);
|
|
if (!customValues.TryGetValue(orderIdKey, out var orderId) || string.IsNullOrEmpty(orderId?.ToString()))
|
|
throw new NopException("Failed to get the PayPal order ID");
|
|
|
|
var (order, orderError) = await _serviceManager.CaptureAsync(_settings, orderId.ToString());
|
|
if (!string.IsNullOrEmpty(orderError))
|
|
return new CapturePaymentResult { Errors = new[] { orderError } };
|
|
|
|
var purchaseUnit = order.PurchaseUnits
|
|
.FirstOrDefault(item => item.ReferenceId.Equals(capturePaymentRequest.Order.OrderGuid.ToString()));
|
|
var orderCapture = purchaseUnit.Payments?.Captures?.FirstOrDefault();
|
|
if (orderCapture is null)
|
|
return new CapturePaymentResult { Errors = new[] { "Order capture is empty" } };
|
|
|
|
//request succeeded
|
|
return new CapturePaymentResult
|
|
{
|
|
CaptureTransactionId = orderCapture.Id,
|
|
CaptureTransactionResult = orderCapture.Status,
|
|
NewPaymentStatus = PaymentStatus.Paid
|
|
};
|
|
}
|
|
|
|
//or capture previously authorized payment
|
|
var (capture, error) = await _serviceManager
|
|
.CaptureAuthorizationAsync(_settings, capturePaymentRequest.Order.AuthorizationTransactionId);
|
|
|
|
if (!string.IsNullOrEmpty(error))
|
|
return new CapturePaymentResult { Errors = new[] { error } };
|
|
|
|
//request succeeded
|
|
return new CapturePaymentResult
|
|
{
|
|
CaptureTransactionId = capture.Id,
|
|
CaptureTransactionResult = capture.Status,
|
|
NewPaymentStatus = PaymentStatus.Paid
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Voids a payment
|
|
/// </summary>
|
|
/// <param name="voidPaymentRequest">Request</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public async Task<VoidPaymentResult> VoidAsync(VoidPaymentRequest voidPaymentRequest)
|
|
{
|
|
//void previously authorized payment
|
|
var (_, error) = await _serviceManager.VoidAsync(_settings, voidPaymentRequest.Order.AuthorizationTransactionId);
|
|
|
|
if (!string.IsNullOrEmpty(error))
|
|
return new VoidPaymentResult { Errors = new[] { error } };
|
|
|
|
//request succeeded
|
|
return new VoidPaymentResult { NewPaymentStatus = PaymentStatus.Voided };
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refunds a payment
|
|
/// </summary>
|
|
/// <param name="refundPaymentRequest">Request</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public async Task<RefundPaymentResult> RefundAsync(RefundPaymentRequest refundPaymentRequest)
|
|
{
|
|
//refund previously captured payment
|
|
var amount = refundPaymentRequest.AmountToRefund != refundPaymentRequest.Order.OrderTotal
|
|
? (decimal?)refundPaymentRequest.AmountToRefund
|
|
: null;
|
|
|
|
//get the primary store currency
|
|
var currency = await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId)
|
|
?? throw new NopException("Primary store currency cannot be loaded");
|
|
|
|
var (refund, error) = await _serviceManager.RefundAsync(
|
|
_settings, refundPaymentRequest.Order.CaptureTransactionId, currency.CurrencyCode, amount);
|
|
|
|
if (!string.IsNullOrEmpty(error))
|
|
return new RefundPaymentResult { Errors = new[] { error } };
|
|
|
|
//request succeeded
|
|
var refundIds = await _genericAttributeService
|
|
.GetAttributeAsync<List<string>>(refundPaymentRequest.Order, PayPalCommerceDefaults.RefundIdAttributeName)
|
|
?? [];
|
|
if (!refundIds.Contains(refund.Id))
|
|
refundIds.Add(refund.Id);
|
|
await _genericAttributeService.SaveAttributeAsync(refundPaymentRequest.Order, PayPalCommerceDefaults.RefundIdAttributeName, refundIds);
|
|
return new RefundPaymentResult
|
|
{
|
|
NewPaymentStatus = refundPaymentRequest.IsPartialRefund ? PaymentStatus.PartiallyRefunded : PaymentStatus.Refunded
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process recurring payment
|
|
/// </summary>
|
|
/// <param name="processPaymentRequest">Payment info required for an order processing</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the process payment result
|
|
/// </returns>
|
|
public Task<ProcessPaymentResult> ProcessRecurringPaymentAsync(ProcessPaymentRequest processPaymentRequest)
|
|
{
|
|
return Task.FromResult(new ProcessPaymentResult { Errors = new[] { "Recurring payment not supported" } });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancels a recurring payment
|
|
/// </summary>
|
|
/// <param name="cancelPaymentRequest">Request</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public Task<CancelRecurringPaymentResult> CancelRecurringPaymentAsync(CancelRecurringPaymentRequest cancelPaymentRequest)
|
|
{
|
|
return Task.FromResult(new CancelRecurringPaymentResult { Errors = new[] { "Recurring payment not supported" } });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a value indicating whether payment method should be hidden during checkout
|
|
/// </summary>
|
|
/// <param name="cart">Shoping cart</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains true - hide; false - display.
|
|
/// </returns>
|
|
public Task<bool> HidePaymentMethodAsync(IList<ShoppingCartItem> cart)
|
|
{
|
|
var notConfigured = !ServiceManager.IsConfigured(_settings);
|
|
return Task.FromResult(notConfigured);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets additional handling fee
|
|
/// </summary>
|
|
/// <param name="cart">Shoping cart</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the additional handling fee
|
|
/// </returns>
|
|
public Task<decimal> GetAdditionalHandlingFeeAsync(IList<ShoppingCartItem> cart)
|
|
{
|
|
return Task.FromResult(decimal.Zero);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods)
|
|
/// </summary>
|
|
/// <param name="order">Order</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public Task<bool> CanRePostProcessPaymentAsync(Order order)
|
|
{
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validate payment form
|
|
/// </summary>
|
|
/// <param name="form">The parsed form values</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the list of validating errors
|
|
/// </returns>
|
|
public Task<IList<string>> ValidatePaymentFormAsync(IFormCollection form)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(form);
|
|
|
|
var errors = new List<string>();
|
|
|
|
//try to get errors from the form parameters
|
|
if (form.TryGetValue(nameof(PaymentInfoModel.Errors), out var errorValue) && !StringValues.IsNullOrEmpty(errorValue))
|
|
errors.Add(errorValue.ToString());
|
|
|
|
return Task.FromResult<IList<string>>(errors);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get payment information
|
|
/// </summary>
|
|
/// <param name="form">The parsed form values</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the payment info holder
|
|
/// </returns>
|
|
public async Task<ProcessPaymentRequest> GetPaymentInfoAsync(IFormCollection form)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(form);
|
|
|
|
//already set
|
|
return await _actionContextAccessor.ActionContext.HttpContext.Session
|
|
.GetAsync<ProcessPaymentRequest>(PayPalCommerceDefaults.PaymentRequestSessionKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a configuration page URL
|
|
/// </summary>
|
|
public override string GetConfigurationPageUrl()
|
|
{
|
|
return _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext).RouteUrl(PayPalCommerceDefaults.ConfigurationRouteName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a view component for displaying plugin in public store ("payment info" checkout step)
|
|
/// </summary>
|
|
public Type GetPublicViewComponent()
|
|
{
|
|
return typeof(PaymentInfoViewComponent);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets widget zones where this widget should be rendered
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the widget zones
|
|
/// </returns>
|
|
public Task<IList<string>> GetWidgetZonesAsync()
|
|
{
|
|
return Task.FromResult<IList<string>>(new List<string>
|
|
{
|
|
PublicWidgetZones.CheckoutPaymentInfoTop,
|
|
PublicWidgetZones.OpcContentBefore,
|
|
PublicWidgetZones.ProductDetailsTop,
|
|
PublicWidgetZones.ProductDetailsAddInfo,
|
|
PublicWidgetZones.OrderSummaryContentBefore,
|
|
PublicWidgetZones.OrderSummaryContentAfter,
|
|
PublicWidgetZones.HeaderLinksBefore,
|
|
PublicWidgetZones.Footer
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a type of a view component for displaying widget
|
|
/// </summary>
|
|
/// <param name="widgetZone">Name of the widget zone</param>
|
|
/// <returns>View component type</returns>
|
|
public Type GetWidgetViewComponent(string widgetZone)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(widgetZone);
|
|
|
|
if (widgetZone.Equals(PublicWidgetZones.CheckoutPaymentInfoTop) ||
|
|
widgetZone.Equals(PublicWidgetZones.OpcContentBefore) ||
|
|
widgetZone.Equals(PublicWidgetZones.ProductDetailsTop) ||
|
|
widgetZone.Equals(PublicWidgetZones.OrderSummaryContentBefore))
|
|
{
|
|
return typeof(ScriptViewComponent);
|
|
}
|
|
|
|
if (widgetZone.Equals(PublicWidgetZones.ProductDetailsAddInfo) || widgetZone.Equals(PublicWidgetZones.OrderSummaryContentAfter))
|
|
return typeof(ButtonsViewComponent);
|
|
|
|
if (widgetZone.Equals(PublicWidgetZones.HeaderLinksBefore) || widgetZone.Equals(PublicWidgetZones.Footer))
|
|
return typeof(LogoViewComponent);
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Install the plugin
|
|
/// </summary>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public override async Task InstallAsync()
|
|
{
|
|
//settings
|
|
await _settingService.SaveSettingAsync(new PayPalCommerceSettings
|
|
{
|
|
PaymentType = PaymentType.Capture,
|
|
LogoInHeaderLinks = @"<!-- PayPal Logo --><li><a href=""https://www.paypal.com/webapps/mpp/paypal-popup"" title=""How PayPal Works"" onclick=""javascript:window.open('https://www.paypal.com/webapps/mpp/paypal-popup','WIPaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700'); return false;""><img style=""padding-top:10px;"" src=""https://www.paypalobjects.com/webstatic/mktg/logo/bdg_now_accepting_pp_2line_w.png"" border=""0"" alt=""Now accepting PayPal""></a></li><!-- PayPal Logo -->",
|
|
LogoInFooter = @"<!-- PayPal Logo --><div><a href=""https://www.paypal.com/webapps/mpp/paypal-popup"" title=""How PayPal Works"" onclick=""javascript:window.open('https://www.paypal.com/webapps/mpp/paypal-popup','WIPaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700'); return false;""><img src=""https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg"" border=""0"" alt=""PayPal Acceptance Mark""></a></div><!-- PayPal Logo -->",
|
|
StyleLayout = "vertical",
|
|
StyleColor = "blue",
|
|
StyleShape = "rect",
|
|
StyleLabel = "paypal",
|
|
DisplayButtonsOnProductDetails = true,
|
|
DisplayButtonsOnShoppingCart = true,
|
|
DisplayPayLaterMessages = false,
|
|
RequestTimeout = PayPalCommerceDefaults.RequestTimeout,
|
|
MinDiscountAmount = 0.5M
|
|
});
|
|
|
|
if (!_paymentSettings.ActivePaymentMethodSystemNames.Contains(PayPalCommerceDefaults.SystemName))
|
|
{
|
|
_paymentSettings.ActivePaymentMethodSystemNames.Add(PayPalCommerceDefaults.SystemName);
|
|
await _settingService.SaveSettingAsync(_paymentSettings);
|
|
}
|
|
|
|
if (!_widgetSettings.ActiveWidgetSystemNames.Contains(PayPalCommerceDefaults.SystemName))
|
|
{
|
|
_widgetSettings.ActiveWidgetSystemNames.Add(PayPalCommerceDefaults.SystemName);
|
|
await _settingService.SaveSettingAsync(_widgetSettings);
|
|
}
|
|
|
|
//locales
|
|
await _localizationService.AddOrUpdateLocaleResourceAsync(new Dictionary<string, string>
|
|
{
|
|
["Enums.Nop.Plugin.Payments.PayPalCommerce.Domain.PaymentType.Authorize"] = "Authorize",
|
|
["Enums.Nop.Plugin.Payments.PayPalCommerce.Domain.PaymentType.Capture"] = "Capture",
|
|
["Plugins.Payments.PayPalCommerce.Configuration.Error"] = "Error: {0} (see details in the <a href=\"{1}\" target=\"_blank\">log</a>)",
|
|
["Plugins.Payments.PayPalCommerce.Credentials.Valid"] = "The specified credentials are valid",
|
|
["Plugins.Payments.PayPalCommerce.Credentials.Invalid"] = "The specified credentials are invalid",
|
|
["Plugins.Payments.PayPalCommerce.Fields.ClientId"] = "Client ID",
|
|
["Plugins.Payments.PayPalCommerce.Fields.ClientId.Hint"] = "Enter your PayPal REST API client ID. This identifies your PayPal account and determines where transactions are paid.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.ClientId.Required"] = "Client ID is required",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayButtonsOnProductDetails"] = "Display buttons on product details",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayButtonsOnProductDetails.Hint"] = "Determine whether to display PayPal buttons on product details pages, clicking on them matches the behavior of the default 'Add to cart' button.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayButtonsOnShoppingCart"] = "Display buttons on shopping cart",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayButtonsOnShoppingCart.Hint"] = "Determine whether to display PayPal buttons on the shopping cart page instead of the default checkout button.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayLogoInFooter"] = "Display logo in footer",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayLogoInFooter.Hint"] = "Determine whether to display PayPal logo in the footer. These logos and banners are a great way to let your buyers know that you choose PayPal to securely process their payments.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayLogoInHeaderLinks"] = "Display logo in header links",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayLogoInHeaderLinks.Hint"] = "Determine whether to display PayPal logo in header links. These logos and banners are a great way to let your buyers know that you choose PayPal to securely process their payments.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayPayLaterMessages"] = "Display Pay Later messages",
|
|
["Plugins.Payments.PayPalCommerce.Fields.DisplayPayLaterMessages.Hint"] = "Determine whether to display Pay Later messages. This message displays how much the customer pays in four payments. The message will be shown next to the PayPal buttons.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.Email"] = "Email",
|
|
["Plugins.Payments.PayPalCommerce.Fields.Email.Hint"] = "Enter your email to get access to PayPal payments.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.LogoInFooter"] = "Logo source code",
|
|
["Plugins.Payments.PayPalCommerce.Fields.LogoInFooter.Hint"] = "Enter source code of the logo. Find more logos and banners on PayPal Logo Center. You can also modify the code to fit correctly into your theme and site style.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.LogoInHeaderLinks"] = "Logo source code",
|
|
["Plugins.Payments.PayPalCommerce.Fields.LogoInHeaderLinks.Hint"] = "Enter source code of the logo. Find more logos and banners on PayPal Logo Center. You can also modify the code to fit correctly into your theme and site style.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.PaymentType"] = "Payment type",
|
|
["Plugins.Payments.PayPalCommerce.Fields.PaymentType.Hint"] = "Choose a payment type to either capture payment immediately or authorize a payment for an order after order creation. Notice, that alternative payment methods don't work with the 'authorize and capture later' feature.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.SecretKey"] = "Secret",
|
|
["Plugins.Payments.PayPalCommerce.Fields.SecretKey.Hint"] = "Enter your PayPal REST API secret.",
|
|
["Plugins.Payments.PayPalCommerce.Fields.SecretKey.Required"] = "Secret is required",
|
|
["Plugins.Payments.PayPalCommerce.Fields.SetCredentialsManually"] = "Specify API credentials manually",
|
|
["Plugins.Payments.PayPalCommerce.Fields.SetCredentialsManually.Hint"] = "Determine whether to manually set the credentials (for example, there is already an app created, or if you want to use the sandbox mode).",
|
|
["Plugins.Payments.PayPalCommerce.Fields.UseSandbox"] = "Use sandbox",
|
|
["Plugins.Payments.PayPalCommerce.Fields.UseSandbox.Hint"] = "Determine whether to use the sandbox environment for testing purposes.",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.AccessRevoked"] = "Profile access has been successfully revoked.",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Button"] = "Sign up for PayPal",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.ButtonRevoke"] = "Revoke access",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Completed"] = "Onboarding is sucessfully completed",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.EmailSet"] = "Email is set, now you are ready to sign up for PayPal",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Error"] = "An error occurred during the onboarding process, the credentials are empty",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.InProcess"] = "Onboarding is in process, see details below",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Process.Account"] = "PayPal account is created",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Process.Email"] = "Email address is confirmed",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Process.Payments"] = "Billing information is set",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Process.Permission"] = "Permissions are granted",
|
|
["Plugins.Payments.PayPalCommerce.Onboarding.Title"] = "Sign up for PayPal",
|
|
["Plugins.Payments.PayPalCommerce.OrderId"] = "PayPal order ID",
|
|
["Plugins.Payments.PayPalCommerce.Prominently"] = "Feature PayPal Prominently",
|
|
["Plugins.Payments.PayPalCommerce.PaymentMethodDescription"] = "PayPal Checkout with using methods like Venmo, PayPal Credit, credit card payments",
|
|
["Plugins.Payments.PayPalCommerce.RoundingWarning"] = "It looks like you have <a href=\"{0}\" target=\"_blank\">RoundPricesDuringCalculation</a> setting disabled. Keep in mind that this can lead to a discrepancy of the order total amount, as PayPal rounds to two decimals only.",
|
|
["Plugins.Payments.PayPalCommerce.WebhookWarning"] = "Webhook was not created, so some functions may not work correctly (see details in the <a href=\"{0}\" target=\"_blank\">log</a>. Please ensure that your store is under SSL, PayPal service doesn't send requests to unsecured sites.)"
|
|
});
|
|
|
|
await base.InstallAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Uninstall the plugin
|
|
/// </summary>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public override async Task UninstallAsync()
|
|
{
|
|
//webhooks
|
|
var stores = await _storeService.GetAllStoresAsync();
|
|
var storeIds = new List<int> { 0 }.Union(stores.Select(store => store.Id));
|
|
foreach (var storeId in storeIds)
|
|
{
|
|
var settings = await _settingService.LoadSettingAsync<PayPalCommerceSettings>(storeId);
|
|
if (!string.IsNullOrEmpty(settings.WebhookUrl))
|
|
await _serviceManager.DeleteWebhookAsync(settings);
|
|
}
|
|
|
|
//settings
|
|
if (_paymentSettings.ActivePaymentMethodSystemNames.Contains(PayPalCommerceDefaults.SystemName))
|
|
{
|
|
_paymentSettings.ActivePaymentMethodSystemNames.Remove(PayPalCommerceDefaults.SystemName);
|
|
await _settingService.SaveSettingAsync(_paymentSettings);
|
|
}
|
|
|
|
if (_widgetSettings.ActiveWidgetSystemNames.Contains(PayPalCommerceDefaults.SystemName))
|
|
{
|
|
_widgetSettings.ActiveWidgetSystemNames.Remove(PayPalCommerceDefaults.SystemName);
|
|
await _settingService.SaveSettingAsync(_widgetSettings);
|
|
}
|
|
|
|
await _settingService.DeleteSettingAsync<PayPalCommerceSettings>();
|
|
|
|
//locales
|
|
await _localizationService.DeleteLocaleResourcesAsync("Enums.Nop.Plugin.Payments.PayPalCommerce");
|
|
await _localizationService.DeleteLocaleResourcesAsync("Plugins.Payments.PayPalCommerce");
|
|
|
|
await base.UninstallAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update plugin
|
|
/// </summary>
|
|
/// <param name="currentVersion">Current version of plugin</param>
|
|
/// <param name="targetVersion">New version of plugin</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public override async Task UpdateAsync(string currentVersion, string targetVersion)
|
|
{
|
|
var current = decimal.TryParse(currentVersion, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : 1.00M;
|
|
|
|
//new setting added in 1.09
|
|
if (current < 1.09M)
|
|
{
|
|
var settings = await _settingService.LoadSettingAsync<PayPalCommerceSettings>();
|
|
if (!await _settingService.SettingExistsAsync(settings, setting => setting.MinDiscountAmount))
|
|
{
|
|
settings.MinDiscountAmount = 0.5M;
|
|
await _settingService.SaveSettingAsync(settings);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a payment method description that will be displayed on checkout pages in the public store
|
|
/// </summary>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public async Task<string> GetPaymentMethodDescriptionAsync()
|
|
{
|
|
return await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.PaymentMethodDescription");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properies
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether capture is supported
|
|
/// </summary>
|
|
public bool SupportCapture => true;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether void is supported
|
|
/// </summary>
|
|
public bool SupportVoid => true;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether refund is supported
|
|
/// </summary>
|
|
public bool SupportRefund => true;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether partial refund is supported
|
|
/// </summary>
|
|
public bool SupportPartiallyRefund => true;
|
|
|
|
/// <summary>
|
|
/// Gets a recurring payment type of payment method
|
|
/// </summary>
|
|
public RecurringPaymentType RecurringPaymentType => RecurringPaymentType.NotSupported;
|
|
|
|
/// <summary>
|
|
/// Gets a payment method type
|
|
/// </summary>
|
|
public PaymentMethodType PaymentMethodType => PaymentMethodType.Standard;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether we should display a payment information page for this plugin
|
|
/// </summary>
|
|
public bool SkipPaymentInfo => false;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether to hide this plugin on the widget list page in the admin area
|
|
/// </summary>
|
|
public bool HideInWidgetList => true;
|
|
|
|
#endregion
|
|
} |