PluginProbe
PayPlug for WooCommerce (Official) / 2.17.1
PayPlug for WooCommerce (Official) v2.17.1
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) 2.17.1, at src/Controller/ApplePay.php

660 lines 19.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 Payplug\Exception\HttpException;
6 use Payplug\PayplugWoocommerce\Gateway\PayplugAddressData;
7 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
8 use Payplug\PayplugWoocommerce\Gateway\PayplugGateway;
9 use Payplug\Resource\Payment as PaymentResource;
10 use function is_cart;
11 use function is_product;
12
13 /**
14 * ApplePay controller for handling Apple Pay payment logic in WooCommerce.
15 */
16 class ApplePay extends PayplugGateway
17 {
18
19 public $domain_name = '';
20
21 protected $cart = false;
22
23 protected $checkout = false;
24
25 protected $carriers = [];
26
27 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
36 parent::__construct();
37
38 /** @var \WC_Settings_API override $id */
39 $this->id = 'apple_pay';
40
41 /** @var \WC_Payment_Gateway overwrite for apple pay settings */
42 $this->method_title = __('payplug_apple_pay_title', 'payplug');
43 $this->method_description = '';
44 $this->has_fields = false;
45
46 $this->title = __('payplug_apple_pay_title', 'payplug');
47 $this->description = '<div id="apple-pay-button-wrapper"><apple-pay-button buttonstyle="black" type="pay" locale="'. get_locale() .'"></apple-pay-button></div>';
48 $this->domain_name = $_SERVER['HTTP_HOST'];
49 $this->enabled = 'no';
50
51 if( $this->checkApplePay() && is_admin()){
52 $this->enabled = 'yes';
53 }else if( $this->checkApplePay() && $this->isSSL() ){
54
55 if (!is_admin() && $this->get_button_checkout()) {
56 $this->enabled = 'yes';
57 }
58
59 if( !is_admin() ){
60 if (!PayplugWoocommerceHelper::is_checkout_block() && $this->get_button_checkout()) {
61 $this->add_apple_pay_css();
62 add_action('wp_enqueue_scripts', [$this, 'add_apple_pay_js']);
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 /**
82 * Processes admin options for Apple Pay settings.
83 *
84 * @return bool|void
85 */
86 public function process_admin_options() {
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 /**
104 * Checks if Apple Pay is authorized and available.
105 *
106 * @return bool
107 */
108 public function checkApplePay(){
109 $options = $this->settings;
110
111
112 //check if module is enabled
113 if(!isset($options['enabled']) || !$options['enabled']){
114 return false;
115 }
116
117
118 if (!isset($options['payment_methods']) || empty($options['payment_methods']))
119 {
120 return false;
121 }
122
123 //it's disabled
124 if(!(bool) $options['payment_methods']['configuration']['apple_pay']['active']){
125 return false;
126 }
127
128 //Amount validations
129 if ( is_cart() && !empty( WC()->cart ) ) {
130 $order_amount = (float) WC()->cart->total;
131 if ($order_amount < self::MIN_AMOUNT || $order_amount > self::MAX_AMOUNT) {
132 return false;
133 }
134 }
135
136 $display = json_decode($options['payment_methods']['configuration']['apple_pay']['display'], true);
137 $this->set_button_checkout($display['checkout']);
138 $this->set_button_cart($display['cart']);
139 $this->set_button_product($display['product']);
140
141 $carriers = json_decode($options['payment_methods']['configuration']['apple_pay']['carriers'], true);
142 if(!empty($carriers)){
143 $this->set_carriers($carriers);
144 }
145
146 $account = PayplugWoocommerceHelper::generic_get_account_data_from_options($this->id);
147 //no auth
148 if(!isset($account['payment_methods']['apple_pay']) || !isset($account['payment_methods']['apple_pay']['allowed_domain_names']) ){
149 return false;
150 }
151
152 //$account has permissions to use apple_pay
153 $auth = isset($account['payment_methods']['apple_pay']['enabled']) && $account['payment_methods']['apple_pay']['enabled'];
154 $domain = parse_url(get_site_url());
155 $auth_domains = in_array($domain['host'], $account['payment_methods']['apple_pay']['allowed_domain_names']);
156
157 //lost auth
158 if(!($auth && $auth_domains)){
159 return false;
160 }
161
162 return true;
163 }
164
165 /**
166 * Outputs the payment fields on the checkout page.
167 *
168 * @return void
169 */
170 public function payment_fields()
171 {
172 $description = $this->get_description();
173
174 if (!empty($description)) {
175 echo wpautop(wptexturize($description));
176 }
177 }
178
179 /**
180 * extend the woocommmerce get description to include personalized html
181 *
182 * @return mixed|string|null
183 */
184 public function get_description()
185 {
186 return apply_filters('woocommerce_gateway_description', $this->description, $this->id);
187 }
188
189 /**
190 * Enqueues Apple Pay scripts for the cart page.
191 *
192 * @return void
193 */
194 public function add_apple_pay_cart_js(){
195 wp_enqueue_script( 'apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', array(), false, true );
196 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);
197 wp_localize_script( 'payplug-apple-pay-cart', 'apple_pay_params',
198 array(
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 'countryCode' => WC()->customer->get_billing_country(),
207 'currencyCode' => get_woocommerce_currency(),
208 'apple_pay_domain' => $_SERVER['HTTP_HOST']
209 )
210 );
211
212 if($this->checkButtonVisibility()){
213 echo $this->get_description();
214 }
215 }
216
217 /**
218 * Enqueues Apple Pay scripts for the product page.
219 *
220 * @return void
221 */
222 public function add_apple_pay_product_js(){
223 global $product;
224 // Only dispay ApplePay on product page for simple and variable products
225 if ($product->get_type() != "simple" && $product->get_type() != "variable") {
226 return;
227 }
228 $apple_pay_params = [
229 'ajax_url_applepay_get_shippings' => \WC_AJAX::get_endpoint('applepay_get_shippings'),
230 'ajax_url_place_order_with_dummy_data' => \WC_AJAX::get_endpoint('place_order_with_dummy_data'),
231 'ajax_url_update_applepay_order' => \WC_AJAX::get_endpoint('update_applepay_order'),
232 'ajax_url_update_applepay_payment' => \WC_AJAX::get_endpoint('update_applepay_payment'),
233 'ajax_url_applepay_get_order_totals' => \WC_AJAX::get_endpoint('applepay_get_order_totals'),
234 'ajax_url_applepay_cancel_order' => \WC_AJAX::get_endpoint('applepay_cancel_order'),
235 'ajax_url_applepay_empty_cart' => \WC_AJAX::get_endpoint('applepay_empty_cart'),
236 'ajax_url_applepay_add_to_cart' => \WC_AJAX::get_endpoint('applepay_add_to_cart'),
237 'is_product' => is_product(),
238 'is_virtual' => $product->is_virtual(),
239 'cart_shipping' => WC()->cart->get_shipping_total(),
240 'countryCode' => WC()->customer->get_billing_country(),
241 'currencyCode' => get_woocommerce_currency(),
242 'apple_pay_domain' => $_SERVER['HTTP_HOST']
243 ];
244 wp_enqueue_script( 'apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', array(), false, true );
245 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);
246 wp_localize_script( 'payplug-apple-pay-product', 'apple_pay_params', $apple_pay_params);
247
248 if($this->checkButtonVisibility()){
249 echo $this->get_description();
250 }
251 }
252
253 /**
254 * Check if the shipping address is a carrier
255 *
256 * @return bool
257 */
258 private function checkButtonVisibility(){
259 $apple_carriers = $this->get_carriers();
260 $allowed = false;
261 $post = $this->get_post_data();
262 $chosen_method = isset($post['shipping_method'][0]) ? $post['shipping_method'][0] : null;
263
264 if( empty($chosen_method) ){
265 $chosen_method = !empty(WC()->session->chosen_shipping_methods[0]) ? WC()->session->chosen_shipping_methods[0] : null;
266 }
267
268 if(!$this->is_shipping_required() || is_product()){
269 return true;
270 }
271
272 foreach ( WC()->shipping()->get_packages() as $i => $package ) {
273 $available_rates = !empty($package['rates']) ? $package['rates'] : [];
274 if(!empty($available_rates)){
275 foreach($available_rates as $method){
276 if(in_array($method->get_method_id(), $apple_carriers) ){
277 if($chosen_method === $method->get_method_id() . ":" . $method->get_instance_id()){
278 $allowed = true;
279 }
280 }
281 }
282 }
283 }
284
285 return $allowed;
286 }
287
288 /**
289 *
290 * check if the shipping is required or not
291 * @return bool
292 */
293 public function is_shipping_required(){
294 $cart = WC()->cart->get_cart();
295
296 $required = true;
297 foreach ($cart as $cart_item){
298 if(!empty($cart_item['product_id']) ){
299 $product = wc_get_product( $cart_item['product_id'] );
300
301 //not required if it enters here
302 if(!$product->is_virtual() && !$product->is_downloadable()){
303 return true;
304 }
305
306 $required = false;
307 }
308 }
309
310 return $required;
311
312 }
313
314
315 /**
316 * Display unauthorized error
317 *
318 * @return void
319 */
320
321 public static function display_notice() {
322 ?>
323 <div class="notice notice-error is-dismissible">
324 <p><?php echo __( 'payplug_apple_pay_unauthorized_error', 'payplug' ); ?></p>
325 </div>
326 <?php
327 }
328
329 /**
330 * Checks if the current connection is using SSL.
331 *
332 * @return bool
333 */
334 public function isSSL()
335 {
336 if( !empty( $_SERVER['HTTPS'] ) ) {
337 if ( 'on' == strtolower($_SERVER['HTTPS']) )
338 return true;
339 } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
340 return true;
341 }
342
343 if( !empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' )
344 return true;
345
346 return false;
347 }
348
349 /**
350 * Enqueues Apple Pay CSS styles.
351 *
352 * @return void
353 */
354 public function add_apple_pay_css() {
355 wp_enqueue_style('payplug-apple-pay', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/css/payplug-apple-pay.css', [], PAYPLUG_GATEWAY_VERSION);
356 }
357
358 /**
359 * Enqueues Apple Pay JavaScript for the checkout page.
360 *
361 * @return void
362 */
363 public function add_apple_pay_js() {
364 wp_enqueue_script( 'apple-pay-sdk', 'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js', array(), false, true );
365 wp_enqueue_script('payplug-apple-pay', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-apple-pay.js',
366 [
367 'jquery',
368 'apple-pay-sdk'
369 ], PAYPLUG_GATEWAY_VERSION, true);
370 wp_localize_script( 'payplug-apple-pay', 'apple_pay_params',
371 array(
372 'ajax_url_payplug_create_order' => \WC_AJAX::get_endpoint('payplug_create_order'),
373 'ajax_url_applepay_update_payment' => \WC_AJAX::get_endpoint('applepay_update_payment'),
374 'ajax_url_applepay_get_order_totals' => \WC_AJAX::get_endpoint('applepay_get_order_totals'),
375 'countryCode' => WC()->customer->get_billing_country(),
376 'currencyCode' => get_woocommerce_currency(),
377 'total' => WC()->cart->total,
378 "is_checkout" => is_checkout(),
379 'apple_pay_domain' => $this->domain_name
380 )
381 );
382 }
383
384 /**
385 * Gets the Apple Pay payment icon HTML.
386 *
387 * @return string
388 */
389 public function get_icon()
390 {
391 $available_img = 'apple-pay-checkout.svg';
392 $icons = apply_filters('payplug_payment_icons', [
393 'payplug' => sprintf('<img src="%s" alt="Apple Pay" class="payplug-payment-icon" />', esc_url(PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/checkout/' . $available_img)),
394 ]);
395 $icons_str = '';
396 foreach ($icons as $icon) {
397 $icons_str .= $icon;
398 }
399 return $icons_str;
400 }
401
402 /**
403 * Processes a payment if it was already generated by an intent.
404 * @param $order
405 * @return array|null
406 * @throws \Exception
407 */
408 private function process_standard_intent_payment($order){
409
410 if ( !is_wc_endpoint_url('order-pay') &&
411 PayplugWoocommerceHelper::is_checkout_block() &&
412 !empty($order->get_transaction_id()) ) {
413
414 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
415
416 try {
417 $payment = $this->payplug_api->payment_retrieve($order->get_transaction_id());
418 if (ob_get_length() > 0) {
419 ob_clean();
420 }
421
422 $return_url = esc_url_raw($order->get_checkout_order_received_url());
423
424 wp_send_json_success(
425 array(
426 'payment_id' => $payment->id,
427 'result' => 'success',
428 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url,
429 'cancel' => !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : null
430 )
431 );
432
433 return array("stt" => "OK");
434
435 } catch (HttpException $e) {
436 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
437 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
438 } catch (\Exception $e) {
439 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
440 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
441 }
442 }
443
444 return null;
445 }
446
447
448 /**
449 * Processes a standard Apple Pay payment.
450 *
451 * @param \WC_Order $order
452 * @param int $amount
453 * @param int $customer_id
454 * @param string $workflow
455 *
456 * @return array
457 * @throws \Exception
458 */
459 public function process_standard_payment($order, $amount, $customer_id, $workflow = 'checkout')
460 {
461
462 $intent = $this->process_standard_intent_payment($order);
463 if( !empty($intent) ){
464 return $intent;
465 }
466
467 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
468 try {
469 $address_data = PayplugAddressData::from_order($order);
470
471 $return_url = esc_url_raw($order->get_checkout_order_received_url());
472
473 if (!(substr( $return_url, 0, 4 ) === "http")) {
474 $return_url = get_site_url().$return_url;
475 }
476
477 // delivery_type must be removed in Apple Pay
478 $billing = $address_data->get_billing();
479 unset($billing['delivery_type']);
480 $shipping = $address_data->get_shipping();
481 unset($shipping['delivery_type']);
482
483 $payment_data = [
484 'amount' => $amount,
485 'currency' => get_woocommerce_currency(),
486 'payment_method' => $this->id,
487 'payment_context' => array(
488 'apple_pay' => array(
489 'domain_name' => $this->domain_name,
490 'application_data' => base64_encode(json_encode(array(
491 'apple_pay_domain' => $this->domain_name,
492 )))
493 )
494 ),
495 'billing' => $billing,
496 'shipping' => $shipping,
497 'hosted_payment' => [
498 'return_url' => $return_url,
499 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
500 ],
501 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')),
502 'metadata' => [
503 'order_id' => $order_id,
504 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
505 'domain' => $this->domain_name,
506 'applepay_workflow' => $workflow
507 ]
508 ];
509
510 if (PayplugWoocommerceHelper::is_checkout_block() && is_checkout()) {
511 $payment_data['metadata']['woocommerce_block'] = "CHECKOUT";
512
513 } elseif (PayplugWoocommerceHelper::is_cart_block() && is_cart()) {
514 $payment_data['metadata']['woocommerce_block'] = "CART";
515 }
516
517
518 /**
519 * Filter the payment data before it's used
520 *
521 * @param array $payment_data
522 * @param int $order_id
523 * @param array $customer_details
524 * @param PayplugAddressData $address_data
525 */
526 $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data);
527 $payment = $this->payplug_api->payment_create($payment_data);
528
529 // Save transaction id for the order
530 PayplugWoocommerceHelper::is_pre_30()
531 ? update_post_meta($order_id, '_transaction_id', $payment->id)
532 : $order->set_transaction_id($payment->id);
533
534 if (is_callable([$order, 'save'])) {
535 $order->save();
536 }
537
538 /**
539 * Fires once a payment has been created.
540 *
541 * @param int $order_id Order ID
542 * @param PaymentResource $payment Payment resource
543 */
544 \do_action('payplug_gateway_payment_created', $order_id, $payment);
545
546 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
547 PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
548
549 PayplugGateway::log(sprintf('Payment creation complete for order #%s', $order_id));
550
551 return [
552 'result' => 'success',
553 'merchant_session' => $payment->payment_method['merchant_session'],
554 'payment_id' => $payment->id,
555 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
556 'return_url' => $return_url,
557 ];
558
559 } catch (HttpException $e) {
560 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
561 if($workflow === 'cart'){
562 wp_send_json_error([
563 'code' => $e->getCode(),
564 'msg' => __('Payment processing failed. Please retry.', 'payplug'),
565 'order_id' => $order_id
566 ]);
567 }
568 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
569 } catch (\Exception $e) {
570 PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
571 if($workflow === "cart"){
572 wp_send_json_error([
573 'code' => $e->getCode(),
574 'msg' => __('Payment processing failed. Please retry.', 'payplug'),
575 'order_id' => $order_id
576 ]);
577 }
578 throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
579 }
580
581 }
582
583 /**
584 * Sets the checkout button status.
585 *
586 * @param bool $status
587 * @return void
588 */
589 private function set_button_checkout($status){
590 $this->checkout = $status;
591 }
592
593 /**
594 * Sets the cart button status.
595 *
596 * @param bool $status
597 * @return void
598 */
599 private function set_button_cart($status){
600 $this->cart = $status;
601 }
602
603 /**
604 * Sets the product button status.
605 *
606 * @param bool $status
607 * @return void
608 */
609 private function set_button_product($status){
610 $this->product = $status;
611 }
612
613 /**
614 * Gets the checkout button status.
615 *
616 * @return bool
617 */
618 private function get_button_checkout(){
619 return $this->checkout;
620 }
621
622 /**
623 * Gets the cart button status.
624 *
625 * @return bool
626 */
627 public function get_button_cart(){
628 return $this->cart;
629 }
630
631 /**
632 * Gets the product button status.
633 *
634 * @return bool
635 */
636 public function get_button_product(){
637 return $this->product;
638 }
639
640 /**
641 * Gets the list of allowed carriers for Apple Pay.
642 *
643 * @return array
644 */
645 public function get_carriers(){
646 return $this->carriers;
647 }
648
649 /**
650 * Sets the list of allowed carriers for Apple Pay.
651 *
652 * @param array $carriers
653 * @return void
654 */
655 private function set_carriers($carriers){
656 $this->carriers = $carriers;
657 }
658
659 }
660