| 1 |
<?php declare( strict_types=1 ); |
| 2 |
|
| 3 |
namespace MultiSafepay\WooCommerce\PaymentMethods\Base; |
| 4 |
|
| 5 |
use MultiSafepay\Api\PaymentMethods\PaymentMethod; |
| 6 |
use MultiSafepay\Api\Transactions\TransactionResponse; |
| 7 |
use MultiSafepay\Exception\ApiException; |
| 8 |
use MultiSafepay\Exception\InvalidArgumentException; |
| 9 |
use MultiSafepay\WooCommerce\Services\BlocksPaymentDataService; |
| 10 |
use MultiSafepay\WooCommerce\Services\OrderService; |
| 11 |
use MultiSafepay\WooCommerce\Services\PaymentComponentService; |
| 12 |
use MultiSafepay\WooCommerce\Services\PaymentMethodService; |
| 13 |
use MultiSafepay\WooCommerce\Services\SdkService; |
| 14 |
use MultiSafepay\WooCommerce\Services\Blocks\BlocksContextService; |
| 15 |
use MultiSafepay\WooCommerce\Utils\Logger; |
| 16 |
use MultiSafepay\WooCommerce\Utils\PaymentMethodTitleBuilder; |
| 17 |
use Psr\Http\Client\ClientExceptionInterface; |
| 18 |
use Throwable; |
| 19 |
use WC_Countries; |
| 20 |
use WC_Order; |
| 21 |
use WC_Payment_Gateway; |
| 22 |
|
| 23 |
/** |
| 24 |
* Class BasePaymentMethod |
| 25 |
* |
| 26 |
* @package MultiSafepay\WooCommerce\PaymentMethods\Base |
| 27 |
*/ |
| 28 |
class BasePaymentMethod extends WC_Payment_Gateway { |
| 29 |
|
| 30 |
use BaseRefunds; |
| 31 |
|
| 32 |
public const TRANSACTION_TYPE_DIRECT = 'direct'; |
| 33 |
public const TRANSACTION_TYPE_REDIRECT = 'redirect'; |
| 34 |
|
| 35 |
public const GOOGLEPAY_TEST_MERCHANT_ID = '12345678901234567890'; |
| 36 |
public const GOOGLEPAY_TEST_MERCHANT_NAME = 'Example Merchant'; |
| 37 |
public const APPLEPAY_TEST_MERCHANT_NAME = 'Example Merchant'; |
| 38 |
|
| 39 |
public const DIRECT_PAYMENT_METHODS_WITHOUT_COMPONENTS = array( |
| 40 |
'BANKTRANS', |
| 41 |
); |
| 42 |
|
| 43 |
public const MULTISAFEPAY_COMPONENT_JS_URL = 'https://pay.multisafepay.com/sdk/components/v2/components.js'; |
| 44 |
public const MULTISAFEPAY_COMPONENT_CSS_URL = 'https://pay.multisafepay.com/sdk/components/v2/components.css'; |
| 45 |
|
| 46 |
public const NOT_ALLOW_REFUND_ORDER_STATUSES = array( |
| 47 |
'pending', |
| 48 |
'on-hold', |
| 49 |
'failed', |
| 50 |
); |
| 51 |
|
| 52 |
public const NOT_ALLOW_REFUND_PAYMENT_METHODS = array( |
| 53 |
'MULTIBANCO', |
| 54 |
); |
| 55 |
|
| 56 |
/** |
| 57 |
* A PaymentMethod object with the information of the payment method object |
| 58 |
* |
| 59 |
* @var PaymentMethod |
| 60 |
*/ |
| 61 |
protected $payment_method; |
| 62 |
|
| 63 |
/** |
| 64 |
* What type of transaction should be 'direct' or 'redirect' |
| 65 |
* |
| 66 |
* @var string |
| 67 |
*/ |
| 68 |
protected $type; |
| 69 |
|
| 70 |
/** |
| 71 |
* The MultiSafepay gateway code. |
| 72 |
* |
| 73 |
* @var string |
| 74 |
*/ |
| 75 |
protected $gateway_code; |
| 76 |
|
| 77 |
/** |
| 78 |
* The minimum amount for the payment method |
| 79 |
* |
| 80 |
* @var string |
| 81 |
*/ |
| 82 |
public $min_amount; |
| 83 |
|
| 84 |
/** |
| 85 |
* A custom initialized order status for this payment method |
| 86 |
* |
| 87 |
* @var string |
| 88 |
*/ |
| 89 |
public $initial_order_status; |
| 90 |
|
| 91 |
/** |
| 92 |
* User Roles |
| 93 |
* |
| 94 |
* @var array |
| 95 |
*/ |
| 96 |
public $user_roles; |
| 97 |
|
| 98 |
/** |
| 99 |
* If supports the payment component |
| 100 |
* |
| 101 |
* @var bool |
| 102 |
*/ |
| 103 |
public $payment_component = false; |
| 104 |
|
| 105 |
/** |
| 106 |
* Merchant name for Google Pay and Apple Pay |
| 107 |
* |
| 108 |
* @var string |
| 109 |
*/ |
| 110 |
public $merchant_name = ''; |
| 111 |
|
| 112 |
/** |
| 113 |
* Merchant ID for Google Pay |
| 114 |
* |
| 115 |
* @var string |
| 116 |
*/ |
| 117 |
public $merchant_id = ''; |
| 118 |
|
| 119 |
/** |
| 120 |
* Is WooCommerce checkout blocks active? |
| 121 |
* |
| 122 |
* @var bool |
| 123 |
*/ |
| 124 |
private $is_checkout_blocks; |
| 125 |
|
| 126 |
/** |
| 127 |
* @var Logger |
| 128 |
*/ |
| 129 |
private $logger; |
| 130 |
|
| 131 |
/** |
| 132 |
* BasePaymentMethod constructor. |
| 133 |
* |
| 134 |
* @param PaymentMethod $payment_method |
| 135 |
* @param Logger|null $logger |
| 136 |
*/ |
| 137 |
public function __construct( PaymentMethod $payment_method, ?Logger $logger = null ) { |
| 138 |
$this->logger = $logger ?? new Logger(); |
| 139 |
$this->payment_method = $payment_method; |
| 140 |
$this->supports = array( 'products', 'refunds' ); |
| 141 |
$this->id = $this->get_payment_method_id(); |
| 142 |
|
| 143 |
$this->is_checkout_blocks = $this->is_woocommerce_checkout_block_active(); |
| 144 |
|
| 145 |
// Classic payment-component assets must always be registered, because the |
| 146 |
// "Pay for order" endpoint (form-pay.php) is rendered with the classic |
| 147 |
// template even when the regular Checkout page uses the WooCommerce |
| 148 |
// Checkout block. The enqueue callbacks themselves are responsible for |
| 149 |
// skipping the standard checkout when Blocks is active to avoid |
| 150 |
// conflicting with the Blocks integration. |
| 151 |
if ( $this->is_payment_component_enabled() ) { |
| 152 |
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_payment_component_styles' ) ); |
| 153 |
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_payment_component_scripts' ) ); |
| 154 |
} |
| 155 |
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_multisafepay_scripts_by_gateway_code' ) ); |
| 156 |
|
| 157 |
$this->type = $this->get_payment_method_type(); |
| 158 |
$this->method_title = $this->get_payment_method_title(); |
| 159 |
$this->method_description = $this->get_payment_method_description(); |
| 160 |
$this->gateway_code = $this->get_payment_method_gateway_code(); |
| 161 |
$this->has_fields = $this->has_fields(); |
| 162 |
$this->icon = $this->get_logo(); |
| 163 |
$this->form_fields = $this->add_form_fields(); |
| 164 |
|
| 165 |
// Init form fields and load the settings. |
| 166 |
$this->init_form_fields(); |
| 167 |
$this->init_settings(); |
| 168 |
|
| 169 |
$this->enabled = $this->get_option( 'enabled', 'yes' ); |
| 170 |
$this->title = $this->get_option( 'title', $this->get_method_title() ); |
| 171 |
$this->description = $this->get_option( 'description' ); |
| 172 |
$this->max_amount = $this->get_option( 'max_amount' ); |
| 173 |
$this->min_amount = $this->get_option( 'min_amount' ); |
| 174 |
$this->user_roles = (array) $this->get_option( 'user_roles', array() ); |
| 175 |
$this->countries = $this->get_option( 'countries' ); |
| 176 |
$this->initial_order_status = $this->get_option( 'initial_order_status', false ); |
| 177 |
$this->payment_component = $this->is_payment_component_enabled(); |
| 178 |
$this->merchant_name = $this->get_option( 'merchant_name', false ); |
| 179 |
$this->merchant_id = $this->get_option( 'merchant_id', false ); |
| 180 |
$this->errors = array(); |
| 181 |
|
| 182 |
add_action( |
| 183 |
'woocommerce_update_options_payment_gateways_' . $this->id, |
| 184 |
array( |
| 185 |
$this, |
| 186 |
'process_admin_options', |
| 187 |
) |
| 188 |
); |
| 189 |
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'display_errors' ) ); |
| 190 |
} |
| 191 |
|
| 192 |
/** |
| 193 |
* @return string |
| 194 |
*/ |
| 195 |
public function get_payment_method_id(): string { |
| 196 |
return PaymentMethodService::get_legacy_woocommerce_payment_gateway_ids( $this->payment_method->getId() ); |
| 197 |
} |
| 198 |
|
| 199 |
/** |
| 200 |
* @return string |
| 201 |
*/ |
| 202 |
public function get_payment_method_gateway_code(): string { |
| 203 |
return $this->payment_method->getId(); |
| 204 |
} |
| 205 |
|
| 206 |
/** |
| 207 |
* Get the defined direct payment methods without components |
| 208 |
* |
| 209 |
* @return array |
| 210 |
*/ |
| 211 |
public function get_defined_direct_payment_methods_without_components(): array { |
| 212 |
return apply_filters( 'multisafepay_direct_payment_methods_without_components', self::DIRECT_PAYMENT_METHODS_WITHOUT_COMPONENTS ); |
| 213 |
} |
| 214 |
|
| 215 |
/** |
| 216 |
* Get the custom payment method type |
| 217 |
* |
| 218 |
* @return bool |
| 219 |
*/ |
| 220 |
public function is_payment_method_type_direct(): bool { |
| 221 |
return (bool) $this->get_option( 'direct_transaction', '0' ) || |
| 222 |
(bool) $this->get_option( 'use_direct_button', '0' ); |
| 223 |
} |
| 224 |
|
| 225 |
/** |
| 226 |
* Checks if the admin is editing the checkout page in the admin area |
| 227 |
* |
| 228 |
* This identifies Checkout block editor context in wp-admin, so Blocks gateway |
| 229 |
* registration can rely on enabled settings instead of runtime availability. |
| 230 |
* |
| 231 |
* @return bool |
| 232 |
* |
| 233 |
* @phpcs:disable WordPress.Security.NonceVerification.Recommended |
| 234 |
*/ |
| 235 |
public function admin_editing_checkout_page(): bool { |
| 236 |
// "null" as default value to avoid matching a potential page with id 0, or false |
| 237 |
$page_post_id = isset( $_GET['post'] ) ? (int) $_GET['post'] : null; |
| 238 |
$checkout_id = (int) get_option( 'woocommerce_checkout_page_id', false ); |
| 239 |
$page_action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : ''; |
| 240 |
|
| 241 |
return $page_post_id && |
| 242 |
( $page_post_id === $checkout_id ) && |
| 243 |
( 'edit' === $page_action ) && |
| 244 |
is_admin() && |
| 245 |
current_user_can( 'edit_pages' ); |
| 246 |
} |
| 247 |
|
| 248 |
/** |
| 249 |
* Get the payment method type |
| 250 |
* |
| 251 |
* @return string |
| 252 |
*/ |
| 253 |
public function get_payment_method_type(): string { |
| 254 |
// Converting to direct the transaction type for iDEAL |
| 255 |
if ( $this->is_ideal_2_0() ) { |
| 256 |
return self::TRANSACTION_TYPE_DIRECT; |
| 257 |
} |
| 258 |
|
| 259 |
return $this->is_payment_method_type_direct() || |
| 260 |
$this->is_payment_component_enabled() |
| 261 |
? self::TRANSACTION_TYPE_DIRECT |
| 262 |
: self::TRANSACTION_TYPE_REDIRECT; |
| 263 |
} |
| 264 |
|
| 265 |
/** |
| 266 |
* Get the status of Google Pay or Apple Pay direct button |
| 267 |
* |
| 268 |
* @param string $payment_method |
| 269 |
* |
| 270 |
* @return string |
| 271 |
*/ |
| 272 |
public function get_google_apple_pay_use_button( string $payment_method ): string { |
| 273 |
$settings = get_option( 'woocommerce_multisafepay_' . $payment_method . '_settings' ); |
| 274 |
if ( is_array( $settings ) && isset( $settings['use_direct_button'] ) ) { |
| 275 |
return '1' === $settings['use_direct_button'] ? self::TRANSACTION_TYPE_DIRECT : self::TRANSACTION_TYPE_REDIRECT; |
| 276 |
} |
| 277 |
return self::TRANSACTION_TYPE_REDIRECT; |
| 278 |
} |
| 279 |
|
| 280 |
/** |
| 281 |
* @return string |
| 282 |
*/ |
| 283 |
public function get_payment_method_title(): string { |
| 284 |
return $this->payment_method->getName(); |
| 285 |
} |
| 286 |
|
| 287 |
/** |
| 288 |
* @return string |
| 289 |
*/ |
| 290 |
public function get_payment_method_description(): string { |
| 291 |
return sprintf( |
| 292 |
/* translators: %2$: The payment method title */ |
| 293 |
__( 'Read more about %2$s on <a href="%1$s" target="_blank">MultiSafepay\'s Docs</a>.', 'multisafepay' ), |
| 294 |
'https://docs.multisafepay.com', |
| 295 |
$this->get_payment_method_title() |
| 296 |
); |
| 297 |
} |
| 298 |
|
| 299 |
/** |
| 300 |
* @return string |
| 301 |
*/ |
| 302 |
public function get_payment_method_icon(): string { |
| 303 |
return $this->payment_method->getLargeIconUrl(); |
| 304 |
} |
| 305 |
|
| 306 |
/** |
| 307 |
* @return string |
| 308 |
*/ |
| 309 |
protected function get_logo(): string { |
| 310 |
return $this->get_payment_method_icon(); |
| 311 |
} |
| 312 |
|
| 313 |
/** |
| 314 |
* @return bool |
| 315 |
*/ |
| 316 |
public function has_fields(): bool { |
| 317 |
if ( $this->is_payment_component_enabled() ) { |
| 318 |
return true; |
| 319 |
} |
| 320 |
|
| 321 |
return false; |
| 322 |
} |
| 323 |
|
| 324 |
/** |
| 325 |
* Return if the tokenization card on file is enabled. |
| 326 |
* |
| 327 |
* @return bool |
| 328 |
*/ |
| 329 |
public function is_tokenization_enabled(): bool { |
| 330 |
$settings = get_option( 'woocommerce_' . $this->id . '_settings', array( 'tokenization' => 'no' ) ); |
| 331 |
if ( ! isset( $settings['tokenization'] ) ) { |
| 332 |
return false; |
| 333 |
} |
| 334 |
return 'yes' === $settings['tokenization']; |
| 335 |
} |
| 336 |
|
| 337 |
/** |
| 338 |
* Return if the payment component is enabled. |
| 339 |
* |
| 340 |
* @return bool |
| 341 |
*/ |
| 342 |
public function is_payment_component_enabled(): bool { |
| 343 |
if ( ! $this->payment_method->supportsPaymentComponent() ) { |
| 344 |
return false; |
| 345 |
} |
| 346 |
|
| 347 |
if ( $this->is_ideal_2_0() ) { |
| 348 |
$settings = get_option( 'woocommerce_' . $this->id . '_settings', array( 'tokenization' => 'yes' ) ); |
| 349 |
if ( ! isset( $settings['tokenization'] ) ) { |
| 350 |
return true; |
| 351 |
} |
| 352 |
return 'yes' === $settings['tokenization']; |
| 353 |
} |
| 354 |
|
| 355 |
$settings = get_option( 'woocommerce_' . $this->id . '_settings', array( 'payment_component' => 'yes' ) ); |
| 356 |
if ( ! isset( $settings['payment_component'] ) ) { |
| 357 |
return true; |
| 358 |
} |
| 359 |
|
| 360 |
if ( $this->is_qr_enabled() || $this->is_qr_only_enabled() ) { |
| 361 |
return true; |
| 362 |
} |
| 363 |
|
| 364 |
return 'yes' === $settings['payment_component']; |
| 365 |
} |
| 366 |
|
| 367 |
/** |
| 368 |
* Return if QR is enabled for payment components. |
| 369 |
* |
| 370 |
* @return bool |
| 371 |
*/ |
| 372 |
public function is_qr_enabled(): bool { |
| 373 |
if ( ! $this->payment_method->supportsQr() ) { |
| 374 |
return false; |
| 375 |
} |
| 376 |
|
| 377 |
$settings = get_option( 'woocommerce_' . $this->id . '_settings', array( 'payment_component' => 'yes' ) ); |
| 378 |
if ( ! isset( $settings['payment_component'] ) ) { |
| 379 |
return false; |
| 380 |
} |
| 381 |
return 'qr' === $settings['payment_component']; |
| 382 |
} |
| 383 |
|
| 384 |
/** |
| 385 |
* Return if QR only is enabled for payment components. |
| 386 |
* |
| 387 |
* @return bool |
| 388 |
*/ |
| 389 |
public function is_qr_only_enabled(): bool { |
| 390 |
if ( ! $this->payment_method->supportsQr() ) { |
| 391 |
return false; |
| 392 |
} |
| 393 |
|
| 394 |
$settings = get_option( 'woocommerce_' . $this->id . '_settings', array( 'payment_component' => 'yes' ) ); |
| 395 |
if ( ! isset( $settings['payment_component'] ) ) { |
| 396 |
return false; |
| 397 |
} |
| 398 |
return 'qr_only' === $settings['payment_component']; |
| 399 |
} |
| 400 |
|
| 401 |
/** |
| 402 |
* Return the custom QR width in pixels |
| 403 |
* |
| 404 |
* @return string |
| 405 |
*/ |
| 406 |
public function get_qr_width(): string { |
| 407 |
return $this->get_option( 'qr_width', '' ); |
| 408 |
} |
| 409 |
|
| 410 |
/** |
| 411 |
* Enqueue JavaScript related with Payment Component. |
| 412 |
* |
| 413 |
* @return void |
| 414 |
*/ |
| 415 |
public function enqueue_payment_component_scripts(): void { |
| 416 |
if ( ! $this->should_enqueue_classic_assets() ) { |
| 417 |
return; |
| 418 |
} |
| 419 |
|
| 420 |
if ( is_checkout() || is_wc_endpoint_url( 'order-pay' ) ) { |
| 421 |
|
| 422 |
wp_enqueue_script( 'multisafepay-payment-component-script', self::MULTISAFEPAY_COMPONENT_JS_URL, array(), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 423 |
|
| 424 |
$multisafepay_payment_component_config = ( new PaymentComponentService() )->get_payment_component_arguments( $this ); |
| 425 |
$gateways_with_payment_component = ( new PaymentMethodService() )->get_woocommerce_payment_gateway_ids_with_payment_component_support(); |
| 426 |
|
| 427 |
$route = MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-payment-component.js'; |
| 428 |
wp_enqueue_script( 'multisafepay-payment-component-js', $route, array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 429 |
|
| 430 |
static $enabled_gateways_added = false; |
| 431 |
if ( ! $enabled_gateways_added ) { |
| 432 |
wp_localize_script( 'multisafepay-payment-component-js', 'multisafepay_payment_component_gateways', $gateways_with_payment_component ); |
| 433 |
$enabled_gateways_added = true; |
| 434 |
} |
| 435 |
wp_localize_script( 'multisafepay-payment-component-js', 'payment_component_config_' . $this->id, $multisafepay_payment_component_config ); |
| 436 |
wp_enqueue_script( 'multisafepay-payment-component-js' ); |
| 437 |
} |
| 438 |
} |
| 439 |
|
| 440 |
/** |
| 441 |
* Whether the classic (non-Blocks) payment-component assets should be |
| 442 |
* enqueued for the current request. |
| 443 |
* |
| 444 |
* The "Pay for order" endpoint is always rendered by the classic |
| 445 |
* `form-pay.php` template, so the classic assets are required there even |
| 446 |
* when the regular Checkout page uses the WooCommerce Checkout block. |
| 447 |
* In every other context, when Blocks is active for the Checkout page, |
| 448 |
* the dedicated Blocks integration is responsible for loading its own |
| 449 |
* assets, and the classic ones must not be loaded to avoid conflicts. |
| 450 |
* |
| 451 |
* @return bool |
| 452 |
*/ |
| 453 |
private function should_enqueue_classic_assets(): bool { |
| 454 |
if ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url( 'order-pay' ) ) { |
| 455 |
return true; |
| 456 |
} |
| 457 |
|
| 458 |
return ! $this->is_checkout_blocks; |
| 459 |
} |
| 460 |
|
| 461 |
/** |
| 462 |
* Check if the woocommerce checkout block is active. |
| 463 |
* |
| 464 |
* @return bool |
| 465 |
*/ |
| 466 |
private function is_woocommerce_checkout_block_active(): bool { |
| 467 |
$checkout_page_id = wc_get_page_id( 'checkout' ); |
| 468 |
$checkout_page = get_post( $checkout_page_id ); |
| 469 |
$has_block = ( new BlocksContextService() )->is_checkout_blocks_active(); |
| 470 |
|
| 471 |
// Fallback: WC_Blocks_Utils::has_block_in_page() doesn't detect nested blocks (e.g. inside columns). |
| 472 |
// If not detected, check directly in post-content. |
| 473 |
if ( ! $has_block && $checkout_page ) { |
| 474 |
$has_block = strpos( $checkout_page->post_content, 'wp:woocommerce/checkout' ) !== false; |
| 475 |
} |
| 476 |
|
| 477 |
return $has_block; |
| 478 |
} |
| 479 |
|
| 480 |
/** |
| 481 |
* Enqueue JavaScript related with a MultiSafepay Payment Method. |
| 482 |
* |
| 483 |
* @return void |
| 484 |
*/ |
| 485 |
public function enqueue_multisafepay_scripts_by_gateway_code(): void { |
| 486 |
if ( ! $this->should_enqueue_classic_assets() ) { |
| 487 |
return; |
| 488 |
} |
| 489 |
|
| 490 |
$gateway_code = $this->get_payment_method_gateway_code(); |
| 491 |
|
| 492 |
if ( ( 'APPLEPAY' === $gateway_code ) && ( ( $this->get_google_apple_pay_use_button( 'applepay' ) === self::TRANSACTION_TYPE_REDIRECT ) || is_wc_endpoint_url( 'order-pay' ) ) ) { |
| 493 |
wp_enqueue_script( 'multisafepay-apple-pay-js', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-apple-pay.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 494 |
} |
| 495 |
|
| 496 |
if ( ( 'GOOGLEPAY' === $gateway_code ) && ( ( $this->get_google_apple_pay_use_button( 'googlepay' ) === self::TRANSACTION_TYPE_REDIRECT ) || is_wc_endpoint_url( 'order-pay' ) ) ) { |
| 497 |
wp_enqueue_script( 'multisafepay-google-pay-js', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-google-pay.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 498 |
} |
| 499 |
|
| 500 |
// Static variable to track if the payment variables have been added |
| 501 |
static $payment_variables_for_applepay_added = false; |
| 502 |
static $payment_variables_for_googlepay_added = false; |
| 503 |
|
| 504 |
if ( is_checkout() && ! is_wc_endpoint_url( 'order-pay' ) ) { |
| 505 |
if ( ( 'APPLEPAY' === $gateway_code ) && ! $payment_variables_for_applepay_added && ( $this->get_google_apple_pay_use_button( 'applepay' ) === self::TRANSACTION_TYPE_DIRECT ) ) { |
| 506 |
wp_enqueue_script( 'multisafepay-apple-pay-wallet', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-apple-pay-wallet.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 507 |
$payment_variables = $this->build_applepay_wallet_variables( self::APPLEPAY_TEST_MERCHANT_NAME ) ?? ''; |
| 508 |
wp_add_inline_script( 'multisafepay-apple-pay-wallet', $payment_variables, 'before' ); |
| 509 |
// Mark that the payment variables have been added |
| 510 |
$payment_variables_for_applepay_added = true; |
| 511 |
} |
| 512 |
|
| 513 |
if ( 'GOOGLEPAY' === $gateway_code ) { |
| 514 |
wp_enqueue_script( 'google-pay-js', 'https://pay.google.com/gp/p/js/pay.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 515 |
if ( ! $payment_variables_for_googlepay_added && ( $this->get_google_apple_pay_use_button( 'googlepay' ) === self::TRANSACTION_TYPE_DIRECT ) ) { |
| 516 |
wp_enqueue_script( 'multisafepay-google-pay-wallet', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-google-pay-wallet.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 517 |
$payment_variables = $this->build_googlepay_wallet_variables( self::GOOGLEPAY_TEST_MERCHANT_ID, self::GOOGLEPAY_TEST_MERCHANT_NAME ) ?? ''; |
| 518 |
wp_add_inline_script( 'multisafepay-google-pay-wallet', $payment_variables, 'before' ); |
| 519 |
// Mark that the payment variables have been added |
| 520 |
$payment_variables_for_googlepay_added = true; |
| 521 |
} |
| 522 |
} |
| 523 |
|
| 524 |
if ( |
| 525 |
( ! $payment_variables_for_googlepay_added || ! $payment_variables_for_applepay_added ) && |
| 526 |
( ( 'GOOGLEPAY' === $gateway_code ) || ( 'APPLEPAY' === $gateway_code ) ) |
| 527 |
) { |
| 528 |
wp_enqueue_script( 'multisafepay-validator-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-validator-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 529 |
wp_enqueue_script( 'multisafepay-common-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-common-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 530 |
// Add parameters for validator wallets |
| 531 |
wp_localize_script( |
| 532 |
'multisafepay-validator-wallets', |
| 533 |
'multisafepayParams', |
| 534 |
array( |
| 535 |
'location' => admin_url( 'admin-ajax.php' ), |
| 536 |
'nonce' => wp_create_nonce( 'multisafepay_validator_nonce' ), |
| 537 |
) |
| 538 |
); |
| 539 |
|
| 540 |
$admin_url_array = array( |
| 541 |
'location' => admin_url( 'admin-ajax.php' ), |
| 542 |
'nonce' => wp_create_nonce( 'total_price_nonce' ), |
| 543 |
); |
| 544 |
wp_localize_script( 'multisafepay-common-wallets', 'configAdminUrlAjax', $admin_url_array ); |
| 545 |
wp_enqueue_script( 'multisafepay-jquery-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-jquery-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 546 |
} |
| 547 |
} |
| 548 |
|
| 549 |
// On the order-pay endpoint, also load wallet direct scripts so that |
| 550 |
// Google Pay / Apple Pay direct buttons work for pending-payment orders. |
| 551 |
if ( is_wc_endpoint_url( 'order-pay' ) && ( ( 'GOOGLEPAY' === $gateway_code ) || ( 'APPLEPAY' === $gateway_code ) ) ) { |
| 552 |
$this->enqueue_wallet_direct_scripts_for_order_pay( $gateway_code, $payment_variables_for_googlepay_added, $payment_variables_for_applepay_added ); |
| 553 |
} |
| 554 |
} |
| 555 |
|
| 556 |
/** |
| 557 |
* Enqueue wallet direct scripts (Google Pay / Apple Pay) specifically for |
| 558 |
* the order-pay endpoint. The order-pay page uses a fixed order total |
| 559 |
* instead of the cart total and does not have customer_details fields. |
| 560 |
* |
| 561 |
* @param string $gateway_code The gateway code (GOOGLEPAY or APPLEPAY). |
| 562 |
* @param bool $payment_variables_for_googlepay_added Whether Google Pay variables were already added. |
| 563 |
* @param bool $payment_variables_for_applepay_added Whether Apple Pay variables were already added. |
| 564 |
* |
| 565 |
* @return void |
| 566 |
*/ |
| 567 |
private function enqueue_wallet_direct_scripts_for_order_pay( string $gateway_code, bool $payment_variables_for_googlepay_added, bool $payment_variables_for_applepay_added ): void { |
| 568 |
// Use static variables to prevent adding inline scripts more than once, |
| 569 |
// since wp_add_inline_script() appends content each time it is called. |
| 570 |
static $order_pay_googlepay_inline_added = false; |
| 571 |
static $order_pay_applepay_inline_added = false; |
| 572 |
|
| 573 |
// Load the supporting scripts (validator, common utilities, jQuery handler). |
| 574 |
wp_enqueue_script( 'multisafepay-validator-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-validator-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 575 |
wp_enqueue_script( 'multisafepay-common-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-common-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 576 |
|
| 577 |
wp_localize_script( |
| 578 |
'multisafepay-validator-wallets', |
| 579 |
'multisafepayParams', |
| 580 |
array( |
| 581 |
'location' => admin_url( 'admin-ajax.php' ), |
| 582 |
'nonce' => wp_create_nonce( 'multisafepay_validator_nonce' ), |
| 583 |
) |
| 584 |
); |
| 585 |
|
| 586 |
$admin_url_array = array( |
| 587 |
'location' => admin_url( 'admin-ajax.php' ), |
| 588 |
'nonce' => wp_create_nonce( 'total_price_nonce' ), |
| 589 |
); |
| 590 |
wp_localize_script( 'multisafepay-common-wallets', 'configAdminUrlAjax', $admin_url_array ); |
| 591 |
wp_enqueue_script( 'multisafepay-jquery-wallets', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-jquery-wallets.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 592 |
|
| 593 |
// Apple Pay wallet script. |
| 594 |
if ( ( 'APPLEPAY' === $gateway_code ) && ! $payment_variables_for_applepay_added && ! $order_pay_applepay_inline_added ) { |
| 595 |
wp_enqueue_script( 'multisafepay-apple-pay-wallet', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-apple-pay-wallet.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 596 |
$payment_variables = $this->build_applepay_wallet_variables( self::APPLEPAY_TEST_MERCHANT_NAME ) ?? ''; |
| 597 |
wp_add_inline_script( 'multisafepay-apple-pay-wallet', $payment_variables, 'before' ); |
| 598 |
$order_pay_applepay_inline_added = true; |
| 599 |
} |
| 600 |
|
| 601 |
// Google Pay wallet script. |
| 602 |
if ( 'GOOGLEPAY' === $gateway_code ) { |
| 603 |
wp_enqueue_script( 'google-pay-js', 'https://pay.google.com/gp/p/js/pay.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 604 |
if ( ! $payment_variables_for_googlepay_added && ! $order_pay_googlepay_inline_added ) { |
| 605 |
wp_enqueue_script( 'multisafepay-google-pay-wallet', MULTISAFEPAY_PLUGIN_URL . '/assets/public/js/multisafepay-google-pay-wallet.js', array( 'jquery' ), MULTISAFEPAY_PLUGIN_VERSION, true ); |
| 606 |
$payment_variables = $this->build_googlepay_wallet_variables( self::GOOGLEPAY_TEST_MERCHANT_ID, self::GOOGLEPAY_TEST_MERCHANT_NAME ) ?? ''; |
| 607 |
wp_add_inline_script( 'multisafepay-google-pay-wallet', $payment_variables, 'before' ); |
| 608 |
$order_pay_googlepay_inline_added = true; |
| 609 |
} |
| 610 |
} |
| 611 |
} |
| 612 |
|
| 613 |
/** |
| 614 |
* @return array |
| 615 |
*/ |
| 616 |
public function add_form_fields(): array { |
| 617 |
$form_fields = array( |
| 618 |
'enabled' => array( |
| 619 |
'title' => __( 'Enable/Disable', 'multisafepay' ), |
| 620 |
'label' => 'Enable ' . $this->get_method_title() . ' Gateway', |
| 621 |
'type' => 'checkbox', |
| 622 |
'default' => 'no', |
| 623 |
), |
| 624 |
'title' => array( |
| 625 |
'title' => __( 'Title', 'multisafepay' ), |
| 626 |
'type' => 'text', |
| 627 |
'desc_tip' => __( 'This controls the title which the user sees during checkout.', 'multisafepay' ), |
| 628 |
'default' => $this->get_method_title(), |
| 629 |
), |
| 630 |
'description' => array( |
| 631 |
'title' => __( 'Description', 'multisafepay' ), |
| 632 |
'type' => 'textarea', |
| 633 |
'desc_tip' => __( 'This controls the description which the user sees during checkout.', 'multisafepay' ), |
| 634 |
'default' => '', |
| 635 |
), |
| 636 |
'initial_order_status' => array( |
| 637 |
'title' => __( 'Initial Order Status', 'multisafepay' ), |
| 638 |
'type' => 'select', |
| 639 |
'options' => $this->get_order_statuses(), |
| 640 |
'desc_tip' => __( 'Initial order status for this payment method.', 'multisafepay' ), |
| 641 |
'default' => 'wc-default', |
| 642 |
), |
| 643 |
'min_amount' => array( |
| 644 |
'title' => __( 'Min Amount', 'multisafepay' ), |
| 645 |
'type' => 'decimal', |
| 646 |
'desc_tip' => __( 'This payment method is not shown in the checkout if the order total is lower than the defined amount. Leave blank for no restrictions.', 'multisafepay' ), |
| 647 |
'default' => ( (int) $this->payment_method->getMinAmount() / 100 ), |
| 648 |
'value' => (float) $this->get_option( 'min_amount', ( (int) $this->payment_method->getMinAmount() / 100 ) ), |
| 649 |
), |
| 650 |
'max_amount' => array( |
| 651 |
'title' => __( 'Max Amount', 'multisafepay' ), |
| 652 |
'type' => 'decimal', |
| 653 |
'desc_tip' => __( 'This payment method is not shown in the checkout if the order total exceeds a certain amount. Leave blank for no restrictions.', 'multisafepay' ), |
| 654 |
'default' => $this->payment_method->getMaxAmount() ? ( (int) $this->payment_method->getMaxAmount() / 100 ) : '', |
| 655 |
'value' => (float) $this->get_option( 'max_amount', ( $this->payment_method->getMaxAmount() ? ( (int) $this->payment_method->getMaxAmount() / 100 ) : '' ) ), |
| 656 |
), |
| 657 |
'countries' => array( |
| 658 |
'title' => __( 'Country', 'multisafepay' ), |
| 659 |
'type' => 'multiselect', |
| 660 |
'description' => __( 'If you select one or more countries, this payment method will be shown in the checkout page, if the payment address`s country of the customer match with the selected values. Leave blank for no restrictions.', 'multisafepay' ), |
| 661 |
'desc_tip' => __( 'For most operating system and configurations, you must hold Ctrl or Cmd in your keyboard, while you click in the options to select more than one value.', 'multisafepay' ), |
| 662 |
'options' => $this->get_countries(), |
| 663 |
'default' => $this->get_option( 'countries', array() ), |
| 664 |
), |
| 665 |
'user_roles' => array( |
| 666 |
'title' => __( 'User Roles', 'multisafepay' ), |
| 667 |
'type' => 'multiselect', |
| 668 |
'description' => __( 'If you select one or more user roles, this payment method will be shown in the checkout page, if the user rules of the customer match with the selected values. Leave blank for no restrictions.', 'multisafepay' ), |
| 669 |
'desc_tip' => __( 'For most operating system and configurations, you must hold Ctrl or Cmd in your keyboard, while you click in the options to select more than one value.', 'multisafepay' ), |
| 670 |
'options' => $this->get_user_roles(), |
| 671 |
'default' => $this->get_option( 'user_roles', array() ), |
| 672 |
), |
| 673 |
); |
| 674 |
|
| 675 |
if ( 'APPLEPAY' === $this->get_payment_method_gateway_code() ) { |
| 676 |
$form_fields['use_direct_button'] = array( |
| 677 |
'title' => __( 'Use Apple Pay Direct Button', 'multisafepay' ), |
| 678 |
'type' => 'select', |
| 679 |
'options' => array( |
| 680 |
'0' => 'Disabled', |
| 681 |
'1' => 'Enabled', |
| 682 |
), |
| 683 |
'description' => __( 'If you enable this, the place order button on the checkout page will be replaced by the Apple Pay button when this method is selected. We strongly recommend you test this feature carefully before enabled. More information about Apple Pay Direct on <a href="https://docs.multisafepay.com/docs/apple-pay-direct" target="_blank">MultiSafepay\'s Documentation Center</a>', 'multisafepay' ), |
| 684 |
'desc_tip' => __( 'Enable this feature, to replace the place order button on the checkout page with the Apple Pay button, when the customer selects this one.', 'multisafepay' ), |
| 685 |
'default' => '0', |
| 686 |
); |
| 687 |
$form_fields['merchant_name'] = array( |
| 688 |
'title' => __( 'Apple Pay Merchant Name', 'multisafepay' ), |
| 689 |
'type' => 'text', |
| 690 |
'desc_tip' => __( 'Field required by Apple Pay direct transactions.', 'multisafepay' ), |
| 691 |
'default' => '', |
| 692 |
); |
| 693 |
} |
| 694 |
|
| 695 |
if ( in_array( $this->get_payment_method_gateway_code(), $this->get_defined_direct_payment_methods_without_components(), true ) ) { |
| 696 |
$form_fields['direct_transaction'] = array( |
| 697 |
'title' => __( 'Transaction Type', 'multisafepay' ), |
| 698 |
'type' => 'select', |
| 699 |
'options' => array( |
| 700 |
'0' => 'Redirect', |
| 701 |
'1' => 'Direct', |
| 702 |
), |
| 703 |
'desc_tip' => __( 'If enabled, the consumer receives an e-mail with payment details, and no extra information is required during checkout.', 'multisafepay' ), |
| 704 |
'default' => '0', |
| 705 |
); |
| 706 |
} |
| 707 |
|
| 708 |
if ( 'GOOGLEPAY' === $this->get_payment_method_gateway_code() ) { |
| 709 |
$form_fields['use_direct_button'] = array( |
| 710 |
'title' => __( 'Use Google Pay Direct Button', 'multisafepay' ), |
| 711 |
'type' => 'select', |
| 712 |
'options' => array( |
| 713 |
'0' => 'Disabled', |
| 714 |
'1' => 'Enabled', |
| 715 |
), |
| 716 |
'description' => __( 'If you enable this, the place order button on the checkout page will be replaced by the Google Pay button when this method is selected. We strongly recommend you test this feature carefully before enabled. More information about Google Pay Direct on <a href="https://docs.multisafepay.com/docs/google-pay-direct" target="_blank">MultiSafepay\'s Documentation Center</a>', 'multisafepay' ), |
| 717 |
'desc_tip' => __( 'Enable this feature, to replace the place order button on the checkout page with the Google Pay button, when the customer selects this one.', 'multisafepay' ), |
| 718 |
'default' => '0', |
| 719 |
); |
| 720 |
$form_fields['merchant_name'] = array( |
| 721 |
'title' => __( 'Google Merchant Name', 'multisafepay' ), |
| 722 |
'type' => 'text', |
| 723 |
'desc_tip' => __( 'Field required by Google Pay direct transactions.', 'multisafepay' ), |
| 724 |
'default' => '', |
| 725 |
); |
| 726 |
$form_fields['merchant_id'] = array( |
| 727 |
'title' => __( 'Google Merchant ID', 'multisafepay' ), |
| 728 |
'type' => 'text', |
| 729 |
'desc_tip' => __( 'Field required by Google Pay direct transactions.', 'multisafepay' ), |
| 730 |
'default' => '', |
| 731 |
); |
| 732 |
} |
| 733 |
|
| 734 |
if ( $this->payment_method->supportsPaymentComponent() && ! $this->payment_method->supportsQr() && ! $this->is_ideal_2_0() ) { |
| 735 |
$form_fields['payment_component'] = array( |
| 736 |
'title' => __( 'Payment Type', 'multisafepay' ), |
| 737 |
'type' => 'select', |
| 738 |
'options' => array( |
| 739 |
'no' => __( 'Redirect', 'multisafepay' ), |
| 740 |
'yes' => __( 'Payment component', 'multisafepay' ), |
| 741 |
), |
| 742 |
'description' => __( 'Redirect - Redirect the customer to a payment page to finish the payment. <br /> Payment Component - Payment components let you embed payment checkout fields directly into your checkout. <br /><br /> More information about Payment Components on <a href="https://docs.multisafepay.com/docs/payment-components" target="_blank">MultiSafepay\'s Documentation Center</a>.', 'multisafepay' ), |
| 743 |
'default' => $this->get_option( 'payment_component', $this->payment_method->supportsPaymentComponent() ? 'yes' : 'no' ), |
| 744 |
'value' => $this->get_option( 'payment_component', $this->payment_method->supportsPaymentComponent() ? 'yes' : 'no' ), |
| 745 |
); |
| 746 |
|
| 747 |
if ( 'BILLINK' === $this->get_payment_method_gateway_code() ) { |
| 748 |
$form_fields['payment_component']['options']['P'] = __( 'B2C Only', 'multisafepay' ); |
| 749 |
$form_fields['payment_component']['options']['B'] = __( 'B2B Only', 'multisafepay' ); |
| 750 |
$form_fields['payment_component']['description'] .= __( '<br /><br /> B2C Only - For individual customers. <br /> B2B Only - For business customers. <br /><br /> Select the appropriate contract type based on your target customer base.', 'multisafepay' ); |
| 751 |
} |
| 752 |
} |
| 753 |
|
| 754 |
if ( $this->payment_method->supportsPaymentComponent() && $this->payment_method->supportsQr() ) { |
| 755 |
$form_fields['payment_component'] = array( |
| 756 |
'title' => __( 'Payment Type', 'multisafepay' ), |
| 757 |
'type' => 'select', |
| 758 |
'options' => array( |
| 759 |
'no' => __( 'Redirect', 'multisafepay' ), |
| 760 |
'yes' => __( 'Payment component', 'multisafepay' ), |
| 761 |
'qr' => __( 'Payment component with QR', 'multisafepay' ), |
| 762 |
'qr_only' => __( 'Payment component with QR only', 'multisafepay' ), |
| 763 |
), |
| 764 |
'description' => __( 'Redirect - Redirect the customer to a payment page to finish the payment. <br /> Payment Component - Payment components let you embed payment checkout fields directly into your checkout. <br /> Payment Component with QR (*) – Similar to the previous option, but now includes the ability to pay using a QR code too. <br /> Payment Component with QR only (*) – Payment can only be completed via a QR code. <br /><br /> (*) Payment Components using QR are an experimental feature and may not work as expected. Contact MultiSafepay support for more information. <br /><br /> More information about Payment Components on <a href="https://docs.multisafepay.com/docs/payment-components" target="_blank">MultiSafepay\'s Documentation Center</a>.', 'multisafepay' ), |
| 765 |
'default' => $this->get_option( 'payment_component', $this->payment_method->supportsPaymentComponent() ? 'yes' : 'no' ), |
| 766 |
'value' => $this->get_option( 'payment_component', $this->payment_method->supportsPaymentComponent() ? 'yes' : 'no' ), |
| 767 |
); |
| 768 |
$form_fields['qr_width'] = array( |
| 769 |
'title' => __( 'QR image width', 'multisafepay' ), |
| 770 |
'type' => 'text', |
| 771 |
'desc_tip' => __( 'Defines the width of the QR code in pixels. An appropriate size improves user experience and makes scanning easier.', 'multisafepay' ), |
| 772 |
'description' => __( 'The numeric value represents the width in pixels. If left blank, the default size will be used.', 'multisafepay' ), |
| 773 |
'default' => '', |
| 774 |
); |
| 775 |
} |
| 776 |
|
| 777 |
if ( $this->payment_method->supportsTokenization() && $this->payment_method->supportsPaymentComponent() ) { |
| 778 |
$form_fields['tokenization'] = array( |
| 779 |
'title' => __( 'Recurring payments', 'multisafepay' ), |
| 780 |
'type' => 'select', |
| 781 |
'options' => array( |
| 782 |
'no' => __( 'Disabled', 'multisafepay' ), |
| 783 |
'yes' => __( 'Enabled', 'multisafepay' ), |
| 784 |
), |
| 785 |
'description' => __( 'Ensure that the Payment component is enabled. It won\'t work using redirect payment type.', 'multisafepay' ), |
| 786 |
'default' => $this->get_option( 'tokenization', 'no' ), |
| 787 |
'value' => $this->get_option( 'tokenization', 'no' ), |
| 788 |
); |
| 789 |
|
| 790 |
if ( $this->is_ideal_2_0() ) { |
| 791 |
unset( $form_fields['tokenization']['description'] ); |
| 792 |
} |
| 793 |
} |
| 794 |
|
| 795 |
return $form_fields; |
| 796 |
} |
| 797 |
|
| 798 |
/** |
| 799 |
* Enqueue CSS styles related with Payment Component. |
| 800 |
* |
| 801 |
* @return void |
| 802 |
*/ |
| 803 |
public function enqueue_payment_component_styles() { |
| 804 |
if ( ! $this->should_enqueue_classic_assets() ) { |
| 805 |
return; |
| 806 |
} |
| 807 |
|
| 808 |
if ( ( is_checkout() || is_wc_endpoint_url( 'order-pay' ) ) ) { |
| 809 |
wp_enqueue_style( |
| 810 |
'multisafepay-payment-component-style', |
| 811 |
self::MULTISAFEPAY_COMPONENT_CSS_URL, |
| 812 |
array(), |
| 813 |
MULTISAFEPAY_PLUGIN_VERSION |
| 814 |
); |
| 815 |
} |
| 816 |
} |
| 817 |
|
| 818 |
/** |
| 819 |
* Prints checkout custom fields |
| 820 |
* |
| 821 |
* @return void |
| 822 |
*/ |
| 823 |
public function payment_fields() { |
| 824 |
require MULTISAFEPAY_PLUGIN_DIR_PATH . 'templates/multisafepay-checkout-fields-display.php'; |
| 825 |
} |
| 826 |
|
| 827 |
/** |
| 828 |
* @param WC_Order $order |
| 829 |
* @return bool |
| 830 |
*/ |
| 831 |
public function can_refund_order( $order ): bool { |
| 832 |
if ( in_array( $this->get_payment_method_gateway_code(), self::NOT_ALLOW_REFUND_PAYMENT_METHODS, true ) ) { |
| 833 |
return false; |
| 834 |
} |
| 835 |
|
| 836 |
if ( in_array( $order->get_status(), self::NOT_ALLOW_REFUND_ORDER_STATUSES, true ) ) { |
| 837 |
return false; |
| 838 |
} |
| 839 |
|
| 840 |
return $order && $this->supports( 'refunds' ); |
| 841 |
} |
| 842 |
|
| 843 |
/** |
| 844 |
* @param int|string $order_id |
| 845 |
* @return array |
| 846 |
*/ |
| 847 |
public function process_payment( $order_id ): array { |
| 848 |
return ( new BlocksContextService() )->is_store_api_request() |
| 849 |
? $this->process_blocks_payment( $order_id ) |
| 850 |
: $this->process_classic_payment( $order_id ); |
| 851 |
} |
| 852 |
|
| 853 |
/** |
| 854 |
* Handles classic checkout payment processing. |
| 855 |
* |
| 856 |
* @param int|string $order_id |
| 857 |
* @return array |
| 858 |
*/ |
| 859 |
private function process_classic_payment( $order_id ): array { |
| 860 |
$order = wc_get_order( $order_id ); |
| 861 |
if ( ! $order instanceof WC_Order ) { |
| 862 |
wc_add_notice( __( 'Invalid order. Please try again.', 'multisafepay' ), 'error' ); |
| 863 |
|
| 864 |
return $this->get_invalid_order_process_payment_response(); |
| 865 |
} |
| 866 |
|
| 867 |
try { |
| 868 |
$transaction = $this->create_transaction_for_payment( $order, new OrderService() ); |
| 869 |
} catch ( ApiException |ClientExceptionInterface |InvalidArgumentException $exception ) { |
| 870 |
$this->logger->log_error( $exception->getMessage() ); |
| 871 |
wc_add_notice( __( 'There was a problem processing your payment. Please try again later or contact with us.', 'multisafepay' ), 'error' ); |
| 872 |
|
| 873 |
return $this->get_failed_process_payment_response(); |
| 874 |
} |
| 875 |
|
| 876 |
$payment_url = $transaction->getPaymentUrl(); |
| 877 |
$this->logger->log_info( 'Start MultiSafepay transaction for the order ID ' . $order_id . ' on ' . date( 'd/m/Y H:i:s' ) . ' with payment URL ' . $payment_url ); |
| 878 |
|
| 879 |
return array( |
| 880 |
'result' => 'success', |
| 881 |
'redirect' => esc_url_raw( $payment_url ), |
| 882 |
); |
| 883 |
} |
| 884 |
|
| 885 |
/** |
| 886 |
* Handles Store API / Blocks payment processing. |
| 887 |
* |
| 888 |
* @param int|string $order_id |
| 889 |
* @return array |
| 890 |
*/ |
| 891 |
private function process_blocks_payment( $order_id ): array { |
| 892 |
$order_service = new OrderService(); |
| 893 |
$order = wc_get_order( $order_id ); |
| 894 |
|
| 895 |
if ( ! $order instanceof WC_Order ) { |
| 896 |
return $this->get_invalid_order_process_payment_response(); |
| 897 |
} |
| 898 |
|
| 899 |
$is_wallet_gateway = in_array( (string) $this->gateway_code, array( 'APPLEPAY', 'GOOGLEPAY' ), true ); |
| 900 |
$has_wallet_token = $is_wallet_gateway && ! empty( $order_service->get_wallet_payment_token( $order ) ); |
| 901 |
$has_wallet_combined_payment_method_title = false; |
| 902 |
|
| 903 |
try { |
| 904 |
$transaction = $this->create_transaction_for_payment( $order, $order_service ); |
| 905 |
|
| 906 |
// In Blocks wallet-direct flows, callback enrichment can arrive after redirect. |
| 907 |
// Use payment_details from the create() transaction to prebuild and persist the |
| 908 |
// combined wallet title, so the initial 'Thank You' render does not show a generic wallet label. |
| 909 |
if ( $is_wallet_gateway && $has_wallet_token ) { |
| 910 |
$has_wallet_combined_payment_method_title = $this->persist_wallet_combined_payment_method_title_from_transaction( $order, $transaction ); |
| 911 |
} |
| 912 |
|
| 913 |
$payment_url = $transaction->getPaymentUrl(); |
| 914 |
$this->logger->log_info( 'Start MultiSafepay transaction for the order ID ' . $order_id . ' on ' . date( 'd/m/Y H:i:s' ) . ' with payment URL ' . $payment_url ); |
| 915 |
|
| 916 |
$redirect_url = ( ( $is_wallet_gateway && $has_wallet_token && $has_wallet_combined_payment_method_title ) || empty( $payment_url ) ) |
| 917 |
? $this->get_return_url( $order ) |
| 918 |
: esc_url_raw( $payment_url ); |
| 919 |
|
| 920 |
return array( |
| 921 |
'result' => 'success', |
| 922 |
'redirect' => $redirect_url, |
| 923 |
); |
| 924 |
} catch ( ApiException |ClientExceptionInterface |InvalidArgumentException $exception ) { |
| 925 |
$this->logger->log_error( $exception->getMessage() ); |
| 926 |
|
| 927 |
return $this->get_failed_process_payment_response(); |
| 928 |
} finally { |
| 929 |
$this->clear_blocks_process_payment_data( $order, $order_id, $order_service ); |
| 930 |
} |
| 931 |
} |
| 932 |
|
| 933 |
/** |
| 934 |
* Creates the MultiSafepay transaction for the given order. |
| 935 |
* |
| 936 |
* Exposed as protected so tests can override it to bypass the real SDK call. |
| 937 |
* |
| 938 |
* @param WC_Order $order |
| 939 |
* @param OrderService $order_service |
| 940 |
* @return TransactionResponse |
| 941 |
* @throws ApiException |
| 942 |
* @throws ClientExceptionInterface |
| 943 |
* @throws InvalidArgumentException |
| 944 |
*/ |
| 945 |
protected function create_transaction_for_payment( WC_Order $order, OrderService $order_service ): TransactionResponse { |
| 946 |
$transaction_manager = ( new SdkService() )->get_transaction_manager(); |
| 947 |
$order_request = $order_service->create_order_request( $order, $this->gateway_code, $this->type ); |
| 948 |
|
| 949 |
return $transaction_manager->create( $order_request ); |
| 950 |
} |
| 951 |
|
| 952 |
/** |
| 953 |
* Best-effort cleanup for request-lifecycle Blocks checkout data. |
| 954 |
* |
| 955 |
* @param WC_Order $order |
| 956 |
* @param int|string $order_id |
| 957 |
* @param OrderService $order_service |
| 958 |
* @return void |
| 959 |
*/ |
| 960 |
private function clear_blocks_process_payment_data( WC_Order $order, $order_id, OrderService $order_service ): void { |
| 961 |
try { |
| 962 |
$order_service->blocks_payment_data_service->clear_blocks_payment_data_from_order_meta_by_pattern( |
| 963 |
$order, |
| 964 |
BlocksPaymentDataService::REQUEST_LIFECYCLE_KEY_PATTERN |
| 965 |
); |
| 966 |
} catch ( Throwable $exception ) { |
| 967 |
$this->logger->log_warning( 'Unable to clear request-lifecycle Blocks payment data for order ID ' . $order_id . ': ' . $exception->getMessage() ); |
| 968 |
} |
| 969 |
} |
| 970 |
|
| 971 |
/** |
| 972 |
* Returns the invalid-order response expected by WooCommerce payment flows. |
| 973 |
* |
| 974 |
* @return array |
| 975 |
*/ |
| 976 |
private function get_invalid_order_process_payment_response(): array { |
| 977 |
return array( |
| 978 |
'result' => 'failure', |
| 979 |
'message' => __( 'Invalid order. Please try again.', 'multisafepay' ), |
| 980 |
); |
| 981 |
} |
| 982 |
|
| 983 |
/** |
| 984 |
* Returns the generic processing failure response expected by WooCommerce payment flows. |
| 985 |
* |
| 986 |
* @return array |
| 987 |
*/ |
| 988 |
private function get_failed_process_payment_response(): array { |
| 989 |
return array( |
| 990 |
'result' => 'failure', |
| 991 |
'message' => __( 'There was a problem processing your payment. Please try again later or contact with us.', 'multisafepay' ), |
| 992 |
); |
| 993 |
} |
| 994 |
|
| 995 |
/** |
| 996 |
* Persist a combined wallet title (e.g., Google Pay (Visa)) using data from |
| 997 |
* the transaction returned by create(). |
| 998 |
* |
| 999 |
* The wallet code and payment instrument type come from payment_details; the |
| 1000 |
* wallet label is resolved from the configured WooCommerce gateway and then |
| 1001 |
* combined with the instrument label. |
| 1002 |
* |
| 1003 |
* This mitigates the Blocks timing gap where the 'Thank You' page can render |
| 1004 |
* before callback enrichment. |
| 1005 |
* |
| 1006 |
* @param WC_Order $order |
| 1007 |
* @param mixed $transaction |
| 1008 |
* @return bool |
| 1009 |
*/ |
| 1010 |
protected function persist_wallet_combined_payment_method_title_from_transaction( WC_Order $order, $transaction ): bool { |
| 1011 |
try { |
| 1012 |
// Guard against unexpected SDK responses; in edge cases the create() transaction |
| 1013 |
// may not include payment_details, so a combined wallet title cannot be built. |
| 1014 |
if ( ! is_object( $transaction ) || ! method_exists( $transaction, 'getPaymentDetails' ) ) { |
| 1015 |
return false; |
| 1016 |
} |
| 1017 |
|
| 1018 |
$payment_details = $transaction->getPaymentDetails(); |
| 1019 |
if ( ! is_object( $payment_details ) || ! method_exists( $payment_details, 'getType' ) || ! method_exists( $payment_details, 'get' ) ) { |
| 1020 |
return false; |
| 1021 |
} |
| 1022 |
|
| 1023 |
// `wallet` identifies the wallet wrapper (Google/Apple Pay), while `type` carries the underlying instrument. |
| 1024 |
$wallet_code = (string) $payment_details->get( 'wallet' ); |
| 1025 |
$gateway_code = (string) $payment_details->getType(); |
| 1026 |
if ( '' === $wallet_code || '' === $gateway_code ) { |
| 1027 |
return false; |
| 1028 |
} |
| 1029 |
|
| 1030 |
// Resolve the wallet title from the configured WooCommerce gateway to keep labels consistent. |
| 1031 |
$wallet_payment_method = $this->resolve_wallet_woocommerce_payment_gateway( $wallet_code ); |
| 1032 |
if ( ! $wallet_payment_method ) { |
| 1033 |
return false; |
| 1034 |
} |
| 1035 |
|
| 1036 |
$wallet_title = $wallet_payment_method->get_payment_method_title(); |
| 1037 |
if ( '' === $wallet_title ) { |
| 1038 |
return false; |
| 1039 |
} |
| 1040 |
|
| 1041 |
$payment_method_title_builder = new PaymentMethodTitleBuilder(); |
| 1042 |
// Only combine titles for known instruments (e.g., Visa, Mastercard, Amex). |
| 1043 |
if ( ! $payment_method_title_builder->can_build_wallet_combined_payment_method_title( $gateway_code ) ) { |
| 1044 |
return false; |
| 1045 |
} |
| 1046 |
|
| 1047 |
$underlying_title = $payment_method_title_builder->get_underlying_payment_method_title( $gateway_code ); |
| 1048 |
$combined_title = $payment_method_title_builder->build_combined_payment_method_title( $wallet_title, $underlying_title ); |
| 1049 |
if ( '' === $combined_title ) { |
| 1050 |
return false; |
| 1051 |
} |
| 1052 |
|
| 1053 |
// Avoid unnecessary order writes when title is already persisted. |
| 1054 |
if ( $order->get_payment_method_title() !== $combined_title ) { |
| 1055 |
$order->set_payment_method_title( $combined_title ); |
| 1056 |
$order->save(); |
| 1057 |
} |
| 1058 |
|
| 1059 |
return true; |
| 1060 |
} catch ( Throwable $exception ) { |
| 1061 |
$this->logger->log_warning( 'Unable to persist combined wallet payment title for order ID ' . $order->get_id() . ': ' . $exception->getMessage() ); |
| 1062 |
return false; |
| 1063 |
} |
| 1064 |
} |
| 1065 |
|
| 1066 |
/** |
| 1067 |
* Resolve a configured WooCommerce gateway for the given MultiSafepay wallet code. |
| 1068 |
* |
| 1069 |
* Extracted as a protected seam so tests can supply a stub wallet gateway without |
| 1070 |
* hitting the MultiSafepay API through PaymentMethodService. |
| 1071 |
* |
| 1072 |
* @param string $wallet_code |
| 1073 |
* @return BasePaymentMethod|null |
| 1074 |
*/ |
| 1075 |
protected function resolve_wallet_woocommerce_payment_gateway( string $wallet_code ): ?BasePaymentMethod { |
| 1076 |
return ( new PaymentMethodService() )->get_woocommerce_payment_gateway_by_multisafepay_gateway_code( $wallet_code ); |
| 1077 |
} |
| 1078 |
|
| 1079 |
/** |
| 1080 |
* Validate_fields |
| 1081 |
* |
| 1082 |
* @return boolean |
| 1083 |
*/ |
| 1084 |
public function validate_fields(): bool { |
| 1085 |
|
| 1086 |
if ( is_wc_endpoint_url( 'add-payment-method' ) ) { |
| 1087 |
return false; |
| 1088 |
} |
| 1089 |
|
| 1090 |
// Checkout Blocks uses the Store API; payloads may be stored in order meta and later |
| 1091 |
// consumed by OrderService. This POST check applies only to classic checkout, since |
| 1092 |
// Store API surfaces errors as REST exceptions rather than HTML notices. |
| 1093 |
$is_store_api_request = ( new BlocksContextService() )->is_store_api_request(); |
| 1094 |
|
| 1095 |
if ( |
| 1096 |
$this->is_payment_component_enabled() && |
| 1097 |
! $is_store_api_request && |
| 1098 |
( |
| 1099 |
! isset( $_POST[ $this->id . '_payment_component_payload' ] ) || |
| 1100 |
empty( $_POST[ $this->id . '_payment_component_payload' ] ) |
| 1101 |
) |
| 1102 |
) { |
| 1103 |
wc_add_notice( '<strong>' . $this->get_payment_method_title() . ' payment details</strong> is a required field.', 'error' ); |
| 1104 |
} |
| 1105 |
|
| 1106 |
if ( isset( $_POST[ $this->id . '_payment_component_errors' ] ) && '' !== $_POST[ $this->id . '_payment_component_errors' ] ) { |
| 1107 |
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 1108 |
foreach ( wp_unslash( $_POST[ $this->id . '_payment_component_errors' ] ) as $payment_component_error ) { |
| 1109 |
wc_add_notice( sanitize_text_field( $payment_component_error ), 'error' ); |
| 1110 |
} |
| 1111 |
} |
| 1112 |
|
| 1113 |
if ( wc_get_notices( 'error' ) ) { |
| 1114 |
return false; |
| 1115 |
} |
| 1116 |
|
| 1117 |
return true; |
| 1118 |
} |
| 1119 |
|
| 1120 |
/** |
| 1121 |
* Returns the WooCommerce registered order statuses |
| 1122 |
* |
| 1123 |
* @see http://hookr.io/functions/wc_get_order_statuses/ |
| 1124 |
* @return array |
| 1125 |
*/ |
| 1126 |
protected function get_order_statuses(): array { |
| 1127 |
$order_statuses = wc_get_order_statuses(); |
| 1128 |
$order_statuses['wc-default'] = __( 'Default value set in common settings', 'multisafepay' ); |
| 1129 |
return $order_statuses; |
| 1130 |
} |
| 1131 |
|
| 1132 |
/** |
| 1133 |
* Build the variables required to initialize the Credit Card direct transactions |
| 1134 |
* |
| 1135 |
* @param string $payment_method |
| 1136 |
* @return ?array |
| 1137 |
*/ |
| 1138 |
private function common_wallets_data( string $payment_method ): ?array { |
| 1139 |
$sdk_service = new SdkService(); |
| 1140 |
$environment = $sdk_service->get_test_mode() ? 'TEST' : 'LIVE'; |
| 1141 |
$debug_mode = (bool) get_option( 'multisafepay_debugmode', false ); |
| 1142 |
$currency_code = get_woocommerce_currency(); |
| 1143 |
|
| 1144 |
// Wallet config is exposed through BasePaymentMethodBlocks::get_payment_method_data() |
| 1145 |
// in both frontend checkout and the Checkout block editor. In the wp-admin / editor context, |
| 1146 |
// WooCommerce may not have initialized customer/cart session objects yet, so guard these reads. |
| 1147 |
$country_code = ''; |
| 1148 |
// On order-pay, prefer the billing country stored in the order. |
| 1149 |
if ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url( 'order-pay' ) ) { |
| 1150 |
global $wp; |
| 1151 |
$pay_order_id = isset( $wp->query_vars['order-pay'] ) ? absint( $wp->query_vars['order-pay'] ) : 0; |
| 1152 |
$pay_order = $pay_order_id ? wc_get_order( $pay_order_id ) : null; |
| 1153 |
if ( $pay_order instanceof WC_Order ) { |
| 1154 |
$country_code = $pay_order->get_billing_country() ? $pay_order->get_billing_country() : $pay_order->get_shipping_country(); |
| 1155 |
} |
| 1156 |
} |
| 1157 |
if ( empty( $country_code ) && function_exists( 'WC' ) && WC() && WC()->customer ) { |
| 1158 |
$country_code = WC()->customer->get_billing_country() ? WC()->customer->get_billing_country() : WC()->customer->get_shipping_country(); |
| 1159 |
} |
| 1160 |
if ( empty( $country_code ) ) { |
| 1161 |
$default_country = (string) get_option( 'woocommerce_default_country', '' ); |
| 1162 |
$country_prefix = strstr( $default_country, ':', true ); |
| 1163 |
$country_code = ( false !== $country_prefix ) ? $country_prefix : $default_country; |
| 1164 |
} |
| 1165 |
|
| 1166 |
$total_price = 0.0; |
| 1167 |
// On the order-pay endpoint the cart may be empty; use the order total instead. |
| 1168 |
if ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url( 'order-pay' ) ) { |
| 1169 |
global $wp; |
| 1170 |
$order_id = isset( $wp->query_vars['order-pay'] ) ? absint( $wp->query_vars['order-pay'] ) : 0; |
| 1171 |
$order = $order_id ? wc_get_order( $order_id ) : null; |
| 1172 |
$total_price = $order instanceof WC_Order ? (float) $order->get_total() : 0.0; |
| 1173 |
} |
| 1174 |
if ( empty( $total_price ) && function_exists( 'WC' ) && WC() && WC()->cart ) { |
| 1175 |
$total_price = (float) WC()->cart->get_total( '' ); |
| 1176 |
} |
| 1177 |
|
| 1178 |
$common_data = array( |
| 1179 |
'environment' => $environment, |
| 1180 |
'gateway_merchant_id' => $sdk_service->get_multisafepay_account_id(), |
| 1181 |
'debug_mode' => $debug_mode, |
| 1182 |
'country_code' => $country_code, |
| 1183 |
'currency_code' => $currency_code, |
| 1184 |
'total_price' => $total_price, |
| 1185 |
); |
| 1186 |
|
| 1187 |
if ( 'apple_pay' === $payment_method ) { |
| 1188 |
unset( $common_data['gateway_merchant_id'] ); |
| 1189 |
} |
| 1190 |
|
| 1191 |
return $common_data; |
| 1192 |
} |
| 1193 |
|
| 1194 |
/** |
| 1195 |
* Build the variables required to initialize the Google Pay direct transactions |
| 1196 |
* |
| 1197 |
* @param string $test_merchant_id |
| 1198 |
* @param string $test_merchant_name |
| 1199 |
* @return string|null |
| 1200 |
*/ |
| 1201 |
public function build_googlepay_wallet_variables( string $test_merchant_id, string $test_merchant_name ): ?string { |
| 1202 |
$google_pay = $this->common_wallets_data( 'google_pay' ); |
| 1203 |
if ( is_null( $google_pay ) ) { |
| 1204 |
return null; |
| 1205 |
} |
| 1206 |
$merchant_id = $test_merchant_id; |
| 1207 |
$merchant_name = $test_merchant_name; |
| 1208 |
|
| 1209 |
if ( 'LIVE' === $google_pay['environment'] ) { |
| 1210 |
$merchant_id = $this->merchant_id; |
| 1211 |
$merchant_name = $this->merchant_name; |
| 1212 |
} |
| 1213 |
|
| 1214 |
return 'var configGooglePay = ' . wp_json_encode( |
| 1215 |
array( |
| 1216 |
'environment' => $google_pay['environment'], |
| 1217 |
'gatewayMerchantId' => $google_pay['gateway_merchant_id'], |
| 1218 |
'debugMode' => $google_pay['debug_mode'], |
| 1219 |
'countryCode' => $google_pay['country_code'], |
| 1220 |
'currencyCode' => $google_pay['currency_code'], |
| 1221 |
'merchantId' => $merchant_id, |
| 1222 |
'merchantName' => $merchant_name, |
| 1223 |
'totalPrice' => $google_pay['total_price'], |
| 1224 |
) |
| 1225 |
) . ';'; |
| 1226 |
} |
| 1227 |
|
| 1228 |
/** |
| 1229 |
* Returns Google Pay configuration for frontend usage (including Blocks). |
| 1230 |
* |
| 1231 |
* @return array|null |
| 1232 |
*/ |
| 1233 |
public function get_googlepay_wallet_config(): ?array { |
| 1234 |
$google_pay = $this->common_wallets_data( 'google_pay' ); |
| 1235 |
if ( is_null( $google_pay ) ) { |
| 1236 |
return null; |
| 1237 |
} |
| 1238 |
|
| 1239 |
$merchant_id = self::GOOGLEPAY_TEST_MERCHANT_ID; |
| 1240 |
$merchant_name = self::GOOGLEPAY_TEST_MERCHANT_NAME; |
| 1241 |
|
| 1242 |
if ( 'LIVE' === $google_pay['environment'] ) { |
| 1243 |
$merchant_id = (string) $this->merchant_id; |
| 1244 |
$merchant_name = (string) $this->merchant_name; |
| 1245 |
} |
| 1246 |
|
| 1247 |
return array( |
| 1248 |
'environment' => $google_pay['environment'], |
| 1249 |
'gatewayMerchantId' => $google_pay['gateway_merchant_id'], |
| 1250 |
'debugMode' => (bool) $google_pay['debug_mode'], |
| 1251 |
'countryCode' => (string) $google_pay['country_code'], |
| 1252 |
'currencyCode' => (string) $google_pay['currency_code'], |
| 1253 |
'merchantId' => (string) $merchant_id, |
| 1254 |
'merchantName' => (string) $merchant_name, |
| 1255 |
'totalPrice' => (float) $google_pay['total_price'], |
| 1256 |
); |
| 1257 |
} |
| 1258 |
|
| 1259 |
/** |
| 1260 |
* Build the variables required to initialize the Apple Pay direct transactions |
| 1261 |
* |
| 1262 |
* @param string $test_merchant_name |
| 1263 |
* @return string|null |
| 1264 |
*/ |
| 1265 |
public function build_applepay_wallet_variables( string $test_merchant_name ): ?string { |
| 1266 |
$apple_pay = $this->common_wallets_data( 'apple_pay' ); |
| 1267 |
if ( is_null( $apple_pay ) ) { |
| 1268 |
return null; |
| 1269 |
} |
| 1270 |
$merchant_name = $test_merchant_name; |
| 1271 |
|
| 1272 |
if ( 'LIVE' === $apple_pay['environment'] ) { |
| 1273 |
$merchant_name = $this->merchant_name; |
| 1274 |
} |
| 1275 |
|
| 1276 |
return 'var configApplePay = ' . wp_json_encode( |
| 1277 |
array( |
| 1278 |
'debugMode' => $apple_pay['debug_mode'], |
| 1279 |
'countryCode' => $apple_pay['country_code'], |
| 1280 |
'currencyCode' => $apple_pay['currency_code'], |
| 1281 |
'merchantName' => $merchant_name, |
| 1282 |
'totalPrice' => $apple_pay['total_price'], |
| 1283 |
) |
| 1284 |
) . ';'; |
| 1285 |
} |
| 1286 |
|
| 1287 |
/** |
| 1288 |
* Returns Apple Pay configuration for frontend usage (including Blocks). |
| 1289 |
* |
| 1290 |
* @return array|null |
| 1291 |
*/ |
| 1292 |
public function get_applepay_wallet_config(): ?array { |
| 1293 |
$apple_pay = $this->common_wallets_data( 'apple_pay' ); |
| 1294 |
if ( is_null( $apple_pay ) ) { |
| 1295 |
return null; |
| 1296 |
} |
| 1297 |
|
| 1298 |
$merchant_name = self::APPLEPAY_TEST_MERCHANT_NAME; |
| 1299 |
|
| 1300 |
if ( 'LIVE' === $apple_pay['environment'] ) { |
| 1301 |
$merchant_name = (string) $this->merchant_name; |
| 1302 |
} |
| 1303 |
|
| 1304 |
return array( |
| 1305 |
'environment' => $apple_pay['environment'], |
| 1306 |
'debugMode' => (bool) $apple_pay['debug_mode'], |
| 1307 |
'countryCode' => (string) $apple_pay['country_code'], |
| 1308 |
'currencyCode' => (string) $apple_pay['currency_code'], |
| 1309 |
'merchantName' => (string) $merchant_name, |
| 1310 |
'totalPrice' => (float) $apple_pay['total_price'], |
| 1311 |
); |
| 1312 |
} |
| 1313 |
|
| 1314 |
/** |
| 1315 |
* Get the countries allowed by WooCommerce |
| 1316 |
* |
| 1317 |
* @return array |
| 1318 |
*/ |
| 1319 |
protected function get_countries(): array { |
| 1320 |
$countries = new WC_Countries(); |
| 1321 |
return $countries->get_allowed_countries(); |
| 1322 |
} |
| 1323 |
|
| 1324 |
/** |
| 1325 |
* Get the user roles allowed by WordPress |
| 1326 |
* |
| 1327 |
* @return array |
| 1328 |
*/ |
| 1329 |
protected function get_user_roles(): array { |
| 1330 |
$roles = wp_roles()->roles; |
| 1331 |
|
| 1332 |
return array_map( |
| 1333 |
static function ( $role ) { |
| 1334 |
return $role['name']; |
| 1335 |
}, |
| 1336 |
$roles |
| 1337 |
); |
| 1338 |
} |
| 1339 |
|
| 1340 |
/** |
| 1341 |
* If the API starts returning that the payment component has no fields for IDEAL, |
| 1342 |
* it's because the payment component is disabled for this payment method. |
| 1343 |
* |
| 1344 |
* @return bool |
| 1345 |
*/ |
| 1346 |
private function is_ideal_2_0(): bool { |
| 1347 |
if ( $this->payment_method->getId() !== 'IDEAL' ) { |
| 1348 |
return false; |
| 1349 |
} |
| 1350 |
|
| 1351 |
$payment_method_apps = $this->payment_method->getApps(); |
| 1352 |
if ( false === $payment_method_apps[ PaymentMethod::PAYMENT_COMPONENT_KEY ][ PaymentMethod::PAYMENT_COMPONENT_HAS_FIELDS_KEY ] ) { |
| 1353 |
return true; |
| 1354 |
} |
| 1355 |
|
| 1356 |
return false; |
| 1357 |
} |
| 1358 |
} |
| 1359 |
|