Try your search with a different keyword or use * as a wildcard.
using System.Globalization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Payments.PayPalCommerce.Domain.Onboarding;
using Nop.Services.Attributes;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Directory;
using Nop.Services.Logging;
using Nop.Services.Orders;
using Nop.Services.Stores;
using Nop.Services.Tax;
using Nop.Web.Framework.Infrastructure;
using PayPal.v1.Webhooks;
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;
using PayPalCheckoutSdk.Payments;
using PayPalHttp;
using Order = PayPalCheckoutSdk.Orders.Order;
namespace Nop.Plugin.Payments.PayPalCommerce.Services;
///
/// Represents the plugin service manager
///
public class ServiceManager
{
#region Fields
protected readonly CurrencySettings _currencySettings;
protected readonly IActionContextAccessor _actionContextAccessor;
protected readonly IAddressService _addresService;
protected readonly IAttributeParser _checkoutAttributeParser;
protected readonly ICountryService _countryService;
protected readonly ICurrencyService _currencyService;
protected readonly IGenericAttributeService _genericAttributeService;
protected readonly ILogger _logger;
protected readonly IOrderProcessingService _orderProcessingService;
protected readonly IOrderService _orderService;
protected readonly IOrderTotalCalculationService _orderTotalCalculationService;
protected readonly IProductService _productService;
protected readonly IShoppingCartService _shoppingCartService;
protected readonly IStateProvinceService _stateProvinceService;
protected readonly IStoreContext _storeContext;
protected readonly IStoreService _storeService;
protected readonly ITaxService _taxService;
protected readonly IUrlHelperFactory _urlHelperFactory;
protected readonly IWebHelper _webHelper;
protected readonly IWorkContext _workContext;
protected readonly OnboardingHttpClient _onboardingHttpClient;
#endregion
#region Ctor
public ServiceManager(CurrencySettings currencySettings,
IActionContextAccessor actionContextAccessor,
IAddressService addresService,
IAttributeParser checkoutAttributeParser,
ICountryService countryService,
ICurrencyService currencyService,
IGenericAttributeService genericAttributeService,
ILogger logger,
IOrderProcessingService orderProcessingService,
IOrderService orderService,
IOrderTotalCalculationService orderTotalCalculationService,
IProductService productService,
IShoppingCartService shoppingCartService,
IStateProvinceService stateProvinceService,
IStoreContext storeContext,
IStoreService storeService,
ITaxService taxService,
IUrlHelperFactory urlHelperFactory,
IWebHelper webHelper,
IWorkContext workContext,
OnboardingHttpClient onboardingHttpClient)
{
_currencySettings = currencySettings;
_actionContextAccessor = actionContextAccessor;
_addresService = addresService;
_checkoutAttributeParser = checkoutAttributeParser;
_countryService = countryService;
_currencyService = currencyService;
_genericAttributeService = genericAttributeService;
_logger = logger;
_orderProcessingService = orderProcessingService;
_orderService = orderService;
_orderTotalCalculationService = orderTotalCalculationService;
_productService = productService;
_shoppingCartService = shoppingCartService;
_stateProvinceService = stateProvinceService;
_storeContext = storeContext;
_storeService = storeService;
_taxService = taxService;
_urlHelperFactory = urlHelperFactory;
_webHelper = webHelper;
_workContext = workContext;
_onboardingHttpClient = onboardingHttpClient;
}
#endregion
#region Utilities
///
/// Handle function and get result
///
/// Result type
/// Function
///
/// A task that represents the asynchronous operation
/// The task result contains the result; error message if exists
///
protected async Task<(TResult Result, string Error)> HandleFunctionAsync(Func> function)
{
try
{
//invoke function
return (await function(), default);
}
catch (Exception exception)
{
//get a short error message
var message = exception.Message;
if (exception is HttpException httpException)
{
//get error details if exist
var details = JsonConvert.DeserializeObject(httpException.Message);
message = details.Message?.Trim('.') ?? details.Name ?? message;
if (details?.Details?.Any() ?? false)
{
message += details.Details.Aggregate(":", (text, issue) => $"{text} " +
$"{(issue.Description ?? issue.Issue).Trim('.')}{(!string.IsNullOrEmpty(issue.Field) ? $"({issue.Field})" : null)},").Trim(',');
}
}
//log errors
var logMessage = $"{PayPalCommerceDefaults.SystemName} error: {System.Environment.NewLine}{message}";
await _logger.ErrorAsync(logMessage, exception, await _workContext.GetCurrentCustomerAsync());
return (default, message);
}
}
///
/// Handle request to checkout services and get result
///
/// Request type
/// Result type
/// Plugin settings
/// Request
///
/// A task that represents the asynchronous operation
/// The task result contains the result
///
protected static async Task HandleCheckoutRequestAsync(PayPalCommerceSettings settings, TRequest request)
where TRequest : HttpRequest where TResult : class
{
//prepare common request params
request.Headers.Add(HeaderNames.UserAgent, PayPalCommerceDefaults.UserAgent);
request.Headers.Add("PayPal-Partner-Attribution-Id", PayPalCommerceDefaults.PartnerCode);
request.Headers.Add("Prefer", "return=representation");
//execute request
var client = new PayPalHttpClient(settings.UseSandbox
? new SandboxEnvironment(settings.ClientId, settings.SecretKey)
: new LiveEnvironment(settings.ClientId, settings.SecretKey));
client.SetConnectTimeout(TimeSpan.FromSeconds(settings.RequestTimeout ?? 10));
var response = await client.Execute(request)
?? throw new NopException("No response from the service");
//return the results if necessary
if (typeof(TResult) == typeof(object))
return default;
var result = response.Result()
?? throw new NopException("No response from the service");
return result;
}
///
/// Handle request to core services and get result
///
/// Request type
/// Result type
/// Plugin settings
/// Request
///
/// A task that represents the asynchronous operation
/// The task result contains the result
///
protected static async Task HandleCoreRequestAsync(PayPalCommerceSettings settings, TRequest request)
where TRequest : BraintreeHttp.HttpRequest where TResult : class
{
//prepare common request params
request.Headers.Add(HeaderNames.UserAgent, PayPalCommerceDefaults.UserAgent);
request.Headers.Add("PayPal-Partner-Attribution-Id", PayPalCommerceDefaults.PartnerCode);
request.Headers.Add("Prefer", "return=representation");
//execute request
var client = new PayPal.Core.PayPalHttpClient(settings.UseSandbox
? new PayPal.Core.SandboxEnvironment(settings.ClientId, settings.SecretKey)
: new PayPal.Core.LiveEnvironment(settings.ClientId, settings.SecretKey));
client.SetConnectTimeout(TimeSpan.FromSeconds(settings.RequestTimeout ?? 10));
var response = await client.Execute(request)
?? throw new NopException("No response from the service");
//return the results if necessary
if (typeof(TResult) == typeof(object))
return default;
var result = response.Result()
?? throw new NopException("No response from the service");
return result;
}
#endregion
#region Methods
///
/// Check whether the plugin is configured
///
/// Plugin settings
/// Result
public static bool IsConfigured(PayPalCommerceSettings settings)
{
//client id and secret are required to request services
return !string.IsNullOrEmpty(settings?.ClientId) && !string.IsNullOrEmpty(settings?.SecretKey);
}
///
/// Get access token
///
/// Plugin settings
///
/// A task that represents the asynchronous operation
/// The task result contains the access token; error message if exists
///
public async Task<(AccessToken AccessToken, string Error)> GetAccessTokenAsync(PayPalCommerceSettings settings)
{
//try to get access token
return await HandleFunctionAsync(async () =>
{
var request = new AccessTokenRequest(settings.UseSandbox
? new SandboxEnvironment(settings.ClientId, settings.SecretKey)
: new LiveEnvironment(settings.ClientId, settings.SecretKey));
return await HandleCheckoutRequestAsync(settings, request);
});
}
///
/// Prepare service script
///
/// Plugin settings
/// Widget zone name
///
/// A task that represents the asynchronous operation
/// The task result contains the script; error message if exists
///
public async Task<(string Script, string Error)> GetScriptAsync(PayPalCommerceSettings settings, string widgetZone)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var components = new List() { "buttons" };
var parameters = new Dictionary
{
["client-id"] = settings.ClientId,
["currency"] = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId))?.CurrencyCode?.ToUpperInvariant(),
["intent"] = settings.PaymentType.ToString().ToLowerInvariant(),
["commit"] = (settings.PaymentType == Domain.PaymentType.Capture).ToString().ToLowerInvariant(),
["vault"] = false.ToString().ToLowerInvariant(),
["debug"] = false.ToString().ToLowerInvariant(),
["components"] = "",
//["buyer-country"] = null, //available in the sandbox only
//["locale"] = null, //PayPal auto detects this
};
if (!string.IsNullOrEmpty(settings.DisabledFunding))
parameters["disable-funding"] = settings.DisabledFunding;
if (!string.IsNullOrEmpty(settings.EnabledFunding))
parameters["enable-funding"] = settings.EnabledFunding;
if (widgetZone.Equals(PublicWidgetZones.OrderSummaryContentBefore) || widgetZone.Equals(PublicWidgetZones.ProductDetailsTop))
components.Add("funding-eligibility");
if (settings.DisplayPayLaterMessages)
components.Add("messages");
parameters["components"] = string.Join(",", components);
var scriptUrl = QueryHelpers.AddQueryString(PayPalCommerceDefaults.ServiceScriptUrl, parameters);
var pageType = widgetZone.Equals(PublicWidgetZones.OrderSummaryContentBefore)
? "cart"
: (widgetZone.Equals(PublicWidgetZones.ProductDetailsTop)
? "product-details"
: "checkout");
return $@"";
});
}
#region Payments
///
/// Create an order
///
/// Plugin settings
/// Order GUID
///
/// A task that represents the asynchronous operation
/// The task result contains the created order; error message if exists
///
public async Task<(Order Order, string Error)> CreateOrderAsync(PayPalCommerceSettings settings, Guid orderGuid)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var customer = await _workContext.GetCurrentCustomerAsync();
var store = await _storeContext.GetCurrentStoreAsync();
var currency = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId))?.CurrencyCode;
if (string.IsNullOrEmpty(currency))
throw new NopException("Primary store currency not set");
var billingAddress = await _addresService.GetAddressByIdAsync(customer.BillingAddressId ?? 0)
?? throw new NopException("Customer billing address not set");
var shoppingCart = (await _shoppingCartService
.GetShoppingCartAsync(customer, Core.Domain.Orders.ShoppingCartType.ShoppingCart, store.Id))
.ToList();
if (await _shoppingCartService.ShoppingCartRequiresShippingAsync(shoppingCart))
{
//in some cases shipping option may be reset, then plugin calculate order totals incorrectly
var shippingOption = await _genericAttributeService
.GetAttributeAsync(customer, NopCustomerDefaults.SelectedShippingOptionAttribute, store.Id);
if (string.IsNullOrEmpty(shippingOption?.Name))
throw new NopException("No shipping option selected");
}
var shippingAddress = await _addresService.GetAddressByIdAsync(customer.ShippingAddressId ?? 0);
if (!await _shoppingCartService.ShoppingCartRequiresShippingAsync(shoppingCart))
shippingAddress = null;
var billStateProvince = await _stateProvinceService.GetStateProvinceByAddressAsync(billingAddress);
var shipStateProvince = await _stateProvinceService.GetStateProvinceByAddressAsync(shippingAddress);
//prepare order details
var orderDetails = new OrderRequest { CheckoutPaymentIntent = settings.PaymentType.ToString().ToUpperInvariant() };
//prepare some common properties
orderDetails.ApplicationContext = new ApplicationContext
{
BrandName = CommonHelper.EnsureMaximumLength(store.Name, 127),
LandingPage = LandingPageType.Billing.ToString().ToUpperInvariant(),
UserAction = settings.PaymentType == Domain.PaymentType.Authorize
? UserActionType.Continue.ToString().ToUpperInvariant()
: UserActionType.Pay_now.ToString().ToUpperInvariant(),
ShippingPreference = (shippingAddress != null ? ShippingPreferenceType.Set_provided_address : ShippingPreferenceType.No_shipping)
.ToString().ToUpperInvariant()
};
//prepare customer billing details
orderDetails.Payer = new Payer
{
Name = new Name
{
GivenName = CommonHelper.EnsureMaximumLength(billingAddress.FirstName, 140),
Surname = CommonHelper.EnsureMaximumLength(billingAddress.LastName, 140)
},
Email = CommonHelper.EnsureMaximumLength(billingAddress.Email, 254),
AddressPortable = new AddressPortable
{
AddressLine1 = CommonHelper.EnsureMaximumLength(billingAddress.Address1, 300),
AddressLine2 = CommonHelper.EnsureMaximumLength(billingAddress.Address2, 300),
AdminArea2 = CommonHelper.EnsureMaximumLength(billingAddress.City, 120),
AdminArea1 = CommonHelper.EnsureMaximumLength(billStateProvince?.Abbreviation, 300),
CountryCode = (await _countryService.GetCountryByIdAsync(billingAddress.CountryId ?? 0))?.TwoLetterIsoCode,
PostalCode = CommonHelper.EnsureMaximumLength(billingAddress.ZipPostalCode, 60)
}
};
if (!string.IsNullOrEmpty(billingAddress.PhoneNumber))
{
var cleanPhone = CommonHelper.EnsureMaximumLength(CommonHelper.EnsureNumericOnly(billingAddress.PhoneNumber), 14);
orderDetails.Payer.PhoneWithType = new PhoneWithType { PhoneNumber = new Phone { NationalNumber = cleanPhone } };
}
//prepare purchase unit details
var taxTotal = Math.Round((await _orderTotalCalculationService.GetTaxTotalAsync(shoppingCart, false)).taxTotal, 2);
var (cartShippingTotal, _, _) = await _orderTotalCalculationService.GetShoppingCartShippingTotalAsync(shoppingCart, false);
var shippingTotal = Math.Round(cartShippingTotal ?? decimal.Zero, 2);
var (shoppingCartTotal, _, _, _, _, _) = await _orderTotalCalculationService
.GetShoppingCartTotalAsync(shoppingCart, usePaymentMethodAdditionalFee: false);
var orderTotal = Math.Round(shoppingCartTotal ?? decimal.Zero, 2);
var purchaseUnit = new PurchaseUnitRequest
{
ReferenceId = CommonHelper.EnsureMaximumLength(orderGuid.ToString(), 256),
CustomId = CommonHelper.EnsureMaximumLength(orderGuid.ToString(), 127),
Description = CommonHelper.EnsureMaximumLength($"Purchase at '{store.Name}'", 127),
SoftDescriptor = CommonHelper.EnsureMaximumLength(store.Name, 22)
};
//prepare shipping address details
if (shippingAddress != null)
{
purchaseUnit.ShippingDetail = new ShippingDetail
{
Name = new Name { FullName = CommonHelper.EnsureMaximumLength($"{shippingAddress.FirstName} {shippingAddress.LastName}", 300) },
AddressPortable = new AddressPortable
{
AddressLine1 = CommonHelper.EnsureMaximumLength(shippingAddress.Address1, 300),
AddressLine2 = CommonHelper.EnsureMaximumLength(shippingAddress.Address2, 300),
AdminArea2 = CommonHelper.EnsureMaximumLength(shippingAddress.City, 120),
AdminArea1 = CommonHelper.EnsureMaximumLength(shipStateProvince?.Abbreviation, 300),
CountryCode = (await _countryService.GetCountryByIdAsync(billingAddress.CountryId ?? 0))?.TwoLetterIsoCode,
PostalCode = CommonHelper.EnsureMaximumLength(shippingAddress.ZipPostalCode, 60)
}
};
}
PayPalCheckoutSdk.Orders.Money prepareMoney(decimal value) => new()
{
CurrencyCode = currency,
Value = value.ToString(PayPalCommerceDefaults.CurrenciesWithoutDecimals.Contains(currency.ToUpperInvariant()) ? "0" : "0.00", CultureInfo.InvariantCulture)
};
//set order items
purchaseUnit.Items = await shoppingCart.SelectAwait(async item =>
{
var product = await _productService.GetProductByIdAsync(item.ProductId);
var (unitPrice, _, _) = await _shoppingCartService.GetUnitPriceAsync(item, true);
var (itemPrice, _) = await _taxService.GetProductPriceAsync(product, unitPrice, false, customer);
return new Item
{
Name = CommonHelper.EnsureMaximumLength(product.Name, 127),
Description = CommonHelper.EnsureMaximumLength(product.ShortDescription, 127),
Sku = CommonHelper.EnsureMaximumLength(product.Sku, 127),
Quantity = item.Quantity.ToString(),
Category = (product.IsDownload ? ItemCategoryType.Digital_goods : ItemCategoryType.Physical_goods)
.ToString().ToUpperInvariant(),
UnitAmount = prepareMoney(itemPrice)
};
}).ToListAsync();
//add checkout attributes as order items
var checkoutAttributes = await _genericAttributeService
.GetAttributeAsync(customer, NopCustomerDefaults.CheckoutAttributes, store.Id);
var checkoutAttributeValues = _checkoutAttributeParser.ParseAttributeValues(checkoutAttributes);
await foreach (var (attribute, values) in checkoutAttributeValues)
{
await foreach (var attributeValue in values)
{
var (attributePrice, _) = await _taxService.GetCheckoutAttributePriceAsync(attribute, attributeValue, false, customer);
purchaseUnit.Items.Add(new Item
{
Name = CommonHelper.EnsureMaximumLength(attribute.Name, 127),
Description = CommonHelper.EnsureMaximumLength($"{attribute.Name} - {attributeValue.Name}", 127),
Quantity = 1.ToString(),
UnitAmount = prepareMoney(attributePrice)
});
}
}
//set totals
//there may be a problem with a mismatch of amounts since ItemTotal should equal sum of (unit amount * quantity) across all items
//but PayPal forcibly rounds all amounts to two decimal, so the more items, the higher the chance of rounding errors
//we obviously cannot change the order total, so slightly adjust other totals to match all requirements
var itemTotal = Math.Round(purchaseUnit.Items.Sum(item =>
decimal.Parse(item.UnitAmount.Value, NumberStyles.Any, CultureInfo.InvariantCulture) * int.Parse(item.Quantity)), 2);
var discountTotal = Math.Round(itemTotal + taxTotal + shippingTotal - orderTotal, 2);
if (discountTotal < decimal.Zero || discountTotal < settings.MinDiscountAmount)
{
taxTotal -= discountTotal;
discountTotal = decimal.Zero;
}
purchaseUnit.AmountWithBreakdown = new AmountWithBreakdown
{
CurrencyCode = currency,
Value = prepareMoney(orderTotal).Value,
AmountBreakdown = new AmountBreakdown
{
ItemTotal = prepareMoney(itemTotal),
TaxTotal = prepareMoney(taxTotal),
Shipping = prepareMoney(shippingTotal),
Discount = prepareMoney(discountTotal)
}
};
orderDetails.PurchaseUnits = [purchaseUnit];
var orderRequest = new OrdersCreateRequest().RequestBody(orderDetails);
return await HandleCheckoutRequestAsync(settings, orderRequest);
});
}
///
/// Authorize a previously created order
///
/// Plugin settings
/// Order id
///
/// A task that represents the asynchronous operation
/// The task result contains the authorized order; error message if exists
///
public async Task<(Order Order, string Error)> AuthorizeAsync(PayPalCommerceSettings settings, string orderId)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var request = new OrdersAuthorizeRequest(orderId).RequestBody(new AuthorizeRequest());
return await HandleCheckoutRequestAsync(settings, request);
});
}
///
/// Capture a previously created order
///
/// Plugin settings
/// Order id
///
/// A task that represents the asynchronous operation
/// The task result contains the captured order; error message if exists
///
public async Task<(Order Order, string Error)> CaptureAsync(PayPalCommerceSettings settings, string orderId)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var request = new OrdersCaptureRequest(orderId).RequestBody(new OrderActionRequest());
return await HandleCheckoutRequestAsync(settings, request);
});
}
///
/// Capture an authorization
///
/// Plugin settings
/// Authorization id
///
/// A task that represents the asynchronous operation
/// The task result contains the capture details; error message if exists
///
public async Task<(PayPalCheckoutSdk.Payments.Capture Capture, string Error)> CaptureAuthorizationAsync
(PayPalCommerceSettings settings, string authorizationId)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var request = new AuthorizationsCaptureRequest(authorizationId).RequestBody(new CaptureRequest());
return await HandleCheckoutRequestAsync(settings, request);
});
}
///
/// Void an authorization
///
/// Plugin settings
/// Authorization id
///
/// A task that represents the asynchronous operation
/// The task result contains the voided order; Error message if exists
///
public async Task<(object Order, string Error)> VoidAsync(PayPalCommerceSettings settings, string authorizationId)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var request = new VoidRequest(authorizationId);
return await HandleCheckoutRequestAsync(settings, request);
});
}
///
/// Refund a captured payment
///
/// Plugin settings
/// Capture id
/// Currency code
/// Amount to refund
///
/// A task that represents the asynchronous operation
/// The task result contains the refund details; error message if exists
///
public async Task<(PayPalCheckoutSdk.Payments.Refund Refund, string Error)> RefundAsync
(PayPalCommerceSettings settings, string captureId, string currency, decimal? amount = null)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var refundRequest = new RefundRequest();
if (amount.HasValue)
{
refundRequest.Amount = new PayPalCheckoutSdk.Payments.Money
{
CurrencyCode = currency,
Value = amount.Value.ToString(PayPalCommerceDefaults.CurrenciesWithoutDecimals.Contains(currency.ToUpperInvariant()) ? "0" : "0.00", CultureInfo.InvariantCulture)
};
}
var request = new CapturesRefundRequest(captureId).RequestBody(refundRequest);
return await HandleCheckoutRequestAsync(settings, request);
});
}
#endregion
#region Webhooks
///
/// Get webhook by the URL
///
/// Plugin settings
/// Webhook URL
///
/// A task that represents the asynchronous operation
/// The task result contains the webhook; error message if exists
///
public async Task<(Webhook Webhook, string Error)> GetWebhookAsync(PayPalCommerceSettings settings, string webhookUrl)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var webhookList = await HandleCoreRequestAsync(settings, new WebhookListRequest());
var webhookByUrl = webhookList?.Webhooks
?.FirstOrDefault(webhook => webhook.Url?.Equals(webhookUrl, StringComparison.InvariantCultureIgnoreCase) ?? false);
return webhookByUrl;
});
}
///
/// Create webhook that receive events for the subscribed event types
///
/// Plugin settings
/// Store id
///
/// A task that represents the asynchronous operation
/// The task result contains the webhook; error message if exists
///
public async Task<(Webhook Webhook, string Error)> CreateWebhookAsync(PayPalCommerceSettings settings, int storeId)
{
return await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
//prepare webhook URL
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
var store = storeId > 0
? await _storeService.GetStoreByIdAsync(storeId)
: await _storeContext.GetCurrentStoreAsync();
var webhookUrl = $"{store.Url.TrimEnd('/')}{urlHelper.RouteUrl(PayPalCommerceDefaults.WebhookRouteName)}".ToLowerInvariant();
//check whether the webhook already exists
var (webhook, _) = await GetWebhookAsync(settings, webhookUrl);
if (webhook is not null)
return webhook;
//or try to create the new one if doesn't exist
var request = new WebhookCreateRequest().RequestBody(new Webhook
{
EventTypes = PayPalCommerceDefaults.WebhookEventNames.Select(name => new EventType { Name = name }).ToList(),
Url = webhookUrl
});
return await HandleCoreRequestAsync(settings, request);
});
}
///
/// Delete webhook
///
/// Plugin settings
/// A task that represents the asynchronous operation
public async Task DeleteWebhookAsync(PayPalCommerceSettings settings)
{
await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
var (webhook, _) = await GetWebhookAsync(settings, settings.WebhookUrl);
if (webhook is null)
return null;
return await HandleCoreRequestAsync(settings, new WebhookDeleteRequest(webhook.Id));
});
}
///
/// Handle webhook request
///
/// Plugin settings
/// HTTP request
/// A task that represents the asynchronous operation
public async Task HandleWebhookAsync(PayPalCommerceSettings settings, Microsoft.AspNetCore.Http.HttpRequest request)
{
await HandleFunctionAsync(async () =>
{
//ensure that plugin is configured
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
//get request details
var rawRequestString = string.Empty;
using (var streamReader = new StreamReader(request.Body))
rawRequestString = await streamReader.ReadToEndAsync();
if (string.IsNullOrEmpty(settings.WebhookUrl))
throw new NopException("Webhook is not set");
var (webhook, _) = await GetWebhookAsync(settings, settings.WebhookUrl);
if (webhook is null)
throw new NopException($"No webhook configured for URL '{settings.WebhookUrl}'");
//define a local function to validate the webhook event and get an appropriate resource
async Task