Completed
Push — master ( 5c4c21...aa8082 )
by Marcin
21s queued 11s
created

WC_Stripe_Payment_Request::are_keys_set()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Stripe Payment Request API
4
 *
5
 * @package WooCommerce_Stripe/Classes/Payment_Request
6
 * @since   4.0.0
7
 */
8
9
if ( ! defined( 'ABSPATH' ) ) {
10
	exit;
11
}
12
13
/**
14
 * WC_Stripe_Payment_Request class.
15
 */
16
class WC_Stripe_Payment_Request {
17
	/**
18
	 * Enabled.
19
	 *
20
	 * @var
21
	 */
22
	public $stripe_settings;
23
24
	/**
25
	 * Total label
26
	 *
27
	 * @var
28
	 */
29
	public $total_label;
30
31
	/**
32
	 * Key
33
	 *
34
	 * @var
35
	 */
36
	public $publishable_key;
37
38
	/**
39
	 * Key
40
	 *
41
	 * @var
42
	 */
43
	public $secret_key;
44
45
	/**
46
	 * Is test mode active?
47
	 *
48
	 * @var bool
49
	 */
50
	public $testmode;
51
52
	/**
53
	 * This Instance.
54
	 *
55
	 * @var
56
	 */
57
	private static $_this;
58
59
	/**
60
	 * Initialize class actions.
61
	 *
62
	 * @since 3.0.0
63
	 * @version 4.0.0
64
	 */
65
	public function __construct() {
66
		self::$_this            = $this;
67
		$this->stripe_settings  = get_option( 'woocommerce_stripe_settings', array() );
68
		$this->testmode         = ( ! empty( $this->stripe_settings['testmode'] ) && 'yes' === $this->stripe_settings['testmode'] ) ? true : false;
69
		$this->publishable_key  = ! empty( $this->stripe_settings['publishable_key'] ) ? $this->stripe_settings['publishable_key'] : '';
70
		$this->secret_key       = ! empty( $this->stripe_settings['secret_key'] ) ? $this->stripe_settings['secret_key'] : '';
71
		$this->total_label      = ! empty( $this->stripe_settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->stripe_settings['statement_descriptor'] ) : '';
72
73
		if ( $this->testmode ) {
74
			$this->publishable_key = ! empty( $this->stripe_settings['test_publishable_key'] ) ? $this->stripe_settings['test_publishable_key'] : '';
75
			$this->secret_key      = ! empty( $this->stripe_settings['test_secret_key'] ) ? $this->stripe_settings['test_secret_key'] : '';
76
		}
77
78
		$this->total_label = str_replace( "'", '', $this->total_label ) . apply_filters( 'wc_stripe_payment_request_total_label_suffix', ' (via WooCommerce)' );
79
80
		// Checks if Stripe Gateway is enabled.
81
		if ( empty( $this->stripe_settings ) || ( isset( $this->stripe_settings['enabled'] ) && 'yes' !== $this->stripe_settings['enabled'] ) ) {
82
			return;
83
		}
84
85
		// Checks if Payment Request is enabled.
86
		if ( ! isset( $this->stripe_settings['payment_request'] ) || 'yes' !== $this->stripe_settings['payment_request'] ) {
87
			return;
88
		}
89
90
		// Don't load for change payment method page.
91
		if ( isset( $_GET['change_payment_method'] ) ) {
92
			return;
93
		}
94
95
		$wc_default_country = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
96
97
		if ( ! in_array( $wc_default_country, $this->get_stripe_supported_countries() ) ) {
98
			return;
99
		}
100
101
		add_action( 'template_redirect', array( $this, 'set_session' ) );
102
		$this->init();
103
	}
104
105
	/**
106
	 * List of supported countries by Stripe.
107
	 *
108
	 * @since 4.1.3
109
	 * @return array The list of countries.
110
	 */
111
	public function get_stripe_supported_countries() {
112
		return apply_filters( 'wc_stripe_supported_countries', array( 'AT', 'AU', 'BE', 'BR', 'CA', 'CH', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'HK', 'IE', 'IN', 'IT', 'JP', 'LT', 'LU', 'LV', 'MX', 'NL', 'NZ', 'NO', 'PH', 'PL', 'PR', 'PT', 'RO', 'SE', 'SG', 'SK', 'US' ) );
113
	}
114
115
	/**
116
	 * Checks if keys are set.
117
	 *
118
	 * @since 4.0.6
119
	 * @return bool
120
	 */
121
	public function are_keys_set() {
122
		if ( empty( $this->secret_key ) || empty( $this->publishable_key ) ) {
123
			return false;
124
		}
125
126
		return true;
127
	}
128
129
	/**
130
	 * Get this instance.
131
	 *
132
	 * @since 4.0.6
133
	 * @return class
134
	 */
135
	public static function instance() {
136
		return self::$_this;
137
	}
138
139
	/**
140
	 * Sets the WC customer session if one is not set.
141
	 * This is needed so nonces can be verified by AJAX Request.
142
	 *
143
	 * @since 4.0.0
144
	 */
145
	public function set_session() {
146
		if ( ! is_product() || ( isset( WC()->session ) && WC()->session->has_session() ) ) {
147
			return;
148
		}
149
150
		WC()->session->set_customer_session_cookie( true );
151
	}
152
153
	/**
154
	 * Initialize hooks.
155
	 *
156
	 * @since 4.0.0
157
	 * @version 4.0.0
158
	 */
159
	public function init() {
160
		add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
161
162
		/*
163
		 * In order to display the Payment Request button in the correct position,
164
		 * a new hook was added to WooCommerce 3.0. In older versions of WooCommerce,
165
		 * CSS is used to position the button.
166
		 */
167
		if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
168
			add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'display_payment_request_button_html' ), 1 );
169
			add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'display_payment_request_button_separator_html' ), 2 );
170
		} else {
171
			add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_html' ), 1 );
172
			add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_separator_html' ), 2 );
173
		}
174
175
		add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 1 );
176
		add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_separator_html' ), 2 );
177
178
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_html' ), 1 );
179
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_separator_html' ), 2 );
180
181
		add_action( 'wc_ajax_wc_stripe_get_cart_details', array( $this, 'ajax_get_cart_details' ) );
182
		add_action( 'wc_ajax_wc_stripe_get_shipping_options', array( $this, 'ajax_get_shipping_options' ) );
183
		add_action( 'wc_ajax_wc_stripe_update_shipping_method', array( $this, 'ajax_update_shipping_method' ) );
184
		add_action( 'wc_ajax_wc_stripe_create_order', array( $this, 'ajax_create_order' ) );
185
		add_action( 'wc_ajax_wc_stripe_add_to_cart', array( $this, 'ajax_add_to_cart' ) );
186
		add_action( 'wc_ajax_wc_stripe_get_selected_product_data', array( $this, 'ajax_get_selected_product_data' ) );
187
		add_action( 'wc_ajax_wc_stripe_clear_cart', array( $this, 'ajax_clear_cart' ) );
188
		add_action( 'wc_ajax_wc_stripe_log_errors', array( $this, 'ajax_log_errors' ) );
189
190
		add_filter( 'woocommerce_gateway_title', array( $this, 'filter_gateway_title' ), 10, 2 );
191
		add_filter( 'woocommerce_validate_postcode', array( $this, 'postal_code_validation' ), 10, 3 );
192
193
		add_action( 'woocommerce_checkout_order_processed', array( $this, 'add_order_meta' ), 10, 2 );
194
	}
195
196
	/**
197
	 * Gets the button type.
198
	 *
199
	 * @since 4.0.0
200
	 * @version 4.0.0
201
	 * @return string
202
	 */
203
	public function get_button_type() {
204
		return isset( $this->stripe_settings['payment_request_button_type'] ) ? $this->stripe_settings['payment_request_button_type'] : 'default';
205
	}
206
207
	/**
208
	 * Gets the button theme.
209
	 *
210
	 * @since 4.0.0
211
	 * @version 4.0.0
212
	 * @return string
213
	 */
214
	public function get_button_theme() {
215
		return isset( $this->stripe_settings['payment_request_button_theme'] ) ? $this->stripe_settings['payment_request_button_theme'] : 'dark';
216
	}
217
218
	/**
219
	 * Gets the button height.
220
	 *
221
	 * @since 4.0.0
222
	 * @version 4.0.0
223
	 * @return string
224
	 */
225
	public function get_button_height() {
226
		return isset( $this->stripe_settings['payment_request_button_height'] ) ? str_replace( 'px', '', $this->stripe_settings['payment_request_button_height'] ) : '64';
227
	}
228
229
	/**
230
	 * Gets the product data for the currently viewed page
231
	 *
232
	 * @since 4.0.0
233
	 * @version 4.0.0
234
	 */
235
	public function get_product_data() {
236
		if ( ! is_product() ) {
237
			return false;
238
		}
239
240
		global $post;
241
242
		$product = wc_get_product( $post->ID );
243
244
		$data  = array();
245
		$items = array();
246
247
		$items[] = array(
248
			'label'  => WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->name : $product->get_name(),
249
			'amount' => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->price : $product->get_price() ),
250
		);
251
252 View Code Duplication
		if ( wc_tax_enabled() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
			$items[] = array(
254
				'label'   => __( 'Tax', 'woocommerce-gateway-stripe' ),
255
				'amount'  => 0,
256
				'pending' => true,
257
			);
258
		}
259
260 View Code Duplication
		if ( wc_shipping_enabled() && $product->needs_shipping() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
261
			$items[] = array(
262
				'label'   => __( 'Shipping', 'woocommerce-gateway-stripe' ),
263
				'amount'  => 0,
264
				'pending' => true,
265
			);
266
267
			$data['shippingOptions'] = array(
268
				'id'     => 'pending',
269
				'label'  => __( 'Pending', 'woocommerce-gateway-stripe' ),
270
				'detail' => '',
271
				'amount' => 0,
272
			);
273
		}
274
275
		$data['displayItems'] = $items;
276
		$data['total']        = array(
277
			'label'   => apply_filters( 'wc_stripe_payment_request_total_label', $this->total_label ),
278
			'amount'  => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->price : $product->get_price() ),
279
			'pending' => true,
280
		);
281
282
		$data['requestShipping'] = ( wc_shipping_enabled() && $product->needs_shipping() );
283
		$data['currency']        = strtolower( get_woocommerce_currency() );
284
		$data['country_code']    = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
285
286
		return apply_filters( 'wc_stripe_payment_request_product_data', $data, $product );
287
	}
288
289
	/**
290
	 * Filters the gateway title to reflect Payment Request type
291
	 *
292
	 */
293
	public function filter_gateway_title( $title, $id ) {
294
		global $post;
295
296
		if ( ! is_object( $post ) ) {
297
			return $title;
298
		}
299
300
		if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
301
			$method_title = get_post_meta( $post->ID, '_payment_method_title', true );
302
		} else {
303
			$order        = wc_get_order( $post->ID );
304
			$method_title = is_object( $order ) ? $order->get_payment_method_title() : '';
305
		}
306
307
		if ( 'stripe' === $id && ! empty( $method_title ) && 'Apple Pay (Stripe)' === $method_title ) {
308
			return $method_title;
309
		}
310
311
		if ( 'stripe' === $id && ! empty( $method_title ) && 'Chrome Payment Request (Stripe)' === $method_title ) {
312
			return $method_title;
313
		}
314
315
		return $title;
316
	}
317
318
	/**
319
	 * Removes postal code validation from WC.
320
	 *
321
	 * @since 3.1.4
322
	 * @version 4.0.0
323
	 */
324
	public function postal_code_validation( $valid, $postcode, $country ) {
325
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
326
327
		if ( ! isset( $gateways['stripe'] ) ) {
328
			return $valid;
329
		}
330
331
		$payment_request_type = isset( $_POST['payment_request_type'] ) ? wc_clean( $_POST['payment_request_type'] ) : '';
332
333
		if ( 'apple_pay' !== $payment_request_type ) {
334
			return $valid;
335
		}
336
337
		/**
338
		 * Currently Apple Pay truncates postal codes from UK and Canada to first 3 characters
339
		 * when passing it back from the shippingcontactselected object. This causes WC to invalidate
340
		 * the order and not let it go through. The remedy for now is just to remove this validation.
341
		 * Note that this only works with shipping providers that don't validate full postal codes.
342
		 */
343
		if ( 'GB' === $country || 'CA' === $country ) {
344
			return true;
345
		}
346
347
		return $valid;
348
	}
349
350
	/**
351
	 * Add needed order meta
352
	 *
353
	 * @since 4.0.0
354
	 * @version 4.0.0
355
	 * @param int $order_id
356
	 * @param array $posted_data The posted data from checkout form.
357
	 */
358
	public function add_order_meta( $order_id, $posted_data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $posted_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
359
		if ( empty( $_POST['payment_request_type'] ) ) {
360
			return;
361
		}
362
363
		$order = wc_get_order( $order_id );
364
365
		$payment_request_type = wc_clean( $_POST['payment_request_type'] );
366
367 View Code Duplication
		if ( 'apple_pay' === $payment_request_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
368
			if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
369
				update_post_meta( $order_id, '_payment_method_title', 'Apple Pay (Stripe)' );
370
			} else {
371
				$order->set_payment_method_title( 'Apple Pay (Stripe)' );
372
				$order->save();
373
			}
374
		}
375
376 View Code Duplication
		if ( 'payment_request_api' === $payment_request_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
377
			if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
378
				update_post_meta( $order_id, '_payment_method_title', 'Chrome Payment Request (Stripe)' );
379
			} else {
380
				$order->set_payment_method_title( 'Chrome Payment Request (Stripe)' );
381
				$order->save();
382
			}
383
		}
384
	}
385
386
	/**
387
	 * Checks to make sure product type is supported.
388
	 *
389
	 * @since 3.1.0
390
	 * @version 4.0.0
391
	 * @return array
392
	 */
393
	public function supported_product_types() {
394
		return apply_filters(
395
			'wc_stripe_payment_request_supported_types',
396
			array(
397
				'simple',
398
				'variable',
399
				'variation',
400
				'subscription',
401
				'variable-subscription',
402
				'subscription_variation',
403
				'booking',
404
				'bundle',
405
				'composite',
406
				'mix-and-match',
407
			)
408
		);
409
	}
410
411
	/**
412
	 * Checks the cart to see if all items are allowed to used.
413
	 *
414
	 * @since 3.1.4
415
	 * @version 4.0.0
416
	 * @return bool
417
	 */
418
	public function allowed_items_in_cart() {
419
		foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
420
			$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
421
422
			if ( ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $_product->product_type : $_product->get_type() ), $this->supported_product_types() ) ) {
423
				return false;
424
			}
425
426
			// Trial subscriptions with shipping are not supported
427
			if ( class_exists( 'WC_Subscriptions_Order' ) && WC_Subscriptions_Cart::cart_contains_subscription() && $_product->needs_shipping() && WC_Subscriptions_Product::get_trial_length( $_product ) > 0 ) {
428
				return false;
429
			}
430
431
			// Pre Orders compatbility where we don't support charge upon release.
432
			if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Cart::cart_contains_pre_order() && WC_Pre_Orders_Product::product_is_charged_upon_release( WC_Pre_Orders_Cart::get_pre_order_product() ) ) {
433
				return false;
434
			}
435
		}
436
437
		return true;
438
	}
439
440
	/**
441
	 * Load public scripts and styles.
442
	 *
443
	 * @since 3.1.0
444
	 * @version 4.0.0
445
	 */
446
	public function scripts() {
447
		// If keys are not set bail.
448
		if ( ! $this->are_keys_set() ) {
449
			WC_Stripe_Logger::log( 'Keys are not set correctly.' );
450
			return;
451
		}
452
453
		// If no SSL bail.
454
		if ( ! $this->testmode && ! is_ssl() ) {
455
			WC_Stripe_Logger::log( 'Stripe Payment Request live mode requires SSL.' );
456
			return;
457
		}
458
459
		if ( ! is_product() && ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
460
			return;
461
		}
462
463
		if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
464
			return;
465
		}
466
467
		$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
468
469
		$stripe_params = array(
470
			'ajax_url'        => WC_AJAX::get_endpoint( '%%endpoint%%' ),
471
			'stripe'          => array(
472
				'key'                => $this->publishable_key,
473
				'allow_prepaid_card' => apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no',
474
			),
475
			'nonce'           => array(
476
				'payment'                   => wp_create_nonce( 'wc-stripe-payment-request' ),
477
				'shipping'                  => wp_create_nonce( 'wc-stripe-payment-request-shipping' ),
478
				'update_shipping'           => wp_create_nonce( 'wc-stripe-update-shipping-method' ),
479
				'checkout'                  => wp_create_nonce( 'woocommerce-process_checkout' ),
480
				'add_to_cart'               => wp_create_nonce( 'wc-stripe-add-to-cart' ),
481
				'get_selected_product_data' => wp_create_nonce( 'wc-stripe-get-selected-product-data' ),
482
				'log_errors'                => wp_create_nonce( 'wc-stripe-log-errors' ),
483
				'clear_cart'                => wp_create_nonce( 'wc-stripe-clear-cart' ),
484
			),
485
			'i18n'            => array(
486
				'no_prepaid_card'  => __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' ),
487
				/* translators: Do not translate the [option] placeholder */
488
				'unknown_shipping' => __( 'Unknown shipping option "[option]".', 'woocommerce-gateway-stripe' ),
489
			),
490
			'checkout'        => array(
491
				'url'            => wc_get_checkout_url(),
492
				'currency_code'  => strtolower( get_woocommerce_currency() ),
493
				'country_code'   => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
494
				'needs_shipping' => WC()->cart->needs_shipping() ? 'yes' : 'no',
495
			),
496
			'button'          => array(
497
				'type'   => $this->get_button_type(),
498
				'theme'  => $this->get_button_theme(),
499
				'height' => $this->get_button_height(),
500
				'locale' => apply_filters( 'wc_stripe_payment_request_button_locale', substr( get_locale(), 0, 2 ) ), // Default format is en_US.
501
			),
502
			'is_product_page' => is_product(),
503
			'product'         => $this->get_product_data(),
504
		);
505
506
		wp_register_script( 'stripe', 'https://js.stripe.com/v3/', '', '3.0', true );
507
		wp_register_script( 'wc_stripe_payment_request', plugins_url( 'assets/js/stripe-payment-request' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'jquery', 'stripe' ), WC_STRIPE_VERSION, true );
508
509
		wp_localize_script( 'wc_stripe_payment_request', 'wc_stripe_payment_request_params', apply_filters( 'wc_stripe_payment_request_params', $stripe_params ) );
510
511
		wp_enqueue_script( 'wc_stripe_payment_request' );
512
513
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
514
		if ( isset( $gateways['stripe'] ) ) {
515
			$gateways['stripe']->payment_scripts();
516
		}
517
	}
518
519
	/**
520
	 * Display the payment request button.
521
	 *
522
	 * @since 4.0.0
523
	 * @version 4.0.0
524
	 */
525 View Code Duplication
	public function display_payment_request_button_html() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
526
		global $post;
527
528
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
529
530
		if ( ! isset( $gateways['stripe'] ) ) {
531
			return;
532
		}
533
534
		if ( ! is_cart() && ! is_checkout() && ! is_product() && ! isset( $_GET['pay_for_order'] ) ) {
535
			return;
536
		}
537
538
		if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
539
			return;
540
		}
541
542
		if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
543
			return;
544
		} else {
545
			if ( ! $this->allowed_items_in_cart() ) {
546
				WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
547
				return;
548
			}
549
		}
550
		?>
551
		<div id="wc-stripe-payment-request-wrapper" style="clear:both;padding-top:1.5em;display:none;">
552
			<div id="wc-stripe-payment-request-button">
553
				<!-- A Stripe Element will be inserted here. -->
554
			</div>
555
		</div>
556
		<?php
557
	}
558
559
	/**
560
	 * Display payment request button separator.
561
	 *
562
	 * @since 4.0.0
563
	 * @version 4.0.0
564
	 */
565 View Code Duplication
	public function display_payment_request_button_separator_html() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
566
		global $post;
567
568
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
569
570
		if ( ! isset( $gateways['stripe'] ) ) {
571
			return;
572
		}
573
574
		if ( ! is_cart() && ! is_checkout() && ! is_product() && ! isset( $_GET['pay_for_order'] ) ) {
575
			return;
576
		}
577
578
		if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
579
			return;
580
		}
581
582
		if ( is_product() && ! $this->should_show_payment_button_on_product_page() ) {
583
			return;
584
		} else {
585
			if ( ! $this->allowed_items_in_cart() ) {
586
				WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
587
				return;
588
			}
589
		}
590
		?>
591
		<p id="wc-stripe-payment-request-button-separator" style="margin-top:1.5em;text-align:center;display:none;">&mdash; <?php esc_html_e( 'OR', 'woocommerce-gateway-stripe' ); ?> &mdash;</p>
592
		<?php
593
	}
594
595
	/**
596
	 * Whether payment button html should be rendered
597
	 *
598
	 * @since 4.3.2
599
	 *
600
	 * @param object $post
0 ignored issues
show
Bug introduced by
There is no parameter named $post. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
601
	 *
602
	 * @return bool
603
	 */
604
	private function should_show_payment_button_on_product_page() {
605
		global $post;
606
607
		$product = wc_get_product( $post->ID );
608
609
		if ( apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
610
			return false;
611
		}
612
613
		if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
614
			return false;
615
		}
616
617
		// Trial subscriptions with shipping are not supported
618
		if ( class_exists( 'WC_Subscriptions_Order' ) && $product->needs_shipping() && WC_Subscriptions_Product::get_trial_length( $product ) > 0 ) {
619
			return false;
620
		}
621
622
		// Pre Orders charge upon release not supported.
623
		if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
624
			WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
625
			return false;
626
		}
627
628
		// File upload addon not supported
629
		if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
630
			$product_addons = WC_Product_Addons_Helper::get_product_addons( $product->get_id() );
631
			foreach ( $product_addons as $addon ) {
632
				if ( 'file_upload' === $addon['type'] ) {
633
					return false;
634
				}
635
			}
636
		}
637
638
		return true;
639
	}
640
641
	/**
642
	 * Log errors coming from Payment Request
643
	 *
644
	 * @since 3.1.4
645
	 * @version 4.0.0
646
	 */
647
	public function ajax_log_errors() {
648
		check_ajax_referer( 'wc-stripe-log-errors', 'security' );
649
650
		$errors = wc_clean( stripslashes( $_POST['errors'] ) );
651
652
		WC_Stripe_Logger::log( $errors );
653
654
		exit;
655
	}
656
657
	/**
658
	 * Clears cart.
659
	 *
660
	 * @since 3.1.4
661
	 * @version 4.0.0
662
	 */
663
	public function ajax_clear_cart() {
664
		check_ajax_referer( 'wc-stripe-clear-cart', 'security' );
665
666
		WC()->cart->empty_cart();
667
		exit;
668
	}
669
670
	/**
671
	 * Get cart details.
672
	 */
673
	public function ajax_get_cart_details() {
674
		check_ajax_referer( 'wc-stripe-payment-request', 'security' );
675
676
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
677
			define( 'WOOCOMMERCE_CART', true );
678
		}
679
680
		WC()->cart->calculate_totals();
681
682
		$currency = get_woocommerce_currency();
683
684
		// Set mandatory payment details.
685
		$data = array(
686
			'shipping_required' => WC()->cart->needs_shipping(),
687
			'order_data'        => array(
688
				'currency'     => strtolower( $currency ),
689
				'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
690
			),
691
		);
692
693
		$data['order_data'] += $this->build_display_items();
694
695
		wp_send_json( $data );
696
	}
697
698
	/**
699
	 * Get shipping options.
700
	 *
701
	 * @see WC_Cart::get_shipping_packages().
702
	 * @see WC_Shipping::calculate_shipping().
703
	 * @see WC_Shipping::get_packages().
704
	 */
705
	public function ajax_get_shipping_options() {
706
		check_ajax_referer( 'wc-stripe-payment-request-shipping', 'security' );
707
708
		try {
709
			// Set the shipping package.
710
			$posted = filter_input_array(
711
				INPUT_POST,
712
				array(
713
					'country'   => FILTER_SANITIZE_STRING,
714
					'state'     => FILTER_SANITIZE_STRING,
715
					'postcode'  => FILTER_SANITIZE_STRING,
716
					'city'      => FILTER_SANITIZE_STRING,
717
					'address'   => FILTER_SANITIZE_STRING,
718
					'address_2' => FILTER_SANITIZE_STRING,
719
				)
720
			);
721
722
			$this->calculate_shipping( apply_filters( 'wc_stripe_payment_request_shipping_posted_values', $posted ) );
723
724
			// Set the shipping options.
725
			$data     = array();
726
			$packages = WC()->shipping->get_packages();
727
728
			if ( ! empty( $packages ) && WC()->customer->has_calculated_shipping() ) {
729
				foreach ( $packages as $package_key => $package ) {
730
					if ( empty( $package['rates'] ) ) {
731
						throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) );
732
					}
733
734
					foreach ( $package['rates'] as $key => $rate ) {
735
						$data['shipping_options'][] = array(
736
							'id'     => $rate->id,
737
							'label'  => $rate->label,
738
							'detail' => '',
739
							'amount' => WC_Stripe_Helper::get_stripe_amount( $rate->cost ),
740
						);
741
					}
742
				}
743
			} else {
744
				throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) );
745
			}
746
747
			if ( isset( $data[0] ) ) {
748
				// Auto select the first shipping method.
749
				WC()->session->set( 'chosen_shipping_methods', array( $data[0]['id'] ) );
750
			}
751
752
			WC()->cart->calculate_totals();
753
754
			$data          += $this->build_display_items();
755
			$data['result'] = 'success';
756
757
			wp_send_json( $data );
758
		} catch ( Exception $e ) {
759
			$data          += $this->build_display_items();
0 ignored issues
show
Bug introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
760
			$data['result'] = 'invalid_shipping_address';
761
762
			wp_send_json( $data );
763
		}
764
	}
765
766
	/**
767
	 * Update shipping method.
768
	 */
769
	public function ajax_update_shipping_method() {
770
		check_ajax_referer( 'wc-stripe-update-shipping-method', 'security' );
771
772
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
773
			define( 'WOOCOMMERCE_CART', true );
774
		}
775
776
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
777
		$shipping_method         = filter_input( INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
778
779
		if ( is_array( $shipping_method ) ) {
780
			foreach ( $shipping_method as $i => $value ) {
781
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
782
			}
783
		}
784
785
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
786
787
		WC()->cart->calculate_totals();
788
789
		$data           = array();
790
		$data          += $this->build_display_items();
791
		$data['result'] = 'success';
792
793
		wp_send_json( $data );
794
	}
795
796
	/**
797
	 * Gets the selected product data.
798
	 *
799
	 * @since 4.0.0
800
	 * @version 4.0.0
801
	 * @return array $data
802
	 */
803
	public function ajax_get_selected_product_data() {
804
		check_ajax_referer( 'wc-stripe-get-selected-product-data', 'security' );
805
806
		try {
807
			$product_id   = absint( $_POST['product_id'] );
808
			$qty          = ! isset( $_POST['qty'] ) ? 1 : apply_filters( 'woocommerce_add_to_cart_quantity', absint( $_POST['qty'] ), $product_id );
809
			$addon_value  = isset( $_POST['addon_value'] ) ? max( floatval( $_POST['addon_value'] ), 0 ) : 0;
810
			$product      = wc_get_product( $product_id );
811
			$variation_id = null;
812
813
			if ( ! is_a( $product, 'WC_Product' ) ) {
814
				throw new Exception( sprintf( __( 'Product with the ID (%d) cannot be found.', 'woocommerce-gateway-stripe' ), $product_id ) );
815
			}
816
817
			if ( 'variable' === ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ) && isset( $_POST['attributes'] ) ) {
818
				$attributes = array_map( 'wc_clean', $_POST['attributes'] );
819
820 View Code Duplication
				if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
821
					$variation_id = $product->get_matching_variation( $attributes );
822
				} else {
823
					$data_store   = WC_Data_Store::load( 'product' );
824
					$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
825
				}
826
827
				if ( ! empty( $variation_id ) ) {
828
					$product = wc_get_product( $variation_id );
829
				}
830
			} elseif ( 'simple' === ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type() ) ) {
831
				$product = wc_get_product( $product_id );
832
			}
833
834
			// Force quantity to 1 if sold individually and check for existing item in cart.
835
			if ( $product->is_sold_individually() ) {
836
				$qty = apply_filters( 'wc_stripe_payment_request_add_to_cart_sold_individually_quantity', 1, $qty, $product_id, $variation_id );
837
			}
838
839
			if ( ! $product->has_enough_stock( $qty ) ) {
840
				/* translators: 1: product name 2: quantity in stock */
841
				throw new Exception( sprintf( __( 'You cannot add that amount of "%1$s"; to the cart because there is not enough stock (%2$s remaining).', 'woocommerce-gateway-stripe' ), $product->get_name(), wc_format_stock_quantity_for_display( $product->get_stock_quantity(), $product ) ) );
842
			}
843
844
			$total = $qty * ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->price : $product->get_price() ) + $addon_value;
845
846
			$quantity_label = 1 < $qty ? ' (x' . $qty . ')' : '';
847
848
			$data  = array();
849
			$items = array();
850
851
			$items[] = array(
852
				'label'  => ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->name : $product->get_name() ) . $quantity_label,
853
				'amount' => WC_Stripe_Helper::get_stripe_amount( $total ),
854
			);
855
856 View Code Duplication
			if ( wc_tax_enabled() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
857
				$items[] = array(
858
					'label'   => __( 'Tax', 'woocommerce-gateway-stripe' ),
859
					'amount'  => 0,
860
					'pending' => true,
861
				);
862
			}
863
864 View Code Duplication
			if ( wc_shipping_enabled() && $product->needs_shipping() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
865
				$items[] = array(
866
					'label'   => __( 'Shipping', 'woocommerce-gateway-stripe' ),
867
					'amount'  => 0,
868
					'pending' => true,
869
				);
870
871
				$data['shippingOptions'] = array(
872
					'id'     => 'pending',
873
					'label'  => __( 'Pending', 'woocommerce-gateway-stripe' ),
874
					'detail' => '',
875
					'amount' => 0,
876
				);
877
			}
878
879
			$data['displayItems'] = $items;
880
			$data['total']        = array(
881
				'label'   => $this->total_label,
882
				'amount'  => WC_Stripe_Helper::get_stripe_amount( $total ),
883
				'pending' => true,
884
			);
885
886
			$data['requestShipping'] = ( wc_shipping_enabled() && $product->needs_shipping() );
887
			$data['currency']        = strtolower( get_woocommerce_currency() );
888
			$data['country_code']    = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
889
890
			wp_send_json( $data );
891
		} catch ( Exception $e ) {
892
			wp_send_json( array( 'error' => wp_strip_all_tags( $e->getMessage() ) ) );
893
		}
894
	}
895
896
	/**
897
	 * Adds the current product to the cart. Used on product detail page.
898
	 *
899
	 * @since 4.0.0
900
	 * @version 4.0.0
901
	 * @return array $data
902
	 */
903
	public function ajax_add_to_cart() {
904
		check_ajax_referer( 'wc-stripe-add-to-cart', 'security' );
905
906
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
907
			define( 'WOOCOMMERCE_CART', true );
908
		}
909
910
		WC()->shipping->reset_shipping();
911
912
		$product_id   = absint( $_POST['product_id'] );
913
		$qty          = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
914
		$product      = wc_get_product( $product_id );
915
		$product_type = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $product->product_type : $product->get_type();
916
917
		// First empty the cart to prevent wrong calculation.
918
		WC()->cart->empty_cart();
919
920
		if ( ( 'variable' === $product_type || 'variable-subscription' === $product_type ) && isset( $_POST['attributes'] ) ) {
921
			$attributes = array_map( 'wc_clean', $_POST['attributes'] );
922
923 View Code Duplication
			if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
924
				$variation_id = $product->get_matching_variation( $attributes );
925
			} else {
926
				$data_store   = WC_Data_Store::load( 'product' );
927
				$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
928
			}
929
930
			WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
931
		}
932
933
		if ( 'simple' === $product_type || 'subscription' === $product_type ) {
934
			WC()->cart->add_to_cart( $product->get_id(), $qty );
935
		}
936
937
		WC()->cart->calculate_totals();
938
939
		$data           = array();
940
		$data          += $this->build_display_items();
941
		$data['result'] = 'success';
942
943
		wp_send_json( $data );
944
	}
945
946
	/**
947
	 * Normalizes the state/county field because in some
948
	 * cases, the state/county field is formatted differently from
949
	 * what WC is expecting and throws an error. An example
950
	 * for Ireland the county dropdown in Chrome shows "Co. Clare" format
951
	 *
952
	 * @since 4.0.0
953
	 * @version 4.0.0
954
	 */
955
	public function normalize_state() {
956
		$billing_country  = ! empty( $_POST['billing_country'] ) ? wc_clean( $_POST['billing_country'] ) : '';
957
		$shipping_country = ! empty( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '';
958
		$billing_state    = ! empty( $_POST['billing_state'] ) ? wc_clean( $_POST['billing_state'] ) : '';
959
		$shipping_state   = ! empty( $_POST['shipping_state'] ) ? wc_clean( $_POST['shipping_state'] ) : '';
960
961 View Code Duplication
		if ( $billing_state && $billing_country ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
962
			$valid_states = WC()->countries->get_states( $billing_country );
963
964
			// Valid states found for country.
965
			if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) {
966
				foreach ( $valid_states as $state_abbr => $state ) {
967
					if ( preg_match( '/' . preg_quote( $state ) . '/i', $billing_state ) ) {
968
						$_POST['billing_state'] = $state_abbr;
969
					}
970
				}
971
			}
972
		}
973
974 View Code Duplication
		if ( $shipping_state && $shipping_country ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
975
			$valid_states = WC()->countries->get_states( $shipping_country );
976
977
			// Valid states found for country.
978
			if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) {
979
				foreach ( $valid_states as $state_abbr => $state ) {
980
					if ( preg_match( '/' . preg_quote( $state ) . '/i', $shipping_state ) ) {
981
						$_POST['shipping_state'] = $state_abbr;
982
					}
983
				}
984
			}
985
		}
986
	}
987
988
	/**
989
	 * Create order. Security is handled by WC.
990
	 *
991
	 * @since 3.1.0
992
	 * @version 4.0.0
993
	 */
994
	public function ajax_create_order() {
995
		if ( WC()->cart->is_empty() ) {
996
			wp_send_json_error( __( 'Empty cart', 'woocommerce-gateway-stripe' ) );
997
		}
998
999
		if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
1000
			define( 'WOOCOMMERCE_CHECKOUT', true );
1001
		}
1002
1003
		$this->normalize_state();
1004
1005
		WC()->checkout()->process_checkout();
1006
1007
		die( 0 );
1008
	}
1009
1010
	/**
1011
	 * Calculate and set shipping method.
1012
	 *
1013
	 * @since 3.1.0
1014
	 * @version 4.0.0
1015
	 * @param array $address
1016
	 */
1017
	protected function calculate_shipping( $address = array() ) {
1018
		$country   = $address['country'];
1019
		$state     = $address['state'];
1020
		$postcode  = $address['postcode'];
1021
		$city      = $address['city'];
1022
		$address_1 = $address['address'];
1023
		$address_2 = $address['address_2'];
1024
		$wc_states = WC()->countries->get_states( $country );
1025
1026
		/**
1027
		 * In some versions of Chrome, state can be a full name. So we need
1028
		 * to convert that to abbreviation as WC is expecting that.
1029
		 */
1030
		if ( 2 < strlen( $state ) && ! empty( $wc_states ) ) {
1031
			$state = array_search( ucwords( strtolower( $state ) ), $wc_states, true );
1032
		}
1033
1034
		WC()->shipping->reset_shipping();
1035
1036
		if ( $postcode && WC_Validation::is_postcode( $postcode, $country ) ) {
1037
			$postcode = wc_format_postcode( $postcode, $country );
1038
		}
1039
1040
		if ( $country ) {
1041
			WC()->customer->set_location( $country, $state, $postcode, $city );
1042
			WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
1043
		} else {
1044
			WC_Stripe_Helper::is_wc_lt( '3.0' ) ? WC()->customer->set_to_base() : WC()->customer->set_billing_address_to_base();
1045
			WC_Stripe_Helper::is_wc_lt( '3.0' ) ? WC()->customer->set_shipping_to_base() : WC()->customer->set_shipping_address_to_base();
1046
		}
1047
1048
		if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
1049
			WC()->customer->calculated_shipping( true );
1050
		} else {
1051
			WC()->customer->set_calculated_shipping( true );
1052
			WC()->customer->save();
1053
		}
1054
1055
		$packages = array();
1056
1057
		$packages[0]['contents']                 = WC()->cart->get_cart();
1058
		$packages[0]['contents_cost']            = 0;
1059
		$packages[0]['applied_coupons']          = WC()->cart->applied_coupons;
1060
		$packages[0]['user']['ID']               = get_current_user_id();
1061
		$packages[0]['destination']['country']   = $country;
1062
		$packages[0]['destination']['state']     = $state;
1063
		$packages[0]['destination']['postcode']  = $postcode;
1064
		$packages[0]['destination']['city']      = $city;
1065
		$packages[0]['destination']['address']   = $address_1;
1066
		$packages[0]['destination']['address_2'] = $address_2;
1067
1068
		foreach ( WC()->cart->get_cart() as $item ) {
1069
			if ( $item['data']->needs_shipping() ) {
1070
				if ( isset( $item['line_total'] ) ) {
1071
					$packages[0]['contents_cost'] += $item['line_total'];
1072
				}
1073
			}
1074
		}
1075
1076
		$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages );
1077
1078
		WC()->shipping->calculate_shipping( $packages );
1079
	}
1080
1081
	/**
1082
	 * Builds the shippings methods to pass to Payment Request
1083
	 *
1084
	 * @since 3.1.0
1085
	 * @version 4.0.0
1086
	 */
1087
	protected function build_shipping_methods( $shipping_methods ) {
1088
		if ( empty( $shipping_methods ) ) {
1089
			return array();
1090
		}
1091
1092
		$shipping = array();
1093
1094
		foreach ( $shipping_methods as $method ) {
1095
			$shipping[] = array(
1096
				'id'     => $method['id'],
1097
				'label'  => $method['label'],
1098
				'detail' => '',
1099
				'amount' => WC_Stripe_Helper::get_stripe_amount( $method['amount']['value'] ),
1100
			);
1101
		}
1102
1103
		return $shipping;
1104
	}
1105
1106
	/**
1107
	 * Builds the line items to pass to Payment Request
1108
	 *
1109
	 * @since 3.1.0
1110
	 * @version 4.0.0
1111
	 */
1112
	protected function build_display_items() {
1113
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
1114
			define( 'WOOCOMMERCE_CART', true );
1115
		}
1116
1117
		$items     = array();
1118
		$subtotal  = 0;
1119
		$discounts = 0;
1120
1121
		// Default show only subtotal instead of itemization.
1122
		if ( ! apply_filters( 'wc_stripe_payment_request_hide_itemization', true ) ) {
1123
			foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
1124
				$amount         = $cart_item['line_subtotal'];
1125
				$subtotal      += $cart_item['line_subtotal'];
1126
				$quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
1127
1128
				$product_name = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $cart_item['data']->post->post_title : $cart_item['data']->get_name();
1129
1130
				$item = array(
1131
					'label'  => $product_name . $quantity_label,
1132
					'amount' => WC_Stripe_Helper::get_stripe_amount( $amount ),
1133
				);
1134
1135
				$items[] = $item;
1136
			}
1137
		}
1138
1139
		if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
1140
			$discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
1141
		} else {
1142
			$applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );
1143
1144
			foreach ( $applied_coupons as $amount ) {
1145
				$discounts += (float) $amount;
1146
			}
1147
		}
1148
1149
		$discounts   = wc_format_decimal( $discounts, WC()->cart->dp );
1150
		$tax         = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
1151
		$shipping    = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
1152
		$items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
1153
		$order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( false );
1154
1155
		if ( wc_tax_enabled() ) {
1156
			$items[] = array(
1157
				'label'  => esc_html( __( 'Tax', 'woocommerce-gateway-stripe' ) ),
1158
				'amount' => WC_Stripe_Helper::get_stripe_amount( $tax ),
1159
			);
1160
		}
1161
1162 View Code Duplication
		if ( WC()->cart->needs_shipping() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1163
			$items[] = array(
1164
				'label'  => esc_html( __( 'Shipping', 'woocommerce-gateway-stripe' ) ),
1165
				'amount' => WC_Stripe_Helper::get_stripe_amount( $shipping ),
1166
			);
1167
		}
1168
1169 View Code Duplication
		if ( WC()->cart->has_discount() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1170
			$items[] = array(
1171
				'label'  => esc_html( __( 'Discount', 'woocommerce-gateway-stripe' ) ),
1172
				'amount' => WC_Stripe_Helper::get_stripe_amount( $discounts ),
1173
			);
1174
		}
1175
1176
		if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
1177
			$cart_fees = WC()->cart->fees;
1178
		} else {
1179
			$cart_fees = WC()->cart->get_fees();
1180
		}
1181
1182
		// Include fees and taxes as display items.
1183
		foreach ( $cart_fees as $key => $fee ) {
1184
			$items[] = array(
1185
				'label'  => $fee->name,
1186
				'amount' => WC_Stripe_Helper::get_stripe_amount( $fee->amount ),
1187
			);
1188
		}
1189
1190
		return array(
1191
			'displayItems' => $items,
1192
			'total'        => array(
1193
				'label'   => $this->total_label,
1194
				'amount'  => max( 0, apply_filters( 'woocommerce_stripe_calculated_total', WC_Stripe_Helper::get_stripe_amount( $order_total ), $order_total, WC()->cart ) ),
1195
				'pending' => false,
1196
			),
1197
		);
1198
	}
1199
}
1200
1201
new WC_Stripe_Payment_Request();
1202