woocommerce-paypal-payments/modules.local/ppcp-button/src/Assets/SmartButton.php

468 lines
16 KiB
PHP
Raw Normal View History

2020-04-02 08:38:00 +03:00
<?php
2020-04-28 12:31:12 +03:00
2020-04-02 08:38:00 +03:00
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Button\Assets;
2020-04-30 15:28:48 +03:00
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
use Inpsyde\PayPalCommerce\ApiClient\Helper\DccApplies;
2020-04-13 09:07:20 +03:00
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
2020-04-02 08:38:00 +03:00
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
2020-07-10 12:33:13 +03:00
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
use Inpsyde\PayPalCommerce\Session\SessionHandler;
2020-07-28 12:27:42 +03:00
use Inpsyde\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
2020-04-02 08:38:00 +03:00
class SmartButton implements SmartButtonInterface
2020-04-02 08:38:00 +03:00
{
private $moduleUrl;
private $sessionHandler;
private $settings;
2020-04-13 09:07:20 +03:00
private $payeeRepository;
2020-04-30 15:28:48 +03:00
private $identityToken;
private $payerFactory;
private $clientId;
2020-07-10 12:33:13 +03:00
private $requestData;
private $dccApplies;
2020-07-28 12:27:42 +03:00
private $subscriptionHelper;
2020-04-02 08:38:00 +03:00
public function __construct(
string $moduleUrl,
SessionHandler $sessionHandler,
2020-04-13 09:07:20 +03:00
Settings $settings,
2020-04-30 15:28:48 +03:00
PayeeRepository $payeeRepository,
IdentityToken $identityToken,
PayerFactory $payerFactory,
2020-07-10 12:33:13 +03:00
string $clientId,
RequestData $requestData,
2020-07-28 12:27:42 +03:00
DccApplies $dccApplies,
SubscriptionHelper $subscriptionHelper
2020-04-02 08:38:00 +03:00
) {
2020-04-06 11:16:18 +03:00
2020-04-02 08:38:00 +03:00
$this->moduleUrl = $moduleUrl;
$this->sessionHandler = $sessionHandler;
$this->settings = $settings;
2020-04-13 09:07:20 +03:00
$this->payeeRepository = $payeeRepository;
2020-04-30 15:28:48 +03:00
$this->identityToken = $identityToken;
$this->payerFactory = $payerFactory;
$this->clientId = $clientId;
2020-07-10 12:33:13 +03:00
$this->requestData = $requestData;
$this->dccApplies = $dccApplies;
2020-07-28 12:27:42 +03:00
$this->subscriptionHelper = $subscriptionHelper;
2020-04-02 08:38:00 +03:00
}
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
2020-07-10 12:56:01 +03:00
// phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
/**
* ToDo: Refactor
* @return bool
*/
public function renderWrapper(): bool
2020-04-02 08:38:00 +03:00
{
2020-04-30 15:28:48 +03:00
if (! $this->canSaveVaultToken() && $this->hasSubscription()) {
return false;
}
$buttonRenderer = static function () {
$product = wc_get_product();
if (
! is_checkout() && is_a($product, \WC_Product::class)
&& (
$product->is_type(['external', 'grouped'])
|| ! $product->is_in_stock()
)
) {
return;
}
2020-04-02 08:38:00 +03:00
echo '<div id="ppc-button"></div>';
};
$notEnabledOnCart = $this->settings->has('button_cart_enabled') &&
!$this->settings->get('button_cart_enabled');
2020-06-15 11:48:37 +03:00
if (
is_cart()
&& !$notEnabledOnCart
2020-06-15 11:48:37 +03:00
) {
2020-04-08 12:33:34 +03:00
add_action(
'woocommerce_proceed_to_checkout',
$buttonRenderer,
20
);
}
$notEnabledOnProductPage = $this->settings->has('button_single_product_enabled') &&
!$this->settings->get('button_single_product_enabled');
2020-06-15 11:48:37 +03:00
if (
(is_product() || wc_post_content_has_shortcode('product_page'))
&& !$notEnabledOnProductPage
2020-06-15 11:48:37 +03:00
) {
add_action(
'woocommerce_single_product_summary',
$buttonRenderer,
31
);
}
2020-08-18 10:12:07 +03:00
$notEnabledOnMiniCart = $this->settings->has('button_mini_cart_enabled') &&
!$this->settings->get('button_mini_cart_enabled');
2020-06-15 11:48:37 +03:00
if (
! $notEnabledOnMiniCart
2020-06-15 11:48:37 +03:00
) {
add_action(
'woocommerce_widget_shopping_cart_after_buttons',
2020-04-28 12:31:12 +03:00
static function () {
echo '<p id="ppc-button-minicart" class="woocommerce-mini-cart__buttons buttons"></p>';
},
30
);
}
add_action(
'woocommerce_review_order_after_submit',
$buttonRenderer,
10
);
2020-06-15 11:48:37 +03:00
if (
$this->settings->has('dcc_checkout_enabled')
&& $this->settings->get('dcc_checkout_enabled')
&& ! $this->sessionHandler->order()
2020-06-15 11:48:37 +03:00
) {
add_action(
'woocommerce_review_order_after_submit',
[
$this,
'dccRenderer',
],
11
);
}
2020-04-08 12:33:34 +03:00
return true;
2020-04-02 08:38:00 +03:00
}
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
2020-07-10 12:56:01 +03:00
// phpcs:enable Generic.Metrics.CyclomaticComplexity.TooHigh
2020-04-02 08:38:00 +03:00
2020-04-09 18:15:57 +03:00
public function enqueue(): bool
2020-04-02 08:38:00 +03:00
{
if (! $this->canSaveVaultToken() && $this->hasSubscription()) {
return false;
}
wp_enqueue_style(
2020-07-17 11:47:00 +03:00
'ppcp-hosted-fields',
2020-07-21 09:14:13 +03:00
$this->moduleUrl . '/assets/css/hosted-fields.css',
[],
1
2020-07-17 11:47:00 +03:00
);
2020-04-02 08:38:00 +03:00
wp_enqueue_script(
2020-06-15 11:48:37 +03:00
'ppcp-smart-button',
2020-04-28 12:31:12 +03:00
$this->moduleUrl . '/assets/js/button.js',
['jquery'],
1,
true
2020-04-02 08:38:00 +03:00
);
2020-04-13 09:07:20 +03:00
wp_localize_script(
2020-06-15 11:48:37 +03:00
'ppcp-smart-button',
2020-04-13 09:07:20 +03:00
'PayPalCommerceGateway',
$this->localizeScript()
);
return true;
}
2020-04-02 08:38:00 +03:00
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
public function dccRenderer()
{
$id = 'ppcp-hosted-fields';
$canRenderDcc = $this->dccApplies->forCountryCurrency()
&& $this->settings->has('client_id')
&& $this->settings->get('client_id');
if (! $canRenderDcc) {
return;
}
$saveCard = $this->canSaveVaultToken() ? sprintf(
2020-07-23 14:29:20 +03:00
'<div>
<label for="ppcp-vault-%1$s">%2$s</label>
<input
type="checkbox"
id="ppcp-vault-%1$s"
class="ppcp-credit-card-vault"
name="vault"
>
</div>',
esc_attr($id),
esc_html__('Save your card', 'woocommerce-paypal-commerce-gateway')
) : '';
printf(
'<form id="%1$s">
<div class="ppcp-dcc-credit-card-wrapper">
<div>
<label for="ppcp-credit-card-%1$s">%2$s</label>
<span id="ppcp-credit-card-%1$s" class="ppcp-credit-card"></span>
</div><div>
<label for="ppcp-expiration-date-%1$s">%3$s</label>
<span id="ppcp-expiration-date-%1$s" class="ppcp-expiration-date"></span>
</div><div>
<label for="ppcp-cvv-%1$s">%4$s</label>
<span id="ppcp-cvv-%1$s" class="ppcp-cvv"></span>
</div>
%5$s
</div>
<button>%6$s</button>
</form><div id="payments-sdk__contingency-lightbox"></div>',
esc_attr($id),
esc_html__('Card number', 'woocommerce-paypal-commerce-gateway'),
esc_html__('Expiration Date', 'woocommerce-paypal-commerce-gateway'),
esc_html__('CVV', 'woocommerce-paypal-commerce-gateway'),
//phpcs:ignore
$saveCard,
esc_html__('Pay with Card', 'woocommerce-paypal-commerce-gateway')
);
}
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
public function canSaveVaultToken(): bool
{
if (! $this->settings->has('client_id') || ! $this->settings->get('client_id')) {
return false;
}
if (! $this->settings->has('vault_enabled') || ! $this->settings->get('vault_enabled')) {
return false;
}
return is_user_logged_in();
}
2020-07-28 12:27:42 +03:00
private function hasSubscription(): bool
{
2020-07-28 12:27:42 +03:00
if (! $this->subscriptionHelper->acceptOnlyAutomaticPaymentGateways()) {
return false;
}
2020-07-28 12:27:42 +03:00
if (is_product()) {
return $this->subscriptionHelper->currentProductIsSubscription();
}
2020-07-28 12:27:42 +03:00
return $this->subscriptionHelper->cartContainsSubscription();
}
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
2020-04-28 12:31:12 +03:00
private function localizeScript(): array
2020-04-13 09:07:20 +03:00
{
2020-07-10 12:33:13 +03:00
$this->requestData->enqueueNonceFix();
2020-04-02 08:38:00 +03:00
$localize = [
2020-04-30 15:28:48 +03:00
'script_attributes' => $this->attributes(),
'data_client_id' => [
'set_attribute' => (is_checkout() && $this->dccIsEnabled()) || $this->canSaveVaultToken(),
'endpoint' => home_url(\WC_AJAX::get_endpoint(DataClientIdEndpoint::ENDPOINT)),
'nonce' => wp_create_nonce(DataClientIdEndpoint::nonce()),
'user' => get_current_user_id(),
],
2020-04-02 08:38:00 +03:00
'redirect' => wc_get_checkout_url(),
'context' => $this->context(),
'ajax' => [
'change_cart' => [
2020-04-06 11:16:18 +03:00
'endpoint' => home_url(\WC_AJAX::get_endpoint(ChangeCartEndpoint::ENDPOINT)),
2020-04-02 08:38:00 +03:00
'nonce' => wp_create_nonce(ChangeCartEndpoint::nonce()),
],
'create_order' => [
2020-04-06 11:16:18 +03:00
'endpoint' => home_url(\WC_AJAX::get_endpoint(CreateOrderEndpoint::ENDPOINT)),
2020-04-02 08:38:00 +03:00
'nonce' => wp_create_nonce(CreateOrderEndpoint::nonce()),
],
'approve_order' => [
'endpoint' => home_url(\WC_AJAX::get_endpoint(ApproveOrderEndpoint::ENDPOINT)),
'nonce' => wp_create_nonce(ApproveOrderEndpoint::nonce()),
],
2020-04-02 08:38:00 +03:00
],
'enforce_vault' => $this->hasSubscription(),
2020-07-15 19:49:32 +03:00
'bn_codes' => $this->bnCodes(),
'payer' => $this->payerData(),
2020-04-02 08:38:00 +03:00
'button' => [
'wrapper' => '#ppc-button',
2020-04-08 12:33:34 +03:00
'mini_cart_wrapper' => '#ppc-button-minicart',
'cancel_wrapper' => '#ppcp-cancel',
2020-04-13 09:07:20 +03:00
'url' => $this->url(),
2020-08-14 10:28:24 +03:00
'mini_cart_style' => [
'layout' => $this->styleForContext('layout', 'mini-cart'),
'size' => $this->styleForContext('size', 'mini-cart'),
'color' => $this->styleForContext('color', 'mini-cart'),
'shape' => $this->styleForContext('shape', 'mini-cart'),
'label' => $this->styleForContext('label', 'mini-cart'),
],
'style' => [
2020-08-14 10:28:24 +03:00
'layout' => $this->styleForContext('layout', $this->context()),
'size' => $this->styleForContext('size', $this->context()),
'color' => $this->styleForContext('color', $this->context()),
'shape' => $this->styleForContext('shape', $this->context()),
'label' => $this->styleForContext('label', $this->context()),
],
2020-04-06 11:16:18 +03:00
],
2020-04-30 15:28:48 +03:00
'hosted_fields' => [
'wrapper' => '#ppcp-hosted-fields',
'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
2020-04-30 15:28:48 +03:00
'labels' => [
'credit_card_number' => __('Credit Card Number', 'woocommerce-paypal-commerce-gateway'),
'cvv' => __('CVV', 'woocommerce-paypal-commerce-gateway'),
'mm_yyyy' => __('MM/YYYY', 'woocommerce-paypal-commerce-gateway'),
2020-07-22 14:12:49 +03:00
'fields_not_valid' => __(
'Unfortunatly, your credit card details are not valid.',
'woocommerce-paypal-commerce-gateway'
),
2020-04-30 15:28:48 +03:00
],
],
2020-07-28 08:05:18 +03:00
'labels' => [
'error' => [
'generic' => __(
'Something went wrong. Please try again or choose another payment source',
'woocommerce-paypal-commerce-gateway'
),
],
],
2020-04-02 08:38:00 +03:00
];
2020-07-10 12:33:13 +03:00
$this->requestData->dequeueNonceFix();
2020-04-13 09:07:20 +03:00
return $localize;
}
//phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
2020-04-13 09:07:20 +03:00
2020-04-28 12:31:12 +03:00
private function payerData(): ?array
{
$customer = WC()->customer;
if (! is_user_logged_in() || ! is_a($customer, \WC_Customer::class)) {
return null;
}
return $this->payerFactory->fromCustomer($customer)->toArray();
}
2020-04-28 12:31:12 +03:00
private function url(): string
2020-04-13 09:07:20 +03:00
{
$params = [
'client-id' => $this->clientId,
2020-04-13 09:07:20 +03:00
'currency' => get_woocommerce_currency(),
'locale' => get_user_locale(),
//'debug' => (defined('WP_DEBUG') && WP_DEBUG) ? 'true' : 'false',
//ToDo: Update date on releases.
'integration-date' => date('Y-m-d'),
2020-04-30 15:28:48 +03:00
'components' => implode(',', $this->components()),
'vault' => (is_checkout() && $this->dccIsEnabled()) || $this->canSaveVaultToken() ? 'true' : 'false',
2020-04-13 09:07:20 +03:00
'commit' => is_checkout() ? 'true' : 'false',
2020-06-29 12:16:06 +03:00
'intent' => ($this->settings->has('intent')) ? $this->settings->get('intent') : 'capture',
2020-04-13 09:07:20 +03:00
];
2020-04-30 15:28:48 +03:00
if (defined('WP_DEBUG') && \WP_DEBUG && WC()->customer) {
$params['buyer-country'] = WC()->customer->get_billing_country();
}
2020-04-13 09:07:20 +03:00
$payee = $this->payeeRepository->payee();
if ($payee->merchantId()) {
$params['merchant-id'] = $payee->merchantId();
}
2020-06-29 13:35:37 +03:00
$disableFunding = $this->settings->has('disable_funding') ?
$this->settings->get('disable_funding') : [];
2020-07-23 11:12:55 +03:00
$disableFunding[] = 'venmo';
$params['disable-funding'] = implode(',', $disableFunding);
2020-04-13 09:07:20 +03:00
$smartButtonUrl = add_query_arg($params, 'https://www.paypal.com/sdk/js');
return $smartButtonUrl;
2020-04-02 08:38:00 +03:00
}
2020-06-29 13:35:37 +03:00
private function attributes(): array
{
return [
2020-07-15 19:49:32 +03:00
'data-partner-attribution-id' => $this->bnCodeForContext($this->context()),
];
2020-04-30 15:28:48 +03:00
}
2020-07-15 19:49:32 +03:00
/**
* @param string $context
* @return string
*/
private function bnCodeForContext(string $context): string
{
$codes = $this->bnCodes();
return (isset($codes[$context])) ? $codes[$context] : '';
}
/**
* BN Codes
*
* @return array
*/
private function bnCodes(): array
{
return [
'checkout' => 'Woo_PPCP',
'cart' => 'Woo_PPCP',
'mini-cart' => 'Woo_PPCP',
'product' => 'Woo_PPCP',
2020-07-15 19:49:32 +03:00
];
}
2020-06-29 13:35:37 +03:00
private function components(): array
2020-04-30 15:28:48 +03:00
{
$components = ['buttons'];
if ($this->dccIsEnabled()) {
$components[] = 'hosted-fields';
}
return $components;
}
2020-04-09 18:15:57 +03:00
private function context(): string
2020-04-06 11:16:18 +03:00
{
2020-04-02 08:38:00 +03:00
$context = 'mini-cart';
if (is_product() || wc_post_content_has_shortcode('product_page')) {
2020-04-02 08:38:00 +03:00
$context = 'product';
}
if (is_cart()) {
$context = 'cart';
}
2020-04-09 18:15:57 +03:00
if (is_checkout() && !$this->sessionHandler->order()) {
2020-04-02 08:38:00 +03:00
$context = 'checkout';
}
return $context;
}
2020-04-30 15:28:48 +03:00
2020-06-29 13:35:37 +03:00
private function dccIsEnabled(): bool
2020-04-30 15:28:48 +03:00
{
if (! $this->dccApplies->forCountryCurrency()) {
return false;
}
2020-06-15 11:48:37 +03:00
$keys = [
2020-07-23 14:53:37 +03:00
'dcc_cart_enabled' => 'is_cart',
'dcc_mini_cart_enabled' => '__return_true',
'dcc_checkout_enabled' => 'is_checkout',
'dcc_single_product_enabled' => 'is_product',
2020-06-15 11:48:37 +03:00
];
2020-07-23 14:53:37 +03:00
foreach ($keys as $key => $callback) {
if ($this->settings->has($key) && $this->settings->get($key) && $callback()) {
2020-06-15 11:48:37 +03:00
return true;
}
}
return false;
2020-04-30 15:28:48 +03:00
}
2020-08-14 10:28:24 +03:00
2020-08-14 10:41:53 +03:00
private function styleForContext(string $style, string $context): string
{
2020-08-14 10:28:24 +03:00
$defaults = [
'layout' => 'vertical',
'size' => 'responsive',
'color' => 'gold',
'shape' => 'pill',
'label' => 'paypal',
];
2020-08-14 10:41:53 +03:00
$value = isset($defaults[$style]) ?
$defaults[$style] : '';
$value = $this->settings->has('button_' . $style) ?
$this->settings->get('button_' . $style) : $value;
$value = $this->settings->has('button_' . $context . '_' . $style) ?
$this->settings->get('button_' . $context . '_' . $style) : $value;
2020-08-14 10:28:24 +03:00
return $value;
}
2020-04-06 11:16:18 +03:00
}