PluginProbe
PayPlug for WooCommerce (Official) / trunk
PayPlug for WooCommerce (Official) vtrunk
3.0.0 2.18.0 1.0.17 1.0.18 1.0.19 1.0.20 1.0.21 1.0.22 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1.0 1.10.0 1.10.1 1.2.1 1.2.10 1.2.11 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 All 101 releases
payplug / src / Controller / ApplePay.php

ApplePay.php in PayPlug for WooCommerce (Official) trunk, at src/Controller/ApplePay.php

765 lines 28.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Payplug\PayplugWoocommerce\Controller;
4
5 use function is_cart;
6 use function is_product;
7
8 use Payplug\Exception\HttpException;
9 use Payplug\PayplugWoocommerce\Gateway\PayplugAddressData;
10 use Payplug\PayplugWoocommerce\Gateway\PayplugGateway;
11 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
12 use Payplug\Resource\Payment as PaymentResource;
13
14 /**
15 * ApplePay controller for handling Apple Pay payment logic in WooCommerce.
16 */
17 class ApplePay extends PayplugGateway
18 {
19 public $domain_name = '';
20
21 protected $cart = false;
22
23 protected $checkout = false;
24
25 protected $carriers = [];
26
27 public const ENABLE_ON_TEST_MODE = false;
28
29 public $image = 'apple-pay-checkout.svg';
30
31 protected $product = false;
32
33 public function __construct()
34 {
35 parent::__construct();
36
37 /** @var \WC_Settings_API override $id */
38 $this->id = 'apple_pay';
39
40 /** @var \WC_Payment_Gateway overwrite for apple pay settings */
41 $this->method_title = __('payplug_apple_pay_title', 'payplug');
42 $this->method_description = '';
43 $this->has_fields = false;
44
45 $this->title = __('payplug_apple_pay_title', 'payplug');
46 $this->description = '<div id="apple-pay-button-wrapper"><apple-pay-button buttonstyle="black" type="pay" locale="' . get_locale() . '"></apple-pay-button></div>';
47 $this->domain_name = wp_parse_url(home_url(), PHP_URL_HOST);
48 $this->enabled = 'no';
49
50 if ($this->checkApplePay() && is_admin()) {
51 $this->enabled = 'yes';
52 } elseif ($this->checkApplePay() && $this->isSSL()) {
53 if (!is_admin() && $this->get_button_checkout()) {
54 $this->enabled = 'yes';
55 }
56
57 if (!is_admin()) {
58 // Gateways are constructed before WordPress finishes parsing the request, so
59 // is_wc_endpoint_url('order-pay') can't be trusted yet here: defer that check
60 // to wp_enqueue_scripts, once routing has completed.
61 if ($this->get_button_checkout()) {
62 add_action('wp_enqueue_scripts', [$this, 'maybe_add_apple_pay_checkout_assets']);
63 }
64
65 if ($this->get_button_cart() && !PayplugWoocommerceHelper::is_cart_block() && !PayplugWoocommerceHelper::is_subscription()) {
66 $this->enabled = 'yes';
67 $this->add_apple_pay_css();
68 add_action('woocommerce_proceed_to_checkout', [$this, 'add_apple_pay_cart_js'], 15);
69 }
70
71 if ($this->get_button_product() && !PayplugWoocommerceHelper::is_product_block()) {
72 $this->enabled = 'yes';
73 $this->add_apple_pay_css();
74 add_action('woocommerce_after_add_to_cart_button', [$this, 'add_apple_pay_product_js'], 15);
75 }
76 }
77 }
78 }
79
80 /**
81 * Processes admin options for Apple Pay settings.
82 *
83 * @return bool|void
84 */
85 public function process_admin_options()
86 {
87 $data = $this->get_post_data();
88 if (isset($data['woocommerce_payplug_mode'])) {
89 if ($this->get_post_data()['woocommerce_payplug_mode'] === '0') {
90 $options = $this->get_configuration()->get_options();
91 $options['payment_methods']['configuration']['apple_pay']['active'] = false;
92 $this->get_configuration()->update_options($options);
93 }
94 }
95 if (isset($data['woocommerce_payplug_apple_pay'])) {
96 if (($data['woocommerce_payplug_apple_pay'] == 1) && (!$this->checkApplePay())) {
97 add_action('admin_notices', [$this, 'display_notice']);
98 }
99 }
100 }
101
102 /**
103 * Checks if Apple Pay is authorized and available.
104 *
105 * @return bool
106 */
107 public function checkApplePay()
108 {
109 $options = $this->settings;
110
111 //check if module is enabled
112 if (!isset($options['enabled']) || !$options['enabled']) {
113 return false;
114 }
115
116 if (!isset($options['payment_methods']) || empty($options['payment_methods'])) {
117 return false;
118 }
119
120 //it's disabled
121 if (!(bool) $options['payment_methods']['configuration']['apple_pay']['active']) {
122 return false;
123 }
124
125 //Amount validations
126 if (is_cart() && !empty(WC()->cart)) {
127 $order_amount = (float) WC()->cart->total;
128 if ($order_amount < self::MIN_AMOUNT || $order_amount > self::MAX_AMOUNT) {
129 return false;
130 }
131 }
132
133 $display = json_decode($options['payment_methods']['configuration']['apple_pay']['display'], true);
134 $this->set_button_checkout($display['checkout']);
135 $this->set_button_cart($display['cart']);
136 $this->set_button_product($display['product']);
137
138 $carriers = json_decode($options['payment_methods']['configuration']['apple_pay']['carriers'], true);
139 if (!empty($carriers)) {
140 $this->set_carriers($carriers);
141 }
142
143 $account = PayplugWoocommerceHelper::generic_get_account_data_from_options($this->id);
144 //no auth
145 if (!isset($account['payment_methods']['apple_pay']) || !isset($account['payment_methods']['apple_pay']['allowed_domain_names'])) {
146 return false;
147 }
148
149 //$account has permissions to use apple_pay
150 $auth = isset($account['payment_methods']['apple_pay']['enabled']) && $account['payment_methods']['apple_pay']['enabled'];
151 $domain = parse_url(get_site_url());
152 $auth_domains = in_array($domain['host'], $account['payment_methods']['apple_pay']['allowed_domain_names']);
153
154 //lost auth
155 if (!($auth && $auth_domains)) {
156 return false;
157 }
158
159 return true;
160 }
161
162 /**
163 * Outputs the payment fields on the checkout page.
164 *
165 * @return void
166 */
167 public function payment_fields(): void
168 {
169 $description = $this->get_description();
170
171 if (!empty($description)) {
172 echo wpautop(wptexturize($description));
173 }
174 }
175
176 /**
177 * extend the woocommmerce get description to include personalized html
178 *
179 * @return mixed|string|null
180 */
181 public function get_description()
182 {
183 return apply_filters('woocommerce_gateway_description', $this->description, $this->id);
184 }
185
186 /**
187 * Enqueues Apple Pay scripts for the cart page.
188 *
189 * @return void
190 */
191 public function add_apple_pay_cart_js(): void
192 {
193 wp_enqueue_script('apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', [], false, true);
194 wp_enqueue_script('payplug-apple-pay-cart', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-apple-pay-cart.js', ['jquery', 'apple-pay-sdk'], PAYPLUG_GATEWAY_VERSION, true);
195 wp_localize_script(
196 'payplug-apple-pay-cart',
197 'apple_pay_params',
198 [
199 'ajax_url_applepay_get_shippings' => \WC_AJAX::get_endpoint('applepay_get_shippings'),
200 'ajax_url_place_order_with_dummy_data' => \WC_AJAX::get_endpoint('place_order_with_dummy_data'),
201 'ajax_url_update_applepay_order' => \WC_AJAX::get_endpoint('update_applepay_order'),
202 'ajax_url_update_applepay_payment' => \WC_AJAX::get_endpoint('update_applepay_payment'),
203 'ajax_url_applepay_get_order_totals' => \WC_AJAX::get_endpoint('applepay_get_order_totals'),
204 'ajax_url_applepay_cancel_order' => \WC_AJAX::get_endpoint('applepay_cancel_order'),
205 'is_cart' => is_cart(),
206 'is_virtual' => !$this->is_shipping_required(),
207 'cart_shipping' => WC()->cart->get_shipping_total(),
208 'countryCode' => WC()->customer->get_billing_country(),
209 'currencyCode' => get_woocommerce_currency(),
210 'apple_pay_domain' => $this->domain_name,
211 ]
212 );
213
214 if ($this->checkButtonVisibility()) {
215 echo $this->get_description();
216 }
217 }
218
219 /**
220 * Enqueues Apple Pay scripts for the product page.
221 *
222 * @return void
223 */
224 public function add_apple_pay_product_js(): void
225 {
226 global $product;
227 // Only dispay ApplePay on product page for simple and variable products
228 if ($product->get_type() != 'simple' && $product->get_type() != 'variable') {
229 return;
230 }
231 $apple_pay_params = [
232 'ajax_url_applepay_get_shippings' => \WC_AJAX::get_endpoint('applepay_get_shippings'),
233 'ajax_url_place_order_with_dummy_data' => \WC_AJAX::get_endpoint('place_order_with_dummy_data'),
234 'ajax_url_update_applepay_order' => \WC_AJAX::get_endpoint('update_applepay_order'),
235 'ajax_url_update_applepay_payment' => \WC_AJAX::get_endpoint('update_applepay_payment'),
236 'ajax_url_applepay_get_order_totals' => \WC_AJAX::get_endpoint('applepay_get_order_totals'),
237 'ajax_url_applepay_cancel_order' => \WC_AJAX::get_endpoint('applepay_cancel_order'),
238 'ajax_url_applepay_empty_cart' => \WC_AJAX::get_endpoint('applepay_empty_cart'),
239 'ajax_url_applepay_add_to_cart' => \WC_AJAX::get_endpoint('applepay_add_to_cart'),
240 'is_product' => is_product(),
241 'is_virtual' => $product->is_virtual(),
242 'cart_shipping' => WC()->cart->get_shipping_total(),
243 'countryCode' => WC()->customer->get_billing_country(),
244 'currencyCode' => get_woocommerce_currency(),
245 'apple_pay_domain' => $this->domain_name,
246 ];
247 wp_enqueue_script('apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', [], false, true);
248 wp_enqueue_script('payplug-apple-pay-product', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-apple-pay-product.js', ['jquery', 'apple-pay-sdk'], PAYPLUG_GATEWAY_VERSION, true);
249 wp_localize_script('payplug-apple-pay-product', 'apple_pay_params', $apple_pay_params);
250
251 if ($this->checkButtonVisibility()) {
252 echo $this->get_description();
253 }
254 }
255
256 /**
257 * Check if the shipping address is a carrier
258 *
259 * @return bool
260 */
261 private function checkButtonVisibility()
262 {
263 $apple_carriers = $this->get_carriers();
264 $allowed = false;
265 $post = $this->get_post_data();
266 $chosen_method = isset($post['shipping_method'][0]) ? $post['shipping_method'][0] : null;
267
268 if (empty($chosen_method)) {
269 $chosen_method = !empty(WC()->session->chosen_shipping_methods[0]) ? WC()->session->chosen_shipping_methods[0] : null;
270 }
271
272 if (!$this->is_shipping_required() || is_product()) {
273 return true;
274 }
275
276 foreach (WC()->shipping()->get_packages() as $i => $package) {
277 $available_rates = !empty($package['rates']) ? $package['rates'] : [];
278 if (!empty($available_rates)) {
279 foreach ($available_rates as $method) {
280 if (in_array($method->get_method_id(), $apple_carriers)) {
281 // On cart page, show the button if any eligible carrier is available —
282 // the actual shipping selection happens inside the Apple Pay modal.
283 // On checkout, restrict to the currently chosen shipping method.
284 if (is_cart() || $chosen_method === $method->get_method_id() . ':' . $method->get_instance_id()) {
285 return true;
286 }
287 }
288 }
289 }
290 }
291
292 return $allowed;
293 }
294
295 /**
296 * check if the shipping is required or not
297 *
298 * @return bool
299 */
300 public function is_shipping_required()
301 {
302 $cart = WC()->cart->get_cart();
303
304 $required = true;
305 foreach ($cart as $cart_item) {
306 if (!empty($cart_item['product_id'])) {
307 $product = wc_get_product($cart_item['product_id']);
308
309 //not required if it enters here
310 if (!$product->is_virtual() && !$product->is_downloadable()) {
311 return true;
312 }
313
314 $required = false;
315 }
316 }
317
318 return $required;
319 }
320
321 /**
322 * Display unauthorized error
323 *
324 * @return void
325 */
326 public static function display_notice(): void
327 {
328 ?>
329 <div class="notice notice-error is-dismissible">
330 <p><?php echo __('payplug_apple_pay_unauthorized_error', 'payplug'); ?></p>
331 </div>
332 <?php
333 }
334
335 /**
336 * Checks if the current connection is using SSL.
337 *
338 * @return bool
339 */
340 public function isSSL()
341 {
342 if (!empty($_SERVER['HTTPS'])) {
343 if ('on' == strtolower($_SERVER['HTTPS'])) {
344 return true;
345 }
346 } elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
347 return true;
348 }
349
350 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') {
351 return true;
352 }
353
354 return false;
355 }
356
357 /**
358 * Enqueues Apple Pay CSS styles.
359 *
360 * @return void
361 */
362 public function add_apple_pay_css(): void
363 {
364 wp_enqueue_style('payplug-apple-pay', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/css/payplug-apple-pay.css', [], PAYPLUG_GATEWAY_VERSION);
365 }
366
367 /**
368 * Enqueues the classic Apple Pay checkout assets, unless the checkout page uses the
369 * Cart & Checkout blocks (the order-pay page always renders the classic payment form,
370 * even then, so it still needs the classic assets).
371 *
372 * @return void
373 */
374 public function maybe_add_apple_pay_checkout_assets(): void
375 {
376 if (PayplugWoocommerceHelper::is_checkout_block() && !is_wc_endpoint_url('order-pay')) {
377 return;
378 }
379
380 $this->add_apple_pay_css();
381 $this->add_apple_pay_js();
382 }
383
384 /**
385 * Enqueues Apple Pay JavaScript for the checkout page.
386 *
387 * @return void
388 */
389 public function add_apple_pay_js(): void
390 {
391 wp_enqueue_script('apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', [], false, true);
392 wp_enqueue_script(
393 'payplug-apple-pay',
394 PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-apple-pay.js',
395 [
396 'jquery',
397 'apple-pay-sdk',
398 ],
399 PAYPLUG_GATEWAY_VERSION,
400 true
401 );
402 wp_localize_script(
403 'payplug-apple-pay',
404 'apple_pay_params',
405 [
406 'ajax_url_payplug_create_order' => \WC_AJAX::get_endpoint('payplug_create_order'),
407 'ajax_url_applepay_update_payment' => \WC_AJAX::get_endpoint('applepay_update_payment'),
408 'ajax_url_applepay_get_order_totals' => \WC_AJAX::get_endpoint('applepay_get_order_totals'),
409 'ajax_url_payplug_apple_pay_create_order_pay' => \WC_AJAX::get_endpoint('payplug_apple_pay_create_order_pay'),
410 'countryCode' => WC()->customer->get_billing_country(),
411 'currencyCode' => get_woocommerce_currency(),
412 'total' => WC()->cart->total,
413 'is_checkout' => is_checkout(),
414 'is_order_pay' => is_wc_endpoint_url('order-pay'),
415 'order_pay_id' => is_wc_endpoint_url('order-pay') ? (int) get_query_var('order-pay') : 0,
416 'order_pay_key' => is_wc_endpoint_url('order-pay') ? wc_clean(wp_unslash($_GET['key'] ?? '')) : '',
417 'wp_nonce' => wp_create_nonce('woocommerce-process_checkout'),
418 'apple_pay_domain' => $this->domain_name,
419 ]
420 );
421 }
422
423 /**
424 * Gets the Apple Pay payment icon HTML.
425 *
426 * @return string
427 */
428 public function get_icon()
429 {
430 $available_img = 'apple-pay-checkout.svg';
431 $icons = apply_filters('payplug_payment_icons', [
432 'payplug' => sprintf('<img src="%s" alt="Apple Pay" class="payplug-payment-icon" />', esc_url(PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/checkout/' . $available_img)),
433 ]);
434 $icons_str = '';
435 foreach ($icons as $icon) {
436 $icons_str .= $icon;
437 }
438
439 return $icons_str;
440 }
441
442 /**
443 * Processes a payment if it was already generated by an intent.
444 *
445 * @param $order
446 *
447 * @throws \Exception
448 *
449 * @return array|null
450 */
451 private function process_standard_intent_payment($order)
452 {
453 // This runs from the payplug_apple_pay_create_order_pay AJAX endpoint too, whose own
454 // request URL never carries the order-pay query var, so is_wc_endpoint_url() alone
455 // can't detect that context here: fall back to the order_key/order_pay_key sent by
456 // that endpoint and by the checkout-block create_payment_intent endpoint.
457 $is_order_pay = $this->is_order_pay_request($order);
458
459 if (!$is_order_pay &&
460 PayplugWoocommerceHelper::is_checkout_block() &&
461 !empty($order->get_transaction_id())) {
462 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
463
464 try {
465 $payment = $this->payplug_api->payment_retrieve($order->get_transaction_id());
466 if (ob_get_length() > 0) {
467 ob_clean();
468 }
469
470 $return_url = esc_url_raw($order->get_checkout_order_received_url());
471 $cancel_url = !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : esc_url_raw(wc_get_checkout_url());
472
473 // Same payload shape as process_standard_payment(): the frontend's
474 // BeginSessionFromPaymentDetails() reads merchant_session/cancel_url/return_url
475 // off of it regardless of which of the two methods produced it.
476 // payment_method is a write-once attribute (merchant_session is tied to the
477 // ApplePaySession that created the payment): a retrieved payment may not carry
478 // it at all, and $payment->payment_method would throw UndefinedAttributeException
479 // rather than just being null/missing, unlike a plain array access.
480 $merchant_session = null;
481 if (isset($payment->payment_method) && is_array($payment->payment_method)) {
482 $merchant_session = $payment->payment_method['merchant_session'] ?? null;
483 }
484
485 if (defined('REST_REQUEST') && REST_REQUEST) {
486 $merchant_session = wp_json_encode($merchant_session);
487 }
488
489 $result = [
490 'result' => 'success',
491 'merchant_session' => $merchant_session,
492 'payment_id' => $payment->id,
493 'cancel_url' => $cancel_url,
494 'return_url' => $return_url,
495 ];
496
497 // wp_send_json_success() calls die(), which is only safe for the classic
498 // wc-ajax request this was written for: the Store API checkout flow (used by
499 // the checkout block) calls process_payment() through the REST framework,
500 // and killing the process mid-request there produces a broken response.
501 if (wp_doing_ajax()) {
502 wp_send_json_success($result);
503 }
504
505 return $result;
506 } catch (HttpException $e) {
507 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
508 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
509 } catch (\Exception $e) {
510 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
511 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
512 }
513 }
514
515 return null;
516 }
517
518 /**
519 * Processes a standard Apple Pay payment.
520 *
521 * @param \WC_Order $order
522 * @param int $amount
523 * @param int $customer_id
524 * @param string $workflow
525 *
526 * @throws \Exception
527 *
528 * @return array
529 */
530 public function process_standard_payment($order, $amount, $customer_id, $workflow = 'checkout')
531 {
532 $intent = $this->process_standard_intent_payment($order);
533 if (!empty($intent)) {
534 return $intent;
535 }
536
537 // Same detection as process_standard_intent_payment(): this can run from AJAX
538 // endpoints whose own request URL never carries the order-pay query var.
539 $is_order_pay = $this->is_order_pay_request($order);
540
541 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
542 try {
543 $address_data = PayplugAddressData::from_order($order);
544
545 $return_url = esc_url_raw($order->get_checkout_order_received_url());
546
547 if (!(substr($return_url, 0, 4) === 'http')) {
548 $return_url = get_site_url() . $return_url;
549 }
550
551 // delivery_type must be removed in Apple Pay
552 $billing = $address_data->get_billing();
553 unset($billing['delivery_type']);
554 $shipping = $address_data->get_shipping();
555 unset($shipping['delivery_type']);
556
557 $payment_data = [
558 'amount' => $amount,
559 'currency' => get_woocommerce_currency(),
560 'payment_method' => $this->id,
561 'payment_context' => [
562 'apple_pay' => [
563 'domain_name' => $this->domain_name,
564 'application_data' => base64_encode(json_encode([
565 'apple_pay_domain' => $this->domain_name,
566 ])),
567 ],
568 ],
569 'billing' => $billing,
570 'shipping' => $shipping,
571 'hosted_payment' => [
572 'return_url' => $return_url,
573 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
574 ],
575 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')),
576 'metadata' => [
577 'order_id' => $order_id,
578 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
579 'domain' => $this->domain_name,
580 'applepay_workflow' => $workflow,
581 ],
582 ];
583
584 if (PayplugWoocommerceHelper::is_checkout_block() && is_checkout()) {
585 $payment_data['metadata']['woocommerce_block'] = 'CHECKOUT';
586 } elseif (PayplugWoocommerceHelper::is_cart_block() && is_cart()) {
587 $payment_data['metadata']['woocommerce_block'] = 'CART';
588 }
589
590 /**
591 * Filter the payment data before it's used
592 *
593 * @param array $payment_data
594 * @param int $order_id
595 * @param array $customer_details
596 * @param PayplugAddressData $address_data
597 */
598 $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data);
599 $payment = $this->payplug_api->payment_create($payment_data);
600
601 // Save transaction id for the order
602 PayplugWoocommerceHelper::is_pre_30()
603 ? update_post_meta($order_id, '_transaction_id', $payment->id)
604 : $order->set_transaction_id($payment->id);
605
606 if (is_callable([$order, 'save'])) {
607 $order->save();
608 }
609
610 /**
611 * Fires once a payment has been created.
612 *
613 * @param int $order_id Order ID
614 * @param PaymentResource $payment Payment resource
615 */
616 \do_action('payplug_gateway_payment_created', $order_id, $payment);
617
618 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
619 PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
620
621 PayplugGateway::log(sprintf('Payment creation complete for order #%s', $order_id));
622
623 // On order-pay, closing the Apple Pay sheet should keep the customer on the
624 // order-pay page. On a regular checkout submission (classic or Blocks), it should
625 // keep them on checkout too, so they can pick another payment method - only the
626 // classic cart/product page flows (workflow 'cart'/'product') actually want the
627 // order-cancelled/cart redirect, since that's where those customers started.
628 if ($is_order_pay) {
629 $cancel_url = esc_url_raw($order->get_checkout_payment_url());
630 } elseif ('checkout' === $workflow) {
631 $cancel_url = esc_url_raw(wc_get_checkout_url());
632 } else {
633 $cancel_url = esc_url_raw($order->get_cancel_order_url_raw());
634 }
635
636 // When process_payment() is invoked through WooCommerce Blocks' Store API (a REST
637 // request), this array is forwarded to the client as `payment_details`, which
638 // coerces every value to a string - an array value would become the literal,
639 // useless string "Array". The classic AJAX flows that call this method directly
640 // (order-pay, cart/product Apple Pay) JSON-encode/decode the whole response
641 // transparently instead, so they need the raw merchant session object.
642 $merchant_session = $payment->payment_method['merchant_session'];
643 if (defined('REST_REQUEST') && REST_REQUEST) {
644 $merchant_session = wp_json_encode($merchant_session);
645 }
646
647 return [
648 'result' => 'success',
649 'merchant_session' => $merchant_session,
650 'payment_id' => $payment->id,
651 'cancel_url' => $cancel_url,
652 'return_url' => $return_url,
653 ];
654 } catch (HttpException $e) {
655 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
656 if ($workflow === 'cart') {
657 wp_send_json_error([
658 'code' => $e->getCode(),
659 'msg' => __('Payment processing failed. Please retry.', 'payplug'),
660 'order_id' => $order_id,
661 ]);
662 }
663 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
664 } catch (\Exception $e) {
665 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
666 if ($workflow === 'cart') {
667 wp_send_json_error([
668 'code' => $e->getCode(),
669 'msg' => __('Payment processing failed. Please retry.', 'payplug'),
670 'order_id' => $order_id,
671 ]);
672 }
673 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
674 }
675 }
676
677 /**
678 * Sets the checkout button status.
679 *
680 * @param bool $status
681 *
682 * @return void
683 */
684 private function set_button_checkout($status): void
685 {
686 $this->checkout = $status;
687 }
688
689 /**
690 * Sets the cart button status.
691 *
692 * @param bool $status
693 *
694 * @return void
695 */
696 private function set_button_cart($status): void
697 {
698 $this->cart = $status;
699 }
700
701 /**
702 * Sets the product button status.
703 *
704 * @param bool $status
705 *
706 * @return void
707 */
708 private function set_button_product($status): void
709 {
710 $this->product = $status;
711 }
712
713 /**
714 * Gets the checkout button status.
715 *
716 * @return bool
717 */
718 private function get_button_checkout()
719 {
720 return $this->checkout;
721 }
722
723 /**
724 * Gets the cart button status.
725 *
726 * @return bool
727 */
728 public function get_button_cart()
729 {
730 return $this->cart;
731 }
732
733 /**
734 * Gets the product button status.
735 *
736 * @return bool
737 */
738 public function get_button_product()
739 {
740 return $this->product;
741 }
742
743 /**
744 * Gets the list of allowed carriers for Apple Pay.
745 *
746 * @return array
747 */
748 public function get_carriers()
749 {
750 return $this->carriers;
751 }
752
753 /**
754 * Sets the list of allowed carriers for Apple Pay.
755 *
756 * @param array $carriers
757 *
758 * @return void
759 */
760 private function set_carriers($carriers): void
761 {
762 $this->carriers = $carriers;
763 }
764 }
765