Completed
Push — master ( e1d1f5...7977ec )
by Roy
02:32
created

WC_Stripe_Payment_Request::calculate_shipping()   C

Complexity

Conditions 9
Paths 64

Size

Total Lines 67
Code Lines 43

Duplication

Lines 20
Ratio 29.85 %

Importance

Changes 0
Metric Value
dl 20
loc 67
rs 6.3448
c 0
b 0
f 0
cc 9
eloc 43
nc 64
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Stripe Payment Request API
4
 *
5
 * @package WooCommerce_Stripe/Classes/Payment_Request
6
 * @since   3.1.0
7
 * @version 3.1.0
8
 */
9
10
if ( ! defined( 'ABSPATH' ) ) {
11
	exit;
12
}
13
14
/**
15
 * WC_Stripe_Payment_Request class.
16
 */
17
class WC_Stripe_Payment_Request {
18
19
	/**
20
	 * Initialize class actions.
21
	 */
22
	public function __construct() {
23
		add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
24
25
		add_action( 'wc_ajax_wc_stripe_get_cart_details', array( $this, 'ajax_get_cart_details' ) );
26
		add_action( 'wc_ajax_wc_stripe_get_shipping_options', array( $this, 'ajax_get_shipping_options' ) );
27
		add_action( 'wc_ajax_wc_stripe_update_shipping_method', array( $this, 'ajax_update_shipping_method' ) );
28
		add_action( 'wc_ajax_wc_stripe_create_order', array( $this, 'ajax_create_order' ) );
29
	}
30
31
	/**
32
	 * Check if Stripe gateway is enabled.
33
	 *
34
	 * @return bool
35
	 */
36
	protected function is_activated() {
37
		$options             = get_option( 'woocommerce_stripe_settings', array() );
38
		$enabled             = isset( $options['enabled'] ) && 'yes' === $options['enabled'];
39
		$stripe_checkout     = isset( $options['stripe_checkout'] ) && 'yes' !== $options['stripe_checkout'];
40
		$request_payment_api = isset( $options['request_payment_api'] ) && 'yes' === $options['request_payment_api'];
41
42
		return $enabled && $stripe_checkout && $request_payment_api && is_ssl();
43
	}
44
45
	/**
46
	 * Get publishable key.
47
	 *
48
	 * @return string
49
	 */
50
	protected function get_publishable_key() {
51
		$options = get_option( 'woocommerce_stripe_settings', array() );
52
53
		if ( empty( $options ) ) {
54
			return '';
55
		}
56
57
		return 'yes' === $options['testmode'] ? $options['test_publishable_key'] : $options['publishable_key'];
58
	}
59
60
	/**
61
	 * Load public scripts.
62
	 */
63
	public function scripts() {
64
		// Load PaymentRequest only on cart for now.
65
		if ( ! is_cart() ) {
66
			return;
67
		}
68
69
		if ( ! $this->is_activated() ) {
70
			return;
71
		}
72
73
		$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
74
75
		wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true );
76
		wp_enqueue_script( 'google-payment-request-shim', 'https://storage.googleapis.com/prshim/v1/payment-shim.js', '', '1.0', false );
77
		wp_enqueue_script( 'wc-stripe-payment-request', plugins_url( 'assets/js/payment-request' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'jquery', 'stripe' ), WC_STRIPE_VERSION, true );
78
79
		wp_localize_script(
80
			'wc-stripe-payment-request',
81
			'wcStripePaymentRequestParams',
82
			array(
83
				'ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
84
				'stripe'   => array(
85
					'key'                => $this->get_publishable_key(),
86
					'allow_prepaid_card' => apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no',
87
				),
88
				'nonce'    => array(
89
					'payment'         => wp_create_nonce( 'wc-stripe-payment-request' ),
90
					'shipping'        => wp_create_nonce( 'wc-stripe-payment-request-shipping' ),
91
					'update_shipping' => wp_create_nonce( 'wc-stripe-update-shipping-method' ),
92
					'checkout'        => wp_create_nonce( 'woocommerce-process_checkout' ),
93
				),
94
				'i18n'     => array(
95
					'no_prepaid_card'  => __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' ),
96
					/* translators: Do not translate the [option] placeholder */
97
					'unknown_shipping' => __( 'Unknown shipping option "[option]".', 'woocommerce-gateway-stripe' ),
98
				),
99
			)
100
		);
101
	}
102
103
	/**
104
	 * Get cart details.
105
	 */
106
	public function ajax_get_cart_details() {
107
		check_ajax_referer( 'wc-stripe-payment-request', 'security' );
108
109
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
110
			define( 'WOOCOMMERCE_CART', true );
111
		}
112
113
		WC()->cart->calculate_totals();
114
115
		$currency = get_woocommerce_currency();
116
117
		// Set mandatory payment details.
118
		$data = array(
119
			'shipping_required' => WC()->cart->needs_shipping(),
120
			'order_data'        => array(
121
				'total' => array(
122
					'label'  => __( 'Total', 'woocommerce-gateway-stripe' ),
123
					'amount' => array(
124
						'value'    => max( 0, apply_filters( 'woocommerce_calculated_total', round( WC()->cart->cart_contents_total + WC()->cart->fee_total + WC()->cart->tax_total, WC()->cart->dp ), WC()->cart ) ),
125
						'currency' => $currency,
126
					),
127
				),
128
				// Include line items such as subtotal, fees and taxes. No shipping option is provided here because it is not chosen yet.
129
				'displayItems' => $this->compute_display_items( null ),
130
			),
131
		);
132
133
		wp_send_json( $data );
134
	}
135
136
	/**
137
	 * Calculate and set shipping method.
138
	 *
139
	 * @since 3.1.0
140
	 * @version 3.2.0
141
	 * @param array $address
142
	 */
143
	public function calculate_shipping( $address = array() ) {
144
		global $states;
145
146
		$country   = $address['country'];
147
		$state     = $address['state'];
148
		$postcode  = $address['postcode'];
149
		$city      = $address['city'];
150
		$address_1 = $address['address'];
151
		$address_2 = $address['address_2'];
152
153
		$country_class = new WC_Countries();
154
		$country_class->load_country_states();
155
156
		/**
157
		 * In some versions of Chrome, state can be a full name. So we need
158
		 * to convert that to abbreviation as WC is expecting that.
159
		 */
160
		if ( 2 < strlen( $state ) ) {
161
			$state = array_search( ucfirst( $state ), $states[ $country ] );
162
		}
163
164
		WC()->shipping->reset_shipping();
165
166
		if ( $postcode && WC_Validation::is_postcode( $postcode, $country ) ) {
167
			$postcode = wc_format_postcode( $postcode, $country );
168
		}
169
170 View Code Duplication
		if ( $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...
171
			WC()->customer->set_location( $country, $state, $postcode, $city );
172
			WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
173
		} else {
174
			WC()->customer->set_to_base();
175
			WC()->customer->set_shipping_to_base();
176
		}
177
178 View Code Duplication
		if ( version_compare( WC_VERSION, '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...
179
			WC()->customer->calculated_shipping( true );
180
		} else {
181
			WC()->customer->set_calculated_shipping( true );
182
			WC()->customer->save();
183
		}
184
185
		$packages = array();
186
187
		$packages[0]['contents']                 = WC()->cart->get_cart();
188
		$packages[0]['contents_cost']            = 0;
189
		$packages[0]['applied_coupons']          = WC()->cart->applied_coupons;
190
		$packages[0]['user']['ID']               = get_current_user_id();
191
		$packages[0]['destination']['country']   = $country;
192
		$packages[0]['destination']['state']     = $state;
193
		$packages[0]['destination']['postcode']  = $postcode;
194
		$packages[0]['destination']['city']      = $city;
195
		$packages[0]['destination']['address']   = $address_1;
196
		$packages[0]['destination']['address_2'] = $address_2;
197
198 View Code Duplication
		foreach ( WC()->cart->get_cart() as $item ) {
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...
199
			if ( $item['data']->needs_shipping() ) {
200
				if ( isset( $item['line_total'] ) ) {
201
					$packages[0]['contents_cost'] += $item['line_total'];
202
				}
203
			}
204
		}
205
206
		$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages );
207
208
		WC()->shipping->calculate_shipping( $packages );
209
	}
210
211
	/**
212
	 * Get shipping options.
213
	 *
214
	 * @see WC_Cart::get_shipping_packages().
215
	 * @see WC_Shipping::calculate_shipping().
216
	 * @see WC_Shipping::get_packages().
217
	 */
218
	public function ajax_get_shipping_options() {
219
		check_ajax_referer( 'wc-stripe-payment-request-shipping', 'security' );
220
221
		// Set the shipping package.
222
		$posted   = filter_input_array( INPUT_POST, array(
223
			'country'   => FILTER_SANITIZE_STRING,
224
			'state'     => FILTER_SANITIZE_STRING,
225
			'postcode'  => FILTER_SANITIZE_STRING,
226
			'city'      => FILTER_SANITIZE_STRING,
227
			'address'   => FILTER_SANITIZE_STRING,
228
			'address_2' => FILTER_SANITIZE_STRING,
229
		) );
230
231
		$this->calculate_shipping( $posted );
232
233
		// Set the shipping options.
234
		$currency = get_woocommerce_currency();
235
		$data     = array();
236
237
		$packages = WC()->shipping->get_packages();
238
239
		if ( ! empty( $packages ) && WC()->customer->has_calculated_shipping() ) {
240
			foreach ( $packages as $package_key => $package ) {
241
				if ( empty( $package['rates'] ) ) {
242
					break;
243
				}
244
245 View Code Duplication
				foreach ( $package['rates'] as $key => $rate ) {
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...
246
					$data[] = array(
247
						'id'       => $rate->id,
248
						'label'    => $rate->label,
249
						'amount'   => array(
250
							'currency' => $currency,
251
							'value'    => $rate->cost,
252
						),
253
						'selected' => false,
254
					);
255
				}
256
			}
257
		}
258
259
		// Auto select when have only one shipping method available.
260
		if ( 1 === count( $data ) ) {
261
			$data[0]['selected'] = true;
262
		}
263
264
		wp_send_json( $data );
265
	}
266
267
	/**
268
	 * Update shipping method.
269
	 */
270
	public function ajax_update_shipping_method() {
271
		check_ajax_referer( 'wc-stripe-update-shipping-method', 'security' );
272
273
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
274
			define( 'WOOCOMMERCE_CART', true );
275
		}
276
277
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
278
		$shipping_method         = filter_input( INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
279
280
		if ( is_array( $shipping_method ) ) {
281
			foreach ( $shipping_method as $i => $value ) {
282
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
283
			}
284
		}
285
286
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
287
288
		WC()->cart->calculate_totals();
289
290
		// Send back the new cart total and line items to be displayed, such as subtotal, shipping rate(s), fees and taxes.
291
		$data      = array(
292
			'total' => WC()->cart->total,
293
			'items' => $this->compute_display_items( $shipping_method[0] ),
294
		);
295
296
		wp_send_json( $data );
297
	}
298
299
	/**
300
	 * Create order.
301
	 */
302
	public function ajax_create_order() {
303
		if ( WC()->cart->is_empty() ) {
304
			wp_send_json_error( __( 'Empty cart', 'woocommerce-gateway-stripe' ) );
305
		}
306
307
		if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
308
			define( 'WOOCOMMERCE_CHECKOUT', true );
309
		}
310
		
311
		$_POST['terms'] = 1;
312
		$_POST['ship_to_different_address'] = 1;
313
314
		WC()->checkout()->process_checkout();
315
316
		die( 0 );
317
	}
318
319
	/**
320
	 * Compute display items to be included in the 'displayItems' key of the PaymentDetails.
321
	 *
322
	 * @param string shipping_method_id If shipping method ID is provided, will include display items about shipping.
323
	 */
324
	protected function compute_display_items( $shipping_method_id ) {
325
		$currency = get_woocommerce_currency();
326
		$items = array(
327
			// Subtotal excluding tax, because taxes is a separate item, below.
328
			array(
329
				'label' => __( 'Subtotal', 'woocommerce-gateway-stripe' ),
330
				'amount' => array(
331
					'value'    => max( 0, round( WC()->cart->subtotal_ex_tax, WC()->cart->dp ) ),
332
					'currency' => $currency,
333
				),
334
			),
335
		);
336
		// If a chosen shipping option was provided, add line item(s) for it and include the shipping tax.
337
		$tax_total = max( 0, round( WC()->cart->tax_total, WC()->cart->dp ) );
338
		if ( $shipping_method_id ) {
339
			$tax_total = max( 0, round( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp ) );
340
			// Look through the package rates for $shipping_method_id, and when found, add a line item.
341
			foreach ( WC()->shipping->get_packages() as $package_key => $package ) {
342
				foreach ( $package['rates'] as $key => $rate ) {
343
					if ( $rate->id  == $shipping_method_id ) {
344
						$items[] = array(
345
							'label' => $rate->label,
346
							'amount' => array(
347
								'value' => $rate->cost,
348
								'currency' => $currency,
349
							),
350
						);
351
						break;
352
					}
353
				}
354
			}
355
		}
356
		// Include fees and taxes as display items.
357
		foreach ( WC()->cart->fees as $key => $fee ) {
358
			$items[] = array(
359
				'label'  => $fee->name,
360
				'amount' => array(
361
					'currency' => $currency,
362
					'value'    => $fee->amount,
363
				),
364
			);
365
		}
366
		// The tax total may include the shipping taxes if a shipping option is provided.
367
		if ( 0 < $tax_total ) {
368
			$items[] = array(
369
				'label'  => __( 'Tax', 'woocommerce-gateway-stripe' ),
370
				'amount' => array(
371
					'currency' => $currency,
372
					'value'    => $tax_total,
373
				),
374
			);
375
		}
376
		return $items;
377
	}
378
}
379
380
new WC_Stripe_Payment_Request();
381