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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 ) { |
|
|
|
|
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
|
|
|
|
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.