Completed
Push — master ( e3a5fe...3adadd )
by Roy
05:10
created

WC_Stripe_Payment_Request   D

Complexity

Total Complexity 214

Size/Duplication

Total Lines 1143
Duplicated Lines 17.15 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 196
loc 1143
rs 4.4102
c 0
b 0
f 0
wmc 214
lcom 1
cbo 2

29 Methods

Rating   Name   Duplication   Size   Complexity  
D display_payment_request_button_html() 47 47 17
D display_payment_request_button_separator_html() 43 43 17
A ajax_log_errors() 0 9 1
A ajax_clear_cart() 0 6 1
B ajax_get_cart_details() 0 24 2
B ajax_get_shipping_options() 0 57 8
B ajax_update_shipping_method() 0 26 4
F ajax_get_selected_product_data() 27 73 16
D ajax_add_to_cart() 6 42 9
F normalize_state() 24 32 19
A ajax_create_order() 0 15 3
C calculate_shipping() 0 67 11
A build_shipping_methods() 0 18 3
F __construct() 0 34 16
A are_keys_set() 0 7 3
A instance() 0 3 1
B set_session() 0 14 5
B init() 0 36 2
A get_button_type() 0 3 2
A get_button_theme() 0 3 2
A get_button_height() 0 3 2
C get_product_data() 21 53 9
C filter_gateway_title() 0 24 10
B postal_code_validation() 0 25 6
B add_order_meta() 16 27 6
A supported_product_types() 0 12 1
B allowed_items_in_cart() 0 16 7
C scripts() 0 78 17
F build_display_items() 12 87 14

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WC_Stripe_Payment_Request often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WC_Stripe_Payment_Request, and based on these observations, apply Extract Interface, too.

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
	 * Stripe Checkout enabled.
26
	 *
27
	 * @var
28
	 */
29
	public $stripe_checkout_enabled;
30
31
	/**
32
	 * Total label
33
	 *
34
	 * @var
35
	 */
36
	public $total_label;
37
38
	/**
39
	 * Key
40
	 *
41
	 * @var
42
	 */
43
	public $publishable_key;
44
45
	/**
46
	 * Key
47
	 *
48
	 * @var
49
	 */
50
	public $secret_key;
51
52
	/**
53
	 * Is test mode active?
54
	 *
55
	 * @var bool
56
	 */
57
	public $testmode;
58
59
	/**
60
	 * This Instance.
61
	 *
62
	 * @var
63
	 */
64
	private static $_this;
65
66
	/**
67
	 * Initialize class actions.
68
	 *
69
	 * @since 3.0.0
70
	 * @version 4.0.0
71
	 */
72
	public function __construct() {
73
		self::$_this                   = $this;
74
		$this->stripe_settings         = get_option( 'woocommerce_stripe_settings', array() );
75
		$this->testmode                = ( ! empty( $this->stripe_settings['testmode'] ) && 'yes' === $this->stripe_settings['testmode'] ) ? true : false;
76
		$this->publishable_key         = ! empty( $this->stripe_settings['publishable_key'] ) ? $this->stripe_settings['publishable_key'] : '';
77
		$this->secret_key              = ! empty( $this->stripe_settings['secret_key'] ) ? $this->stripe_settings['secret_key'] : '';
78
		$this->stripe_checkout_enabled = isset( $this->stripe_settings['stripe_checkout'] ) && 'yes' === $this->stripe_settings['stripe_checkout'];
79
		$this->total_label             = ! empty( $this->stripe_settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->stripe_settings['statement_descriptor'] ) : '';
80
81
		if ( $this->testmode ) {
82
			$this->publishable_key = ! empty( $this->stripe_settings['test_publishable_key'] ) ? $this->stripe_settings['test_publishable_key'] : '';
83
			$this->secret_key      = ! empty( $this->stripe_settings['test_secret_key'] ) ? $this->stripe_settings['test_secret_key'] : '';
84
		}
85
86
		$this->total_label = str_replace( "'", '', $this->total_label ) . apply_filters( 'wc_stripe_payment_request_total_label_suffix', ' (via WooCommerce)' );
87
88
		// Checks if Stripe Gateway is enabled.
89
		if ( empty( $this->stripe_settings ) || ( isset( $this->stripe_settings['enabled'] ) && 'yes' !== $this->stripe_settings['enabled'] ) ) {
90
			return;
91
		}
92
93
		// Checks if Payment Request is enabled.
94
		if ( ! isset( $this->stripe_settings['payment_request'] ) || 'yes' !== $this->stripe_settings['payment_request'] ) {
95
			return;
96
		}
97
98
		// Don't load for change payment method page.
99
		if ( isset( $_GET['change_payment_method'] ) ) {
100
			return;
101
		}
102
103
		add_action( 'template_redirect', array( $this, 'set_session' ) );
104
		$this->init();
105
	}
106
107
	/**
108
	 * Checks if keys are set.
109
	 *
110
	 * @since 4.0.6
111
	 * @return bool
112
	 */
113
	public function are_keys_set() {
114
		if ( empty( $this->secret_key ) || empty( $this->publishable_key ) ) {
115
			return false;
116
		}
117
118
		return true;
119
	}
120
121
	/**
122
	 * Get this instance.
123
	 *
124
	 * @since 4.0.6
125
	 * @return class
126
	 */
127
	public static function instance() {
128
		return self::$_this;
129
	}
130
131
	/**
132
	 * Sets the WC customer session if one is not set.
133
	 * This is needed so nonces can be verified by AJAX Request.
134
	 *
135
	 * @since 4.0.0
136
	 */
137
	public function set_session() {
138
		if ( ! is_product() || ( isset( WC()->session ) && WC()->session->has_session() ) ) {
139
			return;
140
		}
141
142
		$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
143
		$wc_session    = new $session_class();
144
145
		if ( version_compare( WC_VERSION, '3.3', '>=' ) ) {
146
			$wc_session->init();
147
		}
148
149
		$wc_session->set_customer_session_cookie( true );
150
	}
151
152
	/**
153
	 * Initialize hooks.
154
	 *
155
	 * @since 4.0.0
156
	 * @version 4.0.0
157
	 */
158
	public function init() {
159
		add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
160
161
		/*
162
		 * In order to display the Payment Request button in the correct position,
163
		 * a new hook was added to WooCommerce 3.0. In older versions of WooCommerce,
164
		 * CSS is used to position the button.
165
		 */
166
		if ( WC_Stripe_Helper::is_pre_30() ) {
167
			add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'display_payment_request_button_html' ), 1 );
168
			add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'display_payment_request_button_separator_html' ), 2 );
169
		} else {
170
			add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_html' ), 1 );
171
			add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_payment_request_button_separator_html' ), 2 );
172
		}
173
174
		add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_html' ), 1 );
175
		add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_payment_request_button_separator_html' ), 2 );
176
177
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_html' ), 1 );
178
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_payment_request_button_separator_html' ), 2 );
179
180
		add_action( 'wc_ajax_wc_stripe_get_cart_details', array( $this, 'ajax_get_cart_details' ) );
181
		add_action( 'wc_ajax_wc_stripe_get_shipping_options', array( $this, 'ajax_get_shipping_options' ) );
182
		add_action( 'wc_ajax_wc_stripe_update_shipping_method', array( $this, 'ajax_update_shipping_method' ) );
183
		add_action( 'wc_ajax_wc_stripe_create_order', array( $this, 'ajax_create_order' ) );
184
		add_action( 'wc_ajax_wc_stripe_add_to_cart', array( $this, 'ajax_add_to_cart' ) );
185
		add_action( 'wc_ajax_wc_stripe_get_selected_product_data', array( $this, 'ajax_get_selected_product_data' ) );
186
		add_action( 'wc_ajax_wc_stripe_clear_cart', array( $this, 'ajax_clear_cart' ) );
187
		add_action( 'wc_ajax_wc_stripe_log_errors', array( $this, 'ajax_log_errors' ) );
188
189
		add_filter( 'woocommerce_gateway_title', array( $this, 'filter_gateway_title' ), 10, 2 );
190
		add_filter( 'woocommerce_validate_postcode', array( $this, 'postal_code_validation' ), 10, 3 );
191
192
		add_action( 'woocommerce_checkout_order_processed', array( $this, 'add_order_meta' ), 10, 2 );
193
	}
194
195
	/**
196
	 * Gets the button type.
197
	 *
198
	 * @since 4.0.0
199
	 * @version 4.0.0
200
	 * @return string
201
	 */
202
	public function get_button_type() {
203
		return isset( $this->stripe_settings['payment_request_button_type'] ) ? $this->stripe_settings['payment_request_button_type'] : 'default';
204
	}
205
206
	/**
207
	 * Gets the button theme.
208
	 *
209
	 * @since 4.0.0
210
	 * @version 4.0.0
211
	 * @return string
212
	 */
213
	public function get_button_theme() {
214
		return isset( $this->stripe_settings['payment_request_button_theme'] ) ? $this->stripe_settings['payment_request_button_theme'] : 'dark';
215
	}
216
217
	/**
218
	 * Gets the button height.
219
	 *
220
	 * @since 4.0.0
221
	 * @version 4.0.0
222
	 * @return string
223
	 */
224
	public function get_button_height() {
225
		return isset( $this->stripe_settings['payment_request_button_height'] ) ? str_replace( 'px', '', $this->stripe_settings['payment_request_button_height'] ) : '64';
226
	}
227
228
	/**
229
	 * Gets the product data for the currently viewed page
230
	 *
231
	 * @since 4.0.0
232
	 * @version 4.0.0
233
	 */
234
	public function get_product_data() {
235
		if ( ! is_product() ) {
236
			return false;
237
		}
238
239
		global $post;
240
241
		$product = wc_get_product( $post->ID );
242
243
		$data  = array();
244
		$items = array();
245
246
		$items[] = array(
247
			'label'  => WC_Stripe_Helper::is_pre_30() ? $product->name : $product->get_name(),
248
			'amount' => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_pre_30() ? $product->price : $product->get_price() ),
249
		);
250
251 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...
252
			$items[] = array(
253
				'label'   => __( 'Tax', 'woocommerce-gateway-stripe' ),
254
				'amount'  => 0,
255
				'pending' => true,
256
			);
257
		}
258
259 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...
260
			$items[] = array(
261
				'label'   => __( 'Shipping', 'woocommerce-gateway-stripe' ),
262
				'amount'  => 0,
263
				'pending' => true,
264
			);
265
266
			$data['shippingOptions']  = array(
267
				'id'     => 'pending',
268
				'label'  => __( 'Pending', 'woocommerce-gateway-stripe' ),
269
				'detail' => '',
270
				'amount' => 0,
271
			);
272
		}
273
274
		$data['displayItems'] = $items;
275
		$data['total'] = array(
276
			'label'   => apply_filters( 'wc_stripe_payment_request_total_label', $this->total_label ),
277
			'amount'  => WC_Stripe_Helper::get_stripe_amount( WC_Stripe_Helper::is_pre_30() ? $product->price : $product->get_price() ),
278
			'pending' => true,
279
		);
280
281
		$data['requestShipping'] = ( wc_shipping_enabled() && $product->needs_shipping() );
282
		$data['currency']        = strtolower( get_woocommerce_currency() );
283
		$data['country_code']    = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
284
285
		return apply_filters( 'wc_stripe_payment_request_product_data', $data, $product );
286
	}
287
288
	/**
289
	 * Filters the gateway title to reflect Payment Request type
290
	 *
291
	 */
292
	public function filter_gateway_title( $title, $id ) {
293
		global $post;
294
295
		if ( ! is_object( $post ) ) {
296
			return $title;
297
		}
298
299
		if ( WC_Stripe_Helper::is_pre_30() ) {
300
			$method_title = get_post_meta( $post->ID, '_payment_method_title', true );
301
		} else {
302
			$order        = wc_get_order( $post->ID );
303
			$method_title = is_object( $order ) ? $order->get_payment_method_title() : '';
304
		}
305
306
		if ( 'stripe' === $id && ! empty( $method_title ) && 'Apple Pay (Stripe)' === $method_title ) {
307
			return $method_title;
308
		}
309
310
		if ( 'stripe' === $id && ! empty( $method_title ) && 'Chrome Payment Request (Stripe)' === $method_title ) {
311
			return $method_title;
312
		}
313
314
		return $title;
315
	}
316
317
	/**
318
	 * Removes postal code validation from WC.
319
	 *
320
	 * @since 3.1.4
321
	 * @version 4.0.0
322
	 */
323
	public function postal_code_validation( $valid, $postcode, $country ) {
324
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
325
326
		if ( ! isset( $gateways['stripe'] ) ) {
327
			return $valid;
328
		}
329
330
		$payment_request_type = isset( $_POST['payment_request_type'] ) ? wc_clean( $_POST['payment_request_type'] ) : '';
331
332
		if ( 'apple_pay' !== $payment_request_type ) {
333
			return $valid;
334
		}
335
336
		/**
337
		 * Currently Apple Pay truncates postal codes from UK and Canada to first 3 characters
338
		 * when passing it back from the shippingcontactselected object. This causes WC to invalidate
339
		 * the order and not let it go through. The remedy for now is just to remove this validation.
340
		 * Note that this only works with shipping providers that don't validate full postal codes.
341
		 */
342
		if ( 'GB' === $country || 'CA' === $country ) {
343
			return true;
344
		}
345
346
		return $valid;
347
	}
348
349
	/**
350
	 * Add needed order meta
351
	 *
352
	 * @since 4.0.0
353
	 * @version 4.0.0
354
	 * @param int $order_id
355
	 * @param array $posted_data The posted data from checkout form.
356
	 */
357
	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...
358
		if ( empty( $_POST['payment_request_type'] ) ) {
359
			return;
360
		}
361
362
		$order = wc_get_order( $order_id );
363
364
		$payment_request_type = wc_clean( $_POST['payment_request_type'] );
365
366 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...
367
			if ( WC_Stripe_Helper::is_pre_30() ) {
368
				update_post_meta( $order_id, '_payment_method_title', 'Apple Pay (Stripe)' );
369
			} else {
370
				$order->set_payment_method_title( 'Apple Pay (Stripe)' );
371
				$order->save();
372
			}
373
		}
374
375 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...
376
			if ( WC_Stripe_Helper::is_pre_30() ) {
377
				update_post_meta( $order_id, '_payment_method_title', 'Chrome Payment Request (Stripe)' );
378
			} else {
379
				$order->set_payment_method_title( 'Chrome Payment Request (Stripe)' );
380
				$order->save();
381
			}
382
		}
383
	}
384
385
	/**
386
	 * Checks to make sure product type is supported.
387
	 *
388
	 * @since 3.1.0
389
	 * @version 4.0.0
390
	 * @return array
391
	 */
392
	public function supported_product_types() {
393
		return apply_filters( 'wc_stripe_payment_request_supported_types', array(
394
			'simple',
395
			'variable',
396
			'variation',
397
			'subscription',
398
			'booking',
399
			'bundle',
400
			'composite',
401
			'mix-and-match',
402
		) );
403
	}
404
405
	/**
406
	 * Checks the cart to see if all items are allowed to used.
407
	 *
408
	 * @since 3.1.4
409
	 * @version 4.0.0
410
	 * @return bool
411
	 */
412
	public function allowed_items_in_cart() {
413
		foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
414
			$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
415
416
			if ( ! in_array( ( WC_Stripe_Helper::is_pre_30() ? $_product->product_type : $_product->get_type() ), $this->supported_product_types() ) ) {
417
				return false;
418
			}
419
420
			// Pre Orders compatbility where we don't support charge upon release.
421
			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() ) ) {
422
				return false;
423
			}
424
		}
425
426
		return true;
427
	}
428
429
	/**
430
	 * Load public scripts and styles.
431
	 *
432
	 * @since 3.1.0
433
	 * @version 4.0.0
434
	 */
435
	public function scripts() {
436
		// If keys are not set bail.
437
		if ( ! $this->are_keys_set() ) {
438
			WC_Stripe_Logger::log( 'Keys are not set correctly.' );
439
			return;
440
		}
441
442
		// If no SSL bail.
443
		if ( ! $this->testmode && ! is_ssl() ) {
444
			WC_Stripe_Logger::log( 'Stripe Payment Request live mode requires SSL.' );
445
		}
446
447
		if ( ! is_product() && ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
448
			return;
449
		}
450
451
		if ( is_product() ) {
452
			global $post;
453
454
			$product = wc_get_product( $post->ID );
455
456
			if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
457
				return;
458
			}
459
460
			if ( apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
461
				return;
462
			}
463
		}
464
465
		$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
466
467
		wp_register_script( 'stripe', 'https://js.stripe.com/v3/', '', '3.0', true );
468
		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 );
469
470
		wp_localize_script(
471
			'wc_stripe_payment_request',
472
			'wc_stripe_payment_request_params',
473
			array(
474
				'ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
475
				'stripe'   => array(
476
					'key'                => $this->publishable_key,
477
					'allow_prepaid_card' => apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no',
478
				),
479
				'nonce'    => array(
480
					'payment'                        => wp_create_nonce( 'wc-stripe-payment-request' ),
481
					'shipping'                       => wp_create_nonce( 'wc-stripe-payment-request-shipping' ),
482
					'update_shipping'                => wp_create_nonce( 'wc-stripe-update-shipping-method' ),
483
					'checkout'                       => wp_create_nonce( 'woocommerce-process_checkout' ),
484
					'add_to_cart'                    => wp_create_nonce( 'wc-stripe-add-to-cart' ),
485
					'get_selected_product_data'      => wp_create_nonce( 'wc-stripe-get-selected-product-data' ),
486
					'log_errors'                     => wp_create_nonce( 'wc-stripe-log-errors' ),
487
					'clear_cart'                     => wp_create_nonce( 'wc-stripe-clear-cart' ),
488
				),
489
				'i18n'     => array(
490
					'no_prepaid_card'  => __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' ),
491
					/* translators: Do not translate the [option] placeholder */
492
					'unknown_shipping' => __( 'Unknown shipping option "[option]".', 'woocommerce-gateway-stripe' ),
493
				),
494
				'checkout' => array(
495
					'url'            => wc_get_checkout_url(),
496
					'currency_code'  => strtolower( get_woocommerce_currency() ),
497
					'country_code'   => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
498
					'needs_shipping' => WC()->cart->needs_shipping() ? 'yes' : 'no',
499
				),
500
				'button' => array(
501
					'type'   => $this->get_button_type(),
502
					'theme'  => $this->get_button_theme(),
503
					'height' => $this->get_button_height(),
504
					'locale' => substr( get_locale(), 0, 2 ), // Default format is en_US.
505
				),
506
				'is_product_page' => is_product(),
507
				'product'         => $this->get_product_data(),
508
			)
509
		);
510
511
		wp_enqueue_script( 'wc_stripe_payment_request' );
512
	}
513
514
	/**
515
	 * Display the payment request button.
516
	 *
517
	 * @since 4.0.0
518
	 * @version 4.0.0
519
	 */
520 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...
521
		global $post;
522
523
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
524
525
		if ( ! isset( $gateways['stripe'] ) ) {
526
			return;
527
		}
528
529
		if ( ! is_cart() && ! is_checkout() && ! is_product() && ! isset( $_GET['pay_for_order'] ) ) {
530
			return;
531
		}
532
533
		if ( is_product() && apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
534
			return;
535
		}
536
537
		if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
538
			return;
539
		}
540
541
		if ( is_product() ) {
542
			$product = wc_get_product( $post->ID );
543
544
			if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
545
				return;
546
			}
547
548
			// Pre Orders charge upon release not supported.
549
			if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
550
				WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
551
				return;
552
			}
553
		} else {
554
			if ( ! $this->allowed_items_in_cart() ) {
555
				WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
556
				return;
557
			}
558
		}
559
		?>
560
		<div id="wc-stripe-payment-request-wrapper" style="clear:both;padding-top:1.5em;">
561
			<div id="wc-stripe-payment-request-button">
562
				<!-- A Stripe Element will be inserted here. -->
563
			</div>
564
		</div>
565
		<?php
566
	}
567
568
	/**
569
	 * Display payment request button separator.
570
	 *
571
	 * @since 4.0.0
572
	 * @version 4.0.0
573
	 */
574 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...
575
		global $post;
576
577
		$gateways = WC()->payment_gateways->get_available_payment_gateways();
578
579
		if ( ! isset( $gateways['stripe'] ) ) {
580
			return;
581
		}
582
583
		if ( ! is_cart() && ! is_checkout() && ! is_product() && ! isset( $_GET['pay_for_order'] ) ) {
584
			return;
585
		}
586
587
		if ( is_product() && apply_filters( 'wc_stripe_hide_payment_request_on_product_page', false, $post ) ) {
588
			return;
589
		}
590
591
		if ( is_checkout() && ! apply_filters( 'wc_stripe_show_payment_request_on_checkout', false, $post ) ) {
592
			return;
593
		}
594
595
		if ( is_product() ) {
596
			$product = wc_get_product( $post->ID );
597
598
			if ( ! is_object( $product ) || ! in_array( ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) {
599
				return;
600
			}
601
602
			// Pre Orders charge upon release not supported.
603
			if ( class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Product::product_is_charged_upon_release( $product ) ) {
604
				WC_Stripe_Logger::log( 'Pre Order charge upon release is not supported. ( Payment Request button disabled )' );
605
				return;
606
			}
607
		} else {
608
			if ( ! $this->allowed_items_in_cart() ) {
609
				WC_Stripe_Logger::log( 'Items in the cart has unsupported product type ( Payment Request button disabled )' );
610
				return;
611
			}
612
		}
613
		?>
614
		<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>
615
		<?php
616
	}
617
618
	/**
619
	 * Log errors coming from Payment Request
620
	 *
621
	 * @since 3.1.4
622
	 * @version 4.0.0
623
	 */
624
	public function ajax_log_errors() {
625
		check_ajax_referer( 'wc-stripe-log-errors', 'security' );
626
627
		$errors = wc_clean( stripslashes( $_POST['errors'] ) );
628
629
		WC_Stripe_Logger::log( $errors );
630
631
		exit;
632
	}
633
634
	/**
635
	 * Clears cart.
636
	 *
637
	 * @since 3.1.4
638
	 * @version 4.0.0
639
	 */
640
	public function ajax_clear_cart() {
641
		check_ajax_referer( 'wc-stripe-clear-cart', 'security' );
642
643
		WC()->cart->empty_cart();
644
		exit;
645
	}
646
647
	/**
648
	 * Get cart details.
649
	 */
650
	public function ajax_get_cart_details() {
651
		check_ajax_referer( 'wc-stripe-payment-request', 'security' );
652
653
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
654
			define( 'WOOCOMMERCE_CART', true );
655
		}
656
657
		WC()->cart->calculate_totals();
658
659
		$currency = get_woocommerce_currency();
660
661
		// Set mandatory payment details.
662
		$data = array(
663
			'shipping_required' => WC()->cart->needs_shipping(),
664
			'order_data'        => array(
665
				'currency'        => strtolower( $currency ),
666
				'country_code'    => substr( get_option( 'woocommerce_default_country' ), 0, 2 ),
667
			),
668
		);
669
670
		$data['order_data'] += $this->build_display_items();
671
672
		wp_send_json( $data );
673
	}
674
675
	/**
676
	 * Get shipping options.
677
	 *
678
	 * @see WC_Cart::get_shipping_packages().
679
	 * @see WC_Shipping::calculate_shipping().
680
	 * @see WC_Shipping::get_packages().
681
	 */
682
	public function ajax_get_shipping_options() {
683
		check_ajax_referer( 'wc-stripe-payment-request-shipping', 'security' );
684
685
		try {
686
			// Set the shipping package.
687
			$posted = filter_input_array( INPUT_POST, array(
688
				'country'   => FILTER_SANITIZE_STRING,
689
				'state'     => FILTER_SANITIZE_STRING,
690
				'postcode'  => FILTER_SANITIZE_STRING,
691
				'city'      => FILTER_SANITIZE_STRING,
692
				'address'   => FILTER_SANITIZE_STRING,
693
				'address_2' => FILTER_SANITIZE_STRING,
694
			) );
695
696
			$this->calculate_shipping( $posted );
697
698
			// Set the shipping options.
699
			$data     = array();
700
			$packages = WC()->shipping->get_packages();
701
702
			if ( ! empty( $packages ) && WC()->customer->has_calculated_shipping() ) {
703
				foreach ( $packages as $package_key => $package ) {
704
					if ( empty( $package['rates'] ) ) {
705
						throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) );
706
					}
707
708
					foreach ( $package['rates'] as $key => $rate ) {
709
						$data['shipping_options'][] = array(
710
							'id'       => $rate->id,
711
							'label'    => $rate->label,
712
							'detail'   => '',
713
							'amount'   => WC_Stripe_Helper::get_stripe_amount( $rate->cost ),
714
						);
715
					}
716
				}
717
			} else {
718
				throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) );
719
			}
720
721
			if ( isset( $data[0] ) ) {
722
				// Auto select the first shipping method.
723
				WC()->session->set( 'chosen_shipping_methods', array( $data[0]['id'] ) );
724
			}
725
726
			WC()->cart->calculate_totals();
727
728
			$data += $this->build_display_items();
729
			$data['result'] = 'success';
730
731
			wp_send_json( $data );
732
		} catch ( Exception $e ) {
733
			$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...
734
			$data['result'] = 'invalid_shipping_address';
735
736
			wp_send_json( $data );
737
		}
738
	}
739
740
	/**
741
	 * Update shipping method.
742
	 */
743
	public function ajax_update_shipping_method() {
744
		check_ajax_referer( 'wc-stripe-update-shipping-method', 'security' );
745
746
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
747
			define( 'WOOCOMMERCE_CART', true );
748
		}
749
750
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
751
		$shipping_method         = filter_input( INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
752
753
		if ( is_array( $shipping_method ) ) {
754
			foreach ( $shipping_method as $i => $value ) {
755
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
756
			}
757
		}
758
759
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
760
761
		WC()->cart->calculate_totals();
762
763
		$data = array();
764
		$data += $this->build_display_items();
765
		$data['result'] = 'success';
766
767
		wp_send_json( $data );
768
	}
769
770
	/**
771
	 * Gets the selected product data.
772
	 *
773
	 * @since 4.0.0
774
	 * @version 4.0.0
775
	 * @return array $data
776
	 */
777
	public function ajax_get_selected_product_data() {
778
		check_ajax_referer( 'wc-stripe-get-selected-product-data', 'security' );
779
780
		$product_id = absint( $_POST['product_id'] );
781
		$qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
782
783
		$product = wc_get_product( $product_id );
784
785
		if ( 'variable' === ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ) && isset( $_POST['attributes'] ) ) {
786
			$attributes = array_map( 'wc_clean', $_POST['attributes'] );
787
788 View Code Duplication
			if ( WC_Stripe_Helper::is_pre_30() ) {
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...
789
				$variation_id = $product->get_matching_variation( $attributes );
790
			} else {
791
				$data_store = WC_Data_Store::load( 'product' );
792
				$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
793
			}
794
795
			if ( ! empty( $variation_id ) ) {
796
				$product = wc_get_product( $variation_id );
797
			}
798
		} elseif ( 'simple' === ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ) ) {
799
			$product = wc_get_product( $product_id );
800
		}
801
802
		$total = $qty * ( WC_Stripe_Helper::is_pre_30() ? $product->price : $product->get_price() );
803
804
		$quantity_label = 1 < $qty ? ' (x' . $qty . ')' : '';
805
806
		$data  = array();
807
		$items = array();
808
809
		$items[] = array(
810
			'label'  => ( WC_Stripe_Helper::is_pre_30() ? $product->name : $product->get_name() ) . $quantity_label,
811
			'amount' => WC_Stripe_Helper::get_stripe_amount( $total ),
812
		);
813
814 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...
815
			$items[] = array(
816
				'label'   => __( 'Tax', 'woocommerce-gateway-stripe' ),
817
				'amount'  => 0,
818
				'pending' => true,
819
			);
820
		}
821
822 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...
823
			$items[] = array(
824
				'label'   => __( 'Shipping', 'woocommerce-gateway-stripe' ),
825
				'amount'  => 0,
826
				'pending' => true,
827
			);
828
829
			$data['shippingOptions']  = array(
830
				'id'     => 'pending',
831
				'label'  => __( 'Pending', 'woocommerce-gateway-stripe' ),
832
				'detail' => '',
833
				'amount' => 0,
834
			);
835
		}
836
837
		$data['displayItems'] = $items;
838
		$data['total'] = array(
839
			'label'   => $this->total_label,
840
			'amount'  => WC_Stripe_Helper::get_stripe_amount( $total ),
841
			'pending' => true,
842
		);
843
844
		$data['requestShipping'] = ( wc_shipping_enabled() && $product->needs_shipping() );
845
		$data['currency']        = strtolower( get_woocommerce_currency() );
846
		$data['country_code']    = substr( get_option( 'woocommerce_default_country' ), 0, 2 );
847
848
		wp_send_json( $data );
849
	}
850
851
	/**
852
	 * Adds the current product to the cart. Used on product detail page.
853
	 *
854
	 * @since 4.0.0
855
	 * @version 4.0.0
856
	 * @return array $data
857
	 */
858
	public function ajax_add_to_cart() {
859
		check_ajax_referer( 'wc-stripe-add-to-cart', 'security' );
860
861
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
862
			define( 'WOOCOMMERCE_CART', true );
863
		}
864
865
		WC()->shipping->reset_shipping();
866
867
		$product_id = absint( $_POST['product_id'] );
868
		$qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
869
870
		$product = wc_get_product( $product_id );
871
872
		// First empty the cart to prevent wrong calculation.
873
		WC()->cart->empty_cart();
874
875
		if ( 'variable' === ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ) && isset( $_POST['attributes'] ) ) {
876
			$attributes = array_map( 'wc_clean', $_POST['attributes'] );
877
878 View Code Duplication
			if ( WC_Stripe_Helper::is_pre_30() ) {
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...
879
				$variation_id = $product->get_matching_variation( $attributes );
880
			} else {
881
				$data_store = WC_Data_Store::load( 'product' );
882
				$variation_id = $data_store->find_matching_product_variation( $product, $attributes );
883
			}
884
885
			WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
886
		}
887
888
		if ( 'simple' === ( WC_Stripe_Helper::is_pre_30() ? $product->product_type : $product->get_type() ) ) {
889
			WC()->cart->add_to_cart( $product->get_id(), $qty );
890
		}
891
892
		WC()->cart->calculate_totals();
893
894
		$data = array();
895
		$data += $this->build_display_items();
896
		$data['result'] = 'success';
897
898
		wp_send_json( $data );
899
	}
900
901
	/**
902
	 * Normalizes the state/county field because in some
903
	 * cases, the state/county field is formatted differently from
904
	 * what WC is expecting and throws an error. An example
905
	 * for Ireland the county dropdown in Chrome shows "Co. Clare" format
906
	 *
907
	 * @since 4.0.0
908
	 * @version 4.0.0
909
	 */
910
	public function normalize_state() {
911
		$billing_country  = ! empty( $_POST['billing_country'] ) ? wc_clean( $_POST['billing_country'] ) : '';
912
		$shipping_country = ! empty( $_POST['shipping_country'] ) ? wc_clean( $_POST['shipping_country'] ) : '';
913
		$billing_state    = ! empty( $_POST['billing_state'] ) ? wc_clean( $_POST['billing_state'] ) : '';
914
		$shipping_state   = ! empty( $_POST['shipping_state'] ) ? wc_clean( $_POST['shipping_state'] ) : '';
915
916 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...
917
			$valid_states = WC()->countries->get_states( $billing_country );
918
919
			// Valid states found for country.
920
			if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) {
921
				foreach ( $valid_states as $state_abbr => $state ) {
922
					if ( preg_match( '/' . preg_quote( $state ) . '/i', $billing_state ) ) {
923
						$_POST['billing_state'] = $state_abbr;
924
					}
925
				}
926
			}
927
		}
928
929 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...
930
			$valid_states = WC()->countries->get_states( $shipping_country );
931
932
			// Valid states found for country.
933
			if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) {
934
				foreach ( $valid_states as $state_abbr => $state ) {
935
					if ( preg_match( '/' . preg_quote( $state ) . '/i', $shipping_state ) ) {
936
						$_POST['shipping_state'] = $state_abbr;
937
					}
938
				}
939
			}
940
		}
941
	}
942
943
	/**
944
	 * Create order. Security is handled by WC.
945
	 *
946
	 * @since 3.1.0
947
	 * @version 4.0.0
948
	 */
949
	public function ajax_create_order() {
950
		if ( WC()->cart->is_empty() ) {
951
			wp_send_json_error( __( 'Empty cart', 'woocommerce-gateway-stripe' ) );
952
		}
953
954
		if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
955
			define( 'WOOCOMMERCE_CHECKOUT', true );
956
		}
957
958
		$this->normalize_state();
959
960
		WC()->checkout()->process_checkout();
961
962
		die( 0 );
963
	}
964
965
	/**
966
	 * Calculate and set shipping method.
967
	 *
968
	 * @since 3.1.0
969
	 * @version 4.0.0
970
	 * @param array $address
971
	 */
972
	protected function calculate_shipping( $address = array() ) {
973
		global $states;
974
975
		$country   = $address['country'];
976
		$state     = $address['state'];
977
		$postcode  = $address['postcode'];
978
		$city      = $address['city'];
979
		$address_1 = $address['address'];
980
		$address_2 = $address['address_2'];
981
982
		$country_class = new WC_Countries();
983
		$country_class->load_country_states();
984
985
		/**
986
		 * In some versions of Chrome, state can be a full name. So we need
987
		 * to convert that to abbreviation as WC is expecting that.
988
		 */
989
		if ( 2 < strlen( $state ) ) {
990
			$state = array_search( ucfirst( strtolower( $state ) ), $states[ $country ] );
991
		}
992
993
		WC()->shipping->reset_shipping();
994
995
		if ( $postcode && WC_Validation::is_postcode( $postcode, $country ) ) {
996
			$postcode = wc_format_postcode( $postcode, $country );
997
		}
998
999
		if ( $country ) {
1000
			WC()->customer->set_location( $country, $state, $postcode, $city );
1001
			WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
1002
		} else {
1003
			WC_Stripe_Helper::is_pre_30() ? WC()->customer->set_to_base() : WC()->customer->set_billing_address_to_base();
1004
			WC_Stripe_Helper::is_pre_30() ? WC()->customer->set_shipping_to_base() : WC()->customer->set_shipping_address_to_base();
1005
		}
1006
1007
		if ( WC_Stripe_Helper::is_pre_30() ) {
1008
			WC()->customer->calculated_shipping( true );
1009
		} else {
1010
			WC()->customer->set_calculated_shipping( true );
1011
			WC()->customer->save();
1012
		}
1013
1014
		$packages = array();
1015
1016
		$packages[0]['contents']                 = WC()->cart->get_cart();
1017
		$packages[0]['contents_cost']            = 0;
1018
		$packages[0]['applied_coupons']          = WC()->cart->applied_coupons;
1019
		$packages[0]['user']['ID']               = get_current_user_id();
1020
		$packages[0]['destination']['country']   = $country;
1021
		$packages[0]['destination']['state']     = $state;
1022
		$packages[0]['destination']['postcode']  = $postcode;
1023
		$packages[0]['destination']['city']      = $city;
1024
		$packages[0]['destination']['address']   = $address_1;
1025
		$packages[0]['destination']['address_2'] = $address_2;
1026
1027
		foreach ( WC()->cart->get_cart() as $item ) {
1028
			if ( $item['data']->needs_shipping() ) {
1029
				if ( isset( $item['line_total'] ) ) {
1030
					$packages[0]['contents_cost'] += $item['line_total'];
1031
				}
1032
			}
1033
		}
1034
1035
		$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages );
1036
1037
		WC()->shipping->calculate_shipping( $packages );
1038
	}
1039
1040
	/**
1041
	 * Builds the shippings methods to pass to Payment Request
1042
	 *
1043
	 * @since 3.1.0
1044
	 * @version 4.0.0
1045
	 */
1046
	protected function build_shipping_methods( $shipping_methods ) {
1047
		if ( empty( $shipping_methods ) ) {
1048
			return array();
1049
		}
1050
1051
		$shipping = array();
1052
1053
		foreach ( $shipping_methods as $method ) {
1054
			$shipping[] = array(
1055
				'id'         => $method['id'],
1056
				'label'      => $method['label'],
1057
				'detail'     => '',
1058
				'amount'     => WC_Stripe_Helper::get_stripe_amount( $method['amount']['value'] ),
1059
			);
1060
		}
1061
1062
		return $shipping;
1063
	}
1064
1065
	/**
1066
	 * Builds the line items to pass to Payment Request
1067
	 *
1068
	 * @since 3.1.0
1069
	 * @version 4.0.0
1070
	 */
1071
	protected function build_display_items() {
1072
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
1073
			define( 'WOOCOMMERCE_CART', true );
1074
		}
1075
1076
		$items     = array();
1077
		$subtotal  = 0;
1078
		$discounts = 0;
1079
1080
		// Default show only subtotal instead of itemization.
1081
		if ( ! apply_filters( 'wc_stripe_payment_request_hide_itemization', true ) ) {
1082
			foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
1083
				$amount         = $cart_item['line_subtotal'];
1084
				$subtotal       += $cart_item['line_subtotal'];
1085
				$quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
1086
1087
				$product_name = WC_Stripe_Helper::is_pre_30() ? $cart_item['data']->post->post_title : $cart_item['data']->get_name();
1088
1089
				$item = array(
1090
					'label'  => $product_name . $quantity_label,
1091
					'amount' => WC_Stripe_Helper::get_stripe_amount( $amount ),
1092
				);
1093
1094
				$items[] = $item;
1095
			}
1096
		}
1097
1098
		if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
1099
			$discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
1100
		} else {
1101
			$applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );
1102
1103
			foreach ( $applied_coupons as $amount ) {
1104
				$discounts += (float) $amount;
1105
			}
1106
		}
1107
1108
		$discounts   = wc_format_decimal( $discounts, WC()->cart->dp );
1109
		$tax         = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
1110
		$shipping    = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
1111
		$items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
1112
		$order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( false );
1113
1114
		if ( wc_tax_enabled() ) {
1115
			$items[] = array(
1116
				'label'  => esc_html( __( 'Tax', 'woocommerce-gateway-stripe' ) ),
1117
				'amount' => WC_Stripe_Helper::get_stripe_amount( $tax ),
1118
			);
1119
		}
1120
1121 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...
1122
			$items[] = array(
1123
				'label'  => esc_html( __( 'Shipping', 'woocommerce-gateway-stripe' ) ),
1124
				'amount' => WC_Stripe_Helper::get_stripe_amount( $shipping ),
1125
			);
1126
		}
1127
1128 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...
1129
			$items[] = array(
1130
				'label'  => esc_html( __( 'Discount', 'woocommerce-gateway-stripe' ) ),
1131
				'amount' => WC_Stripe_Helper::get_stripe_amount( $discounts ),
1132
			);
1133
		}
1134
1135
		if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
1136
			$cart_fees = WC()->cart->fees;
1137
		} else {
1138
			$cart_fees = WC()->cart->get_fees();
1139
		}
1140
1141
		// Include fees and taxes as display items.
1142
		foreach ( $cart_fees as $key => $fee ) {
1143
			$items[] = array(
1144
				'label'  => $fee->name,
1145
				'amount' => WC_Stripe_Helper::get_stripe_amount( $fee->amount ),
1146
			);
1147
		}
1148
1149
		return array(
1150
			'displayItems' => $items,
1151
			'total'      => array(
1152
				'label'   => $this->total_label,
1153
				'amount'  => max( 0, apply_filters( 'woocommerce_stripe_calculated_total', WC_Stripe_Helper::get_stripe_amount( $order_total ), $order_total, WC()->cart ) ),
1154
				'pending' => false,
1155
			),
1156
		);
1157
	}
1158
}
1159
1160
new WC_Stripe_Payment_Request();
1161