Completed
Pull Request — master (#11889)
by Mike
19:28
created

WC_Cart_Totals   D

Complexity

Total Complexity 82

Size/Duplication

Total Lines 527
Duplicated Lines 10.25 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 54
loc 527
rs 4.8717
c 0
b 0
f 0
wmc 82
lcom 1
cbo 3

33 Methods

Rating   Name   Duplication   Size   Complexity  
A get_default_item_props() 0 12 1
A get_default_coupon_props() 0 7 1
A get_default_fee_props() 0 6 1
A get_default_shipping_props() 0 7 1
A set_items() 0 14 3
A set_coupons() 0 8 2
A get_coupons() 0 3 1
A set_fees() 0 10 2
A set_calculate_tax() 0 3 1
A get_calculate_tax() 0 3 2
B calculate_item_subtotals() 0 20 7
B calculate_item_totals() 0 21 5
B calculate_fee_totals() 0 10 5
A calculate_totals() 0 20 2
A get_item_totals() 0 3 1
A get_item_tax_rates() 0 4 2
B sort_items_callback() 0 8 5
A get_items_subtotal() 9 9 2
A get_items_total() 9 9 2
A get_discount_total() 0 3 1
A get_discount_total_tax() 0 3 1
A calc_discounts_sequentially() 0 3 1
A get_undiscounted_price() 0 7 2
C get_discounted_price() 0 57 11
A adjust_non_base_location_price() 0 15 2
A get_fees_total() 9 9 2
C get_merged_taxes() 18 25 7
A get_taxes() 0 3 1
A get_tax_total() 0 3 1
A get_shipping_tax_total() 0 3 1
A get_total() 0 3 1
A get_shipping_total() 9 9 2
A set_shipping() 0 14 3

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_Cart_Totals 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_Cart_Totals, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * Handles cart totals calculations.
9
 *
10
 * @class 		WC_Cart_Totals
11
 * @version		2.7.0
12
 * @package		WooCommerce/Classes
13
 * @category	Class
14
 * @author 		WooThemes
15
 */
16
class WC_Cart_Totals {
17
18
	protected $calculate_tax  = true;
19
	protected $totals         = null;
20
	protected $coupons        = array();
21
	protected $items          = array();
22
	protected $fees           = array();
23
	protected $shipping_lines = array();
24
25
	/**
26
	 * Get default blank set of props used per item.
27
	 * @return array
28
	 */
29
	private function get_default_item_props() {
30
		return (object) array(
31
			'price_includes_tax' => wc_prices_include_tax(),
32
			'subtotal'           => 0,
33
			'subtotal_tax'       => 0,
34
			'subtotal_taxes'     => array(),
35
			'total'              => 0,
36
			'tax'                => 0,
37
			'taxes'              => array(),
38
			'discounted_price'   => 0,
39
		);
40
	}
41
42
	/**
43
	 * Get default blank set of props used per coupon.
44
	 * @return array
45
	 */
46
	private function get_default_coupon_props() {
47
		return (object) array(
48
			'count'     => 0,
49
			'total'     => 0,
50
			'total_tax' => 0,
51
		);
52
	}
53
54
	/**
55
	 * Get default blank set of props used per fee.
56
	 * @return array
57
	 */
58
	private function get_default_fee_props() {
59
		return (object) array(
60
			'tax'   => 0,
61
			'taxes' => array(),
62
		);
63
	}
64
65
	/**
66
	 * Get default blank set of props used per shipping row.
67
	 * @return array
68
	 */
69
	private function get_default_shipping_props() {
70
		return (object) array(
71
			'total'     => 0,
72
			'total_tax' => 0,
73
			'taxes'     => array(),
74
		);
75
	}
76
77
	/**
78
	 * Sets items and adds precision which lets us work with integers.
79
	 * @param array $items
80
	 */
81
	public function set_items( $items ) {
82
		foreach ( $items as $item_key => $maybe_item ) {
83
			if ( ! is_a( $maybe_item, 'WC_Item_Product' ) ) {
84
				continue;
85
			}
86
			$item                     = $this->get_default_item_props();
87
			$item->product            = $maybe_item->get_product();
88
			$item->values             = $maybe_item;
89
			$item->quantity           = $maybe_item->get_quantity();
90
			$item->price              = $item->product->get_price();
91
			$this->items[ $item_key ] = $item;
92
		}
93
		$this->totals = null;
94
	}
95
96
	/**
97
	 * Set coupons.
98
	 * @param array $coupons
99
	 */
100
	public function set_coupons( $coupons ) {
101
		foreach ( $coupons as $code => $coupon_object ) {
102
			$coupon                 = $this->get_default_coupon_props();
103
			$coupon->coupon         = $coupon_object;
104
			$this->coupons[ $code ] = $coupon;
105
		}
106
		$this->totals = null;
107
	}
108
109
	/**
110
	 * Get fees.
111
	 * @return array
112
	 */
113
	public function get_coupons() {
114
		return $this->coupons;
115
	}
116
117
	/**
118
	 * Set fees.
119
	 * @param array $fees
120
	 */
121
	public function set_fees( $fees ) {
122
		foreach ( $fees as $fee_key => $fee_object ) {
123
			$fee                    = $this->get_default_fee_props();
124
			$fee->amount            = $fee_object->amount;
125
			$fee->taxable           = $fee_object->taxable;
126
			$fee->tax_class         = $fee_object->tax_class;
127
			$this->fees[ $fee_key ] = $fee;
128
		}
129
		$this->totals = null;
130
	}
131
132
	/**
133
	 * Should we calc tax?
134
	 * @param bool
135
	 */
136
	public function set_calculate_tax( $value ) {
137
		$this->calculate_tax = (bool) $value;
138
	}
139
140
	/**
141
	 * Should we calc tax?
142
	 * @param bool
143
	 */
144
	public function get_calculate_tax() {
145
		return wc_tax_enabled() && $this->calculate_tax;
146
	}
147
148
	/**
149
	 * Subtotals are costs before discounts.
150
	 *
151
	 * To prevent rounding issues we need to work with the inclusive price where possible.
152
	 * otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would.
153
	 * be 8.325 leading to totals being 1p off.
154
	 *
155
	 * Pre tax coupons come off the price the customer thinks they are paying - tax is calculated.
156
	 * afterwards.
157
	 *
158
	 * e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that.
159
	 */
160
	private function calculate_item_subtotals() {
161
		foreach ( $this->items as $item ) {
162
			$item->subtotal     = $item->price * $item->quantity;
163
			$item->subtotal_tax = 0;
164
165
			if ( $item->price_includes_tax && apply_filters( 'woocommerce_adjust_non_base_location_prices', false ) ) {
166
				$item           = $this->adjust_non_base_location_price( $item );
167
				$item->subtotal = $item->price * $item->quantity;
168
			}
169
170
			if ( $this->get_calculate_tax() && $item->product->is_taxable() ) {
171
				$item->subtotal_taxes = WC_Tax::calc_tax( $item->subtotal, $this->get_item_tax_rates( $item ), $item->price_includes_tax );
172
				$item->subtotal_tax      = array_sum( $item->subtotal_taxes );
173
174
				if ( $item->price_includes_tax ) {
175
					$item->subtotal = $item->subtotal - $item->subtotal_tax;
176
				}
177
			}
178
		}
179
	}
180
181
	/**
182
	 * Totals are costs after discounts.
183
	 */
184
	public function calculate_item_totals() {
185
		$this->calculate_item_subtotals();
186
		uasort( $this->items, array( $this, 'sort_items_callback' ) );
187
188
		foreach ( $this->items as $item ) {
189
			$item->discounted_price = $this->get_discounted_price( $item );
190
			$item->total            = $item->discounted_price * $item->quantity;
191
			$item->tax              = 0;
192
193
			if ( $this->get_calculate_tax() && $item->product->is_taxable() ) {
194
				$item->taxes = WC_Tax::calc_tax( $item->total, $this->get_item_tax_rates( $item ), $item->price_includes_tax );
195
				$item->tax   = array_sum( $item->taxes );
196
197
				if ( $item->price_includes_tax ) {
198
					$item->total = $item->total - $item->tax;
199
				} else {
200
					$item->total = $item->total;
201
				}
202
			}
203
		}
204
	}
205
206
	/**
207
	 * Calculate any fees taxes.
208
	 */
209
	private function calculate_fee_totals() {
210
		if ( ! empty( $this->fees ) ) {
211
			foreach ( $this->fees as $fee_key => $fee ) {
212
				if ( $this->get_calculate_tax() && $fee->taxable ) {
213
					$fee->taxes = WC_Tax::calc_tax( $fee->amount, $tax_rates, false );
214
					$fee->tax   = array_sum( $fee->taxes );
215
				}
216
			}
217
		}
218
	}
219
220
	/**
221
	 * Main cart totals.
222
	 */
223
	public function calculate_totals() {
224
		$this->calculate_fee_totals();
225
		$this->totals        = new stdClass();
226
		$this->totals->taxes = $this->get_merged_taxes();
227
228
		// Total up/round taxes and shipping taxes
229
		if ( 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
230
			$this->totals->tax_total          = WC_Tax::get_tax_total( wc_list_pluck( $this->totals->taxes, 'get_tax_total' ) );
231
			$this->totals->shipping_tax_total = WC_Tax::get_tax_total( wc_list_pluck( $this->totals->taxes, 'get_shipping_tax_total' ) );
232
		} else {
233
			$this->totals->tax_total          = array_sum( wc_list_pluck( $this->totals->taxes, 'get_tax_total' ) );
234
			$this->totals->shipping_tax_total = array_sum( wc_list_pluck( $this->totals->taxes, 'get_shipping_tax_total' ) );
235
		}
236
237
		// Allow plugins to hook and alter totals before final total is calculated
238
		do_action( 'woocommerce_calculate_totals', WC()->cart );
239
240
		// Grand Total - Discounted product prices, discounted tax, shipping cost + tax
241
		$this->totals->total = max( 0, apply_filters( 'woocommerce_calculated_total', round( $this->get_items_total( false ) + $this->get_fees_total( false ) + $this->get_shipping_total( false ) + $this->totals->tax_total + $this->totals->shipping_tax_total, wc_get_price_decimals() ), WC()->cart ) );
242
	}
243
244
	/**
245
	 * Returns items and their totals.
246
	 * @return array
247
	 */
248
	public function get_item_totals() {
249
		return $this->items;
250
	}
251
252
	/**
253
	 * Get tax rates for an item. Caches rates in class to avoid multiple look ups.
254
	 * @param  object $item
255
	 * @return array of taxes
256
	 */
257
	private function get_item_tax_rates( $item ) {
258
		$tax_class = $item->product->get_tax_class();
259
		return isset( $this->item_tax_rates[ $tax_class ] ) ? $this->item_tax_rates[ $tax_class ] : $this->item_tax_rates[ $tax_class ] = WC_Tax::get_rates( $item->product->get_tax_class() );
260
	}
261
262
	/**
263
	 * Sort items by the subtotal.
264
	 */
265
	private function sort_items_callback( $a, $b ) {
266
		$first_item_subtotal  = isset( $a->subtotal ) ? $a->subtotal : 0;
267
		$second_item_subtotal = isset( $b->subtotal ) ? $b->subtotal : 0;
268
		if ( $first_item_subtotal === $second_item_subtotal ) {
269
			return 0;
270
		}
271
		return ( $first_item_subtotal < $second_item_subtotal ) ? 1 : -1;
272
	}
273
274
	/**
275
	 * Get the subtotal for all items.
276
	 *
277
	 * @param  boolean $inc_tax Should tax also be included in the subtotal?
278
	 * @return float
279
	 */
280 View Code Duplication
	public function get_items_subtotal( $inc_tax = true ) {
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...
281
		$totals = array_values( wp_list_pluck( $this->items, 'subtotal' ) );
282
283
		if ( $inc_tax ) {
284
			$totals = array_merge( $totals, array_values( wp_list_pluck( $this->items, 'subtotal_tax' ) ) );
285
		}
286
287
		return array_sum( $totals );
288
	}
289
290
	/**
291
	 * Get the total for all items.
292
	 *
293
	 * @param  boolean $inc_tax Should tax also be included in the subtotal?
294
	 * @return float
295
	 */
296 View Code Duplication
	public function get_items_total( $inc_tax = true ) {
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...
297
		$totals = array_values( wp_list_pluck( $this->items, 'total' ) );
298
299
		if ( $inc_tax ) {
300
			$totals = array_merge( $totals, array_values( wp_list_pluck( $this->items, 'tax' ) ) );
301
		}
302
303
		return array_sum( $totals );
304
	}
305
306
	/**
307
	 * Get the total discount amount.
308
	 * @return float
309
	 */
310
	public function get_discount_total() {
311
		return wc_cart_round_discount( array_sum( array_values( wp_list_pluck( $this->coupons, 'total' ) ) ), wc_get_price_decimals() );
312
	}
313
314
	/**
315
	 * Get the total discount amount.
316
	 * @return float
317
	 */
318
	public function get_discount_total_tax() {
319
		return wc_cart_round_discount( array_sum( array_values( wp_list_pluck( $this->coupons, 'total_tax' ) ) ), wc_get_price_decimals() );
320
	}
321
322
	/**
323
	 * Should discounts be applied sequentially?
324
	 * @return bool
325
	 */
326
	private function calc_discounts_sequentially() {
327
		return 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' );
328
	}
329
330
	/**
331
	 * Get an items price to discount (undiscounted price).
332
	 * @param  object $item
333
	 * @return float
334
	 */
335
	private function get_undiscounted_price( $item ) {
336
		if ( $item->price_includes_tax ) {
337
			return ( $item->subtotal + $item->subtotal_tax ) / $item->quantity;
338
		} else {
339
			return $item->subtotal / $item->quantity;
340
		}
341
	}
342
343
	/**
344
	 * Get an individual items price after discounts are applied.
345
	 * @param  object $item
346
	 * @return float
347
	 */
348
	public function get_discounted_price( $item ) {
349
		$price = $this->get_undiscounted_price( $item );
350
351
		foreach ( $this->coupons as $code => $coupon ) {
352
			if ( $coupon->coupon->is_valid_for_product( $item->product ) || $coupon->coupon->is_valid_for_cart() ) {
353
				$price_to_discount = $this->calc_discounts_sequentially() ? $price : $this->get_undiscounted_price( $item );
354
355
				if ( $coupon->coupon->is_type( 'fixed_product' ) ) {
356
					$discount = min( $coupon->coupon->get_amount(), $price_to_discount );
357
358
				} elseif ( $coupon->coupon->is_type( array( 'percent_product', 'percent' ) ) ) {
359
					$discount = $coupon->coupon->get_amount() * ( $price_to_discount / 100 );
360
361
				/**
362
				 * This is the most complex discount - we need to divide the discount between rows based on their price in
363
				 * proportion to the subtotal. This is so rows with different tax rates get a fair discount, and so rows
364
				 * with no price (free) don't get discounted. Get item discount by dividing item cost by subtotal to get a %.
365
				 *
366
				 * Uses price inc tax if prices include tax to work around https://github.com/woothemes/woocommerce/issues/7669 and https://github.com/woothemes/woocommerce/issues/8074.
367
				 */
368
				} elseif ( $coupon->coupon->is_type( 'fixed_cart' ) ) {
369
					$discount_percent = ( $item->subtotal + $item->subtotal_tax ) / array_sum( array_merge( array_values( wp_list_pluck( $this->items, 'subtotal' ) ), array_values( wp_list_pluck( $this->items, 'subtotal_tax' ) ) ) );
370
					$discount         = ( $coupon->coupon->get_amount() * $discount_percent ) / $item->quantity;
371
				}
372
373
				// Discount cannot be greater than the price we are discounting.
374
				$discount_amount = min( $price_to_discount, $discount );
375
376
				// Reduce the price so the next coupon discounts the new amount.
377
				$price           = max( $price - $discount_amount, 0 );
378
379
				// Store how much each coupon has discounted in total.
380
				$coupon->count += $item->quantity;
381
				$coupon->total += $discount_amount * $item->quantity;
382
383
				// If taxes are enabled, we should also note how much tax would have been paid if it was not discounted.
384
				if ( $this->get_calculate_tax() ) {
385
					$tax_amount    = WC_Tax::get_tax_total( WC_Tax::calc_tax( $discount_amount, $this->get_item_tax_rates( $item ), $item->price_includes_tax ) );
386
					$coupon->total_tax += $tax_amount * $item->quantity;
387
					$coupon->total = $item->price_includes_tax ? $coupon->total - ( $tax_amount * $item->quantity ) : $coupon->total;
388
				}
389
			}
390
391
			// If the price is 0, we can stop going through coupons because there is nothing more to discount for this product.
392
			if ( 0 >= $price ) {
393
				break;
394
			}
395
		}
396
397
		/**
398
		 * woocommerce_get_discounted_price filter.
399
		 * @param float $price the price to return.
400
		 * @param array $item->values Cart item values. Used in legacy cart class function.
401
		 * @param object WC()->cart. Used in legacy cart class function.
402
		 */
403
		return apply_filters( 'woocommerce_get_discounted_price', $price, $item->values, WC()->cart );
404
	}
405
406
	/**
407
	 * Only ran if woocommerce_adjust_non_base_location_prices is true.
408
	 *
409
	 * If the customer is outside of the base location, this removes the base taxes.
410
	 *
411
	 * Pre 2.7, this was on by default. From 2.7 onwards this is off by default meaning
412
	 * that if a product costs 10 including tax, all users will pay 10 regardless of location and taxes. This was experiemental from 2.4.7.
413
	 */
414
	private function adjust_non_base_location_price( $item ) {
415
		$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->tax_class );
416
		$item_tax_rates = $this->get_item_tax_rates( $item );
417
418
		if ( $item_tax_rates !== $base_tax_rates ) {
419
			// Work out a new base price without the shop's base tax
420
			$taxes                    = WC_Tax::calc_tax( $item->price, $base_tax_rates, true, true );
421
422
			// Now we have a new item price (excluding TAX)
423
			$item->price              = $item->price - array_sum( $taxes );
424
			$item->price_includes_tax = false;
425
		}
426
427
		return $item;
428
	}
429
430
	/**
431
	 * Get the total for all items.
432
	 *
433
	 * @param  boolean $inc_tax Should tax also be included in the subtotal?
434
	 * @return float
435
	 */
436 View Code Duplication
	public function get_fees_total( $inc_tax = true ) {
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...
437
		$totals = array_values( wp_list_pluck( $this->fees, 'amount' ) );
438
439
		if ( $inc_tax ) {
440
			$totals = array_merge( $totals, array_values( wp_list_pluck( $this->fees, 'tax' ) ) );
441
		}
442
443
		return array_sum( $totals );
444
	}
445
446
	/**
447
	 * Get all tax rows for a set of items and shipping methods.
448
	 * @return array
449
	 */
450
	public function get_merged_taxes() {
451
		$taxes = array();
452
453 View Code Duplication
		foreach ( $this->items 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...
454
			foreach ( $item->taxes as $rate_id => $rate ) {
455
				if ( ! isset( $taxes[ $rate_id ] ) ) {
456
					$taxes[ $rate_id ] = new WC_Item_Tax();
457
				}
458
				$taxes[ $rate_id ]->set_rate( $rate_id );
459
				$taxes[ $rate_id ]->set_tax_total( $taxes[ $rate_id ]->get_tax_total() + $rate );
460
			}
461
		}
462
463 View Code Duplication
		foreach ( $this->shipping_lines 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...
464
			foreach ( $item->taxes as $rate_id => $rate ) {
465
				if ( ! isset( $taxes[ $rate_id ] ) ) {
466
					$taxes[ $rate_id ] = new WC_Item_Tax();
467
				}
468
				$taxes[ $rate_id ]->set_rate( $rate_id );
469
				$taxes[ $rate_id ]->set_shipping_tax_total( $taxes[ $rate_id ]->get_shipping_tax_total() + $rate );
470
			}
471
		}
472
473
		return $taxes;
474
	}
475
476
	/**
477
	 * Get taxes.
478
	 * @return array
479
	 */
480
	public function get_taxes() {
481
		return $this->totals->taxes;
482
	}
483
484
	/**
485
	 * Get tax total.
486
	 * @return float
487
	 */
488
	public function get_tax_total() {
489
		return $this->totals->tax_total;
490
	}
491
492
	/**
493
	 * Get shipping tax total.
494
	 * @return float
495
	 */
496
	public function get_shipping_tax_total() {
497
		return $this->totals->shipping_tax_total;
498
	}
499
500
	/**
501
	 * Get grand total.
502
	 * @return float
503
	 */
504
	public function get_total() {
505
		return $this->totals->total;
506
	}
507
508
	/**
509
	 * Get the total for all items.
510
	 *
511
	 * @param  boolean $inc_tax Should tax also be included in the subtotal?
512
	 * @return float
513
	 */
514 View Code Duplication
	public function get_shipping_total( $inc_tax = true ) {
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...
515
		$totals = array_values( wp_list_pluck( $this->shipping_lines, 'total' ) );
516
517
		if ( $inc_tax ) {
518
			$totals = array_merge( $totals, array_values( wp_list_pluck( $this->shipping_lines, 'total_tax' ) ) );
519
		}
520
521
		return array_sum( $totals );
522
	}
523
524
	/**
525
	 * Set shipping lines.
526
	 * @param array
527
	 */
528
	public function set_shipping( $shipping_objects ) {
529
		$this->shipping_lines = array();
530
531
		if ( is_array( $shipping_objects ) ) {
532
			foreach ( $shipping_objects as $key => $shipping_object ) {
533
				$shipping                     = $this->get_default_shipping_props();
534
				$shipping->total              = $shipping_object->cost;
535
				$shipping->taxes              = $shipping_object->taxes;
536
				$shipping->total_tax          = array_sum( $shipping_object->taxes );
537
				$this->shipping_lines[ $key ] = $shipping;
538
			}
539
		}
540
		$this->totals = null;
541
	}
542
}
543