Try your search with a different keyword or use * as a wildcard.
using Nop.Core;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Services.Catalog;
using Nop.Services.Customers;
namespace Nop.Services.Payments;
/// <summary>
/// Payment service
/// </summary>
public partial class PaymentService : IPaymentService
{
#region Fields
protected readonly ICustomerService _customerService;
protected readonly IPaymentPluginManager _paymentPluginManager;
protected readonly IPriceCalculationService _priceCalculationService;
protected readonly PaymentSettings _paymentSettings;
protected readonly ShoppingCartSettings _shoppingCartSettings;
#endregion
#region Ctor
public PaymentService(ICustomerService customerService,
IPaymentPluginManager paymentPluginManager,
IPriceCalculationService priceCalculationService,
PaymentSettings paymentSettings,
ShoppingCartSettings shoppingCartSettings)
{
_customerService = customerService;
_paymentPluginManager = paymentPluginManager;
_priceCalculationService = priceCalculationService;
_paymentSettings = paymentSettings;
_shoppingCartSettings = shoppingCartSettings;
}
#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 virtual async Task<ProcessPaymentResult> ProcessPaymentAsync(ProcessPaymentRequest processPaymentRequest)
{
if (processPaymentRequest.OrderTotal == decimal.Zero)
{
var result = new ProcessPaymentResult
{
NewPaymentStatus = PaymentStatus.Paid
};
return result;
}
//We should strip out any white space or dash in the CC number entered.
if (!string.IsNullOrWhiteSpace(processPaymentRequest.CreditCardNumber))
{
processPaymentRequest.CreditCardNumber = processPaymentRequest.CreditCardNumber.Replace(" ", string.Empty);
processPaymentRequest.CreditCardNumber = processPaymentRequest.CreditCardNumber.Replace("-", string.Empty);
}
var customer = await _customerService.GetCustomerByIdAsync(processPaymentRequest.CustomerId);
var paymentMethod = await _paymentPluginManager
.LoadPluginBySystemNameAsync(processPaymentRequest.PaymentMethodSystemName, customer, processPaymentRequest.StoreId)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.ProcessPaymentAsync(processPaymentRequest);
}
/// <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 virtual async Task PostProcessPaymentAsync(PostProcessPaymentRequest postProcessPaymentRequest)
{
//already paid or order.OrderTotal == decimal.Zero
if (postProcessPaymentRequest.Order.PaymentStatus == PaymentStatus.Paid)
return;
var customer = await _customerService.GetCustomerByIdAsync(postProcessPaymentRequest.Order.CustomerId);
var paymentMethod = await _paymentPluginManager
.LoadPluginBySystemNameAsync(postProcessPaymentRequest.Order.PaymentMethodSystemName, customer, postProcessPaymentRequest.Order.StoreId)
?? throw new NopException("Payment method couldn't be loaded");
await paymentMethod.PostProcessPaymentAsync(postProcessPaymentRequest);
}
/// <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 virtual async Task<bool> CanRePostProcessPaymentAsync(Order order)
{
ArgumentNullException.ThrowIfNull(order);
if (!_paymentSettings.AllowRePostingPayments)
return false;
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(order.PaymentMethodSystemName, customer, order.StoreId);
if (paymentMethod == null)
return false; //Payment method couldn't be loaded (for example, was uninstalled)
if (paymentMethod.PaymentMethodType != PaymentMethodType.Redirection)
return false; //this option is available only for redirection payment methods
if (order.Deleted)
return false; //do not allow for deleted orders
if (order.OrderStatus == OrderStatus.Cancelled)
return false; //do not allow for cancelled orders
if (order.PaymentStatus != PaymentStatus.Pending)
return false; //payment status should be Pending
return await paymentMethod.CanRePostProcessPaymentAsync(order);
}
/// <summary>
/// Gets an additional handling fee of a payment method
/// </summary>
/// <param name="cart">Shopping cart</param>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the additional handling fee
/// </returns>
public virtual async Task<decimal> GetAdditionalHandlingFeeAsync(IList<ShoppingCartItem> cart, string paymentMethodSystemName)
{
if (string.IsNullOrEmpty(paymentMethodSystemName))
return decimal.Zero;
var customer = await _customerService.GetCustomerByIdAsync(cart.FirstOrDefault()?.CustomerId ?? 0);
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName, customer, cart.FirstOrDefault()?.StoreId ?? 0);
if (paymentMethod == null)
return decimal.Zero;
var result = await paymentMethod.GetAdditionalHandlingFeeAsync(cart);
if (result < decimal.Zero)
result = decimal.Zero;
if (!_shoppingCartSettings.RoundPricesDuringCalculation)
return result;
result = await _priceCalculationService.RoundPriceAsync(result);
return result;
}
/// <summary>
/// Gets a value indicating whether capture is supported by payment method
/// </summary>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a value indicating whether capture is supported
/// </returns>
public virtual async Task<bool> SupportCaptureAsync(string paymentMethodSystemName)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName);
if (paymentMethod == null)
return false;
return paymentMethod.SupportCapture;
}
/// <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 virtual async Task<CapturePaymentResult> CaptureAsync(CapturePaymentRequest capturePaymentRequest)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(capturePaymentRequest.Order.PaymentMethodSystemName)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.CaptureAsync(capturePaymentRequest);
}
/// <summary>
/// Gets a value indicating whether partial refund is supported by payment method
/// </summary>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a value indicating whether partial refund is supported
/// </returns>
public virtual async Task<bool> SupportPartiallyRefundAsync(string paymentMethodSystemName)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName);
if (paymentMethod == null)
return false;
return paymentMethod.SupportPartiallyRefund;
}
/// <summary>
/// Gets a value indicating whether refund is supported by payment method
/// </summary>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a value indicating whether refund is supported
/// </returns>
public virtual async Task<bool> SupportRefundAsync(string paymentMethodSystemName)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName);
if (paymentMethod == null)
return false;
return paymentMethod.SupportRefund;
}
/// <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 virtual async Task<RefundPaymentResult> RefundAsync(RefundPaymentRequest refundPaymentRequest)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(refundPaymentRequest.Order.PaymentMethodSystemName)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.RefundAsync(refundPaymentRequest);
}
/// <summary>
/// Gets a value indicating whether void is supported by payment method
/// </summary>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a value indicating whether void is supported
/// </returns>
public virtual async Task<bool> SupportVoidAsync(string paymentMethodSystemName)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName);
if (paymentMethod == null)
return false;
return paymentMethod.SupportVoid;
}
/// <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 virtual async Task<VoidPaymentResult> VoidAsync(VoidPaymentRequest voidPaymentRequest)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(voidPaymentRequest.Order.PaymentMethodSystemName)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.VoidAsync(voidPaymentRequest);
}
/// <summary>
/// Gets a recurring payment type of payment method
/// </summary>
/// <param name="paymentMethodSystemName">Payment method system name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a recurring payment type of payment method
/// </returns>
public virtual async Task<RecurringPaymentType> GetRecurringPaymentTypeAsync(string paymentMethodSystemName)
{
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(paymentMethodSystemName);
if (paymentMethod == null)
return RecurringPaymentType.NotSupported;
return paymentMethod.RecurringPaymentType;
}
/// <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 virtual async Task<ProcessPaymentResult> ProcessRecurringPaymentAsync(ProcessPaymentRequest processPaymentRequest)
{
if (processPaymentRequest.OrderTotal == decimal.Zero)
{
var result = new ProcessPaymentResult
{
NewPaymentStatus = PaymentStatus.Paid
};
return result;
}
var customer = await _customerService.GetCustomerByIdAsync(processPaymentRequest.CustomerId);
var paymentMethod = await _paymentPluginManager
.LoadPluginBySystemNameAsync(processPaymentRequest.PaymentMethodSystemName, customer, processPaymentRequest.StoreId)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.ProcessRecurringPaymentAsync(processPaymentRequest);
}
/// <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 virtual async Task<CancelRecurringPaymentResult> CancelRecurringPaymentAsync(CancelRecurringPaymentRequest cancelPaymentRequest)
{
if (cancelPaymentRequest.Order.OrderTotal == decimal.Zero)
return new CancelRecurringPaymentResult();
var paymentMethod = await _paymentPluginManager.LoadPluginBySystemNameAsync(cancelPaymentRequest.Order.PaymentMethodSystemName)
?? throw new NopException("Payment method couldn't be loaded");
return await paymentMethod.CancelRecurringPaymentAsync(cancelPaymentRequest);
}
/// <summary>
/// Gets masked credit card number
/// </summary>
/// <param name="creditCardNumber">Credit card number</param>
/// <returns>Masked credit card number</returns>
public virtual string GetMaskedCreditCardNumber(string creditCardNumber)
{
if (string.IsNullOrEmpty(creditCardNumber))
return string.Empty;
if (creditCardNumber.Length <= 4)
return creditCardNumber;
var last4 = creditCardNumber[(creditCardNumber.Length - 4)..creditCardNumber.Length];
var maskedChars = string.Empty;
for (var i = 0; i < creditCardNumber.Length - 4; i++)
{
maskedChars += "*";
}
return maskedChars + last4;
}
#endregion
}