Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

PayPalCommerceController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Payments.PayPalCommerce.Domain;
using Nop.Plugin.Payments.PayPalCommerce.Models;
using Nop.Plugin.Payments.PayPalCommerce.Services;
using Nop.Services;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Localization;
using Nop.Services.Messages;
using Nop.Services.Security;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Mvc.Filters;

namespace Nop.Plugin.Payments.PayPalCommerce.Controllers;

[Area(AreaNames.ADMIN)]
[AutoValidateAntiforgeryToken]
[ValidateIpAddress]
[AuthorizeAdmin]
public class PayPalCommerceController : BasePluginController
{
    #region Fields

    protected readonly IGenericAttributeService _genericAttributeService;
    protected readonly ILocalizationService _localizationService;
    protected readonly INotificationService _notificationService;
    protected readonly IPermissionService _permissionService;
    protected readonly ISettingService _settingService;
    protected readonly IStoreContext _storeContext;
    protected readonly IWorkContext _workContext;
    protected readonly ServiceManager _serviceManager;
    protected readonly ShoppingCartSettings _shoppingCartSettings;

    #endregion

    #region Ctor

    public PayPalCommerceController(IGenericAttributeService genericAttributeService,
        ILocalizationService localizationService,
        INotificationService notificationService,
        IPermissionService permissionService,
        ISettingService settingService,
        IStoreContext storeContext,
        IWorkContext workContext,
        ServiceManager serviceManager,
        ShoppingCartSettings shoppingCartSettings)
    {
        _genericAttributeService = genericAttributeService;
        _localizationService = localizationService;
        _notificationService = notificationService;
        _permissionService = permissionService;
        _settingService = settingService;
        _storeContext = storeContext;
        _workContext = workContext;
        _serviceManager = serviceManager;
        _shoppingCartSettings = shoppingCartSettings;
    }

    #endregion

    #region Utilities

    /// 
    /// Prepare credentials and onboarding model properties
    /// 
    /// Configuration model
    /// Plugin settings
    /// Store id
    /// A task that represents the asynchronous operation
    protected async Task PrepareCredentialsAsync(ConfigurationModel model, PayPalCommerceSettings settings, int storeId)
    {
        model.OnboardingModel.MerchantGuid = settings.MerchantGuid;
        model.OnboardingModel.SignUpUrl = settings.SignUpUrl;

        //no need to check credentials if the plugin is already configured or credentials were manually set
        if (settings.SetCredentialsManually || ServiceManager.IsConfigured(settings))
            return;

        //no need to check credentials until the merchant has been onboarded and signed up
        if (string.IsNullOrEmpty(settings.MerchantGuid) || !string.IsNullOrEmpty(settings.SignUpUrl))
            return;

        var (merchant, error) = await _serviceManager.GetMerchantAsync(settings.MerchantGuid);
        if (merchant is null || !string.IsNullOrEmpty(error))
        {
            var locale = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Configuration.Error");
            var errorMessage = string.Format(locale, error, Url.Action("List", "Log"));
            _notificationService.ErrorNotification(errorMessage, false);
            return;
        }

        model.OnboardingModel.AccountCreated = !string.IsNullOrEmpty(merchant.MerchantId);
        model.OnboardingModel.EmailConfirmed = merchant.EmailConfirmed;
        model.OnboardingModel.PaymentsReceivable = merchant.PaymentsReceivable;
        model.OnboardingModel.PermissionGranted = merchant.PermissionGranted;
        model.OnboardingModel.DisplayStatus = true;

        if (!merchant.EmailConfirmed || !merchant.PaymentsReceivable || !merchant.PermissionGranted)
        {
            var onboardingNotCompleted = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Onboarding.InProcess");
            _notificationService.WarningNotification(onboardingNotCompleted);
            return;
        }

        if (string.IsNullOrEmpty(merchant.ClientId) || string.IsNullOrEmpty(merchant.ClientSecret))
        {
            var onboardingError = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Onboarding.Error");
            _notificationService.ErrorNotification(onboardingError);
            return;
        }

        var onboardingCompleted = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Onboarding.Completed");
        _notificationService.SuccessNotification(onboardingCompleted);

        //first delete the unused webhook on a previous client, if changed
        if ((!merchant.ClientId?.Equals(settings.ClientId) ?? true) &&
            !string.IsNullOrEmpty(settings.WebhookUrl) &&
            !string.IsNullOrEmpty(settings.ClientId) &&
            !string.IsNullOrEmpty(settings.SecretKey))
        {
            await _serviceManager.DeleteWebhookAsync(settings);
        }

        //set new settings values
        settings.ClientId = merchant.ClientId;
        settings.SecretKey = merchant.ClientSecret;
        model.IsConfigured = ServiceManager.IsConfigured(settings);

        //ensure that webhook created, display warning in case of fail
        if (!string.IsNullOrEmpty(settings.ClientId) && !string.IsNullOrEmpty(settings.SecretKey))
        {
            var (webhook, _) = await _serviceManager.CreateWebhookAsync(settings, storeId);
            settings.WebhookUrl = webhook?.Url;
            if (string.IsNullOrEmpty(settings.WebhookUrl))
            {
                var url = Url.Action("List", "Log");
                var warning = string.Format(await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.WebhookWarning"), url);
                _notificationService.WarningNotification(warning, false);
            }
        }

        if (!string.IsNullOrEmpty(merchant.Email) && !merchant.Email.Equals(settings.Email, StringComparison.InvariantCultureIgnoreCase))
        {
            settings.Email = merchant.Email;
            model.Email = merchant.Email;
        }

        var overrideSettings = storeId > 0;
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.Email, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.WebhookUrl, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.ClientId, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SecretKey, overrideSettings, storeId, false);
        await _settingService.ClearCacheAsync();
    }

    #endregion

    #region Methods

    public async Task Configure(bool showtour = false)
    {
        if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManagePaymentMethods))
            return AccessDeniedView();

        var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();
        var settings = await _settingService.LoadSettingAsync(storeId);

        //we don't need some of the shared settings that loaded above, so load them separately for chosen store
        if (storeId > 0)
        {
            settings.WebhookUrl = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.WebhookUrl)}", storeId: storeId);
            settings.UseSandbox = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.UseSandbox)}", storeId: storeId);
            settings.ClientId = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.ClientId)}", storeId: storeId);
            settings.SecretKey = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.SecretKey)}", storeId: storeId);
            settings.Email = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.Email)}", storeId: storeId);
            settings.MerchantGuid = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.MerchantGuid)}", storeId: storeId);
            settings.SignUpUrl = await _settingService
                .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.SignUpUrl)}", storeId: storeId);
        }

        var model = new ConfigurationModel
        {
            Email = settings.Email,
            SetCredentialsManually = settings.SetCredentialsManually,
            UseSandbox = settings.UseSandbox,
            ClientId = settings.SetCredentialsManually ? settings.ClientId : string.Empty,
            SecretKey = settings.SetCredentialsManually ? settings.SecretKey : string.Empty,
            PaymentTypeId = (int)settings.PaymentType,
            DisplayButtonsOnShoppingCart = settings.DisplayButtonsOnShoppingCart,
            DisplayButtonsOnProductDetails = settings.DisplayButtonsOnProductDetails,
            DisplayLogoInHeaderLinks = settings.DisplayLogoInHeaderLinks,
            LogoInHeaderLinks = settings.LogoInHeaderLinks,
            DisplayLogoInFooter = settings.DisplayLogoInFooter,
            DisplayPayLaterMessages = settings.DisplayPayLaterMessages,
            LogoInFooter = settings.LogoInFooter,
            ActiveStoreScopeConfiguration = storeId,
            IsConfigured = ServiceManager.IsConfigured(settings)
        };

        await PrepareCredentialsAsync(model, settings, storeId);

        if (storeId > 0)
        {
            model.Email_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.Email, storeId);
            model.SetCredentialsManually_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.SetCredentialsManually, storeId);
            model.UseSandbox_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.UseSandbox, storeId);
            model.ClientId_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.ClientId, storeId);
            model.SecretKey_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.SecretKey, storeId);
            model.PaymentTypeId_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.PaymentType, storeId);
            model.DisplayButtonsOnShoppingCart_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.DisplayButtonsOnShoppingCart, storeId);
            model.DisplayButtonsOnProductDetails_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.DisplayButtonsOnProductDetails, storeId);
            model.DisplayLogoInHeaderLinks_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.DisplayLogoInHeaderLinks, storeId);
            model.LogoInHeaderLinks_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.LogoInHeaderLinks, storeId);
            model.DisplayLogoInFooter_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.DisplayLogoInFooter, storeId);
            model.DisplayPayLaterMessages_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.DisplayPayLaterMessages, storeId);
            model.LogoInFooter_OverrideForStore = await _settingService.SettingExistsAsync(settings, setting => setting.LogoInFooter, storeId);
        }

        model.PaymentTypes = (await PaymentType.Capture.ToSelectListAsync(false))
            .Select(item => new SelectListItem(item.Text, item.Value))
            .ToList();

        //prices and total aren't rounded, so display warning
        if (model.IsConfigured && !_shoppingCartSettings.RoundPricesDuringCalculation)
        {
            var url = Url.Action("AllSettings", "Setting", new { settingName = nameof(ShoppingCartSettings.RoundPricesDuringCalculation) });
            var warning = string.Format(await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.RoundingWarning"), url);
            _notificationService.WarningNotification(warning, false);
        }

        //ensure credentials are valid
        if (!string.IsNullOrEmpty(settings.ClientId) && !string.IsNullOrEmpty(settings.SecretKey))
        {
            var (_, credentialsError) = await _serviceManager.GetAccessTokenAsync(settings);
            if (!string.IsNullOrEmpty(credentialsError))
                _notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Credentials.Invalid"));
            else
                _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Credentials.Valid"));
        }

        //show configuration tour
        if (showtour)
        {
            var customer = await _workContext.GetCurrentCustomerAsync();
            var hideCard = await _genericAttributeService.GetAttributeAsync(customer, NopCustomerDefaults.HideConfigurationStepsAttribute);
            var closeCard = await _genericAttributeService.GetAttributeAsync(customer, NopCustomerDefaults.CloseConfigurationStepsAttribute);

            if (!hideCard && !closeCard)
                ViewBag.ShowTour = true;
        }

        return View("~/Plugins/Payments.PayPalCommerce/Views/Configure.cshtml", model);
    }

    [HttpPost, ActionName("Configure")]
    [FormValueRequired("save")]
    public async Task Configure(ConfigurationModel model)
    {
        if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManagePaymentMethods))
            return AccessDeniedView();

        var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();
        var settings = await _settingService.LoadSettingAsync(storeId);

        //set new settings values
        settings.SetCredentialsManually = model.SetCredentialsManually;
        settings.PaymentType = (PaymentType)model.PaymentTypeId;
        settings.DisplayButtonsOnShoppingCart = model.DisplayButtonsOnShoppingCart;
        settings.DisplayButtonsOnProductDetails = model.DisplayButtonsOnProductDetails;
        settings.DisplayLogoInHeaderLinks = model.DisplayLogoInHeaderLinks;
        settings.LogoInHeaderLinks = model.LogoInHeaderLinks;
        settings.DisplayLogoInFooter = model.DisplayLogoInFooter;
        settings.DisplayPayLaterMessages = model.DisplayPayLaterMessages;
        settings.LogoInFooter = model.LogoInFooter;

        if (model.SetCredentialsManually)
        {
            //we don't need some of the shared settings that loaded above, so load them separately for chosen store
            if (storeId > 0)
            {
                settings.WebhookUrl = await _settingService
                    .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.WebhookUrl)}", storeId: storeId);
                settings.UseSandbox = await _settingService
                    .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.UseSandbox)}", storeId: storeId);
                settings.ClientId = await _settingService
                    .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.ClientId)}", storeId: storeId);
                settings.SecretKey = await _settingService
                    .GetSettingByKeyAsync($"{nameof(PayPalCommerceSettings)}.{nameof(PayPalCommerceSettings.SecretKey)}", storeId: storeId);
            }

            //first delete the unused webhook on a previous client, if changed
            if ((!model.ClientId?.Equals(settings.ClientId) ?? true) &&
                !string.IsNullOrEmpty(settings.WebhookUrl) &&
                !string.IsNullOrEmpty(settings.ClientId) &&
                !string.IsNullOrEmpty(settings.SecretKey))
            {
                await _serviceManager.DeleteWebhookAsync(settings);
            }

            settings.UseSandbox = model.UseSandbox;
            settings.ClientId = model.ClientId;
            settings.SecretKey = model.SecretKey;

            //ensure that webhook created, display warning in case of fail
            if (!string.IsNullOrEmpty(settings.ClientId) && !string.IsNullOrEmpty(settings.SecretKey))
            {
                var (webhook, _) = await _serviceManager.CreateWebhookAsync(settings, storeId);
                settings.WebhookUrl = webhook?.Url;
                if (string.IsNullOrEmpty(settings.WebhookUrl))
                {
                    var url = Url.Action("List", "Log");
                    var warning = string.Format(await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.WebhookWarning"), url);
                    _notificationService.WarningNotification(warning, false);
                }
            }

            await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.WebhookUrl, model.ClientId_OverrideForStore, storeId, false);
            await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.UseSandbox, model.UseSandbox_OverrideForStore, storeId, false);
            await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.ClientId, model.ClientId_OverrideForStore, storeId, false);
            await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SecretKey, model.SecretKey_OverrideForStore, storeId, false);
        }

        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SetCredentialsManually, model.SetCredentialsManually_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.PaymentType, model.PaymentTypeId_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.DisplayButtonsOnShoppingCart, model.DisplayButtonsOnShoppingCart_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.DisplayButtonsOnProductDetails, model.DisplayButtonsOnProductDetails_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.DisplayLogoInHeaderLinks, model.DisplayLogoInHeaderLinks_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.LogoInHeaderLinks, model.LogoInHeaderLinks_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.DisplayLogoInFooter, model.DisplayLogoInFooter_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.DisplayPayLaterMessages, model.DisplayPayLaterMessages_OverrideForStore, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.LogoInFooter, model.LogoInFooter_OverrideForStore, storeId, false);
        await _settingService.ClearCacheAsync();

        _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Plugins.Saved"));

        return await Configure();
    }

    [HttpPost, ActionName("Configure")]
    [FormValueRequired("onboarding")]
    public async Task Onboarding(OnboardingModel model)
    {
        if (!ModelState.IsValid)
            return await Configure();

        var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();
        var settings = await _settingService.LoadSettingAsync(storeId);

        //try to onboard merchant with the passed email
        var (merchant, error) = await _serviceManager.OnboardAsync(model.Email);
        if (!string.IsNullOrEmpty(error))
        {
            var locale = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Configuration.Error");
            var errorMessage = string.Format(locale, error, Url.Action("List", "Log"));
            _notificationService.ErrorNotification(errorMessage, false);
            return await Configure();
        }

        settings.SetCredentialsManually = false;
        settings.UseSandbox = false;
        settings.ClientId = string.Empty;
        settings.SecretKey = string.Empty;
        settings.Email = merchant.Email;
        settings.SignUpUrl = merchant.SignUpUrl;
        settings.MerchantGuid = merchant.MerchantGuid;
        var overrideSettings = model.Email_OverrideForStore;
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SetCredentialsManually, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.UseSandbox, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.ClientId, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SecretKey, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.Email, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SignUpUrl, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.MerchantGuid, overrideSettings, storeId, false);
        await _settingService.ClearCacheAsync();

        var emailSet = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Onboarding.EmailSet");
        _notificationService.SuccessNotification(emailSet);

        return await Configure();
    }

    [HttpPost, ActionName("Configure")]
    [FormValueRequired("revoke")]
    public async Task RevokeAccess()
    {
        var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();
        var settings = await _settingService.LoadSettingAsync(storeId);

        var (_, error) = await _serviceManager.RevokeAccessAsync(settings.MerchantGuid);
        if (!string.IsNullOrEmpty(error))
        {
            var locale = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Configuration.Error");
            var errorMessage = string.Format(locale, error, Url.Action("List", "Log"));
            _notificationService.ErrorNotification(errorMessage, false);
            return await Configure();
        }

        settings.Email = string.Empty;
        settings.SignUpUrl = string.Empty;
        settings.MerchantGuid = string.Empty;
        settings.ClientId = string.Empty;
        settings.SecretKey = string.Empty;
        settings.WebhookUrl = string.Empty;
        var overrideSettings = storeId > 0;
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.Email, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SignUpUrl, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.MerchantGuid, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.ClientId, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SecretKey, overrideSettings, storeId, false);
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.WebhookUrl, overrideSettings, storeId, false);
        await _settingService.ClearCacheAsync();

        var accessRevoked = await _localizationService.GetResourceAsync("Plugins.Payments.PayPalCommerce.Onboarding.AccessRevoked");
        _notificationService.SuccessNotification(accessRevoked);

        return await Configure();
    }

    [HttpPost]
    public async Task SignUp(OnboardingModel model)
    {
        await _serviceManager.SignUpAsync(model.MerchantGuid, model.AuthCode, model.SharedId);

        //clear URL since the merchant is already signed up
        var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();
        var settings = await _settingService.LoadSettingAsync(storeId);
        settings.SignUpUrl = null;
        await _settingService.SaveSettingOverridablePerStoreAsync(settings, setting => setting.SignUpUrl, model.Email_OverrideForStore, storeId, false);
        await _settingService.ClearCacheAsync();

        return Ok();
    }

    #endregion
}