1
|
|
|
<?php |
2
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
3
|
|
|
exit; |
4
|
|
|
} |
5
|
|
|
|
6
|
|
|
include_once( 'abstract-wc-legacy-order.php' ); |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Abstract Order |
10
|
|
|
* |
11
|
|
|
* Handles generic order data and database interaction which is extended by both |
12
|
|
|
* WC_Order (regular orders) and WC_Order_Refund (refunds are negative orders). |
13
|
|
|
* |
14
|
|
|
* @class WC_Abstract_Order |
15
|
|
|
* @version 2.7.0 |
16
|
|
|
* @package WooCommerce/Classes |
17
|
|
|
* @category Class |
18
|
|
|
* @author WooThemes |
19
|
|
|
*/ |
20
|
|
|
abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Order Data array. This is the core order data exposed in APIs since 2.7.0. |
24
|
|
|
* |
25
|
|
|
* Notes: cart_tax = cart_tax is the new name for the legacy 'order_tax' |
26
|
|
|
* which is the tax for items only, not shipping. |
27
|
|
|
* @since 2.7.0 |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
protected $data = array( |
31
|
|
|
'parent_id' => 0, |
32
|
|
|
'status' => '', |
33
|
|
|
'currency' => '', |
34
|
|
|
'version' => '', |
35
|
|
|
'prices_include_tax' => false, |
36
|
|
|
'date_created' => '', |
37
|
|
|
'date_modified' => '', |
38
|
|
|
'discount_total' => 0, |
39
|
|
|
'discount_tax' => 0, |
40
|
|
|
'shipping_total' => 0, |
41
|
|
|
'shipping_tax' => 0, |
42
|
|
|
'cart_tax' => 0, |
43
|
|
|
'total' => 0, |
44
|
|
|
'total_tax' => 0, |
45
|
|
|
); |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Data stored in meta keys, but not considered "meta" for an order. |
49
|
|
|
* @since 2.7.0 |
50
|
|
|
* @var array |
51
|
|
|
*/ |
52
|
|
|
protected $internal_meta_keys = array( |
53
|
|
|
'_order_currency', |
54
|
|
|
'_cart_discount', |
55
|
|
|
'_cart_discount_tax', |
56
|
|
|
'_order_shipping', |
57
|
|
|
'_order_shipping_tax', |
58
|
|
|
'_order_tax', |
59
|
|
|
'_order_total', |
60
|
|
|
'_order_version', |
61
|
|
|
'_prices_include_tax', |
62
|
|
|
'_payment_tokens', |
63
|
|
|
); |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Order items will be stored here, sometimes before they persist in the DB. |
67
|
|
|
* @since 2.7.0 |
68
|
|
|
* @var array |
69
|
|
|
*/ |
70
|
|
|
protected $items = array( |
71
|
|
|
'line_items' => null, |
72
|
|
|
'coupon_lines' => null, |
73
|
|
|
'shipping_lines' => null, |
74
|
|
|
'fee_lines' => null, |
75
|
|
|
'tax_lines' => null, |
76
|
|
|
); |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Order items that need deleting are stored here. |
80
|
|
|
* @since 2.7.0 |
81
|
|
|
* @var array |
82
|
|
|
*/ |
83
|
|
|
protected $items_to_delete = array(); |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Internal meta type used to store order data. |
87
|
|
|
* @var string |
88
|
|
|
*/ |
89
|
|
|
protected $meta_type = 'post'; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Stores meta in cache for future reads. |
93
|
|
|
* A group must be set to to enable caching. |
94
|
|
|
* @var string |
95
|
|
|
*/ |
96
|
|
|
protected $cache_group = 'order'; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Get the order if ID is passed, otherwise the order is new and empty. |
100
|
|
|
* This class should NOT be instantiated, but the get_order function or new WC_Order_Factory. |
101
|
|
|
* should be used. It is possible, but the aforementioned are preferred and are the only. |
102
|
|
|
* methods that will be maintained going forward. |
103
|
|
|
* |
104
|
|
|
* @param int|object|WC_Order $read Order to init. |
105
|
|
|
*/ |
106
|
|
|
public function __construct( $read = 0 ) { |
107
|
|
|
parent::__construct( $read ); |
108
|
|
|
|
109
|
|
View Code Duplication |
if ( is_numeric( $read ) && $read > 0 ) { |
|
|
|
|
110
|
|
|
$this->read( $read ); |
111
|
|
|
} elseif ( $read instanceof self ) { |
112
|
|
|
$this->read( absint( $read->get_id() ) ); |
113
|
|
|
} elseif ( ! empty( $read->ID ) ) { |
114
|
|
|
$this->read( absint( $read->ID ) ); |
115
|
|
|
} |
116
|
|
|
// Set default status if none were read. |
117
|
|
|
if ( ! $this->get_status() ) { |
118
|
|
|
$this->set_status( apply_filters( 'woocommerce_default_order_status', 'pending' ) ); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/* |
123
|
|
|
|-------------------------------------------------------------------------- |
124
|
|
|
| CRUD methods |
125
|
|
|
|-------------------------------------------------------------------------- |
126
|
|
|
| |
127
|
|
|
| Methods which create, read, update and delete orders from the database. |
128
|
|
|
| Written in abstract fashion so that the way orders are stored can be |
129
|
|
|
| changed more easily in the future. |
130
|
|
|
| |
131
|
|
|
| A save method is included for convenience (chooses update or create based |
132
|
|
|
| on if the order exists yet). |
133
|
|
|
| |
134
|
|
|
*/ |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Get internal type (post type.) |
138
|
|
|
* @return string |
139
|
|
|
*/ |
140
|
|
|
public function get_type() { |
141
|
|
|
return 'shop_order'; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Get a title for the new post type. |
146
|
|
|
*/ |
147
|
|
|
protected function get_post_title() { |
148
|
|
|
// @codingStandardsIgnoreStart |
149
|
|
|
return sprintf( __( 'Order – %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ); |
150
|
|
|
// @codingStandardsIgnoreEnd |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Insert data into the database. |
155
|
|
|
* @since 2.7.0 |
156
|
|
|
*/ |
157
|
|
|
public function create() { |
158
|
|
|
$this->set_date_created( current_time( 'timestamp' ) ); |
159
|
|
|
$this->set_currency( $this->get_currency() ? $this->get_currency() : get_woocommerce_currency() ); |
160
|
|
|
|
161
|
|
|
$order_id = wp_insert_post( apply_filters( 'woocommerce_new_order_data', array( |
162
|
|
|
'post_date' => date( 'Y-m-d H:i:s', $this->get_date_created() ), |
163
|
|
|
'post_date_gmt' => get_gmt_from_date( date( 'Y-m-d H:i:s', $this->get_date_created() ) ), |
164
|
|
|
'post_type' => $this->get_type(), |
165
|
|
|
'post_status' => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ), |
166
|
|
|
'ping_status' => 'closed', |
167
|
|
|
'post_author' => 1, |
168
|
|
|
'post_title' => $this->get_post_title(), |
169
|
|
|
'post_password' => uniqid( 'order_' ), |
170
|
|
|
'post_parent' => $this->get_parent_id(), |
171
|
|
|
) ), true ); |
172
|
|
|
|
173
|
|
|
if ( $order_id ) { |
174
|
|
|
$this->set_id( $order_id ); |
175
|
|
|
|
176
|
|
|
// Set meta data |
177
|
|
|
$this->update_post_meta( '_order_currency', $this->get_currency() ); |
178
|
|
|
$this->update_post_meta( '_cart_discount', $this->get_discount_total( true ) ); |
179
|
|
|
$this->update_post_meta( '_cart_discount_tax', $this->get_discount_tax( true ) ); |
180
|
|
|
$this->update_post_meta( '_order_shipping', $this->get_shipping_total( true ) ); |
181
|
|
|
$this->update_post_meta( '_order_shipping_tax', $this->get_shipping_tax( true ) ); |
182
|
|
|
$this->update_post_meta( '_order_tax', $this->get_cart_tax( true ) ); |
183
|
|
|
$this->update_post_meta( '_order_total', $this->get_total( true ) ); |
184
|
|
|
$this->update_post_meta( '_order_version', $this->get_version() ); |
185
|
|
|
$this->update_post_meta( '_prices_include_tax', $this->get_prices_include_tax() ); |
186
|
|
|
$this->save_meta_data(); |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Read from the database. |
192
|
|
|
* @since 2.7.0 |
193
|
|
|
* @param int $id ID of object to read. |
194
|
|
|
*/ |
195
|
|
|
public function read( $id ) { |
196
|
|
|
$this->set_defaults(); |
197
|
|
|
|
198
|
|
|
if ( empty( $id ) || ! ( $post_object = get_post( $id ) ) ) { |
199
|
|
|
return; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
$this->set_id( $id ); |
203
|
|
|
$this->set_props( array( |
204
|
|
|
'parent_id' => $post_object->post_parent, |
205
|
|
|
'date_created' => $post_object->post_date, |
206
|
|
|
'date_modified' => $post_object->post_modified, |
207
|
|
|
'status' => $post_object->post_status, |
208
|
|
|
'currency' => get_post_meta( $id, '_order_currency', true ), |
209
|
|
|
'discount_total' => get_post_meta( $id, '_cart_discount', true ), |
210
|
|
|
'discount_tax' => get_post_meta( $id, '_cart_discount_tax', true ), |
211
|
|
|
'shipping_total' => get_post_meta( $id, '_order_shipping', true ), |
212
|
|
|
'shipping_tax' => get_post_meta( $id, '_order_shipping_tax', true ), |
213
|
|
|
'cart_tax' => get_post_meta( $id, '_order_tax', true ), |
214
|
|
|
'total' => get_post_meta( $id, '_order_total', true ), |
215
|
|
|
'version' => get_post_meta( $id, '_order_version', true ), |
216
|
|
|
'prices_include_tax' => metadata_exists( 'post', $id, '_prices_include_tax' ) ? 'yes' === get_post_meta( $id, '_prices_include_tax', true ) : 'yes' === get_option( 'woocommerce_prices_include_tax' ), |
217
|
|
|
) ); |
218
|
|
|
|
219
|
|
|
$this->read_meta_data(); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Post meta update wrapper. Sets or deletes based on value. |
224
|
|
|
* @since 2.7.0 |
225
|
|
|
* @return bool Was it changed? |
226
|
|
|
*/ |
227
|
|
|
protected function update_post_meta( $key, $value ) { |
228
|
|
|
if ( '' !== $value ) { |
229
|
|
|
return update_post_meta( $this->get_id(), $key, $value ); |
230
|
|
|
} else { |
231
|
|
|
return delete_post_meta( $this->get_id(), $key ); |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Update data in the database. |
237
|
|
|
* @since 2.7.0 |
238
|
|
|
*/ |
239
|
|
|
public function update() { |
240
|
|
|
global $wpdb; |
241
|
|
|
|
242
|
|
|
$order_id = $this->get_id(); |
243
|
|
|
|
244
|
|
|
$wpdb->update( |
245
|
|
|
$wpdb->posts, |
246
|
|
|
array( |
247
|
|
|
'post_date' => date( 'Y-m-d H:i:s', $this->get_date_created() ), |
248
|
|
|
'post_date_gmt' => get_gmt_from_date( date( 'Y-m-d H:i:s', $this->get_date_created() ) ), |
249
|
|
|
'post_status' => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ), |
250
|
|
|
'post_parent' => $this->get_parent_id(), |
251
|
|
|
), |
252
|
|
|
array( |
253
|
|
|
'ID' => $order_id, |
254
|
|
|
) |
255
|
|
|
); |
256
|
|
|
|
257
|
|
|
// Update meta data |
258
|
|
|
$this->update_post_meta( '_order_currency', $this->get_currency() ); |
259
|
|
|
$this->update_post_meta( '_cart_discount', $this->get_discount_total( true ) ); |
260
|
|
|
$this->update_post_meta( '_cart_discount_tax', $this->get_discount_tax( true ) ); |
261
|
|
|
$this->update_post_meta( '_order_shipping', $this->get_shipping_total( true ) ); |
262
|
|
|
$this->update_post_meta( '_order_shipping_tax', $this->get_shipping_tax( true ) ); |
263
|
|
|
$this->update_post_meta( '_order_tax', $this->get_cart_tax( true ) ); |
264
|
|
|
$this->update_post_meta( '_order_total', $this->get_total( true ) ); |
265
|
|
|
$this->update_post_meta( '_order_version', $this->get_version() ); |
266
|
|
|
$this->update_post_meta( '_prices_include_tax', $this->get_prices_include_tax() ); |
267
|
|
|
$this->save_meta_data(); |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Delete data from the database. |
272
|
|
|
* @since 2.7.0 |
273
|
|
|
*/ |
274
|
|
|
public function delete() { |
275
|
|
|
wp_delete_post( $this->get_id() ); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Save data to the database. |
280
|
|
|
* @since 2.7.0 |
281
|
|
|
* @return int order ID |
282
|
|
|
*/ |
283
|
|
|
public function save() { |
284
|
|
|
$this->set_version( WC_VERSION ); |
285
|
|
|
|
286
|
|
|
if ( ! $this->get_id() ) { |
287
|
|
|
$this->create(); |
288
|
|
|
} else { |
289
|
|
|
$this->update(); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
$this->save_items(); |
293
|
|
|
clean_post_cache( $this->get_id() ); |
294
|
|
|
wc_delete_shop_order_transients( $this->get_id() ); |
295
|
|
|
|
296
|
|
|
return $this->get_id(); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Save all order items which are part of this order. |
301
|
|
|
*/ |
302
|
|
|
protected function save_items() { |
303
|
|
|
// remove items |
304
|
|
|
foreach ( $this->items_to_delete as $item ) { |
305
|
|
|
$item->delete(); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
$this->items_to_delete = array(); |
309
|
|
|
|
310
|
|
|
// Add/save items |
311
|
|
|
foreach ( $this->items as $item_group => $items ) { |
312
|
|
|
if ( is_array( $items ) ) { |
313
|
|
|
foreach ( $items as $item_key => $item ) { |
314
|
|
|
$item->set_order_id( $this->get_id() ); |
315
|
|
|
$item_id = $item->save(); |
316
|
|
|
|
317
|
|
|
// If ID changed (new item saved to DB)... |
318
|
|
|
if ( $item_id !== $item_key ) { |
319
|
|
|
$this->items[ $item_group ][ $item_id ] = $item; |
320
|
|
|
unset( $this->items[ $item_group ][ $item_key ] ); |
321
|
|
|
|
322
|
|
|
// Legacy action handler |
323
|
|
|
switch ( $item_group ) { |
324
|
|
|
case 'fee_lines' : |
325
|
|
|
if ( isset( $item->legacy_fee, $item->legacy_fee_key ) ) { |
326
|
|
|
wc_do_deprecated_action( 'woocommerce_add_order_fee_meta', array( $this->get_id(), $item_id, $item->legacy_fee, $item->legacy_fee_key ), '2.7', 'Use woocommerce_new_order_item action instead.' ); |
327
|
|
|
} |
328
|
|
|
break; |
329
|
|
|
case 'shipping_lines' : |
330
|
|
|
if ( isset( $item->legacy_package_key ) ) { |
331
|
|
|
wc_do_deprecated_action( 'woocommerce_add_shipping_order_item', array( $item_id, $item->legacy_package_key ), '2.7', 'Use woocommerce_new_order_item action instead.' ); |
332
|
|
|
} |
333
|
|
|
break; |
334
|
|
|
case 'line_items' : |
335
|
|
|
if ( isset( $item->legacy_values, $item->legacy_cart_item_key ) ) { |
336
|
|
|
wc_do_deprecated_action( 'woocommerce_add_order_item_meta', array( $item_id, $item->legacy_values, $item->legacy_cart_item_key ), '2.7', 'Use woocommerce_new_order_item action instead.' ); |
337
|
|
|
} |
338
|
|
|
break; |
339
|
|
|
} |
340
|
|
|
} |
341
|
|
|
} |
342
|
|
|
} |
343
|
|
|
} |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/* |
347
|
|
|
|-------------------------------------------------------------------------- |
348
|
|
|
| Getters |
349
|
|
|
|-------------------------------------------------------------------------- |
350
|
|
|
| |
351
|
|
|
| Methods for getting data from the order object. |
352
|
|
|
| |
353
|
|
|
*/ |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Get all class data in array format. |
357
|
|
|
* @since 2.7.0 |
358
|
|
|
* @return array |
359
|
|
|
*/ |
360
|
|
View Code Duplication |
public function get_data() { |
|
|
|
|
361
|
|
|
return array_merge( |
362
|
|
|
$this->data, |
363
|
|
|
array( |
364
|
|
|
'meta_data' => $this->get_meta_data(), |
365
|
|
|
'line_items' => $this->get_items( 'line_item' ), |
366
|
|
|
'tax_lines' => $this->get_items( 'tax' ), |
367
|
|
|
'shipping_lines' => $this->get_items( 'shipping' ), |
368
|
|
|
'fee_lines' => $this->get_items( 'fee' ), |
369
|
|
|
'coupon_lines' => $this->get_items( 'coupon' ), |
370
|
|
|
) |
371
|
|
|
); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
/** |
375
|
|
|
* Get parent order ID. |
376
|
|
|
* @since 2.7.0 |
377
|
|
|
* @return integer |
378
|
|
|
*/ |
379
|
|
|
public function get_parent_id() { |
380
|
|
|
return $this->data['parent_id']; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* Gets order currency. |
385
|
|
|
* @return string |
386
|
|
|
*/ |
387
|
|
|
public function get_currency() { |
388
|
|
|
return apply_filters( 'woocommerce_get_currency', $this->data['currency'], $this ); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
/** |
392
|
|
|
* Get order_version |
393
|
|
|
* @return string |
394
|
|
|
*/ |
395
|
|
|
public function get_version() { |
396
|
|
|
return $this->data['version']; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* Get prices_include_tax |
401
|
|
|
* @return bool |
402
|
|
|
*/ |
403
|
|
|
public function get_prices_include_tax() { |
404
|
|
|
return $this->data['prices_include_tax']; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Get date_created |
409
|
|
|
* @return int |
410
|
|
|
*/ |
411
|
|
|
public function get_date_created() { |
412
|
|
|
return $this->data['date_created']; |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
/** |
416
|
|
|
* Get date_modified |
417
|
|
|
* @return int |
418
|
|
|
*/ |
419
|
|
|
public function get_date_modified() { |
420
|
|
|
return $this->data['date_modified']; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
/** |
424
|
|
|
* Return the order statuses without wc- internal prefix. |
425
|
|
|
* @return string |
426
|
|
|
*/ |
427
|
|
|
public function get_status() { |
428
|
|
|
$status = $this->data['status']; |
429
|
|
|
return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $status, 0, 3 ) ? substr( $status, 3 ) : $status, $this ); |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
/** |
433
|
|
|
* Get discount_total |
434
|
|
|
* @param bool $raw Gets raw unfiltered value. |
435
|
|
|
* @return string |
436
|
|
|
*/ |
437
|
|
|
public function get_discount_total( $raw = false ) { |
438
|
|
|
$value = wc_format_decimal( $this->data['discount_total'] ); |
439
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_discount_total', $value, $this ); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Get discount_tax |
444
|
|
|
* @param bool $raw Gets raw unfiltered value. |
445
|
|
|
* @return string |
446
|
|
|
*/ |
447
|
|
|
public function get_discount_tax( $raw = false ) { |
448
|
|
|
$value = wc_format_decimal( $this->data['discount_tax'] ); |
449
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_discount_tax', $value, $this ); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
/** |
453
|
|
|
* Get shipping_total |
454
|
|
|
* @param bool $raw Gets raw unfiltered value. |
455
|
|
|
* @return string |
456
|
|
|
*/ |
457
|
|
|
public function get_shipping_total( $raw = false ) { |
458
|
|
|
$value = wc_format_decimal( $this->data['shipping_total'] ); |
459
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_shipping_total', $value, $this ); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Get shipping_tax. |
464
|
|
|
* @param bool $raw Gets raw unfiltered value. |
465
|
|
|
* @return string |
466
|
|
|
*/ |
467
|
|
|
public function get_shipping_tax( $raw = false ) { |
468
|
|
|
$value = wc_format_decimal( $this->data['shipping_tax'] ); |
469
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_shipping_tax', $value, $this ); |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
/** |
473
|
|
|
* Gets cart tax amount. |
474
|
|
|
* @param bool $raw Gets raw unfiltered value. |
475
|
|
|
* @return float |
476
|
|
|
*/ |
477
|
|
|
public function get_cart_tax( $raw = false ) { |
478
|
|
|
$value = wc_format_decimal( $this->data['cart_tax'] ); |
479
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_cart_tax', $value, $this ); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Gets order grand total. incl. taxes. Used in gateways. Filtered. |
484
|
|
|
* @param bool $raw Gets raw unfiltered value. |
485
|
|
|
* @return float |
486
|
|
|
*/ |
487
|
|
|
public function get_total( $raw = false ) { |
488
|
|
|
return $raw ? $this->data['total'] : apply_filters( 'woocommerce_order_amount_total', $this->data['total'], $this ); |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
/** |
492
|
|
|
* Get total tax amount. Alias for get_order_tax(). |
493
|
|
|
* |
494
|
|
|
* @since 2.7.0 woocommerce_order_amount_total_tax filter has been removed to avoid |
495
|
|
|
* these values being modified and then saved back to the DB. There are |
496
|
|
|
* other, later hooks available to change totals on display. e.g. |
497
|
|
|
* woocommerce_get_order_item_totals. |
498
|
|
|
* @param bool $raw Gets raw unfiltered value. |
499
|
|
|
* @return float |
500
|
|
|
*/ |
501
|
|
|
public function get_total_tax( $raw = false ) { |
502
|
|
|
$value = wc_format_decimal( $this->data['total_tax'] ); |
503
|
|
|
return $raw ? $value : apply_filters( 'woocommerce_order_amount_total_tax', $value, $this ); |
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
/** |
507
|
|
|
* Gets the total discount amount. |
508
|
|
|
* @param bool $ex_tax Show discount excl any tax. |
509
|
|
|
* @return float |
510
|
|
|
*/ |
511
|
|
|
public function get_total_discount( $ex_tax = true ) { |
512
|
|
|
if ( $ex_tax ) { |
513
|
|
|
$total_discount = $this->get_discount_total(); |
514
|
|
|
} else { |
515
|
|
|
$total_discount = $this->get_discount_total() + $this->get_discount_tax(); |
516
|
|
|
} |
517
|
|
|
return apply_filters( 'woocommerce_order_amount_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this ); |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* Gets order subtotal. |
522
|
|
|
* @return float |
523
|
|
|
*/ |
524
|
|
|
public function get_subtotal() { |
525
|
|
|
$subtotal = 0; |
526
|
|
|
|
527
|
|
|
foreach ( $this->get_items() as $item ) { |
528
|
|
|
$subtotal += $item->get_subtotal(); |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
return apply_filters( 'woocommerce_order_amount_subtotal', (double) $subtotal, $this ); |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Get taxes, merged by code, formatted ready for output. |
536
|
|
|
* |
537
|
|
|
* @return array |
538
|
|
|
*/ |
539
|
|
|
public function get_tax_totals() { |
540
|
|
|
$tax_totals = array(); |
541
|
|
|
|
542
|
|
|
foreach ( $this->get_items( 'tax' ) as $key => $tax ) { |
543
|
|
|
$code = $tax->get_rate_code(); |
544
|
|
|
|
545
|
|
View Code Duplication |
if ( ! isset( $tax_totals[ $code ] ) ) { |
|
|
|
|
546
|
|
|
$tax_totals[ $code ] = new stdClass(); |
547
|
|
|
$tax_totals[ $code ]->amount = 0; |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
$tax_totals[ $code ]->id = $key; |
551
|
|
|
$tax_totals[ $code ]->rate_id = $tax->get_rate_id(); |
552
|
|
|
$tax_totals[ $code ]->is_compound = $tax->is_compound(); |
553
|
|
|
$tax_totals[ $code ]->label = $tax->get_label(); |
554
|
|
|
$tax_totals[ $code ]->amount += $tax->get_tax_total() + $tax->get_shipping_tax_total(); |
555
|
|
|
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array( 'currency' => $this->get_currency() ) ); |
556
|
|
|
} |
557
|
|
|
|
558
|
|
View Code Duplication |
if ( apply_filters( 'woocommerce_order_hide_zero_taxes', true ) ) { |
|
|
|
|
559
|
|
|
$amounts = array_filter( wp_list_pluck( $tax_totals, 'amount' ) ); |
560
|
|
|
$tax_totals = array_intersect_key( $tax_totals, $amounts ); |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ); |
564
|
|
|
} |
565
|
|
|
|
566
|
|
|
/* |
567
|
|
|
|-------------------------------------------------------------------------- |
568
|
|
|
| Setters |
569
|
|
|
|-------------------------------------------------------------------------- |
570
|
|
|
| |
571
|
|
|
| Functions for setting order data. These should not update anything in the |
572
|
|
|
| database itself and should only change what is stored in the class |
573
|
|
|
| object. However, for backwards compatibility pre 2.7.0 some of these |
574
|
|
|
| setters may handle both. |
575
|
|
|
| |
576
|
|
|
*/ |
577
|
|
|
|
578
|
|
|
/** |
579
|
|
|
* Set parent order ID. |
580
|
|
|
* @since 2.7.0 |
581
|
|
|
* @param int $value |
582
|
|
|
* @throws WC_Data_Exception |
583
|
|
|
*/ |
584
|
|
|
public function set_parent_id( $value ) { |
585
|
|
|
if ( $value && ! get_post( $value ) ) { |
586
|
|
|
$this->error( 'order_invalid_parent_id', __( 'Invalid parent ID', 'woocommerce' ) ); |
587
|
|
|
} |
588
|
|
|
$this->data['parent_id'] = absint( $value ); |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* Set order status. |
593
|
|
|
* @since 2.7.0 |
594
|
|
|
* @param string $new_status Status to change the order to. No internal wc- prefix is required. |
595
|
|
|
* @return array details of change |
596
|
|
|
*/ |
597
|
|
|
public function set_status( $new_status ) { |
598
|
|
|
$old_status = $this->get_status(); |
599
|
|
|
$new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status; |
600
|
|
|
|
601
|
|
|
// Only allow valid new status |
602
|
|
|
if ( ! in_array( 'wc-' . $new_status, array_keys( wc_get_order_statuses() ) ) ) { |
603
|
|
|
$new_status = 'pending'; |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
$this->data['status'] = 'wc-' . $new_status; |
607
|
|
|
|
608
|
|
|
// If the old status is set but unknown (e.g. draft) assume its pending for action usage. |
609
|
|
|
if ( $old_status && ! in_array( 'wc-' . $old_status, array_keys( wc_get_order_statuses() ) ) ) { |
610
|
|
|
$old_status = 'pending'; |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
return array( |
614
|
|
|
'from' => $old_status, |
615
|
|
|
'to' => $new_status, |
616
|
|
|
); |
617
|
|
|
} |
618
|
|
|
|
619
|
|
|
/** |
620
|
|
|
* Set order_version |
621
|
|
|
* @param string $value |
622
|
|
|
* @throws WC_Data_Exception |
623
|
|
|
*/ |
624
|
|
|
public function set_version( $value ) { |
625
|
|
|
$this->data['version'] = $value; |
626
|
|
|
} |
627
|
|
|
|
628
|
|
|
/** |
629
|
|
|
* Set order_currency |
630
|
|
|
* @param string $value |
631
|
|
|
* @throws WC_Data_Exception |
632
|
|
|
*/ |
633
|
|
|
public function set_currency( $value ) { |
634
|
|
|
if ( $value && ! in_array( $value, array_keys( get_woocommerce_currencies() ) ) ) { |
635
|
|
|
$this->error( 'order_invalid_currency', __( 'Invalid currency code', 'woocommerce' ) ); |
636
|
|
|
} |
637
|
|
|
$this->data['currency'] = $value ? $value : get_woocommerce_currency(); |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
/** |
641
|
|
|
* Set prices_include_tax |
642
|
|
|
* @param bool $value |
643
|
|
|
* @throws WC_Data_Exception |
644
|
|
|
*/ |
645
|
|
|
public function set_prices_include_tax( $value ) { |
646
|
|
|
$this->data['prices_include_tax'] = (bool) $value; |
647
|
|
|
} |
648
|
|
|
|
649
|
|
|
/** |
650
|
|
|
* Set date_created |
651
|
|
|
* @param string $timestamp Timestamp |
652
|
|
|
* @throws WC_Data_Exception |
653
|
|
|
*/ |
654
|
|
|
public function set_date_created( $timestamp ) { |
655
|
|
|
$this->data['date_created'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp ); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* Set date_modified |
660
|
|
|
* @param string $timestamp |
661
|
|
|
* @throws WC_Data_Exception |
662
|
|
|
*/ |
663
|
|
|
public function set_date_modified( $timestamp ) { |
664
|
|
|
$this->data['date_modified'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp ); |
665
|
|
|
} |
666
|
|
|
|
667
|
|
|
/** |
668
|
|
|
* Set discount_total |
669
|
|
|
* @param string $value |
670
|
|
|
* @throws WC_Data_Exception |
671
|
|
|
*/ |
672
|
|
|
public function set_discount_total( $value ) { |
673
|
|
|
$this->data['discount_total'] = wc_format_decimal( $value ); |
674
|
|
|
} |
675
|
|
|
|
676
|
|
|
/** |
677
|
|
|
* Set discount_tax |
678
|
|
|
* @param string $value |
679
|
|
|
* @throws WC_Data_Exception |
680
|
|
|
*/ |
681
|
|
|
public function set_discount_tax( $value ) { |
682
|
|
|
$this->data['discount_tax'] = wc_format_decimal( $value ); |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* Set shipping_total |
687
|
|
|
* @param string $value |
688
|
|
|
* @throws WC_Data_Exception |
689
|
|
|
*/ |
690
|
|
|
public function set_shipping_total( $value ) { |
691
|
|
|
$this->data['shipping_total'] = wc_format_decimal( $value ); |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
/** |
695
|
|
|
* Set shipping_tax |
696
|
|
|
* @param string $value |
697
|
|
|
* @throws WC_Data_Exception |
698
|
|
|
*/ |
699
|
|
|
public function set_shipping_tax( $value ) { |
700
|
|
|
$this->data['shipping_tax'] = wc_format_decimal( $value ); |
701
|
|
|
$this->set_total_tax( $this->get_cart_tax() + $this->get_shipping_tax() ); |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
/** |
705
|
|
|
* Set cart tax |
706
|
|
|
* @param string $value |
707
|
|
|
* @throws WC_Data_Exception |
708
|
|
|
*/ |
709
|
|
|
public function set_cart_tax( $value ) { |
710
|
|
|
$this->data['cart_tax'] = wc_format_decimal( $value ); |
711
|
|
|
$this->set_total_tax( $this->get_cart_tax() + $this->get_shipping_tax() ); |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
/** |
715
|
|
|
* Sets order tax (sum of cart and shipping tax). Used internaly only. |
716
|
|
|
* @param string $value |
717
|
|
|
* @throws WC_Data_Exception |
718
|
|
|
*/ |
719
|
|
|
protected function set_total_tax( $value ) { |
720
|
|
|
$this->data['total_tax'] = wc_format_decimal( $value ); |
721
|
|
|
} |
722
|
|
|
|
723
|
|
|
/** |
724
|
|
|
* Set total |
725
|
|
|
* @param string $value |
726
|
|
|
* @param string $deprecated Function used to set different totals based on this. |
727
|
|
|
* @throws WC_Data_Exception |
728
|
|
|
*/ |
729
|
|
|
public function set_total( $value, $deprecated = '' ) { |
730
|
|
|
if ( $deprecated ) { |
731
|
|
|
_deprecated_argument( 'total_type', '2.7', 'Use dedicated total setter methods instead.' ); |
732
|
|
|
return $this->legacy_set_total( $value, $deprecated ); |
733
|
|
|
} |
734
|
|
|
$this->data['total'] = wc_format_decimal( $value, wc_get_price_decimals() ); |
735
|
|
|
} |
736
|
|
|
|
737
|
|
|
/* |
738
|
|
|
|-------------------------------------------------------------------------- |
739
|
|
|
| Order Item Handling |
740
|
|
|
|-------------------------------------------------------------------------- |
741
|
|
|
| |
742
|
|
|
| Order items are used for products, taxes, shipping, and fees within |
743
|
|
|
| each order. |
744
|
|
|
| |
745
|
|
|
*/ |
746
|
|
|
|
747
|
|
|
/** |
748
|
|
|
* Remove all line items (products, coupons, shipping, taxes) from the order. |
749
|
|
|
* @param string $type Order item type. Default null. |
750
|
|
|
*/ |
751
|
|
|
public function remove_order_items( $type = null ) { |
752
|
|
|
global $wpdb; |
753
|
|
|
if ( ! empty( $type ) ) { |
754
|
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id AND items.order_id = %d AND items.order_item_type = %s", $this->get_id(), $type ) ); |
755
|
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->get_id(), $type ) ); |
756
|
|
|
if ( $group = $this->type_to_group( $type ) ) { |
757
|
|
|
$this->items[ $group ] = null; |
758
|
|
|
} |
759
|
|
|
} else { |
760
|
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id and items.order_id = %d", $this->get_id() ) ); |
761
|
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->get_id() ) ); |
762
|
|
|
$this->items = array( |
763
|
|
|
'line_items' => null, |
764
|
|
|
'coupon_lines' => null, |
765
|
|
|
'shipping_lines' => null, |
766
|
|
|
'fee_lines' => null, |
767
|
|
|
'tax_lines' => null, |
768
|
|
|
); |
769
|
|
|
} |
770
|
|
|
} |
771
|
|
|
|
772
|
|
|
/** |
773
|
|
|
* Convert a type to a types group. |
774
|
|
|
* @param string $type |
775
|
|
|
* @return string group |
776
|
|
|
*/ |
777
|
|
|
protected function type_to_group( $type ) { |
778
|
|
|
$type_to_group = array( |
779
|
|
|
'line_item' => 'line_items', |
780
|
|
|
'tax' => 'tax_lines', |
781
|
|
|
'shipping' => 'shipping_lines', |
782
|
|
|
'fee' => 'fee_lines', |
783
|
|
|
'coupon' => 'coupon_lines', |
784
|
|
|
); |
785
|
|
|
return isset( $type_to_group[ $type ] ) ? $type_to_group[ $type ] : ''; |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
/** |
789
|
|
|
* Return an array of items/products within this order. |
790
|
|
|
* @param string|array $types Types of line items to get (array or string). |
791
|
|
|
* @return Array of WC_Order_item |
792
|
|
|
*/ |
793
|
|
|
public function get_items( $types = 'line_item' ) { |
794
|
|
|
$items = array(); |
795
|
|
|
$types = array_filter( (array) $types ); |
796
|
|
|
|
797
|
|
|
foreach ( $types as $type ) { |
798
|
|
|
if ( $group = $this->type_to_group( $type ) ) { |
799
|
|
|
if ( is_null( $this->items[ $group ] ) ) { |
800
|
|
|
$this->items[ $group ] = $this->get_items_from_db( $type ); |
801
|
|
|
} |
802
|
|
|
// Don't use array_merge here because keys are numeric |
803
|
|
|
$items = $items + $this->items[ $group ]; |
804
|
|
|
} |
805
|
|
|
} |
806
|
|
|
|
807
|
|
|
return apply_filters( 'woocommerce_order_get_items', $items, $this ); |
808
|
|
|
} |
809
|
|
|
|
810
|
|
|
/** |
811
|
|
|
* Gets items from the database by type. |
812
|
|
|
* @param string $type |
813
|
|
|
* @return array |
814
|
|
|
*/ |
815
|
|
|
protected function get_items_from_db( $type ) { |
816
|
|
|
global $wpdb; |
817
|
|
|
|
818
|
|
|
$get_items_sql = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s ORDER BY order_item_id;", $this->get_id(), $type ); |
819
|
|
|
$items = $wpdb->get_results( $get_items_sql ); |
820
|
|
|
|
821
|
|
|
if ( ! empty( $items ) ) { |
822
|
|
|
$items = array_map( array( $this, 'get_item' ), array_combine( wp_list_pluck( $items, 'order_item_id' ), $items ) ); |
823
|
|
|
} else { |
824
|
|
|
$items = array(); |
825
|
|
|
} |
826
|
|
|
|
827
|
|
|
return $items; |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
/** |
831
|
|
|
* Return an array of fees within this order. |
832
|
|
|
* @return array |
833
|
|
|
*/ |
834
|
|
|
public function get_fees() { |
835
|
|
|
return $this->get_items( 'fee' ); |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
/** |
839
|
|
|
* Return an array of taxes within this order. |
840
|
|
|
* @return array |
841
|
|
|
*/ |
842
|
|
|
public function get_taxes() { |
843
|
|
|
return $this->get_items( 'tax' ); |
844
|
|
|
} |
845
|
|
|
|
846
|
|
|
/** |
847
|
|
|
* Return an array of shipping costs within this order. |
848
|
|
|
* @return array |
849
|
|
|
*/ |
850
|
|
|
public function get_shipping_methods() { |
851
|
|
|
return $this->get_items( 'shipping' ); |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
/** |
855
|
|
|
* Gets formatted shipping method title. |
856
|
|
|
* @return string |
857
|
|
|
*/ |
858
|
|
|
public function get_shipping_method() { |
859
|
|
|
$names = array(); |
860
|
|
|
foreach ( $this->get_shipping_methods() as $shipping_method ) { |
861
|
|
|
$names[] = $shipping_method->get_name(); |
862
|
|
|
} |
863
|
|
|
return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $names ), $this ); |
864
|
|
|
} |
865
|
|
|
|
866
|
|
|
/** |
867
|
|
|
* Get coupon codes only. |
868
|
|
|
* @return array |
869
|
|
|
*/ |
870
|
|
|
public function get_used_coupons() { |
871
|
|
|
$coupon_codes = array(); |
872
|
|
|
if ( $coupons = $this->get_items( 'coupon' ) ) { |
873
|
|
|
foreach ( $coupons as $coupon ) { |
874
|
|
|
$coupon_codes[] = $coupon->get_code(); |
875
|
|
|
} |
876
|
|
|
} |
877
|
|
|
return $coupon_codes; |
878
|
|
|
} |
879
|
|
|
|
880
|
|
|
/** |
881
|
|
|
* Gets the count of order items of a certain type. |
882
|
|
|
* |
883
|
|
|
* @param string $item_type |
884
|
|
|
* @return string |
885
|
|
|
*/ |
886
|
|
|
public function get_item_count( $item_type = '' ) { |
887
|
|
|
$items = $this->get_items( empty( $item_type ) ? 'line_item' : $item_type ); |
888
|
|
|
$count = 0; |
889
|
|
|
|
890
|
|
|
foreach ( $items as $item ) { |
891
|
|
|
$count += $item->get_quantity(); |
892
|
|
|
} |
893
|
|
|
|
894
|
|
|
return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this ); |
895
|
|
|
} |
896
|
|
|
|
897
|
|
|
/** |
898
|
|
|
* Get an order item object, based on it's type. |
899
|
|
|
* @since 2.7.0 |
900
|
|
|
* @param int $item_id |
901
|
|
|
* @return WC_Order_Item |
902
|
|
|
*/ |
903
|
|
|
public function get_item( $item_id ) { |
904
|
|
|
return WC_Order_Factory::get_order_item( $item_id ); |
905
|
|
|
} |
906
|
|
|
|
907
|
|
|
/** |
908
|
|
|
* Get key for where a certain item type is stored in _items. |
909
|
|
|
* @since 2.7.0 |
910
|
|
|
* @param $item object Order item (product, shipping, fee, coupon, tax) |
911
|
|
|
* @return string |
912
|
|
|
*/ |
913
|
|
|
protected function get_items_key( $item ) { |
914
|
|
|
if ( is_a( $item, 'WC_Order_Item_Product' ) ) { |
915
|
|
|
return 'line_items'; |
916
|
|
|
} elseif ( is_a( $item, 'WC_Order_Item_Fee' ) ) { |
917
|
|
|
return 'fee_lines'; |
918
|
|
|
} elseif ( is_a( $item, 'WC_Order_Item_Shipping' ) ) { |
919
|
|
|
return 'shipping_lines'; |
920
|
|
|
} elseif ( is_a( $item, 'WC_Order_Item_Tax' ) ) { |
921
|
|
|
return 'tax_lines'; |
922
|
|
|
} elseif ( is_a( $item, 'WC_Order_Item_Coupon' ) ) { |
923
|
|
|
return 'coupon_lines'; |
924
|
|
|
} else { |
925
|
|
|
return ''; |
926
|
|
|
} |
927
|
|
|
} |
928
|
|
|
|
929
|
|
|
/** |
930
|
|
|
* Remove item from the order. |
931
|
|
|
* @param int $item_id |
932
|
|
|
*/ |
933
|
|
|
public function remove_item( $item_id ) { |
934
|
|
|
$item = $this->get_item( $item_id ); |
935
|
|
|
|
936
|
|
|
if ( ! $item || ! ( $items_key = $this->get_items_key( $item ) ) ) { |
937
|
|
|
return false; |
938
|
|
|
} |
939
|
|
|
|
940
|
|
|
// Unset and remove later |
941
|
|
|
$this->items_to_delete[] = $item; |
942
|
|
|
unset( $this->items[ $items_key ][ $item->get_id() ] ); |
943
|
|
|
} |
944
|
|
|
|
945
|
|
|
/** |
946
|
|
|
* Adds an order item to this order. The order item will not persist until save. |
947
|
|
|
* @since 2.7.0 |
948
|
|
|
* @param WC_Order_Item Order item object (product, shipping, fee, coupon, tax) |
949
|
|
|
*/ |
950
|
|
|
public function add_item( $item ) { |
951
|
|
|
if ( ! $items_key = $this->get_items_key( $item ) ) { |
952
|
|
|
return false; |
953
|
|
|
} |
954
|
|
|
|
955
|
|
|
// Make sure existing items are loaded so we can append this new one. |
956
|
|
|
if ( is_null( $this->items[ $items_key ] ) ) { |
957
|
|
|
$this->items[ $items_key ] = $this->get_items( $item->get_type() ); |
958
|
|
|
} |
959
|
|
|
|
960
|
|
|
// Append new row with generated temporary ID |
961
|
|
|
if ( $item->get_id() ) { |
962
|
|
|
$this->items[ $items_key ][ $item->get_id() ] = $item; |
963
|
|
|
} else { |
964
|
|
|
$this->items[ $items_key ][ 'new:' . sizeof( $this->items[ $items_key ] ) ] = $item; |
965
|
|
|
} |
966
|
|
|
} |
967
|
|
|
|
968
|
|
|
/** |
969
|
|
|
* Add a product line item to the order. This is the only line item type with |
970
|
|
|
* it's own method because it saves looking up order amounts (costs are added up for you). |
971
|
|
|
* @param \WC_Product $product |
972
|
|
|
* @param int $qty |
973
|
|
|
* @param array $args |
974
|
|
|
* @return int order item ID |
975
|
|
|
* @throws WC_Data_Exception |
976
|
|
|
*/ |
977
|
|
|
public function add_product( $product, $qty = 1, $args = array() ) { |
978
|
|
|
if ( $product ) { |
979
|
|
|
$default_args = array( |
980
|
|
|
'name' => $product->get_title(), |
981
|
|
|
'tax_class' => $product->get_tax_class(), |
982
|
|
|
'product_id' => $product->get_id(), |
983
|
|
|
'variation_id' => isset( $product->variation_id ) ? $product->variation_id : 0, |
984
|
|
|
'variation' => isset( $product->variation_id ) ? $product->get_variation_attributes() : array(), |
|
|
|
|
985
|
|
|
'subtotal' => $product->get_price_excluding_tax( $qty ), |
986
|
|
|
'total' => $product->get_price_excluding_tax( $qty ), |
987
|
|
|
'quantity' => $qty, |
988
|
|
|
); |
989
|
|
|
} else { |
990
|
|
|
$default_args = array( |
991
|
|
|
'quantity' => $qty, |
992
|
|
|
); |
993
|
|
|
} |
994
|
|
|
|
995
|
|
|
$args = wp_parse_args( $args, $default_args ); |
996
|
|
|
|
997
|
|
|
// BW compatibility with old args |
998
|
|
View Code Duplication |
if ( isset( $args['totals'] ) ) { |
|
|
|
|
999
|
|
|
foreach ( $args['totals'] as $key => $value ) { |
1000
|
|
|
if ( 'tax' === $key ) { |
1001
|
|
|
$args['total_tax'] = $value; |
1002
|
|
|
} elseif ( 'tax_data' === $key ) { |
1003
|
|
|
$args['taxes'] = $value; |
1004
|
|
|
} else { |
1005
|
|
|
$args[ $key ] = $value; |
1006
|
|
|
} |
1007
|
|
|
} |
1008
|
|
|
} |
1009
|
|
|
|
1010
|
|
|
$item = new WC_Order_Item_Product( $args ); |
1011
|
|
|
$item->set_backorder_meta(); |
1012
|
|
|
$item->set_order_id( $this->get_id() ); |
1013
|
|
|
$item->save(); |
1014
|
|
|
$this->add_item( $item ); |
1015
|
|
|
wc_do_deprecated_action( 'woocommerce_order_add_product', array( $this->get_id(), $item->get_id(), $product, $qty, $args ), '2.7', 'Use woocommerce_new_order_item action instead.' ); |
1016
|
|
|
return $item->get_id(); |
1017
|
|
|
} |
1018
|
|
|
|
1019
|
|
|
/* |
1020
|
|
|
|-------------------------------------------------------------------------- |
1021
|
|
|
| Payment Token Handling |
1022
|
|
|
|-------------------------------------------------------------------------- |
1023
|
|
|
| |
1024
|
|
|
| Payment tokens are hashes used to take payments by certain gateways. |
1025
|
|
|
| |
1026
|
|
|
*/ |
1027
|
|
|
|
1028
|
|
|
/** |
1029
|
|
|
* Add a payment token to an order |
1030
|
|
|
* |
1031
|
|
|
* @since 2.6 |
1032
|
|
|
* @param WC_Payment_Token $token Payment token object |
1033
|
|
|
* @return boolean|int The new token ID or false if it failed. |
1034
|
|
|
*/ |
1035
|
|
|
public function add_payment_token( $token ) { |
1036
|
|
|
if ( empty( $token ) || ! ( $token instanceof WC_Payment_Token ) ) { |
1037
|
|
|
return false; |
1038
|
|
|
} |
1039
|
|
|
|
1040
|
|
|
$token_ids = get_post_meta( $this->get_id(), '_payment_tokens', true ); |
1041
|
|
|
|
1042
|
|
|
if ( empty( $token_ids ) ) { |
1043
|
|
|
$token_ids = array(); |
1044
|
|
|
} |
1045
|
|
|
|
1046
|
|
|
$token_ids[] = $token->get_id(); |
1047
|
|
|
|
1048
|
|
|
update_post_meta( $this->get_id(), '_payment_tokens', $token_ids ); |
1049
|
|
|
do_action( 'woocommerce_payment_token_added_to_order', $this->get_id(), $token->get_id(), $token, $token_ids ); |
1050
|
|
|
return $token->get_id(); |
1051
|
|
|
} |
1052
|
|
|
|
1053
|
|
|
/** |
1054
|
|
|
* Returns a list of all payment tokens associated with the current order |
1055
|
|
|
* |
1056
|
|
|
* @since 2.6 |
1057
|
|
|
* @return array An array of payment token objects |
1058
|
|
|
*/ |
1059
|
|
|
public function get_payment_tokens() { |
1060
|
|
|
return WC_Payment_Tokens::get_order_tokens( $this->get_id() ); |
1061
|
|
|
} |
1062
|
|
|
|
1063
|
|
|
/* |
1064
|
|
|
|-------------------------------------------------------------------------- |
1065
|
|
|
| Calculations. |
1066
|
|
|
|-------------------------------------------------------------------------- |
1067
|
|
|
| |
1068
|
|
|
| These methods calculate order totals and taxes based on the current data. |
1069
|
|
|
| |
1070
|
|
|
*/ |
1071
|
|
|
|
1072
|
|
|
/** |
1073
|
|
|
* Calculate shipping total. |
1074
|
|
|
* |
1075
|
|
|
* @since 2.2 |
1076
|
|
|
* @return float |
1077
|
|
|
*/ |
1078
|
|
|
public function calculate_shipping() { |
1079
|
|
|
$shipping_total = 0; |
1080
|
|
|
|
1081
|
|
|
foreach ( $this->get_shipping_methods() as $shipping ) { |
1082
|
|
|
$shipping_total += $shipping->get_total(); |
1083
|
|
|
} |
1084
|
|
|
|
1085
|
|
|
$this->set_shipping_total( $shipping_total ); |
1086
|
|
|
$this->save(); |
1087
|
|
|
|
1088
|
|
|
return $this->get_shipping_total(); |
1089
|
|
|
} |
1090
|
|
|
|
1091
|
|
|
/** |
1092
|
|
|
* Get all tax classes for items in the order. |
1093
|
|
|
* |
1094
|
|
|
* @since 2.6.3 |
1095
|
|
|
* @return array |
1096
|
|
|
*/ |
1097
|
|
|
public function get_items_tax_classes() { |
1098
|
|
|
$found_tax_classes = array(); |
1099
|
|
|
|
1100
|
|
|
foreach ( $this->get_items() as $item ) { |
1101
|
|
|
if ( $_product = $item->get_product() ) { |
1102
|
|
|
$found_tax_classes[] = $_product->get_tax_class(); |
1103
|
|
|
} |
1104
|
|
|
} |
1105
|
|
|
|
1106
|
|
|
return array_unique( $found_tax_classes ); |
1107
|
|
|
} |
1108
|
|
|
|
1109
|
|
|
/** |
1110
|
|
|
* Calculate taxes for all line items and shipping, and store the totals and tax rows. |
1111
|
|
|
* |
1112
|
|
|
* Will use the base country unless customer addresses are set. |
1113
|
|
|
* @param $args array Added in 2.7.0 to pass things like location. |
1114
|
|
|
*/ |
1115
|
|
|
public function calculate_taxes( $args = array() ) { |
1116
|
|
|
$tax_based_on = get_option( 'woocommerce_tax_based_on' ); |
1117
|
|
|
$args = wp_parse_args( $args, array( |
1118
|
|
|
'country' => 'billing' === $tax_based_on ? $this->get_billing_country() : $this->get_shipping_country(), |
|
|
|
|
1119
|
|
|
'state' => 'billing' === $tax_based_on ? $this->get_billing_state() : $this->get_shipping_state(), |
|
|
|
|
1120
|
|
|
'postcode' => 'billing' === $tax_based_on ? $this->get_billing_postcode() : $this->get_shipping_postcode(), |
|
|
|
|
1121
|
|
|
'city' => 'billing' === $tax_based_on ? $this->get_billing_city() : $this->get_shipping_city(), |
|
|
|
|
1122
|
|
|
) ); |
1123
|
|
|
|
1124
|
|
|
// Default to base |
1125
|
|
|
if ( 'base' === $tax_based_on || empty( $args['country'] ) ) { |
1126
|
|
|
$default = wc_get_base_location(); |
1127
|
|
|
$args['country'] = $default['country']; |
1128
|
|
|
$args['state'] = $default['state']; |
1129
|
|
|
$args['postcode'] = ''; |
1130
|
|
|
$args['city'] = ''; |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
|
|
// Calc taxes for line items |
1134
|
|
|
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { |
1135
|
|
|
$tax_class = $item->get_tax_class(); |
1136
|
|
|
$tax_status = $item->get_tax_status(); |
1137
|
|
|
|
1138
|
|
|
if ( '0' !== $tax_class && 'taxable' === $tax_status ) { |
1139
|
|
|
$tax_rates = WC_Tax::find_rates( array( |
1140
|
|
|
'country' => $args['country'], |
1141
|
|
|
'state' => $args['state'], |
1142
|
|
|
'postcode' => $args['postcode'], |
1143
|
|
|
'city' => $args['city'], |
1144
|
|
|
'tax_class' => $tax_class, |
1145
|
|
|
) ); |
1146
|
|
|
|
1147
|
|
|
$total = $item->get_total(); |
1148
|
|
|
$taxes = WC_Tax::calc_tax( $total, $tax_rates, false ); |
1149
|
|
|
|
1150
|
|
|
if ( $item->is_type( 'line_item' ) ) { |
1151
|
|
|
$subtotal = $item->get_subtotal(); |
1152
|
|
|
$subtotal_taxes = WC_Tax::calc_tax( $subtotal, $tax_rates, false ); |
1153
|
|
|
$item->set_taxes( array( 'total' => $taxes, 'subtotal' => $subtotal_taxes ) ); |
1154
|
|
|
} else { |
1155
|
|
|
$item->set_taxes( array( 'total' => $taxes ) ); |
1156
|
|
|
} |
1157
|
|
|
$item->save(); |
1158
|
|
|
} |
1159
|
|
|
} |
1160
|
|
|
|
1161
|
|
|
// Calc taxes for shipping |
1162
|
|
|
foreach ( $this->get_shipping_methods() as $item_id => $item ) { |
1163
|
|
|
$shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' ); |
1164
|
|
|
|
1165
|
|
|
// Inherit tax class from items |
1166
|
|
|
if ( '' === $shipping_tax_class ) { |
1167
|
|
|
$tax_rates = array(); |
1168
|
|
|
$tax_classes = array_merge( array( '' ), WC_Tax::get_tax_classes() ); |
1169
|
|
|
$found_tax_classes = $this->get_items_tax_classes(); |
1170
|
|
|
|
1171
|
|
|
foreach ( $tax_classes as $tax_class ) { |
1172
|
|
|
$tax_class = sanitize_title( $tax_class ); |
1173
|
|
|
if ( in_array( $tax_class, $found_tax_classes ) ) { |
1174
|
|
|
$tax_rates = WC_Tax::find_shipping_rates( array( |
1175
|
|
|
'country' => $args['country'], |
1176
|
|
|
'state' => $args['state'], |
1177
|
|
|
'postcode' => $args['postcode'], |
1178
|
|
|
'city' => $args['city'], |
1179
|
|
|
'tax_class' => $tax_class, |
1180
|
|
|
) ); |
1181
|
|
|
break; |
1182
|
|
|
} |
1183
|
|
|
} |
1184
|
|
|
} else { |
1185
|
|
|
$tax_rates = WC_Tax::find_shipping_rates( array( |
1186
|
|
|
'country' => $args['country'], |
1187
|
|
|
'state' => $args['state'], |
1188
|
|
|
'postcode' => $args['postcode'], |
1189
|
|
|
'city' => $args['city'], |
1190
|
|
|
'tax_class' => 'standard' === $shipping_tax_class ? '' : $shipping_tax_class, |
1191
|
|
|
) ); |
1192
|
|
|
} |
1193
|
|
|
|
1194
|
|
|
$item->set_taxes( array( 'total' => WC_Tax::calc_tax( $item->get_total(), $tax_rates, false ) ) ); |
1195
|
|
|
$item->save(); |
1196
|
|
|
} |
1197
|
|
|
$this->update_taxes(); |
1198
|
|
|
} |
1199
|
|
|
|
1200
|
|
|
/** |
1201
|
|
|
* Update tax lines for the order based on the line item taxes themselves. |
1202
|
|
|
*/ |
1203
|
|
|
public function update_taxes() { |
1204
|
|
|
$cart_taxes = array(); |
1205
|
|
|
$shipping_taxes = array(); |
1206
|
|
|
|
1207
|
|
|
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { |
1208
|
|
|
$taxes = $item->get_taxes(); |
1209
|
|
View Code Duplication |
foreach ( $taxes['total'] as $tax_rate_id => $tax ) { |
|
|
|
|
1210
|
|
|
$cart_taxes[ $tax_rate_id ] = isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] + $tax : $tax; |
1211
|
|
|
} |
1212
|
|
|
} |
1213
|
|
|
|
1214
|
|
|
foreach ( $this->get_shipping_methods() as $item_id => $item ) { |
1215
|
|
|
$taxes = $item->get_taxes(); |
1216
|
|
View Code Duplication |
foreach ( $taxes['total'] as $tax_rate_id => $tax ) { |
|
|
|
|
1217
|
|
|
$shipping_taxes[ $tax_rate_id ] = isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] + $tax : $tax; |
1218
|
|
|
} |
1219
|
|
|
} |
1220
|
|
|
|
1221
|
|
|
// Remove old existing tax rows. |
1222
|
|
|
$this->remove_order_items( 'tax' ); |
1223
|
|
|
|
1224
|
|
|
// Now merge to keep tax rows. |
1225
|
|
|
foreach ( array_keys( $cart_taxes + $shipping_taxes ) as $tax_rate_id ) { |
1226
|
|
|
$item = new WC_Order_Item_Tax(); |
1227
|
|
|
$item->set_rate( $tax_rate_id ); |
1228
|
|
|
$item->set_tax_total( isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] : 0 ); |
1229
|
|
|
$item->set_shipping_tax_total( isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 ); |
1230
|
|
|
$this->add_item( $item ); |
1231
|
|
|
} |
1232
|
|
|
|
1233
|
|
|
// Save tax totals |
1234
|
|
|
$this->set_shipping_tax( WC_Tax::round( array_sum( $shipping_taxes ) ) ); |
1235
|
|
|
$this->set_cart_tax( WC_Tax::round( array_sum( $cart_taxes ) ) ); |
1236
|
|
|
$this->save(); |
1237
|
|
|
} |
1238
|
|
|
|
1239
|
|
|
/** |
1240
|
|
|
* Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total. |
1241
|
|
|
* |
1242
|
|
|
* @since 2.2 |
1243
|
|
|
* @param bool $and_taxes Calc taxes if true. |
1244
|
|
|
* @return float calculated grand total. |
1245
|
|
|
*/ |
1246
|
|
|
public function calculate_totals( $and_taxes = true ) { |
1247
|
|
|
$cart_subtotal = 0; |
1248
|
|
|
$cart_total = 0; |
1249
|
|
|
$fee_total = 0; |
1250
|
|
|
$cart_subtotal_tax = 0; |
1251
|
|
|
$cart_total_tax = 0; |
1252
|
|
|
|
1253
|
|
|
if ( $and_taxes && wc_tax_enabled() ) { |
1254
|
|
|
$this->calculate_taxes(); |
1255
|
|
|
} |
1256
|
|
|
|
1257
|
|
|
// line items |
1258
|
|
|
foreach ( $this->get_items() as $item ) { |
1259
|
|
|
$cart_subtotal += $item->get_subtotal(); |
1260
|
|
|
$cart_total += $item->get_total(); |
1261
|
|
|
$cart_subtotal_tax += $item->get_subtotal_tax(); |
1262
|
|
|
$cart_total_tax += $item->get_total_tax(); |
1263
|
|
|
} |
1264
|
|
|
|
1265
|
|
|
$this->calculate_shipping(); |
1266
|
|
|
|
1267
|
|
|
foreach ( $this->get_fees() as $item ) { |
1268
|
|
|
$fee_total += $item->get_total(); |
1269
|
|
|
} |
1270
|
|
|
|
1271
|
|
|
$grand_total = round( $cart_total + $fee_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ); |
1272
|
|
|
|
1273
|
|
|
$this->set_discount_total( $cart_subtotal - $cart_total ); |
1274
|
|
|
$this->set_discount_tax( $cart_subtotal_tax - $cart_total_tax ); |
1275
|
|
|
$this->set_total( $grand_total ); |
1276
|
|
|
$this->save(); |
1277
|
|
|
|
1278
|
|
|
return $grand_total; |
1279
|
|
|
} |
1280
|
|
|
|
1281
|
|
|
/** |
1282
|
|
|
* Get item subtotal - this is the cost before discount. |
1283
|
|
|
* |
1284
|
|
|
* @param object $item |
1285
|
|
|
* @param bool $inc_tax (default: false). |
1286
|
|
|
* @param bool $round (default: true). |
1287
|
|
|
* @return float |
1288
|
|
|
*/ |
1289
|
|
View Code Duplication |
public function get_item_subtotal( $item, $inc_tax = false, $round = true ) { |
|
|
|
|
1290
|
|
|
$subtotal = 0; |
1291
|
|
|
|
1292
|
|
|
if ( is_callable( array( $item, 'get_subtotal' ) ) ) { |
1293
|
|
|
if ( $inc_tax ) { |
1294
|
|
|
$subtotal = ( $item->get_subtotal() + $item->get_subtotal_tax() ) / max( 1, $item->get_quantity() ); |
1295
|
|
|
} else { |
1296
|
|
|
$subtotal = ( $item->get_subtotal() / max( 1, $item->get_quantity() ) ); |
1297
|
|
|
} |
1298
|
|
|
|
1299
|
|
|
$subtotal = $round ? number_format( (float) $subtotal, wc_get_price_decimals(), '.', '' ) : $subtotal; |
1300
|
|
|
} |
1301
|
|
|
|
1302
|
|
|
return apply_filters( 'woocommerce_order_amount_item_subtotal', $subtotal, $this, $item, $inc_tax, $round ); |
1303
|
|
|
} |
1304
|
|
|
|
1305
|
|
|
/** |
1306
|
|
|
* Get line subtotal - this is the cost before discount. |
1307
|
|
|
* |
1308
|
|
|
* @param object $item |
1309
|
|
|
* @param bool $inc_tax (default: false). |
1310
|
|
|
* @param bool $round (default: true). |
1311
|
|
|
* @return float |
1312
|
|
|
*/ |
1313
|
|
View Code Duplication |
public function get_line_subtotal( $item, $inc_tax = false, $round = true ) { |
|
|
|
|
1314
|
|
|
$subtotal = 0; |
1315
|
|
|
|
1316
|
|
|
if ( is_callable( array( $item, 'get_subtotal' ) ) ) { |
1317
|
|
|
if ( $inc_tax ) { |
1318
|
|
|
$subtotal = $item->get_subtotal() + $item->get_subtotal_tax(); |
1319
|
|
|
} else { |
1320
|
|
|
$subtotal = $item->get_subtotal(); |
1321
|
|
|
} |
1322
|
|
|
|
1323
|
|
|
$subtotal = $round ? round( $subtotal, wc_get_price_decimals() ) : $subtotal; |
1324
|
|
|
} |
1325
|
|
|
|
1326
|
|
|
return apply_filters( 'woocommerce_order_amount_line_subtotal', $subtotal, $this, $item, $inc_tax, $round ); |
1327
|
|
|
} |
1328
|
|
|
|
1329
|
|
|
/** |
1330
|
|
|
* Calculate item cost - useful for gateways. |
1331
|
|
|
* |
1332
|
|
|
* @param object $item |
1333
|
|
|
* @param bool $inc_tax (default: false). |
1334
|
|
|
* @param bool $round (default: true). |
1335
|
|
|
* @return float |
1336
|
|
|
*/ |
1337
|
|
View Code Duplication |
public function get_item_total( $item, $inc_tax = false, $round = true ) { |
|
|
|
|
1338
|
|
|
$total = 0; |
1339
|
|
|
|
1340
|
|
|
if ( is_callable( array( $item, 'get_total' ) ) ) { |
1341
|
|
|
if ( $inc_tax ) { |
1342
|
|
|
$total = ( $item->get_total() + $item->get_total_tax() ) / max( 1, $item->get_quantity() ); |
1343
|
|
|
} else { |
1344
|
|
|
$total = $item->get_total() / max( 1, $item->get_quantity() ); |
1345
|
|
|
} |
1346
|
|
|
|
1347
|
|
|
$total = $round ? round( $total, wc_get_price_decimals() ) : $total; |
1348
|
|
|
} |
1349
|
|
|
|
1350
|
|
|
return apply_filters( 'woocommerce_order_amount_item_total', $total, $this, $item, $inc_tax, $round ); |
1351
|
|
|
} |
1352
|
|
|
|
1353
|
|
|
/** |
1354
|
|
|
* Calculate line total - useful for gateways. |
1355
|
|
|
* |
1356
|
|
|
* @param object $item |
1357
|
|
|
* @param bool $inc_tax (default: false). |
1358
|
|
|
* @param bool $round (default: true). |
1359
|
|
|
* @return float |
1360
|
|
|
*/ |
1361
|
|
View Code Duplication |
public function get_line_total( $item, $inc_tax = false, $round = true ) { |
|
|
|
|
1362
|
|
|
$total = 0; |
1363
|
|
|
|
1364
|
|
|
if ( is_callable( array( $item, 'get_total' ) ) ) { |
1365
|
|
|
// Check if we need to add line tax to the line total. |
1366
|
|
|
$total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total(); |
1367
|
|
|
|
1368
|
|
|
// Check if we need to round. |
1369
|
|
|
$total = $round ? round( $total, wc_get_price_decimals() ) : $total; |
1370
|
|
|
} |
1371
|
|
|
|
1372
|
|
|
return apply_filters( 'woocommerce_order_amount_line_total', $total, $this, $item, $inc_tax, $round ); |
1373
|
|
|
} |
1374
|
|
|
|
1375
|
|
|
/** |
1376
|
|
|
* Get item tax - useful for gateways. |
1377
|
|
|
* |
1378
|
|
|
* @param mixed $item |
1379
|
|
|
* @param bool $round (default: true). |
1380
|
|
|
* @return float |
1381
|
|
|
*/ |
1382
|
|
|
public function get_item_tax( $item, $round = true ) { |
1383
|
|
|
$tax = 0; |
1384
|
|
|
|
1385
|
|
|
if ( is_callable( array( $item, 'get_total_tax' ) ) ) { |
1386
|
|
|
$tax = $item->get_total_tax() / max( 1, $item->get_quantity() ); |
1387
|
|
|
$tax = $round ? wc_round_tax_total( $tax ) : $tax; |
1388
|
|
|
} |
1389
|
|
|
|
1390
|
|
|
return apply_filters( 'woocommerce_order_amount_item_tax', $tax, $item, $round, $this ); |
1391
|
|
|
} |
1392
|
|
|
|
1393
|
|
|
/** |
1394
|
|
|
* Get line tax - useful for gateways. |
1395
|
|
|
* |
1396
|
|
|
* @param mixed $item |
1397
|
|
|
* @return float |
1398
|
|
|
*/ |
1399
|
|
|
public function get_line_tax( $item ) { |
1400
|
|
|
return apply_filters( 'woocommerce_order_amount_line_tax', is_callable( array( $item, 'get_total_tax' ) ) ? wc_round_tax_total( $item->get_total_tax() ) : 0, $item, $this ); |
1401
|
|
|
} |
1402
|
|
|
|
1403
|
|
|
/** |
1404
|
|
|
* Gets line subtotal - formatted for display. |
1405
|
|
|
* |
1406
|
|
|
* @param array $item |
1407
|
|
|
* @param string $tax_display |
1408
|
|
|
* @return string |
1409
|
|
|
*/ |
1410
|
|
|
public function get_formatted_line_subtotal( $item, $tax_display = '' ) { |
1411
|
|
|
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); |
1412
|
|
|
|
1413
|
|
|
if ( 'excl' == $tax_display ) { |
1414
|
|
|
$ex_tax_label = $this->get_prices_include_tax() ? 1 : 0; |
1415
|
|
|
|
1416
|
|
|
$subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_currency() ) ); |
|
|
|
|
1417
|
|
|
} else { |
1418
|
|
|
$subtotal = wc_price( $this->get_line_subtotal( $item, true ), array( 'currency' => $this->get_currency() ) ); |
|
|
|
|
1419
|
|
|
} |
1420
|
|
|
|
1421
|
|
|
return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this ); |
1422
|
|
|
} |
1423
|
|
|
|
1424
|
|
|
/** |
1425
|
|
|
* Gets order total - formatted for display. |
1426
|
|
|
* @return string |
1427
|
|
|
*/ |
1428
|
|
|
public function get_formatted_order_total() { |
1429
|
|
|
$formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_currency() ) ); |
1430
|
|
|
return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this ); |
1431
|
|
|
} |
1432
|
|
|
|
1433
|
|
|
/** |
1434
|
|
|
* Gets subtotal - subtotal is shown before discounts, but with localised taxes. |
1435
|
|
|
* |
1436
|
|
|
* @param bool $compound (default: false). |
1437
|
|
|
* @param string $tax_display (default: the tax_display_cart value). |
1438
|
|
|
* @return string |
1439
|
|
|
*/ |
1440
|
|
|
public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { |
1441
|
|
|
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); |
1442
|
|
|
$subtotal = 0; |
1443
|
|
|
|
1444
|
|
|
if ( ! $compound ) { |
1445
|
|
|
foreach ( $this->get_items() as $item ) { |
1446
|
|
|
$subtotal += $item->get_subtotal(); |
1447
|
|
|
|
1448
|
|
|
if ( 'incl' === $tax_display ) { |
1449
|
|
|
$subtotal += $item->get_subtotal_tax(); |
1450
|
|
|
} |
1451
|
|
|
} |
1452
|
|
|
|
1453
|
|
|
$subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) ); |
1454
|
|
|
|
1455
|
|
|
if ( 'excl' === $tax_display && $this->get_prices_include_tax() ) { |
1456
|
|
|
$subtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; |
1457
|
|
|
} |
1458
|
|
|
} else { |
1459
|
|
|
if ( 'incl' === $tax_display ) { |
1460
|
|
|
return ''; |
1461
|
|
|
} |
1462
|
|
|
|
1463
|
|
|
foreach ( $this->get_items() as $item ) { |
1464
|
|
|
$subtotal += $item->get_subtotal(); |
1465
|
|
|
} |
1466
|
|
|
|
1467
|
|
|
// Add Shipping Costs. |
1468
|
|
|
$subtotal += $this->get_shipping_total(); |
1469
|
|
|
|
1470
|
|
|
// Remove non-compound taxes. |
1471
|
|
|
foreach ( $this->get_taxes() as $tax ) { |
1472
|
|
|
if ( $this->is_compound() ) { |
|
|
|
|
1473
|
|
|
continue; |
1474
|
|
|
} |
1475
|
|
|
$subtotal = $subtotal + $tax->get_tax_total() + $tax->get_shipping_tax_total(); |
1476
|
|
|
} |
1477
|
|
|
|
1478
|
|
|
// Remove discounts. |
1479
|
|
|
$subtotal = $subtotal - $this->get_total_discount(); |
1480
|
|
|
$subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) ); |
1481
|
|
|
} |
1482
|
|
|
|
1483
|
|
|
return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this ); |
1484
|
|
|
} |
1485
|
|
|
|
1486
|
|
|
/** |
1487
|
|
|
* Gets shipping (formatted). |
1488
|
|
|
* |
1489
|
|
|
* @return string |
1490
|
|
|
*/ |
1491
|
|
|
public function get_shipping_to_display( $tax_display = '' ) { |
1492
|
|
|
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); |
1493
|
|
|
|
1494
|
|
|
if ( $this->get_shipping_total() != 0 ) { |
1495
|
|
|
|
1496
|
|
|
if ( $tax_display == 'excl' ) { |
1497
|
|
|
|
1498
|
|
|
// Show shipping excluding tax. |
1499
|
|
|
$shipping = wc_price( $this->get_shipping_total(), array( 'currency' => $this->get_currency() ) ); |
1500
|
|
|
|
1501
|
|
View Code Duplication |
if ( $this->get_shipping_tax() != 0 && $this->get_prices_include_tax() ) { |
|
|
|
|
1502
|
|
|
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>', $this, $tax_display ); |
1503
|
|
|
} |
1504
|
|
|
} else { |
1505
|
|
|
|
1506
|
|
|
// Show shipping including tax. |
1507
|
|
|
$shipping = wc_price( $this->get_shipping_total() + $this->get_shipping_tax(), array( 'currency' => $this->get_currency() ) ); |
1508
|
|
|
|
1509
|
|
View Code Duplication |
if ( $this->get_shipping_tax() != 0 && ! $this->get_prices_include_tax() ) { |
|
|
|
|
1510
|
|
|
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>', $this, $tax_display ); |
1511
|
|
|
} |
1512
|
|
|
} |
1513
|
|
|
|
1514
|
|
|
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_shipped_via', ' <small class="shipped_via">' . sprintf( __( 'via %s', 'woocommerce' ), $this->get_shipping_method() ) . '</small>', $this ); |
1515
|
|
|
|
1516
|
|
|
} elseif ( $this->get_shipping_method() ) { |
1517
|
|
|
$shipping = $this->get_shipping_method(); |
1518
|
|
|
} else { |
1519
|
|
|
$shipping = __( 'Free!', 'woocommerce' ); |
1520
|
|
|
} |
1521
|
|
|
|
1522
|
|
|
return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this ); |
1523
|
|
|
} |
1524
|
|
|
|
1525
|
|
|
/** |
1526
|
|
|
* Get the discount amount (formatted). |
1527
|
|
|
* @since 2.3.0 |
1528
|
|
|
* @return string |
1529
|
|
|
*/ |
1530
|
|
|
public function get_discount_to_display( $tax_display = '' ) { |
1531
|
|
|
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); |
1532
|
|
|
return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_total_discount( 'excl' === $tax_display && 'excl' === get_option( 'woocommerce_tax_display_cart' ) ), array( 'currency' => $this->get_currency() ) ), $this ); |
1533
|
|
|
} |
1534
|
|
|
|
1535
|
|
|
/** |
1536
|
|
|
* Get totals for display on pages and in emails. |
1537
|
|
|
* |
1538
|
|
|
* @param mixed $tax_display |
1539
|
|
|
* @return array |
1540
|
|
|
*/ |
1541
|
|
|
public function get_order_item_totals( $tax_display = '' ) { |
1542
|
|
|
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); |
1543
|
|
|
$total_rows = array(); |
1544
|
|
|
|
1545
|
|
|
if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) { |
1546
|
|
|
$total_rows['cart_subtotal'] = array( |
1547
|
|
|
'label' => __( 'Subtotal:', 'woocommerce' ), |
1548
|
|
|
'value' => $subtotal, |
1549
|
|
|
); |
1550
|
|
|
} |
1551
|
|
|
|
1552
|
|
|
if ( $this->get_total_discount() > 0 ) { |
1553
|
|
|
$total_rows['discount'] = array( |
1554
|
|
|
'label' => __( 'Discount:', 'woocommerce' ), |
1555
|
|
|
'value' => '-' . $this->get_discount_to_display( $tax_display ), |
1556
|
|
|
); |
1557
|
|
|
} |
1558
|
|
|
|
1559
|
|
|
if ( $this->get_shipping_method() ) { |
1560
|
|
|
$total_rows['shipping'] = array( |
1561
|
|
|
'label' => __( 'Shipping:', 'woocommerce' ), |
1562
|
|
|
'value' => $this->get_shipping_to_display( $tax_display ), |
1563
|
|
|
); |
1564
|
|
|
} |
1565
|
|
|
|
1566
|
|
|
if ( $fees = $this->get_fees() ) { |
1567
|
|
|
foreach ( $fees as $id => $fee ) { |
1568
|
|
|
if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', empty( $fee['line_total'] ) && empty( $fee['line_tax'] ), $id ) ) { |
1569
|
|
|
continue; |
1570
|
|
|
} |
1571
|
|
|
$total_rows[ 'fee_' . $fee->get_id() ] = array( |
1572
|
|
|
'label' => $fee->get_name() . ':', |
1573
|
|
|
'value' => wc_price( 'excl' === $tax_display ? $fee->get_total() : $fee->get_total() + $fee->get_total_tax(), array( 'currency' => $this->get_currency() ) ), |
1574
|
|
|
); |
1575
|
|
|
} |
1576
|
|
|
} |
1577
|
|
|
|
1578
|
|
|
// Tax for tax exclusive prices. |
1579
|
|
|
if ( 'excl' === $tax_display ) { |
1580
|
|
|
|
1581
|
|
|
if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) { |
1582
|
|
|
|
1583
|
|
|
foreach ( $this->get_tax_totals() as $code => $tax ) { |
1584
|
|
|
|
1585
|
|
|
$total_rows[ sanitize_title( $code ) ] = array( |
1586
|
|
|
'label' => $tax->label . ':', |
1587
|
|
|
'value' => $tax->formatted_amount, |
1588
|
|
|
); |
1589
|
|
|
} |
1590
|
|
|
} else { |
1591
|
|
|
|
1592
|
|
|
$total_rows['tax'] = array( |
1593
|
|
|
'label' => WC()->countries->tax_or_vat() . ':', |
1594
|
|
|
'value' => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_currency() ) ), |
1595
|
|
|
); |
1596
|
|
|
} |
1597
|
|
|
} |
1598
|
|
|
|
1599
|
|
|
if ( $this->get_total() > 0 && $this->get_payment_method_title() ) { |
|
|
|
|
1600
|
|
|
$total_rows['payment_method'] = array( |
1601
|
|
|
'label' => __( 'Payment Method:', 'woocommerce' ), |
1602
|
|
|
'value' => $this->get_payment_method_title(), |
|
|
|
|
1603
|
|
|
); |
1604
|
|
|
} |
1605
|
|
|
|
1606
|
|
|
if ( $refunds = $this->get_refunds() ) { |
|
|
|
|
1607
|
|
|
foreach ( $refunds as $id => $refund ) { |
1608
|
|
|
$total_rows[ 'refund_' . $id ] = array( |
1609
|
|
|
'label' => $refund->get_reason() ? $refund->get_reason() : __( 'Refund', 'woocommerce' ) . ':', |
1610
|
|
|
'value' => wc_price( '-' . $refund->get_amount(), array( 'currency' => $this->get_currency() ) ), |
1611
|
|
|
); |
1612
|
|
|
} |
1613
|
|
|
} |
1614
|
|
|
|
1615
|
|
|
$total_rows['order_total'] = array( |
1616
|
|
|
'label' => __( 'Total:', 'woocommerce' ), |
1617
|
|
|
'value' => $this->get_formatted_order_total( $tax_display ), |
|
|
|
|
1618
|
|
|
); |
1619
|
|
|
|
1620
|
|
|
return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this ); |
1621
|
|
|
} |
1622
|
|
|
|
1623
|
|
|
/* |
1624
|
|
|
|-------------------------------------------------------------------------- |
1625
|
|
|
| Conditionals |
1626
|
|
|
|-------------------------------------------------------------------------- |
1627
|
|
|
| |
1628
|
|
|
| Checks if a condition is true or false. |
1629
|
|
|
| |
1630
|
|
|
*/ |
1631
|
|
|
|
1632
|
|
|
/** |
1633
|
|
|
* Checks the order status against a passed in status. |
1634
|
|
|
* |
1635
|
|
|
* @return bool |
1636
|
|
|
*/ |
1637
|
|
|
public function has_status( $status ) { |
1638
|
|
|
return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status ); |
1639
|
|
|
} |
1640
|
|
|
|
1641
|
|
|
/** |
1642
|
|
|
* Check whether this order has a specific shipping method or not. |
1643
|
|
|
* |
1644
|
|
|
* @param string $method_id |
1645
|
|
|
* @return bool |
1646
|
|
|
*/ |
1647
|
|
|
public function has_shipping_method( $method_id ) { |
1648
|
|
|
foreach ( $this->get_shipping_methods() as $shipping_method ) { |
1649
|
|
|
if ( strpos( $shipping_method->get_method_id(), $method_id ) === 0 ) { |
1650
|
|
|
return true; |
1651
|
|
|
} |
1652
|
|
|
} |
1653
|
|
|
return false; |
1654
|
|
|
} |
1655
|
|
|
|
1656
|
|
|
/** |
1657
|
|
|
* Returns true if the order contains a free product. |
1658
|
|
|
* @since 2.5.0 |
1659
|
|
|
* @return bool |
1660
|
|
|
*/ |
1661
|
|
|
public function has_free_item() { |
1662
|
|
|
foreach ( $this->get_items() as $item ) { |
1663
|
|
|
if ( ! $item->get_total() ) { |
1664
|
|
|
return true; |
1665
|
|
|
} |
1666
|
|
|
} |
1667
|
|
|
return false; |
1668
|
|
|
} |
1669
|
|
|
} |
1670
|
|
|
|
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.