Completed
Push — master ( a3a855...7eee7c )
by Roy
02:21
created

WC_Stripe_Payment_Request::calculate_shipping()   B

Complexity

Conditions 8
Paths 32

Size

Total Lines 54
Code Lines 38

Duplication

Lines 14
Ratio 25.93 %

Importance

Changes 0
Metric Value
dl 14
loc 54
rs 7.4119
c 0
b 0
f 0
cc 8
eloc 38
nc 32
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.1.0
141
	 * @param array $address
142
	 */
143
	public function calculate_shipping( $address = array() ) {
144
		$country   = $address['country'];
145
		$state     = $address['state'];
146
		$postcode  = $address['postcode'];
147
		$city      = $address['city'];
148
		$address_1 = $address['address'];
149
		$address_2 = $address['address_2'];
150
151
		WC()->shipping->reset_shipping();
152
153
		if ( $postcode && WC_Validation::is_postcode( $postcode, $country ) ) {
154
			$postcode = wc_format_postcode( $postcode, $country );
155
		}
156
157 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...
158
			WC()->customer->set_location( $country, $state, $postcode, $city );
159
			WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
160
		} else {
161
			WC()->customer->set_to_base();
162
			WC()->customer->set_shipping_to_base();
163
		}
164
165
		if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
166
			WC()->customer->calculated_shipping( true );
167
		} else {
168
			WC()->customer->set_calculated_shipping( true );
169
			WC()->customer->save();
170
		}
171
172
		$packages = array();
173
174
		$packages[0]['contents']                 = WC()->cart->get_cart();
175
		$packages[0]['contents_cost']            = 0;
176
		$packages[0]['applied_coupons']          = WC()->cart->applied_coupons;
177
		$packages[0]['user']['ID']               = get_current_user_id();
178
		$packages[0]['destination']['country']   = $country;
179
		$packages[0]['destination']['state']     = $state;
180
		$packages[0]['destination']['postcode']  = $postcode;
181
		$packages[0]['destination']['city']      = $city;
182
		$packages[0]['destination']['address']   = $address_1;
183
		$packages[0]['destination']['address_2'] = $address_2;
184
185 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...
186
			if ( $item['data']->needs_shipping() ) {
187
				if ( isset( $item['line_total'] ) ) {
188
					$packages[0]['contents_cost'] += $item['line_total'];
189
				}
190
			}
191
		}
192
193
		$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages );
194
195
		WC()->shipping->calculate_shipping( $packages );
196
	}
197
198
	/**
199
	 * Get shipping options.
200
	 *
201
	 * @see WC_Cart::get_shipping_packages().
202
	 * @see WC_Shipping::calculate_shipping().
203
	 * @see WC_Shipping::get_packages().
204
	 */
205
	public function ajax_get_shipping_options() {
206
		check_ajax_referer( 'wc-stripe-payment-request-shipping', 'security' );
207
208
		// Set the shipping package.
209
		$posted   = filter_input_array( INPUT_POST, array(
210
			'country'   => FILTER_SANITIZE_STRING,
211
			'state'     => FILTER_SANITIZE_STRING,
212
			'postcode'  => FILTER_SANITIZE_STRING,
213
			'city'      => FILTER_SANITIZE_STRING,
214
			'address'   => FILTER_SANITIZE_STRING,
215
			'address_2' => FILTER_SANITIZE_STRING,
216
		) );
217
218
		$this->calculate_shipping( $posted );
219
220
		// Set the shipping options.
221
		$currency = get_woocommerce_currency();
222
		$data     = array();
223
224
		$packages = WC()->shipping->get_packages();
225
226
		if ( ! empty( $packages ) && WC()->customer->has_calculated_shipping() ) {
227
			foreach ( $packages as $package_key => $package ) {
228
				if ( empty( $package['rates'] ) ) {
229
					break;
230
				}
231
232 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...
233
					$data[] = array(
234
						'id'       => $rate->id,
235
						'label'    => $rate->label,
236
						'amount'   => array(
237
							'currency' => $currency,
238
							'value'    => $rate->cost,
239
						),
240
						'selected' => false,
241
					);
242
				}
243
			}
244
		}
245
246
		// Auto select when have only one shipping method available.
247
		if ( 1 === count( $data ) ) {
248
			$data[0]['selected'] = true;
249
		}
250
251
		wp_send_json( $data );
252
	}
253
254
	/**
255
	 * Update shipping method.
256
	 */
257
	public function ajax_update_shipping_method() {
258
		check_ajax_referer( 'wc-stripe-update-shipping-method', 'security' );
259
260
		if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
261
			define( 'WOOCOMMERCE_CART', true );
262
		}
263
264
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
265
		$shipping_method         = filter_input( INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
266
267
		if ( is_array( $shipping_method ) ) {
268
			foreach ( $shipping_method as $i => $value ) {
269
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
270
			}
271
		}
272
273
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
274
275
		WC()->cart->calculate_totals();
276
277
		// Send back the new cart total and line items to be displayed, such as subtotal, shipping rate(s), fees and taxes.
278
		$data      = array(
279
			'total' => WC()->cart->total,
280
			'items' => $this->compute_display_items( $shipping_method[0] ),
281
		);
282
283
		wp_send_json( $data );
284
	}
285
286
	/**
287
	 * Create order.
288
	 */
289
	public function ajax_create_order() {
290
		if ( WC()->cart->is_empty() ) {
291
			wp_send_json_error( __( 'Empty cart', 'woocommerce-gateway-stripe' ) );
292
		}
293
294
		if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
295
			define( 'WOOCOMMERCE_CHECKOUT', true );
296
		}
297
		
298
		$_POST['terms'] = 1;
299
300
		WC()->checkout()->process_checkout();
301
302
		die( 0 );
303
	}
304
305
	/**
306
	 * Compute display items to be included in the 'displayItems' key of the PaymentDetails.
307
	 *
308
	 * @param string shipping_method_id If shipping method ID is provided, will include display items about shipping.
309
	 */
310
	protected function compute_display_items( $shipping_method_id ) {
311
		$currency = get_woocommerce_currency();
312
		$items = array(
313
			// Subtotal excluding tax, because taxes is a separate item, below.
314
			array(
315
				'label' => __( 'Subtotal', 'woocommerce-gateway-stripe' ),
316
				'amount' => array(
317
					'value'    => max( 0, round( WC()->cart->subtotal_ex_tax, WC()->cart->dp ) ),
318
					'currency' => $currency,
319
				),
320
			),
321
		);
322
		// If a chosen shipping option was provided, add line item(s) for it and include the shipping tax.
323
		$tax_total = max( 0, round( WC()->cart->tax_total, WC()->cart->dp ) );
324
		if ( $shipping_method_id ) {
325
			$tax_total = max( 0, round( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp ) );
326
			// Look through the package rates for $shipping_method_id, and when found, add a line item.
327
			foreach ( WC()->shipping->get_packages() as $package_key => $package ) {
328
				foreach ( $package['rates'] as $key => $rate ) {
329
					if ( $rate->id  == $shipping_method_id ) {
330
						$items[] = array(
331
							'label' => $rate->label,
332
							'amount' => array(
333
								'value' => $rate->cost,
334
								'currency' => $currency,
335
							),
336
						);
337
						break;
338
					}
339
				}
340
			}
341
		}
342
		// Include fees and taxes as display items.
343 View Code Duplication
		foreach ( WC()->cart->fees as $key => $fee ) {
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...
344
			$items[] = array(
345
				'label'  => $fee->name,
346
				'amount' => array(
347
					'currency' => $currency,
348
					'value'    => $fee->amount,
349
				),
350
			);
351
		}
352
		// The tax total may include the shipping taxes if a shipping option is provided.
353 View Code Duplication
		if ( 0 < $tax_total ) {
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...
354
			$items[] = array(
355
				'label'  => __( 'Tax', 'woocommerce-gateway-stripe' ),
356
				'amount' => array(
357
					'currency' => $currency,
358
					'value'    => $tax_total,
359
				),
360
			);
361
		}
362
		return $items;
363
	}
364
}
365
366
new WC_Stripe_Payment_Request();
367