WC_Gateway_Paypal_Request   F
last analyzed

Complexity

Total Complexity 61

Size/Duplication

Total Lines 565
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 565
ccs 0
cts 313
cp 0
rs 3.52
c 0
b 0
f 0
wmc 61
lcom 1
cbo 5

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A get_request_url() 0 25 2
A get_transaction_args() 0 37 2
A fix_request_length() 0 18 2
A get_paypal_args() 0 20 4
A get_phone_number_args() 0 25 4
A get_shipping_args() 0 21 4
A get_shipping_cost_line_item() 0 19 6
A get_line_item_args_single_item() 0 9 2
A get_line_item_args() 0 28 3
A get_order_item_names() 0 27 3
A get_order_item_name() 0 21 2
A get_line_items() 0 3 1
A delete_line_items() 0 3 1
A line_items_valid() 0 21 5
A prepare_line_items() 0 16 4
A add_line_item() 0 22 2
A get_paypal_state() 0 13 3
A currency_has_decimals() 0 7 2
A round() 0 9 2
A number_format() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like WC_Gateway_Paypal_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_Gateway_Paypal_Request, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class WC_Gateway_Paypal_Request file.
4
 *
5
 * @package WooCommerce\Gateways
6
 */
7
8
if ( ! defined( 'ABSPATH' ) ) {
9
	exit;
10
}
11
12
/**
13
 * Generates requests to send to PayPal.
14
 */
15
class WC_Gateway_Paypal_Request {
16
17
	/**
18
	 * Stores line items to send to PayPal.
19
	 *
20
	 * @var array
21
	 */
22
	protected $line_items = array();
23
24
	/**
25
	 * Pointer to gateway making the request.
26
	 *
27
	 * @var WC_Gateway_Paypal
28
	 */
29
	protected $gateway;
30
31
	/**
32
	 * Endpoint for requests from PayPal.
33
	 *
34
	 * @var string
35
	 */
36
	protected $notify_url;
37
38
	/**
39
	 * Endpoint for requests to PayPal.
40
	 *
41
	 * @var string
42
	 */
43
	protected $endpoint;
44
45
46
	/**
47
	 * Constructor.
48
	 *
49
	 * @param WC_Gateway_Paypal $gateway Paypal gateway object.
50
	 */
51
	public function __construct( $gateway ) {
52
		$this->gateway    = $gateway;
53
		$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
54
	}
55
56
	/**
57
	 * Get the PayPal request URL for an order.
58
	 *
59
	 * @param  WC_Order $order Order object.
60
	 * @param  bool     $sandbox Whether to use sandbox mode or not.
61
	 * @return string
62
	 */
63
	public function get_request_url( $order, $sandbox = false ) {
64
		$this->endpoint    = $sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&' : 'https://www.paypal.com/cgi-bin/webscr?';
65
		$paypal_args       = $this->get_paypal_args( $order );
66
		$paypal_args['bn'] = 'WooThemes_Cart'; // Append WooCommerce PayPal Partner Attribution ID. This should not be overridden for this gateway.
67
68
		// Mask (remove) PII from the logs.
69
		$mask = array(
70
			'first_name'    => '***',
71
			'last_name'     => '***',
72
			'address1'      => '***',
73
			'address2'      => '***',
74
			'city'          => '***',
75
			'state'         => '***',
76
			'zip'           => '***',
77
			'country'       => '***',
78
			'email'         => '***@***',
79
			'night_phone_a' => '***',
80
			'night_phone_b' => '***',
81
			'night_phone_c' => '***',
82
		);
83
84
		WC_Gateway_Paypal::log( 'PayPal Request Args for order ' . $order->get_order_number() . ': ' . wc_print_r( array_merge( $paypal_args, array_intersect_key( $mask, $paypal_args ) ), true ) );
85
86
		return $this->endpoint . http_build_query( $paypal_args, '', '&' );
87
	}
88
89
	/**
90
	 * Limit length of an arg.
91
	 *
92
	 * @param  string  $string Argument to limit.
93
	 * @param  integer $limit Limit size in characters.
94
	 * @return string
95
	 */
96
	protected function limit_length( $string, $limit = 127 ) {
97
		$str_limit = $limit - 3;
98
		if ( function_exists( 'mb_strimwidth' ) ) {
99
			if ( mb_strlen( $string ) > $limit ) {
100
				$string = mb_strimwidth( $string, 0, $str_limit ) . '...';
101
			}
102
		} else {
103
			if ( strlen( $string ) > $limit ) {
104
				$string = substr( $string, 0, $str_limit ) . '...';
105
			}
106
		}
107
		return $string;
108
	}
109
110
	/**
111
	 * Get transaction args for paypal request, except for line item args.
112
	 *
113
	 * @param WC_Order $order Order object.
114
	 * @return array
115
	 */
116
	protected function get_transaction_args( $order ) {
117
		return array_merge(
118
			array(
119
				'cmd'           => '_cart',
120
				'business'      => $this->gateway->get_option( 'email' ),
121
				'no_note'       => 1,
122
				'currency_code' => get_woocommerce_currency(),
123
				'charset'       => 'utf-8',
124
				'rm'            => is_ssl() ? 2 : 1,
125
				'upload'        => 1,
126
				'return'        => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
127
				'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
128
				'page_style'    => $this->gateway->get_option( 'page_style' ),
129
				'image_url'     => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
130
				'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
131
				'invoice'       => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
132
				'custom'        => wp_json_encode(
133
					array(
134
						'order_id'  => $order->get_id(),
135
						'order_key' => $order->get_order_key(),
136
					)
137
				),
138
				'notify_url'    => $this->limit_length( $this->notify_url, 255 ),
139
				'first_name'    => $this->limit_length( $order->get_billing_first_name(), 32 ),
140
				'last_name'     => $this->limit_length( $order->get_billing_last_name(), 64 ),
141
				'address1'      => $this->limit_length( $order->get_billing_address_1(), 100 ),
142
				'address2'      => $this->limit_length( $order->get_billing_address_2(), 100 ),
143
				'city'          => $this->limit_length( $order->get_billing_city(), 40 ),
144
				'state'         => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
145
				'zip'           => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
146
				'country'       => $this->limit_length( $order->get_billing_country(), 2 ),
147
				'email'         => $this->limit_length( $order->get_billing_email() ),
148
			),
149
			$this->get_phone_number_args( $order ),
150
			$this->get_shipping_args( $order )
151
		);
152
	}
153
154
	/**
155
	 * If the default request with line items is too long, generate a new one with only one line item.
156
	 *
157
	 * If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
158
	 * One item's name can only be 127 characters long, so the URL should not be longer than limit.
159
	 * URL character limit via:
160
	 * https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer.
161
	 *
162
	 * @param WC_Order $order Order to be sent to Paypal.
163
	 * @param array    $paypal_args Arguments sent to Paypal in the request.
164
	 * @return array
165
	 */
166
	protected function fix_request_length( $order, $paypal_args ) {
167
		$max_paypal_length = 2083;
168
		$query_candidate   = http_build_query( $paypal_args, '', '&' );
169
170
		if ( strlen( $this->endpoint . $query_candidate ) <= $max_paypal_length ) {
171
			return $paypal_args;
172
		}
173
174
		return apply_filters(
175
			'woocommerce_paypal_args',
176
			array_merge(
177
				$this->get_transaction_args( $order ),
178
				$this->get_line_item_args( $order, true )
179
			),
180
			$order
181
		);
182
183
	}
184
185
	/**
186
	 * Get PayPal Args for passing to PP.
187
	 *
188
	 * @param  WC_Order $order Order object.
189
	 * @return array
190
	 */
191
	protected function get_paypal_args( $order ) {
192
		WC_Gateway_Paypal::log( 'Generating payment form for order ' . $order->get_order_number() . '. Notify URL: ' . $this->notify_url );
193
194
		$force_one_line_item = apply_filters( 'woocommerce_paypal_force_one_line_item', false, $order );
195
196
		if ( ( wc_tax_enabled() && wc_prices_include_tax() ) || ! $this->line_items_valid( $order ) ) {
197
			$force_one_line_item = true;
198
		}
199
200
		$paypal_args = apply_filters(
201
			'woocommerce_paypal_args',
202
			array_merge(
203
				$this->get_transaction_args( $order ),
204
				$this->get_line_item_args( $order, $force_one_line_item )
205
			),
206
			$order
207
		);
208
209
		return $this->fix_request_length( $order, $paypal_args );
210
	}
211
212
	/**
213
	 * Get phone number args for paypal request.
214
	 *
215
	 * @param  WC_Order $order Order object.
216
	 * @return array
217
	 */
218
	protected function get_phone_number_args( $order ) {
219
		$phone_number = wc_sanitize_phone_number( $order->get_billing_phone() );
220
221
		if ( in_array( $order->get_billing_country(), array( 'US', 'CA' ), true ) ) {
222
			$phone_number = ltrim( $phone_number, '+1' );
223
			$phone_args   = array(
224
				'night_phone_a' => substr( $phone_number, 0, 3 ),
225
				'night_phone_b' => substr( $phone_number, 3, 3 ),
226
				'night_phone_c' => substr( $phone_number, 6, 4 ),
227
			);
228
		} else {
229
			$calling_code = WC()->countries->get_country_calling_code( $order->get_billing_country() );
230
			$calling_code = is_array( $calling_code ) ? $calling_code[0] : $calling_code;
231
232
			if ( $calling_code ) {
233
				$phone_number = str_replace( $calling_code, '', preg_replace( '/^0/', '', $order->get_billing_phone() ) );
234
			}
235
236
			$phone_args = array(
237
				'night_phone_a' => $calling_code,
238
				'night_phone_b' => $phone_number,
239
			);
240
		}
241
		return $phone_args;
242
	}
243
244
	/**
245
	 * Get shipping args for paypal request.
246
	 *
247
	 * @param  WC_Order $order Order object.
248
	 * @return array
249
	 */
250
	protected function get_shipping_args( $order ) {
251
		$shipping_args = array();
252
		if ( $order->needs_shipping_address() ) {
253
			$shipping_args['address_override'] = $this->gateway->get_option( 'address_override' ) === 'yes' ? 1 : 0;
254
			$shipping_args['no_shipping']      = 0;
255
			if ( 'yes' === $this->gateway->get_option( 'send_shipping' ) ) {
256
				// If we are sending shipping, send shipping address instead of billing.
257
				$shipping_args['first_name'] = $this->limit_length( $order->get_shipping_first_name(), 32 );
258
				$shipping_args['last_name']  = $this->limit_length( $order->get_shipping_last_name(), 64 );
259
				$shipping_args['address1']   = $this->limit_length( $order->get_shipping_address_1(), 100 );
260
				$shipping_args['address2']   = $this->limit_length( $order->get_shipping_address_2(), 100 );
261
				$shipping_args['city']       = $this->limit_length( $order->get_shipping_city(), 40 );
262
				$shipping_args['state']      = $this->get_paypal_state( $order->get_shipping_country(), $order->get_shipping_state() );
263
				$shipping_args['country']    = $this->limit_length( $order->get_shipping_country(), 2 );
264
				$shipping_args['zip']        = $this->limit_length( wc_format_postcode( $order->get_shipping_postcode(), $order->get_shipping_country() ), 32 );
265
			}
266
		} else {
267
			$shipping_args['no_shipping'] = 1;
268
		}
269
		return $shipping_args;
270
	}
271
272
	/**
273
	 * Get shipping cost line item args for paypal request.
274
	 *
275
	 * @param  WC_Order $order Order object.
276
	 * @param  bool     $force_one_line_item Whether one line item was forced by validation or URL length.
277
	 * @return array
278
	 */
279
	protected function get_shipping_cost_line_item( $order, $force_one_line_item ) {
280
		$line_item_args = array();
281
		$shipping_total = $order->get_shipping_total();
282
		if ( $force_one_line_item ) {
283
			$shipping_total += $order->get_shipping_tax();
284
		}
285
286
		// Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
287
		// We also check that shipping is not the **only** cost as PayPal won't allow payment
288
		// if the items have no cost.
289
		if ( $order->get_shipping_total() > 0 && $order->get_shipping_total() < 999.99 && $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
290
			$line_item_args['shipping_1'] = $this->number_format( $shipping_total, $order );
291
		} elseif ( $order->get_shipping_total() > 0 ) {
292
			/* translators: %s: Order shipping method */
293
			$this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $shipping_total, $order ) );
294
		}
295
296
		return $line_item_args;
297
	}
298
299
	/**
300
	 * Get line item args for paypal request as a single line item.
301
	 *
302
	 * @param  WC_Order $order Order object.
303
	 * @return array
304
	 */
305
	protected function get_line_item_args_single_item( $order ) {
306
		$this->delete_line_items();
307
308
		$all_items_name = $this->get_order_item_names( $order );
309
		$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
310
		$line_item_args = $this->get_shipping_cost_line_item( $order, true );
311
312
		return array_merge( $line_item_args, $this->get_line_items() );
313
	}
314
315
	/**
316
	 * Get line item args for paypal request.
317
	 *
318
	 * @param  WC_Order $order Order object.
319
	 * @param  bool     $force_one_line_item Create only one item for this order.
320
	 * @return array
321
	 */
322
	protected function get_line_item_args( $order, $force_one_line_item = false ) {
323
		$line_item_args = array();
324
325
		if ( $force_one_line_item ) {
326
			/**
327
			 * Send order as a single item.
328
			 *
329
			 * For shipping, we longer use shipping_1 because paypal ignores it if *any* shipping rules are within paypal, and paypal ignores anything over 5 digits (999.99 is the max).
330
			 */
331
			$line_item_args = $this->get_line_item_args_single_item( $order );
332
		} else {
333
			/**
334
			 * Passing a line item per product if supported.
335
			 */
336
			$this->prepare_line_items( $order );
337
			$line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
338
339
			if ( $order->get_total_discount() > 0 ) {
340
				$line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
341
			}
342
343
			$line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, false ) );
344
			$line_item_args = array_merge( $line_item_args, $this->get_line_items() );
345
346
		}
347
348
		return $line_item_args;
349
	}
350
351
	/**
352
	 * Get order item names as a string.
353
	 *
354
	 * @param  WC_Order $order Order object.
355
	 * @return string
356
	 */
357
	protected function get_order_item_names( $order ) {
358
		$item_names = array();
359
360
		foreach ( $order->get_items() as $item ) {
361
			$item_name = $item->get_name();
362
			$item_meta = wp_strip_all_tags(
363
				wc_display_item_meta(
364
					$item,
365
					array(
366
						'before'    => '',
367
						'separator' => ', ',
368
						'after'     => '',
369
						'echo'      => false,
370
						'autop'     => false,
371
					)
372
				)
373
			);
374
375
			if ( $item_meta ) {
376
				$item_name .= ' (' . $item_meta . ')';
377
			}
378
379
			$item_names[] = $item_name . ' x ' . $item->get_quantity();
380
		}
381
382
		return apply_filters( 'woocommerce_paypal_get_order_item_names', implode( ', ', $item_names ), $order );
383
	}
384
385
	/**
386
	 * Get order item names as a string.
387
	 *
388
	 * @param  WC_Order      $order Order object.
389
	 * @param  WC_Order_Item $item Order item object.
390
	 * @return string
391
	 */
392
	protected function get_order_item_name( $order, $item ) {
393
		$item_name = $item->get_name();
394
		$item_meta = wp_strip_all_tags(
395
			wc_display_item_meta(
396
				$item,
397
				array(
398
					'before'    => '',
399
					'separator' => ', ',
400
					'after'     => '',
401
					'echo'      => false,
402
					'autop'     => false,
403
				)
404
			)
405
		);
406
407
		if ( $item_meta ) {
408
			$item_name .= ' (' . $item_meta . ')';
409
		}
410
411
		return apply_filters( 'woocommerce_paypal_get_order_item_name', $item_name, $order, $item );
412
	}
413
414
	/**
415
	 * Return all line items.
416
	 */
417
	protected function get_line_items() {
418
		return $this->line_items;
419
	}
420
421
	/**
422
	 * Remove all line items.
423
	 */
424
	protected function delete_line_items() {
425
		$this->line_items = array();
426
	}
427
428
	/**
429
	 * Check if the order has valid line items to use for PayPal request.
430
	 *
431
	 * The line items are invalid in case of mismatch in totals or if any amount < 0.
432
	 *
433
	 * @param WC_Order $order Order to be examined.
434
	 * @return bool
435
	 */
436
	protected function line_items_valid( $order ) {
437
		$negative_item_amount = false;
438
		$calculated_total     = 0;
439
440
		// Products.
441
		foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
442
			if ( 'fee' === $item['type'] ) {
443
				$item_line_total   = $this->number_format( $item['line_total'], $order );
444
				$calculated_total += $item_line_total;
445
			} else {
446
				$item_line_total   = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
447
				$calculated_total += $item_line_total * $item->get_quantity();
448
			}
449
450
			if ( $item_line_total < 0 ) {
451
				$negative_item_amount = true;
452
			}
453
		}
454
		$mismatched_totals = $this->number_format( $calculated_total + $order->get_total_tax() + $this->round( $order->get_shipping_total(), $order ) - $this->round( $order->get_total_discount(), $order ), $order ) !== $this->number_format( $order->get_total(), $order );
455
		return ! $negative_item_amount && ! $mismatched_totals;
456
	}
457
458
	/**
459
	 * Get line items to send to paypal.
460
	 *
461
	 * @param  WC_Order $order Order object.
462
	 */
463
	protected function prepare_line_items( $order ) {
464
		$this->delete_line_items();
465
466
		// Products.
467
		foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
468
			if ( 'fee' === $item['type'] ) {
469
				$item_line_total = $this->number_format( $item['line_total'], $order );
470
				$this->add_line_item( $item->get_name(), 1, $item_line_total );
471
			} else {
472
				$product         = $item->get_product();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Order_Item as the method get_product() does only exist in the following sub-classes of WC_Order_Item: WC_Order_Item_Product. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
473
				$sku             = $product ? $product->get_sku() : '';
474
				$item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
475
				$this->add_line_item( $this->get_order_item_name( $order, $item ), $item->get_quantity(), $item_line_total, $sku );
476
			}
477
		}
478
	}
479
480
	/**
481
	 * Add PayPal Line Item.
482
	 *
483
	 * @param  string $item_name Item name.
484
	 * @param  int    $quantity Item quantity.
485
	 * @param  float  $amount Amount.
486
	 * @param  string $item_number Item number.
487
	 */
488
	protected function add_line_item( $item_name, $quantity = 1, $amount = 0.0, $item_number = '' ) {
489
		$index = ( count( $this->line_items ) / 4 ) + 1;
490
491
		$item = apply_filters(
492
			'woocommerce_paypal_line_item',
493
			array(
494
				'item_name'   => html_entity_decode( wc_trim_string( $item_name ? wp_strip_all_tags( $item_name ) : __( 'Item', 'woocommerce' ), 127 ), ENT_NOQUOTES, 'UTF-8' ),
495
				'quantity'    => (int) $quantity,
496
				'amount'      => wc_float_to_string( (float) $amount ),
497
				'item_number' => $item_number,
498
			),
499
			$item_name,
500
			$quantity,
501
			$amount,
502
			$item_number
503
		);
504
505
		$this->line_items[ 'item_name_' . $index ]   = $this->limit_length( $item['item_name'], 127 );
506
		$this->line_items[ 'quantity_' . $index ]    = $item['quantity'];
507
		$this->line_items[ 'amount_' . $index ]      = $item['amount'];
508
		$this->line_items[ 'item_number_' . $index ] = $this->limit_length( $item['item_number'], 127 );
509
	}
510
511
	/**
512
	 * Get the state to send to paypal.
513
	 *
514
	 * @param  string $cc Country two letter code.
515
	 * @param  string $state State code.
516
	 * @return string
517
	 */
518
	protected function get_paypal_state( $cc, $state ) {
519
		if ( 'US' === $cc ) {
520
			return $state;
521
		}
522
523
		$states = WC()->countries->get_states( $cc );
524
525
		if ( isset( $states[ $state ] ) ) {
526
			return $states[ $state ];
527
		}
528
529
		return $state;
530
	}
531
532
	/**
533
	 * Check if currency has decimals.
534
	 *
535
	 * @param  string $currency Currency to check.
536
	 * @return bool
537
	 */
538
	protected function currency_has_decimals( $currency ) {
539
		if ( in_array( $currency, array( 'HUF', 'JPY', 'TWD' ), true ) ) {
540
			return false;
541
		}
542
543
		return true;
544
	}
545
546
	/**
547
	 * Round prices.
548
	 *
549
	 * @param  double   $price Price to round.
550
	 * @param  WC_Order $order Order object.
551
	 * @return double
552
	 */
553
	protected function round( $price, $order ) {
554
		$precision = 2;
555
556
		if ( ! $this->currency_has_decimals( $order->get_currency() ) ) {
557
			$precision = 0;
558
		}
559
560
		return round( $price, $precision );
561
	}
562
563
	/**
564
	 * Format prices.
565
	 *
566
	 * @param  float|int $price Price to format.
567
	 * @param  WC_Order  $order Order object.
568
	 * @return string
569
	 */
570
	protected function number_format( $price, $order ) {
571
		$decimals = 2;
572
573
		if ( ! $this->currency_has_decimals( $order->get_currency() ) ) {
574
			$decimals = 0;
575
		}
576
577
		return number_format( $price, $decimals, '.', '' );
578
	}
579
}
580