Completed
Pull Request — master (#10259)
by Mike
08:17
created

WC_Abstract_Order::set_billing_phone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 19 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Abstract Order
8
 *
9
 * Handles order data and database interaction.
10
 *
11
 * @class       WC_Abstract_Order
12
 * @version     2.6.0
13
 * @package     WooCommerce/Classes
14
 * @category    Class
15
 * @author      WooThemes
16
 *
17
 * @todo check date formats are bw compat and consistant
18
 */
19
abstract class WC_Abstract_Order implements WC_Data {
20
21
    /**
22
     * Data array, with defaults.
23
     *
24
     * @todo when migrating to custom tables, these will be columns
25
     * @since 2.6.0
26
     * @var array
27
     */
28
    protected $_data = array(
29
		'order_id'             => 0,
30
        'parent_id'            => 0,
31
		'status'               => '',
32
        /**
33
         * @todo confusion. Was 'simple'. But this was not the same as post_type, which is shop_order. Other post types in core are shop_order_refund
34
         * The order type for shop_order_refund is refund.
35
         * Why do we need two separate variables? This should be unified, especially once this is in a custom table and post_type is redundent.
36
         * Switching to 'shop_order', and then using this value in the order factory instead of post_type. @thenbrent might have feedback on this.
37
         */
38
		'order_type'           => 'shop_order',
39
		'order_key'            => '',
40
		'order_currency'       => '',
41
		'date_created'         => '',
42
		'date_modified'        => '',
43
		'customer_id'          => 0,
44
		'billing_first_name'   => '',
45
		'billing_last_name'    => '',
46
		'billing_company'      => '',
47
		'billing_address_1'    => '',
48
		'billing_address_2'    => '',
49
		'billing_city'         => '',
50
		'billing_state'        => '',
51
		'billing_postcode'     => '',
52
		'billing_country'      => '',
53
		'billing_email'        => '',
54
		'billing_phone'        => '',
55
		'shipping_first_name'  => '',
56
		'shipping_last_name'   => '',
57
		'shipping_company'     => '',
58
		'shipping_address_1'   => '',
59
		'shipping_address_2'   => '',
60
		'shipping_city'        => '',
61
		'shipping_state'       => '',
62
		'shipping_postcode'    => '',
63
		'shipping_country'     => '',
64
		'discount_total'       => 0,
65
		'discount_tax'         => 0,
66
		'shipping_total'       => 0,
67
		'shipping_tax'         => 0,
68
		'cart_tax'             => 0, // cart_tax is the new name for the legacy 'order_tax' which is the tax for items only, not shipping.
69
		'order_total'          => 0,
70
		'order_tax'            => 0, // Sum of all taxes.
71
    );
72
73
    /**
74
     * Stores meta data.
75
     * @var array
76
     */
77
    protected $_meta = array(
78
        'payment_method'       => '',
79
		'payment_method_title' => '',
80
		'transaction_id'       => '',
81
		'customer_ip_address'  => '',
82
		'customer_user_agent'  => '',
83
		'created_via'          => '',
84
		'order_version'        => '',
85
		'prices_include_tax'   => false,
86
		'customer_note'        => '',
87
		'date_completed'       => '',
88
		'date_paid'            => '',
89
    );
90
91
    /**
92
     * Stores data about status changes so relevant hooks can be fired.
93
     * @var bool|array
94
     */
95
    protected $_status_transition = false;
96
97
    /**
98
     * Get the order if ID is passed, otherwise the order is new and empty.
99
     * This class should NOT be instantiated, but the get_order function or new WC_Order_Factory.
100
     * should be used. It is possible, but the aforementioned are preferred and are the only.
101
     * methods that will be maintained going forward.
102
     *
103
     * @param  int|object|WC_Order $order Order to init.
104
     */
105 View Code Duplication
    public function __construct( $order = 0 ) {
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...
106
		if ( is_numeric( $order ) ) {
107
            $this->read( $order );
108
        } elseif ( $order instanceof WC_Order ) {
109
            $this->read( absint( $order->get_id() ) );
110
        } elseif ( ! empty( $order->ID ) ) {
111
            $this->read( absint( $order->ID ) );
112
        }
113
    }
114
115
    /**
116
     * Change data to JSON format.
117
     * @return string Data in JSON format.
118
     */
119
    public function __toString() {
120
        return json_encode( $this->get_data() );
121
    }
122
123
    /**
124
     * Get Meta Data by Key
125
     * @param  string $key
126
     * @return mixed
127
     */
128
    public function get_meta( $key ){
129
        return isset( $this->_meta[ $key ] ) ? $this->_meta[ $key ] : null;
130
    }
131
132
    /*
133
    |--------------------------------------------------------------------------
134
    | Getters
135
    |--------------------------------------------------------------------------
136
    |
137
    | Methods for getting data from the order object.
138
    |
139
    */
140
141
    /**
142
     * Get all class data in array format.
143
     * @since 2.6.0
144
     * @return array
145
     */
146
    public function get_data() {
147
        return array_merge(
148
            $this->_data,
149
            $this->_meta,
150
            array(
151
                'line_items'     => $this->get_items( 'line_item' ),
152
                'tax_lines'      => $this->get_items( 'tax' ),
153
                'shipping_lines' => $this->get_items( 'shipping' ),
154
                'fee_lines'      => $this->get_items( 'fee' ),
155
                'coupon_lines'   => $this->get_items( 'coupon' ),
156
            )
157
        );
158
    }
159
160
    /**
161
     * Get order ID.
162
     * @since 2.6.0
163
     * @return integer
164
     */
165
    public function get_id() {
166
        return $this->get_order_id();
167
    }
168
169
    /**
170
     * Get order ID.
171
     * @since 2.6.0
172
     * @return integer
173
     */
174
    public function get_order_id() {
175
        return absint( $this->_data['order_id'] );
176
    }
177
178
    /**
179
     * Get parent order ID.
180
     * @since 2.6.0
181
     * @return integer
182
     */
183
    public function get_parent_id() {
184
        return absint( $this->_data['parent_id'] );
185
    }
186
187
    /**
188
     * get_order_number function.
189
     *
190
     * Gets the order number for display (by default, order ID).
191
     *
192
     * @return string
193
     */
194
    public function get_order_number() {
195
        return apply_filters( 'woocommerce_order_number', $this->get_id(), $this );
196
    }
197
198
    /**
199
     * Get order key.
200
     * @since 2.6.0
201
     * @return string
202
     */
203
    public function get_order_key() {
204
        return $this->_data['order_key'];
205
    }
206
207
    /**
208
     * Gets order currency.
209
     * @return string
210
     */
211
    public function get_order_currency() {
212
        return apply_filters( 'woocommerce_get_order_currency', $this->_data['order_currency'], $this );
213
    }
214
215
    /**
216
     * Get Order Type
217
     * @return string
218
     */
219
    public function get_order_type() {
220
        return $this->_data['order_type'];
221
    }
222
223
    /**
224
     * Get date_created
225
     * @return string
226
     */
227
    public function get_date_created() {
228
        return $this->_data['date_created'];
229
    }
230
231
    /**
232
     * Get date_modified
233
     * @return string
234
     */
235
    public function get_date_modified() {
236
        return $this->_data['date_modified'];
237
    }
238
239
    /**
240
     * Get date_completed
241
     * @return string
242
     */
243
    public function get_date_completed() {
244
        return $this->_data['date_completed'];
245
    }
246
247
	/**
248
     * Get date_paid
249
     * @return string
250
     */
251
    public function get_date_paid() {
252
        return $this->_data['date_paid'];
253
    }
254
255
    /**
256
     * Get customer_id
257
     * @return int
258
     */
259
    public function get_customer_id() {
260
        return absint( $this->_data['customer_id'] );
261
    }
262
263
    /**
264
     * Get billing_first_name
265
     * @return string
266
     */
267
    public function get_billing_first_name() {
268
        return $this->_data['billing_first_name'];
269
    }
270
271
    /**
272
     * Get billing_last_name
273
     * @return string
274
     */
275
    public function get_billing_last_name() {
276
        return $this->_data['billing_last_name'];
277
    }
278
279
    /**
280
     * Get billing_company
281
     * @return string
282
     */
283
    public function get_billing_company() {
284
        return $this->_data['billing_company'];
285
    }
286
287
    /**
288
     * Get billing_address_1
289
     * @return string
290
     */
291
    public function get_billing_address_1() {
292
        return $this->_data['billing_address_1'];
293
    }
294
295
    /**
296
     * Get billing_address_2
297
     * @return string $value
298
     */
299
    public function get_billing_address_2() {
300
        return $this->_data['billing_address_2'];
301
    }
302
303
    /**
304
     * Get billing_city
305
     * @return string $value
306
     */
307
    public function get_billing_city() {
308
        return $this->_data['billing_city'];
309
    }
310
311
    /**
312
     * Get billing_state
313
     * @return string
314
     */
315
    public function get_billing_state() {
316
        return $this->_data['billing_state'];
317
    }
318
319
    /**
320
     * Get billing_postcode
321
     * @return string
322
     */
323
    public function get_billing_postcode() {
324
        return $this->_data['billing_postcode'];
325
    }
326
327
    /**
328
     * Get billing_country
329
     * @return string
330
     */
331
    public function get_billing_country() {
332
        return $this->_data['billing_country'];
333
    }
334
335
    /**
336
     * Get billing_email
337
     * @return string
338
     */
339
    public function get_billing_email() {
340
        return sanitize_email( $this->_data['billing_email'] );
341
    }
342
343
    /**
344
     * Get billing_phone
345
     * @return string
346
     */
347
    public function get_billing_phone() {
348
        return $this->_data['billing_phone'];
349
    }
350
351
    /**
352
     * Get shipping_first_name
353
     * @return string
354
     */
355
    public function get_shipping_first_name() {
356
        return $this->_data['shipping_first_name'];
357
    }
358
359
    /**
360
     * Get shipping_last_name
361
     * @return string
362
     */
363
    public function get_shipping_last_name() {
364
         return $this->_data['shipping_last_name'];
365
    }
366
367
    /**
368
     * Get shipping_company
369
     * @return string
370
     */
371
    public function get_shipping_company() {
372
        return $this->_data['shipping_company'];
373
    }
374
375
    /**
376
     * Get shipping_address_1
377
     * @return string
378
     */
379
    public function get_shipping_address_1() {
380
        return $this->_data['shipping_address_1'];
381
    }
382
383
    /**
384
     * Get shipping_address_2
385
     * @return string
386
     */
387
    public function get_shipping_address_2() {
388
        return $this->_data['shipping_address_2'];
389
    }
390
391
    /**
392
     * Get shipping_city
393
     * @return string
394
     */
395
    public function get_shipping_city() {
396
        return $this->_data['shipping_city'];
397
    }
398
399
    /**
400
     * Get shipping_state
401
     * @return string
402
     */
403
    public function get_shipping_state() {
404
        return $this->_data['shipping_state'];
405
    }
406
407
    /**
408
     * Get shipping_postcode
409
     * @return string
410
     */
411
    public function get_shipping_postcode() {
412
        return $this->_data['shipping_postcode'];
413
    }
414
415
    /**
416
     * Get shipping_country
417
     * @return string
418
     */
419
    public function get_shipping_country() {
420
        return $this->_data['shipping_country'];
421
    }
422
423
    /**
424
     * Get the payment method.
425
     * @return string
426
     */
427
    public function get_payment_method() {
428
        return $this->_data['payment_method'];
429
    }
430
431
    /**
432
     * Get payment_method_title
433
     * @return string
434
     */
435
    public function get_payment_method_title() {
436
        return $this->_data['payment_method_title'];
437
    }
438
439
    /**
440
     * Get transaction_id
441
     * @return string
442
     */
443
    public function get_transaction_id() {
444
        return $this->_data['transaction_id'];
445
    }
446
447
    /**
448
     * Get customer_ip_address
449
     * @return string
450
     */
451
    public function get_customer_ip_address() {
452
        return $this->_data['customer_ip_address'];
453
    }
454
455
    /**
456
     * Get customer_user_agent
457
     * @return string
458
     */
459
    public function get_customer_user_agent() {
460
        return $this->_data['customer_user_agent'];
461
    }
462
463
    /**
464
     * Get created_via
465
     * @return string
466
     */
467
    public function get_created_via() {
468
        return $this->_data['created_via'];
469
    }
470
471
    /**
472
     * Get order_version
473
     * @return string
474
     */
475
    public function get_order_version() {
476
        return $this->_data['order_version'];
477
    }
478
479
    /**
480
     * Get prices_include_tax
481
     * @return bool
482
     */
483
    public function get_prices_include_tax() {
484
        return (bool) $this->_data['prices_include_tax'];
485
    }
486
487
    /**
488
     * Get customer_note
489
     * @return string
490
     */
491
    public function get_customer_note() {
492
        return $this->_data['customer_note'];
493
    }
494
495
    /**
496
     * Returns the requested address in raw, non-formatted way.
497
     * @since  2.4.0
498
     * @param  string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
499
     * @return array The stored address after filter.
500
     */
501
    public function get_address( $type = 'billing' ) {
502
        if ( 'billing' === $type ) {
503
            $address = array(
504
                'first_name' => $this->get_billing_first_name(),
505
                'last_name'  => $this->get_billing_last_name(),
506
                'company'    => $this->get_billing_company(),
507
                'address_1'  => $this->get_billing_address_1(),
508
                'address_2'  => $this->get_billing_address_2(),
509
                'city'       => $this->get_billing_city(),
510
                'state'      => $this->get_billing_state(),
511
                'postcode'   => $this->get_billing_postcode(),
512
                'country'    => $this->get_billing_country(),
513
                'email'      => $this->get_billing_email(),
514
                'phone'      => $this->get_billing_phone()
515
            );
516
        } else {
517
            $address = array(
518
                'first_name' => $this->get_shipping_first_name(),
519
                'last_name'  => $this->get_shipping_last_name(),
520
                'company'    => $this->get_shipping_company(),
521
                'address_1'  => $this->get_shipping_address_1(),
522
                'address_2'  => $this->get_shipping_address_2(),
523
                'city'       => $this->get_shipping_city(),
524
                'state'      => $this->get_shipping_state(),
525
                'postcode'   => $this->get_shipping_postcode(),
526
                'country'    => $this->get_shipping_country()
527
            );
528
        }
529
        return apply_filters( 'woocommerce_get_order_address', $address, $type, $this );
530
    }
531
532
    /**
533
     * Return the order statuses without wc- internal prefix.
534
     * @return string
535
     */
536
    public function get_status() {
537
        return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->_data['status'], 0, 3 ) ? substr( $this->_data['status'], 3 ) : $this->_data['status'], $this );
538
    }
539
540
    /**
541
     * Alias for get_customer_id().
542
     * @since  2.2
543
     * @return int
544
     */
545
    public function get_user_id() {
546
        return $this->get_customer_id();
547
    }
548
549
    /**
550
     * Get the user associated with the order. False for guests.
551
     *
552
     * @since  2.2
553
     * @return WP_User|false
554
     */
555
    public function get_user() {
556
        return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
557
    }
558
559
    /**
560
     * Get a formatted billing address for the order.
561
     * @return string
562
     */
563
    public function get_formatted_billing_address() {
564
        return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this ) );
565
    }
566
567
    /**
568
     * Get a formatted shipping address for the order.
569
     * @return string
570
     */
571
    public function get_formatted_shipping_address() {
572
        if ( $this->get_shipping_address_1() || $this->get_shipping_address_2() ) {
573
            return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_shipping_address', $this->get_address( 'shipping' ), $this ) );
574
        } else {
575
            return '';
576
        }
577
    }
578
579
    /**
580
     * Get a formatted shipping address for the order.
581
     *
582
     * @return string
583
     */
584
    public function get_shipping_address_map_url() {
585
        $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', array(
586
            'address_1' => $this->get_shipping_address_1(),
587
            'address_2' => $this->get_shipping_address_2(),
588
            'city'      => $this->get_shipping_city(),
589
            'state'     => $this->get_shipping_state(),
590
            'postcode'  => $this->get_shipping_postcode(),
591
            'country'   => $this->get_shipping_country()
592
        ), $this );
593
        return apply_filters( 'woocommerce_shipping_address_map_url', 'http://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this );
594
    }
595
596
    /**
597
     * Get a formatted billing full name.
598
     *
599
     * @since 2.4.0
600
     *
601
     * @return string
602
     */
603
    public function get_formatted_billing_full_name() {
604
        return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ),  $this->get_billing_first_name(), $this->get_billing_last_name() );
605
    }
606
607
    /**
608
     * Get a formatted shipping full name.
609
     *
610
     * @since 2.4.0
611
     *
612
     * @return string
613
     */
614
    public function get_formatted_shipping_full_name() {
615
        return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ),  $this->get_shipping_first_name(), $this->get_shipping_last_name() );
616
    }
617
618
    /**
619
     * Get discount_total
620
     * @return string
621
     */
622
    public function get_discount_total() {
623
        $discount_total = wc_format_decimal( $this->_data['discount_total'] );
624
625
        // Backwards compatible total calculation - totals were not stored consistently in old versions.
626
        if ( ( ! $this->get_order_version() || version_compare( $this->get_order_version(), '2.3.7', '<' ) ) && $this->get_prices_include_tax() ) {
627
            $discount_total = $discount_total - $this->get_discount_tax();
628
        }
629
630
        return $discount_total;
631
    }
632
633
    /**
634
     * Get discount_tax
635
     * @return string
636
     */
637
    public function get_discount_tax() {
638
        return wc_format_decimal( $this->_data['discount_tax'] );
639
    }
640
641
    /**
642
     * Get shipping_total
643
     * woocommerce_order_amount_total_shipping filter has been removed to avoid
644
     * these values being modified and then saved back to the DB. There are
645
     * other, later hooks available to change totals on display. e.g.
646
     * woocommerce_get_order_item_totals.
647
     * @return string
648
     */
649
    public function get_shipping_total() {
650
        return wc_format_decimal( $this->_data['shipping_total'] );
651
    }
652
653
    /**
654
     * Gets cart tax amount.
655
     *
656
     * @since 2.6.0 woocommerce_order_amount_cart_tax filter has been removed to avoid
657
     * these values being modified and then saved back to the DB or used in
658
     * calculations. There are other, later hooks available to change totals on
659
     * display. e.g. woocommerce_get_order_item_totals.
660
     * @return float
661
     */
662
    public function get_cart_tax() {
663
        return wc_format_decimal( $this->_data['cart_tax'] );
664
    }
665
666
    /**
667
     * Get shipping_tax.
668
     *
669
     * @since 2.6.0 woocommerce_order_amount_shipping_tax filter has been removed to avoid
670
     * these values being modified and then saved back to the DB or used in
671
     * calculations. There are other, later hooks available to change totals on
672
     * display. e.g. woocommerce_get_order_item_totals.
673
     * @return string
674
     */
675
    public function get_shipping_tax() {
676
        return wc_format_decimal( $this->_data['shipping_tax'] );
677
    }
678
679
    /**
680
     * Order tax is the sum of all taxes.
681
     * @return string
682
     */
683
    public function get_order_tax() {
684
        return wc_round_tax_total( $this->_data['order_tax'] );
685
    }
686
687
    /**
688
     * Get the stored order total. Includes taxes and everything else.
689
     * @return string
690
     */
691
    public function get_order_total() {
692
        return wc_format_decimal( $this->_data['order_total'], wc_get_price_decimals() );
693
    }
694
695
    /**
696
     * Gets the total discount amount.
697
     * @param  bool $ex_tax Show discount excl any tax.
698
     * @return float
699
     */
700
    public function get_total_discount( $ex_tax = true ) {
701
        if ( $ex_tax ) {
702
            $total_discount = $this->get_discount_total();
703
        } else {
704
            $total_discount = $this->get_discount_total() + $this->get_discount_tax();
705
        }
706
        return apply_filters( 'woocommerce_order_amount_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this );
707
    }
708
709
    /**
710
     * Get total tax amount. Alias for get_order_tax().
711
     *
712
     * @since 2.6.0 woocommerce_order_amount_total_tax filter has been removed to avoid
713
     * these values being modified and then saved back to the DB. There are
714
     * other, later hooks available to change totals on display. e.g.
715
     * woocommerce_get_order_item_totals.
716
     * @return float
717
     */
718
    public function get_total_tax() {
719
        return $this->get_order_tax();
720
    }
721
722
    /**
723
     * Gets shipping total. Alias of WC_Order::get_shipping_total().
724
     *
725
     * @since 2.6.0 woocommerce_order_amount_total_shipping filter has been removed to avoid
726
     * these values being modified and then saved back to the DB or used in
727
     * calculations. There are other, later hooks available to change totals on
728
     * display. e.g. woocommerce_get_order_item_totals.
729
     * @return float
730
     */
731
    public function get_total_shipping() {
732
        return $this->get_shipping_total();
733
    }
734
735
    /**
736
     * Gets order grand total. incl. taxes. Used in gateways. Filtered.
737
     * @return float
738
     */
739
    public function get_total() {
740
        return apply_filters( 'woocommerce_order_amount_total', $this->get_order_total(), $this );
741
    }
742
743
    /**
744
     * Gets order subtotal.
745
     * @return float
746
     */
747
    public function get_subtotal() {
748
        $subtotal = 0;
749
750
        foreach ( $this->get_items() as $item ) {
751
            $subtotal += isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0;
752
        }
753
754
        return apply_filters( 'woocommerce_order_amount_subtotal', (double) $subtotal, $this );
755
    }
756
757
    /**
758
     * Get taxes, merged by code, formatted ready for output.
759
     *
760
     * @return array
761
     */
762
    public function get_tax_totals() {
763
        $tax_totals = array();
764
765
        foreach ( $this->get_items( 'tax' ) as $key => $tax ) {
766
            $code = $tax[ 'name' ];
767
768 View Code Duplication
            if ( ! isset( $tax_totals[ $code ] ) ) {
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...
769
                $tax_totals[ $code ] = new stdClass();
770
                $tax_totals[ $code ]->amount = 0;
771
            }
772
773
            $tax_totals[ $code ]->id                = $key;
774
            $tax_totals[ $code ]->rate_id           = $tax['rate_id'];
775
            $tax_totals[ $code ]->is_compound       = $tax[ 'compound' ];
776
            $tax_totals[ $code ]->label             = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
777
            $tax_totals[ $code ]->amount           += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
778
            $tax_totals[ $code ]->formatted_amount  = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) );
779
        }
780
781
        return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this );
782
    }
783
784
    /**
785
     * Gets formatted shipping method title.
786
     * @return string
787
     */
788
    public function get_shipping_method() {
789
        $names = array();
790
        foreach ( $this->get_shipping_methods() as $shipping_method ) {
791
            $names[] = $shipping_method->get_name();
792
        }
793
        return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $names ), $this );
794
    }
795
796
    /*
797
    |--------------------------------------------------------------------------
798
    | Setters
799
    |--------------------------------------------------------------------------
800
    |
801
    | Functions for setting order data. These should not update anything in the
802
    | database itself and should only change what is stored in the class
803
    | object. However, for backwards compatibility pre 2.6.0 some of these
804
    | setters may handle both.
805
    |
806
    */
807
808
    /**
809
     * Set order ID.
810
     * @since 2.6.0
811
     * @param int $value
812
     */
813
    public function set_order_id( $value ) {
814
        $this->_data['order_id'] = absint( $value );
815
    }
816
817
    /**
818
     * Set parent order ID.
819
     * @since 2.6.0
820
     * @param int $value
821
     */
822
    public function set_parent_id( $value ) {
823
        $this->_data['parent_id'] = absint( $value );
824
    }
825
826
    /**
827
     * Set order status.
828
     * @since 2.6.0
829
     * @param string $new_status Status to change the order to. No internal wc- prefix is required.
830
     * @param string $note (default: '') Optional note to add.
831
     * @param bool $manual is this a manual order status change?
0 ignored issues
show
Documentation introduced by
There is no parameter named $manual. Did you maybe mean $manual_update?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
832
     */
833
    public function set_status( $new_status, $note = '', $manual_update = false ) {
834
        // Remove prefixes and standardize
835
        $current_status = $this->get_status();
836
        $new_status     = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status;
837
838
        if ( in_array( 'wc-' . $new_status, array_keys( wc_get_order_statuses() ) ) && $new_status !== $current_status ) {
839
            if ( ! empty( $current_status ) ) {
840
                $this->_status_transition = array(
841
                    'original' => ! empty( $this->_status_transition['original'] ) ? $this->_status_transition['original'] : $current_status,
842
                    'note'     => $note ? $note : '',
843
                    'manual'   => (bool) $manual_update
844
                );
845
				if ( 'completed' === $new_status ) {
846
					$this->set_date_completed( current_time( 'timestamp' ) );
847
				}
848
            }
849
            $this->_data['status'] = 'wc-' . $new_status;
850
        }
851
    }
852
853
	/**
854
     * Updates status of order immediately.
855
     * @uses WC_Order::set_status()
856
     */
857
    public function update_status( $new_status, $note = '', $manual = false ) {
858
        if ( ! $this->get_id() ) {
859
            return false;
860
        }
861
		$this->set_status( $new_status, $note, $manual );
862
		$this->save();
863
        return true;
864
    }
865
866
    /**
867
     * Set Order Type
868
     * @param string $value
869
     */
870
    public function set_order_type( $value ) {
871
        $this->_data['order_type'] = $value;
872
    }
873
874
    /**
875
     * Set order_key
876
     * @param string $value
877
     */
878
    public function set_order_key( $value ) {
879
        $this->_data['order_key'] = $value;
880
    }
881
882
    /**
883
     * Set order_currency
884
     * @param string $value
885
     */
886
    public function set_order_currency( $value ) {
887
        $this->_data['order_currency'] = $value;
888
    }
889
890
    /**
891
     * Set date_created
892
     * @param string $timestamp Timestamp
893
     */
894
    public function set_date_created( $timestamp ) {
895
        $this->_data['date_created'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
896
    }
897
898
    /**
899
     * Set date_modified
900
     * @param string $timestamp
901
     */
902
    public function set_date_modified( $timestamp ) {
903
        $this->_data['date_modified'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
904
    }
905
906
    /**
907
     * Set date_completed
908
     * @param string $timestamp
909
     */
910
    public function set_date_completed( $timestamp ) {
911
        $this->_data['date_completed'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
912
    }
913
914
	/**
915
     * Set date_paid
916
     * @param string $timestamp
917
     */
918
    public function set_date_paid( $timestamp ) {
919
        $this->_data['date_paid'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
920
    }
921
922
    /**
923
     * Set customer_id
924
     * @param int $value
925
     */
926
    public function set_customer_id( $value ) {
927
        $this->_data['customer_id'] = absint( $value );
928
    }
929
930
    /**
931
     * Set billing_first_name
932
     * @param string $value
933
     */
934
    public function set_billing_first_name( $value ) {
935
        $this->_data['billing_first_name'] = $value;
936
    }
937
938
    /**
939
     * Set billing_last_name
940
     * @param string $value
941
     */
942
    public function set_billing_last_name( $value ) {
943
        $this->_data['billing_last_name'] = $value;
944
    }
945
946
    /**
947
     * Set billing_company
948
     * @param string $value
949
     */
950
    public function set_billing_company( $value ) {
951
        $this->_data['billing_company'] = $value;
952
    }
953
954
    /**
955
     * Set billing_address_1
956
     * @param string $value
957
     */
958
    public function set_billing_address_1( $value ) {
959
        $this->_data['billing_address_1'] = $value;
960
    }
961
962
    /**
963
     * Set billing_address_2
964
     * @param string $value
965
     */
966
    public function set_billing_address_2( $value ) {
967
        $this->_data['billing_address_2'] = $value;
968
    }
969
970
    /**
971
     * Set billing_city
972
     * @param string $value
973
     */
974
    public function set_billing_city( $value ) {
975
        $this->_data['billing_city'] = $value;
976
    }
977
978
    /**
979
     * Set billing_state
980
     * @param string $value
981
     */
982
    public function set_billing_state( $value ) {
983
        $this->_data['billing_state'] = $value;
984
    }
985
986
    /**
987
     * Set billing_postcode
988
     * @param string $value
989
     */
990
    public function set_billing_postcode( $value ) {
991
        $this->_data['billing_postcode'] = $value;
992
    }
993
994
    /**
995
     * Set billing_country
996
     * @param string $value
997
     */
998
    public function set_billing_country( $value ) {
999
        $this->_data['billing_country'] = $value;
1000
    }
1001
1002
    /**
1003
     * Set billing_email
1004
     * @param string $value
1005
     */
1006
    public function set_billing_email( $value ) {
1007
		$value = sanitize_email( $value );
1008
        $this->_data['billing_email'] = is_email( $value ) ? $value : '';
1009
    }
1010
1011
    /**
1012
     * Set billing_phone
1013
     * @param string $value
1014
     */
1015
    public function set_billing_phone( $value ) {
1016
        $this->_data['billing_phone'] = $value;
1017
    }
1018
1019
    /**
1020
     * Set shipping_first_name
1021
     * @param string $value
1022
     */
1023
    public function set_shipping_first_name( $value ) {
1024
        $this->_data['shipping_first_name'] = $value;
1025
    }
1026
1027
    /**
1028
     * Set shipping_last_name
1029
     * @param string $value
1030
     */
1031
    public function set_shipping_last_name( $value ) {
1032
        $this->_data['shipping_last_name'] = $value;
1033
    }
1034
1035
    /**
1036
     * Set shipping_company
1037
     * @param string $value
1038
     */
1039
    public function set_shipping_company( $value ) {
1040
        $this->_data['shipping_company'] = $value;
1041
    }
1042
1043
    /**
1044
     * Set shipping_address_1
1045
     * @param string $value
1046
     */
1047
    public function set_shipping_address_1( $value ) {
1048
        $this->_data['shipping_address_1'] = $value;
1049
    }
1050
1051
    /**
1052
     * Set shipping_address_2
1053
     * @param string $value
1054
     */
1055
    public function set_shipping_address_2( $value ) {
1056
        $this->_data['shipping_address_2'] = $value;
1057
    }
1058
1059
    /**
1060
     * Set shipping_city
1061
     * @param string $value
1062
     */
1063
    public function set_shipping_city( $value ) {
1064
        $this->_data['shipping_city'] = $value;
1065
    }
1066
1067
    /**
1068
     * Set shipping_state
1069
     * @param string $value
1070
     */
1071
    public function set_shipping_state( $value ) {
1072
        $this->_data['shipping_state'] = $value;
1073
    }
1074
1075
    /**
1076
     * Set shipping_postcode
1077
     * @param string $value
1078
     */
1079
    public function set_shipping_postcode( $value ) {
1080
        $this->_data['shipping_postcode'] = $value;
1081
    }
1082
1083
    /**
1084
     * Set shipping_country
1085
     * @param string $value
1086
     */
1087
    public function set_shipping_country( $value ) {
1088
        $this->_data['shipping_country'] = $value;
1089
    }
1090
1091
    /**
1092
     * Set discount_total
1093
     * @param string $value
1094
     */
1095
    public function set_discount_total( $value ) {
1096
        $this->_data['discount_total'] = wc_format_decimal( $value );
1097
    }
1098
1099
    /**
1100
     * Set discount_tax
1101
     * @param string $value
1102
     */
1103
    public function set_discount_tax( $value ) {
1104
        $this->_data['discount_tax'] = wc_format_decimal( $value );
1105
    }
1106
1107
    /**
1108
     * Set shipping_total
1109
     * @param string $value
1110
     */
1111
    public function set_shipping_total( $value ) {
1112
        $this->_data['shipping_total'] = wc_format_decimal( $value );
1113
    }
1114
1115
    /**
1116
     * Set shipping_tax
1117
     * @param string $value
1118
     */
1119
    public function set_shipping_tax( $value ) {
1120
        $this->_data['shipping_tax'] = wc_format_decimal( $value );
1121
        $this->set_order_tax( $this->get_cart_tax() + $this->get_shipping_tax() );
1122
    }
1123
1124
    /**
1125
     * Set cart tax
1126
     * @param string $value
1127
     */
1128
    public function set_cart_tax( $value ) {
1129
        $this->_data['cart_tax'] = wc_format_decimal( $value );
1130
        $this->set_order_tax( $this->get_cart_tax() + $this->get_shipping_tax() );
1131
    }
1132
1133
    /**
1134
     * Sets order tax (sum of cart and shipping tax). Used internaly only.
1135
     * @access protected
1136
     * @param string $value
1137
     */
1138
    protected function set_order_tax( $value ) {
1139
        $this->_data['order_tax'] = wc_format_decimal( $value );
1140
    }
1141
1142
    /**
1143
     * Set order_total
1144
     * @param string $value
1145
     */
1146
    public function set_order_total( $value ) {
1147
        $this->_data['order_total'] = wc_format_decimal( $value, wc_get_price_decimals() );
1148
    }
1149
1150
    /**
1151
     * Set the payment method ID.
1152
     * @since 2.2.0
1153
     * @param string $value Supports WC_Payment_Gateway for bw compatibility with < 2.6
1154
     */
1155
    public function set_payment_method( $value ) {
1156
        if ( is_object( $value ) ) {
1157
            update_post_meta( $this->get_id(), '_payment_method', $value->id );
1158
            update_post_meta( $this->get_id(), '_payment_method_title', $value->get_title() );
1159
            $this->set_payment_method( $value->id );
1160
            $this->set_payment_method_title( $value->get_title() );
1161
        } else {
1162
            $this->_data['payment_method'] = $value;
1163
        }
1164
    }
1165
1166
    /**
1167
     * Set payment_method_title
1168
     * @param string $value
1169
     */
1170
    public function set_payment_method_title( $value ) {
1171
        $this->_data['payment_method_title'] = $value;
1172
    }
1173
1174
    /**
1175
     * Set transaction_id
1176
     * @param string $value
1177
     */
1178
    public function set_transaction_id( $value ) {
1179
        $this->_data['transaction_id'] = $value;
1180
    }
1181
1182
    /**
1183
     * Set customer_ip_address
1184
     * @param string $value
1185
     */
1186
    public function set_customer_ip_address( $value ) {
1187
        $this->_data['customer_ip_address'] = $value;
1188
    }
1189
1190
    /**
1191
     * Set customer_user_agent
1192
     * @param string $value
1193
     */
1194
    public function set_customer_user_agent( $value ) {
1195
        $this->_data['customer_user_agent'] = $value;
1196
    }
1197
1198
    /**
1199
     * Set created_via
1200
     * @param string $value
1201
     */
1202
    public function set_created_via( $value ) {
1203
        $this->_data['created_via'] = $value;
1204
    }
1205
1206
    /**
1207
     * Set order_version
1208
     * @param string $value
1209
     */
1210
    public function set_order_version( $value ) {
1211
        $this->_data['order_version'] = $value;
1212
    }
1213
1214
    /**
1215
     * Set prices_include_tax
1216
     * @param bool $value
1217
     */
1218
    public function set_prices_include_tax( $value ) {
1219
        $this->_data['prices_include_tax'] = (bool) $value;
1220
    }
1221
1222
    /**
1223
     * Set customer_note
1224
     * @param string $value
1225
     */
1226
    public function set_customer_note( $value ) {
1227
        $this->_data['customer_note'] = $value;
1228
    }
1229
1230
    /**
1231
     * Set the customer address.
1232
     * @since 2.2.0
1233
     * @param array $address Address data.
1234
     * @param string $type billing or shipping.
1235
     */
1236
    public function set_address( $address, $type = 'billing' ) {
1237
        foreach ( $address as $key => $value ) {
1238
            update_post_meta( $this->get_id(), "_{$type}_" . $key, $value );
1239
            if ( method_exists( $this, "set_{$type}_{$key}" ) ) {
1240
                $this->{"set_{$type}_{$key}"}( $value );
1241
            }
1242
        }
1243
    }
1244
1245
    /**
1246
     * Set an order total.
1247
     * @since 2.2.0
1248
     * @param float $amount
1249
     * @param string $total_type
1250
     * @return bool
1251
     */
1252
    public function set_total( $amount, $total_type = 'total' ) {
1253
        if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
1254
            return false;
1255
        }
1256
1257
        switch ( $total_type ) {
1258
            case 'total' :
1259
                $amount = wc_format_decimal( $amount, wc_get_price_decimals() );
1260
                $this->set_order_total( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amoun...c_get_price_decimals()) on line 1259 can also be of type array; however, WC_Abstract_Order::set_order_total() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1261
                update_post_meta( $this->get_id(), '_order_total', $amount );
1262
                break;
1263
            case 'cart_discount' :
1264
                $amount = wc_format_decimal( $amount );
1265
                $this->set_discount_total( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1264 can also be of type array; however, WC_Abstract_Order::set_discount_total() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1266
                update_post_meta( $this->get_id(), '_cart_discount', $amount );
1267
                break;
1268
            case 'cart_discount_tax' :
1269
                $amount = wc_format_decimal( $amount );
1270
                $this->set_discount_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1269 can also be of type array; however, WC_Abstract_Order::set_discount_tax() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1271
                update_post_meta( $this->get_id(), '_cart_discount_tax', $amount );
1272
                break;
1273
            case 'shipping' :
1274
                $amount = wc_format_decimal( $amount );
1275
                $this->set_shipping_total( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1274 can also be of type array; however, WC_Abstract_Order::set_shipping_total() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1276
                update_post_meta( $this->get_id(), '_order_shipping', $amount );
1277
                break;
1278
            case 'shipping_tax' :
1279
                $amount = wc_format_decimal( $amount );
1280
                $this->set_shipping_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1279 can also be of type array; however, WC_Abstract_Order::set_shipping_tax() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1281
                update_post_meta( $this->get_id(), '_order_shipping_tax', $amount );
1282
                break;
1283
            case 'tax' :
1284
                $amount = wc_format_decimal( $amount );
1285
                $this->set_cart_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1284 can also be of type array; however, WC_Abstract_Order::set_cart_tax() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1286
                update_post_meta( $this->get_id(), '_order_tax', $amount );
1287
                break;
1288
        }
1289
1290
        return true;
1291
    }
1292
1293
    /*
1294
    |--------------------------------------------------------------------------
1295
    | CRUD methods
1296
    |--------------------------------------------------------------------------
1297
    |
1298
    | Methods which create, read, update and delete orders from the database.
1299
    | Written in abstract fashion so that the way orders are stored can be
1300
    | changed more easily in the future.
1301
    |
1302
    | A save method is included for convenience (chooses update or create based
1303
    | on if the order exists yet).
1304
    |
1305
    */
1306
1307
    /**
1308
     * Insert data into the database.
1309
     * @since 2.6.0
1310
     * @access protected
1311
     */
1312
    public function create() {
1313
        // Set random key
1314
        $this->set_order_key( uniqid( 'order_' ) );
1315
1316
        $order_id = wp_insert_post( apply_filters( 'woocommerce_new_order_data', array(
1317
            'post_type'     => $this->get_order_type(),
1318
            'post_status'   => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
1319
            'ping_status'   => 'closed',
1320
            'post_author'   => 1,
1321
            'post_title'    => sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ),
1322
            'post_password' => $this->get_order_key(),
1323
            'post_parent'   => $this->get_parent_id()
1324
        ) ), true );
1325
1326
        if ( $order_id ) {
1327
            $this->set_order_id( $order_id );
1328
1329
            // Set meta data
1330
            update_post_meta( $order_id, '_billing_first_name', $this->get_billing_first_name() );
1331
            update_post_meta( $order_id, '_billing_last_name', $this->get_billing_last_name() );
1332
            update_post_meta( $order_id, '_billing_company', $this->get_billing_company() );
1333
            update_post_meta( $order_id, '_billing_address_1', $this->get_billing_address_1() );
1334
            update_post_meta( $order_id, '_billing_address_2', $this->get_billing_address_2() );
1335
            update_post_meta( $order_id, '_billing_city', $this->get_billing_city() );
1336
            update_post_meta( $order_id, '_billing_state', $this->get_billing_state() );
1337
            update_post_meta( $order_id, '_billing_postcode', $this->get_billing_postcode() );
1338
            update_post_meta( $order_id, '_billing_country', $this->get_billing_country() );
1339
            update_post_meta( $order_id, '_billing_email', $this->get_billing_email() );
1340
            update_post_meta( $order_id, '_billing_phone', $this->get_billing_phone() );
1341
            update_post_meta( $order_id, '_shipping_first_name', $this->get_shipping_first_name() );
1342
            update_post_meta( $order_id, '_shipping_last_name', $this->get_shipping_last_name() );
1343
            update_post_meta( $order_id, '_shipping_company', $this->get_shipping_company() );
1344
            update_post_meta( $order_id, '_shipping_address_1', $this->get_shipping_address_1() );
1345
            update_post_meta( $order_id, '_shipping_address_2', $this->get_shipping_address_2() );
1346
            update_post_meta( $order_id, '_shipping_city', $this->get_shipping_city() );
1347
            update_post_meta( $order_id, '_shipping_state', $this->get_shipping_state() );
1348
            update_post_meta( $order_id, '_shipping_postcode', $this->get_shipping_postcode() );
1349
            update_post_meta( $order_id, '_shipping_country', $this->get_shipping_country() );
1350
            update_post_meta( $order_id, '_payment_method', $this->get_payment_method() );
1351
            update_post_meta( $order_id, '_payment_method_title', $this->get_payment_method_title() );
1352
            update_post_meta( $order_id, '_transaction_id', $this->get_transaction_id() );
1353
            update_post_meta( $order_id, '_customer_user', $this->get_customer_id() );
1354
            update_post_meta( $order_id, '_customer_ip_address', $this->get_customer_ip_address() );
1355
            update_post_meta( $order_id, '_customer_user_agent', $this->get_customer_user_agent() );
1356
            update_post_meta( $order_id, '_created_via', $this->get_created_via() );
1357
            update_post_meta( $order_id, '_order_version', $this->get_order_version() );
1358
            update_post_meta( $order_id, '_prices_include_tax', $this->get_prices_include_tax() );
1359
            update_post_meta( $order_id, '_completed_date', $this->get_date_completed() );
1360
			update_post_meta( $order_id, '_paid_date', $this->get_date_paid() );
1361
            update_post_meta( $order_id, '_order_currency', $this->get_order_currency() );
1362
            update_post_meta( $order_id, '_order_key', $this->get_order_key() );
1363
            update_post_meta( $order_id, '_cart_discount', $this->get_discount_total() );
1364
            update_post_meta( $order_id, '_cart_discount_tax', $this->get_discount_tax() );
1365
            update_post_meta( $order_id, '_order_shipping', $this->get_shipping_total() );
1366
            update_post_meta( $order_id, '_order_shipping_tax', $this->get_shipping_tax() );
1367
            update_post_meta( $order_id, '_order_tax', $this->get_cart_tax() );
1368
            update_post_meta( $order_id, '_order_total', $this->get_order_total() );
1369
        }
1370
    }
1371
1372
    /**
1373
     * Read from the database.
1374
     * @since 2.6.0
1375
     * @access protected
1376
     * @param int $id ID of object to read.
1377
     */
1378
    public function read( $id ) {
1379
        $post_object = get_post( $id );
1380
        $order_id    = absint( $post_object->ID );
1381
1382
        // Map standard post data
1383
        $this->set_order_id( $order_id );
1384
        $this->set_date_created( $post_object->post_date );
1385
        $this->set_date_modified( $post_object->post_modified );
1386
        $this->set_status( $post_object->post_status );
1387
        $this->set_customer_note( $post_object->post_excerpt );
1388
1389
        // Map meta data
1390
        $this->set_customer_id( get_post_meta( $order_id, '_customer_user', true ) );
1391
        $this->set_order_key( get_post_meta( $order_id, '_order_key', true ) );
1392
        $this->set_order_currency( get_post_meta( $order_id, '_order_currency', true ) );
1393
        $this->set_billing_first_name( get_post_meta( $order_id, '_billing_first_name', true ) );
1394
        $this->set_billing_last_name( get_post_meta( $order_id, '_billing_last_name', true ) );
1395
        $this->set_billing_company( get_post_meta( $order_id, '_billing_company', true ) );
1396
        $this->set_billing_address_1( get_post_meta( $order_id, '_billing_address_1', true ) );
1397
        $this->set_billing_address_2( get_post_meta( $order_id, '_billing_address_2', true ) );
1398
        $this->set_billing_city( get_post_meta( $order_id, '_billing_city', true ) );
1399
        $this->set_billing_state( get_post_meta( $order_id, '_billing_state', true ) );
1400
        $this->set_billing_postcode( get_post_meta( $order_id, '_billing_postcode', true ) );
1401
        $this->set_billing_country( get_post_meta( $order_id, '_billing_country', true ) );
1402
        $this->set_billing_email( get_post_meta( $order_id, 'billing_email', true ) );
1403
        $this->set_billing_phone( get_post_meta( $order_id, '_billing_phone', true ) );
1404
        $this->set_shipping_first_name( get_post_meta( $order_id, '_shipping_first_name', true ) );
1405
        $this->set_shipping_last_name( get_post_meta( $order_id, '_shipping_last_name', true ) );
1406
        $this->set_shipping_company( get_post_meta( $order_id, '_shipping_company', true ) );
1407
        $this->set_shipping_address_1( get_post_meta( $order_id, '_shipping_address_1', true ) );
1408
        $this->set_shipping_address_2( get_post_meta( $order_id, '_shipping_address_2', true ) );
1409
        $this->set_shipping_city( get_post_meta( $order_id, '_shipping_city', true ) );
1410
        $this->set_shipping_state( get_post_meta( $order_id, '_shipping_state', true ) );
1411
        $this->set_shipping_postcode( get_post_meta( $order_id, '_shipping_postcode', true ) );
1412
        $this->set_shipping_country( get_post_meta( $order_id, '_shipping_country', true ) );
1413
        $this->set_payment_method( get_post_meta( $order_id, '_payment_method', true ) );
1414
        $this->set_payment_method_title( get_post_meta( $order_id, '_payment_method_title', true ) );
1415
        $this->set_transaction_id( get_post_meta( $order_id, '_transaction_id', true ) );
1416
        $this->set_customer_ip_address( get_post_meta( $order_id, '_customer_ip_address', true ) );
1417
        $this->set_customer_user_agent(get_post_meta( $order_id, '_customer_user_agent', true ) );
1418
        $this->set_created_via( get_post_meta( $order_id, '_created_via', true ) );
1419
        $this->set_order_version( get_post_meta( $order_id, '_order_version', true ) );
1420
        $this->set_prices_include_tax( get_post_meta( $order_id, '_prices_include_tax', true ) );
1421
        $this->set_date_completed( get_post_meta( $order_id, '_completed_date', true ) );
1422
		$this->set_date_paid( get_post_meta( $order_id, '_paid_date', true ) );
1423
1424
        // Map totals
1425
        $this->set_discount_total( get_post_meta( $order_id, '_cart_discount', true ) );
1426
        $this->set_discount_tax( get_post_meta( $order_id, '_cart_discount_tax', true ) );
1427
        $this->set_shipping_total( get_post_meta( $order_id, '_order_shipping', true ) );
1428
        $this->set_shipping_tax( get_post_meta( $order_id, '_order_shipping_tax', true ) );
1429
        $this->set_cart_tax( get_post_meta( $order_id, '_order_tax', true ) );
1430
        $this->set_order_total( get_post_meta( $order_id, '_order_total', true ) );
1431
1432
        // Map user data
1433
        if ( empty( $this->get_billing_email() ) && ( $user = $this->get_user() ) ) {
1434
            $this->set_billing_email( $user->user_email );
1435
        }
1436
1437
        // Orders store the state of prices including tax when created.
1438
        $this->prices_include_tax = metadata_exists( 'post', $order_id, '_prices_include_tax' ) ? 'yes' === get_post_meta( $order_id, '_prices_include_tax', true ) : 'yes' === get_option( 'woocommerce_prices_include_tax' );
1439
    }
1440
1441
    /**
1442
     * Update data in the database.
1443
     * @since 2.6.0
1444
     * @access protected
1445
     */
1446
    public function update() {
1447
        global $wpdb;
1448
1449
        $order_id = $this->get_id();
1450
1451
        $wpdb->update(
1452
            $wpdb->posts,
1453
            array(
1454
                'post_date'     => date( 'Y-m-d H:i:s', $this->get_date_created() ),
1455
                'post_date_gmt' => get_gmt_from_date( date( 'Y-m-d H:i:s', $this->get_date_created() ) ),
1456
                'post_status'   => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
1457
                'post_parent'   => $this->get_parent_id()
1458
            ),
1459
            array(
1460
                'ID' => $order_id
1461
            )
1462
        );
1463
1464
        // Update meta data
1465
        update_post_meta( $order_id, '_billing_first_name', $this->get_billing_first_name() );
1466
        update_post_meta( $order_id, '_billing_last_name', $this->get_billing_last_name() );
1467
        update_post_meta( $order_id, '_billing_company', $this->get_billing_company() );
1468
        update_post_meta( $order_id, '_billing_address_1', $this->get_billing_address_1() );
1469
        update_post_meta( $order_id, '_billing_address_2', $this->get_billing_address_2() );
1470
        update_post_meta( $order_id, '_billing_city', $this->get_billing_city() );
1471
        update_post_meta( $order_id, '_billing_state', $this->get_billing_state() );
1472
        update_post_meta( $order_id, '_billing_postcode', $this->get_billing_postcode() );
1473
        update_post_meta( $order_id, '_billing_country', $this->get_billing_country() );
1474
        update_post_meta( $order_id, '_billing_email', $this->get_billing_email() );
1475
        update_post_meta( $order_id, '_billing_phone', $this->get_billing_phone() );
1476
        update_post_meta( $order_id, '_shipping_first_name', $this->get_shipping_first_name() );
1477
        update_post_meta( $order_id, '_shipping_last_name', $this->get_shipping_last_name() );
1478
        update_post_meta( $order_id, '_shipping_company', $this->get_shipping_company() );
1479
        update_post_meta( $order_id, '_shipping_address_1', $this->get_shipping_address_1() );
1480
        update_post_meta( $order_id, '_shipping_address_2', $this->get_shipping_address_2() );
1481
        update_post_meta( $order_id, '_shipping_city', $this->get_shipping_city() );
1482
        update_post_meta( $order_id, '_shipping_state', $this->get_shipping_state() );
1483
        update_post_meta( $order_id, '_shipping_postcode', $this->get_shipping_postcode() );
1484
        update_post_meta( $order_id, '_shipping_country', $this->get_shipping_country() );
1485
        update_post_meta( $order_id, '_payment_method', $this->get_payment_method() );
1486
        update_post_meta( $order_id, '_payment_method_title', $this->get_payment_method_title() );
1487
        update_post_meta( $order_id, '_transaction_id', $this->get_transaction_id() );
1488
        update_post_meta( $order_id, '_customer_user', $this->get_customer_id() );
1489
        update_post_meta( $order_id, '_customer_ip_address', $this->get_customer_ip_address() );
1490
        update_post_meta( $order_id, '_customer_user_agent', $this->get_customer_user_agent() );
1491
        update_post_meta( $order_id, '_created_via', $this->get_created_via() );
1492
        update_post_meta( $order_id, '_order_version', $this->get_order_version() );
1493
        update_post_meta( $order_id, '_prices_include_tax', $this->get_prices_include_tax() );
1494
        update_post_meta( $order_id, '_order_currency', $this->get_order_currency() );
1495
        update_post_meta( $order_id, '_order_key', $this->get_order_key() );
1496
        update_post_meta( $order_id, '_cart_discount', $this->get_discount_total() );
1497
        update_post_meta( $order_id, '_cart_discount_tax', $this->get_discount_tax() );
1498
        update_post_meta( $order_id, '_order_shipping', $this->get_shipping_total() );
1499
        update_post_meta( $order_id, '_order_shipping_tax', $this->get_shipping_tax() );
1500
        update_post_meta( $order_id, '_order_tax', $this->get_cart_tax() );
1501
        update_post_meta( $order_id, '_order_total', $this->get_order_total() );
1502
1503
        if ( $this->_status_transition ) {
1504
            if ( ! empty( $this->_status_transition['original'] ) ) {
1505
                $transition_note = sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), wc_get_order_status_name( $this->_status_transition['original'] ), wc_get_order_status_name( $this->get_status() ) );
1506
1507
                do_action( 'woocommerce_order_status_' . $this->_status_transition['original'] . '_to_' . $this->get_status(), $this->get_id() );
1508
                do_action( 'woocommerce_order_status_changed', $this->get_id(), $this->_status_transition['original'], $this->get_status() );
1509
            } else {
1510
                $transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $this->get_status() ) );
1511
            }
1512
1513
            do_action( 'woocommerce_order_status_' . $this->get_status(), $this->get_id() );
1514
1515
            // Note the transition occured
1516
            $this->add_order_note( trim( $this->_status_transition['note'] . ' ' . $transition_note ), 0, $this->_status_transition['manual'] );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Order as the method add_order_note() does only exist in the following sub-classes of WC_Abstract_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

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

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

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

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

Available Fixes

  1. Change the type-hint for the parameter:

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

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

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
1517
1518
            // This has ran, so reset status transition variable
1519
            $this->_status_transition = false;
1520
        }
1521
    }
1522
1523
    /**
1524
     * Delete data from the database.
1525
     * @since 2.6.0
1526
     * @access protected
1527
     */
1528
    public function delete() {
1529
        wp_delete_post( $this->get_id() );
1530
    }
1531
1532
    /**
1533
     * Save data to the database.
1534
     * @since 2.6.0
1535
     * @access protected
1536
     */
1537
    public function save() {
1538
        if ( ! $this->get_id() ) {
1539
            $this->create();
1540
        } else {
1541
            $this->update();
1542
        }
1543
        wc_delete_shop_order_transients( $this->get_id() );
1544
    }
1545
1546
    /*
1547
    |--------------------------------------------------------------------------
1548
    | Order Item Handling
1549
    |--------------------------------------------------------------------------
1550
    |
1551
    | Order items are used for products, taxes, shipping, and fees within
1552
    | each order.
1553
    |
1554
    */
1555
1556
    /**
1557
     * Return an array of items/products within this order.
1558
     *
1559
     * @param string|array $type Types of line items to get (array or string).
1560
     * @return Array of WC_Order_item
1561
     */
1562
    public function get_items( $type = 'line_item' ) {
1563
        global $wpdb;
1564
1565
        $type            = ! is_array( $type ) ? array( $type ) : $type;
1566
        $items           = array();
1567
        $get_items_sql   = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d ", $this->get_id() );
1568
        $get_items_sql  .= "AND order_item_type IN ( '" . implode( "','", array_map( 'esc_sql', $type ) ) . "' ) ORDER BY order_item_id;";
1569
        $raw_items       = $wpdb->get_results( $get_items_sql );
1570
1571
        foreach ( $raw_items as $item ) {
1572
            $item                                = $this->get_item( $item );
1573
            $items[ $item->get_order_item_id() ] = $item;
1574
        }
1575
1576
        return apply_filters( 'woocommerce_order_get_items', $items, $this );
1577
    }
1578
1579
    /**
1580
     * Get an order item object, based on it's type.
1581
     * @param  int $item_id
1582
     * @return WC_Order_Item
1583
     */
1584
    public function get_item( $item_id ) {
1585
        return WC_Order_Factory::get_order_item( $item_id );
1586
    }
1587
1588
    /**
1589
     * Display meta data belonging to an item. @todo
1590
     * @param  array $item
1591
     */
1592
    public function display_item_meta( $item ) {
1593
        $product   = $this->get_product_from_item( $item );
0 ignored issues
show
Documentation introduced by
$item is of type array, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1594
        $item_meta = new WC_Order_Item_Meta( $item, $product );
0 ignored issues
show
Bug introduced by
It seems like $product defined by $this->get_product_from_item($item) on line 1593 can also be of type boolean; however, WC_Order_Item_Meta::__construct() does only seem to accept object<WC_Product>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1595
        $item_meta->display();
1596
    }
1597
1598
    /**
1599
     * Return an array of fees within this order.
1600
     *
1601
     * @return array
1602
     */
1603
    public function get_fees() {
1604
        return $this->get_items( 'fee' );
1605
    }
1606
1607
    /**
1608
     * Return an array of taxes within this order.
1609
     *
1610
     * @return array
1611
     */
1612
    public function get_taxes() {
1613
        return $this->get_items( 'tax' );
1614
    }
1615
1616
    /**
1617
     * Return an array of shipping costs within this order.
1618
     *
1619
     * @return array
1620
     */
1621
    public function get_shipping_methods() {
1622
        return $this->get_items( 'shipping' );
1623
    }
1624
1625
    /**
1626
     * Get coupon codes only.
1627
     *
1628
     * @return array
1629
     */
1630
    public function get_used_coupons() {
1631
        return array_map( 'trim', wp_list_pluck( $this->get_items( 'coupon' ), 'name' ) );
1632
    }
1633
1634
    /**
1635
     * Gets the count of order items of a certain type.
1636
     *
1637
     * @param string $item_type
1638
     * @return string
1639
     */
1640
    public function get_item_count( $item_type = '' ) {
1641
        if ( empty( $item_type ) ) {
1642
            $item_type = array( 'line_item' );
1643
        }
1644
        if ( ! is_array( $item_type ) ) {
1645
            $item_type = array( $item_type );
1646
        }
1647
1648
        $items = $this->get_items( $item_type );
1649
        $count = 0;
1650
1651
        foreach ( $items as $item ) {
1652
            $count += $item->get_qty();
1653
        }
1654
1655
        return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this );
1656
    }
1657
1658
    /**
1659
     * Remove all line items (products, coupons, shipping, taxes) from the order.
1660
     *
1661
     * @param string $type Order item type. Default null.
1662
     */
1663
    public function remove_order_items( $type = null ) {
1664
        global $wpdb;
1665
1666
        if ( ! empty( $type ) ) {
1667
            $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 ) );
1668
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->get_id(), $type ) );
1669
        } else {
1670
            $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() ) );
1671
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->get_id() ) );
1672
        }
1673
    }
1674
1675
    /**
1676
     * Add a product line item to the order.
1677
     * Order must be saved prior to adding items.
1678
     *
1679
     * @since 2.2
1680
     * @param \WC_Product $product
1681
     * @param int $qty Line item quantity.
1682
     * @param array $args
1683
     * @return int updated order item ID
1684
     */
1685
    public function add_product( $product, $qty = 1, $args = array() ) {
1686
        $args = wp_parse_args( $args, array(
1687
            'name'         => $product->get_title(),
1688
            'qty'          => absint( $qty ),
1689
            'tax_class'    => $product->get_tax_class(),
1690
            'product_id'   => $product->id,
1691
            'variation_id' => isset( $product->variation_id ) ? $product->variation_id : 0,
1692
            'variation'    => array(),
1693
            'subtotal'     => $product->get_price_excluding_tax( $qty ),
1694
            'subtotal_tax' => 0,
1695
            'total'        => $product->get_price_excluding_tax( $qty ),
1696
            'total_tax'    => 0,
1697
            'taxes'        => array(
1698
                'subtotal' => array(),
1699
                'total'    => array()
1700
            )
1701
        ) );
1702
        $item = new WC_Order_Item_Product();
1703
        $item_id = $this->update_product( $item, $product, $args );
1704
1705
		do_action( 'woocommerce_order_add_product', $this->get_id(), $item->get_order_item_id(), $product, $qty, $args );
1706
1707
		return $item_id;
1708
    }
1709
1710
    /**
1711
     * Update a line item for the order.
1712
     *
1713
     * Note this does not update order totals.
1714
     *
1715
     * @since 2.2
1716
     * @param object|int $item order item ID or item object.
1717
     * @param WC_Product $product
1718
     * @param array $args data to update.
1719
     * @return int updated order item ID
1720
     */
1721
    public function update_product( $item, $product, $args ) {
1722
        if ( is_numeric( $item ) ) {
1723
            $item = $this->get_item( $item );
1724
        }
1725
1726
        if ( ! is_object( $product ) || ! $item->is_type( 'line_item' ) ) {
1727
            return false;
1728
        }
1729
1730
        if ( ! $this->get_id() ) {
1731
            $this->save();
1732
        }
1733
1734
		$item->set_order_id( $this->get_id() );
1735
1736
        if ( ! $item->get_order_item_id() ) {
1737
            $inserting = true;
1738
        } else {
1739
            $inserting = false;
1740
        }
1741
1742
        if ( isset( $args['name'] ) ) {
1743
            $item->set_name( $args['name'] );
1744
        }
1745
1746
        if ( isset( $args['qty'] ) ) {
1747
            $item->set_qty( $args['qty'] );
1748
1749
            if ( $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
1750
                $item->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ), true );
1751
            }
1752
1753
            $item->set_line_subtotal( $product->get_price_excluding_tax( $args['qty'] ) );
1754
            $item->set_line_total( $product->get_price_excluding_tax( $args['qty'] ) );
1755
        }
1756
1757
        if ( isset( $args['tax_class'] ) ) {
1758
            $item->set_tax_class( $args['tax_class'] );
1759
        }
1760
1761
        if ( isset( $args['product_id'] ) ) {
1762
            $item->set_product_id( $args['product_id'] );
1763
        }
1764
1765
        if ( isset( $args['variation_id'] ) ) {
1766
            $item->set_variation_id( $args['variation_id'] );
1767
        }
1768
1769
        if ( isset( $args['variation'] ) && is_array( $args['variation'] ) ) {
1770
            foreach ( $args['variation'] as $key => $value ) {
1771
                $item->add_meta_data( str_replace( 'attribute_', '', $key ), $value, true );
1772
            }
1773
        }
1774
1775
        if ( isset( $args['totals'] ) ) {
1776
            // BW compatibility with old args
1777
            if ( isset( $args['totals']['subtotal'] ) ) {
1778
                $args['subtotal'] = $args['totals']['subtotal'];
1779
            }
1780
            if ( isset( $args['totals']['total'] ) ) {
1781
                $args['total'] = $args['totals']['total'];
1782
            }
1783
            if ( isset( $args['totals']['subtotal_tax'] ) ) {
1784
                $args['subtotal_tax'] = $args['totals']['subtotal_tax'];
1785
            }
1786
            if ( isset( $args['totals']['tax'] ) ) {
1787
                $args['total_tax'] = $args['totals']['tax'];
1788
            }
1789
            if ( isset( $args['totals']['tax_data'] ) ) {
1790
                $args['taxes'] = $args['totals']['tax_data'];
1791
            }
1792
        }
1793
1794
        if ( isset( $args['subtotal'] ) ) {
1795
            $item->set_subtotal( $args['subtotal'] );
1796
        }
1797
        if ( isset( $args['total'] ) ) {
1798
            $item->set_total( $args['total'] );
1799
        }
1800
        if ( isset( $args['subtotal_tax'] ) ) {
1801
            $item->set_line_subtotal_tax( $args['subtotal_tax'] );
1802
        }
1803
        if ( isset( $args['total_tax'] ) ) {
1804
            $item->set_total_tax( $args['total_tax'] );
1805
        }
1806
        if ( isset( $args['taxes'] ) ) {
1807
            $item->set_taxes( $args['taxes'] );
1808
        }
1809
1810
        $item->save();
1811
1812
        if ( ! $inserting ) {
1813
            do_action( 'woocommerce_order_edit_product', $this->get_id(), $item->get_order_item_id(), $args, $product );
1814
        }
1815
1816
        return $item->get_order_item_id();
1817
    }
1818
1819
    /**
1820
     * Add coupon code to the order.
1821
     * Order must be saved prior to adding items.
1822
     *
1823
     * @param string $code
1824
     * @param int $discount_amount
1825
     * @param int $discount_amount_tax "Discounted" tax - used for tax inclusive prices.
1826
     * @return int updated order item ID
1827
     */
1828
    public function add_coupon( $code, $discount_amount = 0, $discount_amount_tax = 0 ) {
1829
        $args = wp_parse_args( $args, array(
1830
            'code'                => $code,
1831
            'discount_amount'     => $discount_amount,
1832
            'discount_amount_tax' => $discount_amount_tax
1833
        ) );
1834
        $item = new WC_Order_Item_Coupon();
1835
        $item_id = $this->update_coupon( $item, $args );
1836
1837
		do_action( 'woocommerce_order_add_coupon', $this->get_id(), $item->get_order_item_id(), $code, $discount_amount, $discount_amount_tax );
1838
1839
		return $item_id;
1840
    }
1841
1842
    /**
1843
     * Update coupon for order. Note this does not update order totals.
1844
     * @since 2.2
1845
     * @param object|int $item
1846
     * @param array $args
1847
     * @return int updated order item ID
1848
     */
1849
    public function update_coupon( $item, $args ) {
1850
        if ( is_numeric( $item ) ) {
1851
            $item = $this->get_item( $item );
1852
        }
1853
1854
        if ( ! is_object( $product ) || ! $item->is_type( 'coupon' ) ) {
1855
            return false;
1856
        }
1857
1858
        if ( ! $this->get_id() ) {
1859
            $this->save();
1860
        }
1861
1862
		$item->set_order_id( $this->get_id() );
1863
1864
        if ( ! $item->get_order_item_id() ) {
1865
            $inserting = true;
1866
        } else {
1867
            $inserting = false;
1868
        }
1869
1870
        if ( isset( $args['code'] ) ) {
1871
            $item->set_coupon_code( $args['code'] );
1872
        }
1873
        if ( isset( $args['discount_amount'] ) ) {
1874
            $item->set_discount_amount( $args['discount_amount'] );
1875
        }
1876
        if ( isset( $args['discount_amount_tax'] ) ) {
1877
            $item->set_discount_amount_tax( $args['discount_amount_tax'] );
1878
        }
1879
1880
        $item->save();
1881
1882
        if ( ! $inserting ) {
1883
            do_action( 'woocommerce_order_update_coupon', $this->get_id(), $item->get_order_item_id(), $args );
1884
        }
1885
1886
        return $item->get_order_item_id();
1887
    }
1888
1889
    /**
1890
     * Add a shipping row to the order.
1891
     * Order must be saved prior to adding items.
1892
     *
1893
     * @param WC_Shipping_Rate shipping_rate
1894
     * @return int updated order item ID
1895
     */
1896
    public function add_shipping( $shipping_rate ) {
1897
        $args = wp_parse_args( $args, array(
1898
            'method_title' => $shipping_rate->label,
1899
            'method_id'    => $shipping_rate->id,
1900
            'cost'         => wc_format_decimal( $shipping_rate->cost ),
1901
            'taxes'        => $shipping_rate->taxes,
1902
            'meta'         => $shipping_rate->get_meta_data(),
1903
        ) );
1904
1905
        $item = new WC_Order_Item_Shipping();
1906
        $item_id = $this->update_shipping( $item, $args );
1907
1908
		do_action( 'woocommerce_order_add_shipping', $this->get_id(), $item->get_order_item_id(), $shipping_rate );
1909
1910
		return $item_id;
1911
    }
1912
1913
    /**
1914
     * Update shipping method for order.
1915
     *
1916
     * Note this does not update the order total.
1917
     *
1918
     * @since 2.2
1919
     * @param object|int $item
1920
     * @param array $args
1921
     * @return int updated order item ID
1922
     */
1923
    public function update_shipping( $item, $args ) {
1924
        if ( is_numeric( $item ) ) {
1925
            $item = $this->get_item( $item );
1926
        }
1927
1928
        if ( ! is_object( $product ) || ! $item->is_type( 'shipping' ) ) {
1929
            return false;
1930
        }
1931
1932
        if ( ! $this->get_id() ) {
1933
            $this->save();
1934
        }
1935
1936
		$item->set_order_id( $this->get_id() );
1937
1938
        if ( ! $item->get_order_item_id() ) {
1939
            $inserting = true;
1940
        } else {
1941
            $inserting = false;
1942
        }
1943
1944
        if ( isset( $args['method_title'] ) ) {
1945
            $item->set_method_title( $args['method_title'] );
1946
        }
1947
1948
        if ( isset( $args['method_id'] ) ) {
1949
            $item->set_method_id( $args['method_id'] );
1950
        }
1951
1952
        if ( isset( $args['cost'] ) ) {
1953
            // Get old cost before updating
1954
            $old_cost = $item->get_cost();
1955
1956
            // Update
1957
            $item->set_cost( $args['cost'] );
1958
1959
            // Update total
1960
            $this->set_total( $this->get_total_shipping() - wc_format_decimal( $old_cost ) + $item->get_cost(), 'shipping' );
1961
        }
1962
1963
        if ( isset( $args['taxes'] ) && is_array( $args['taxes'] ) ) {
1964
            $item->set_taxes( $args['taxes'] );
1965
        }
1966
1967
        if ( isset( $args['meta'] ) && is_array( $args['meta'] ) ) {
1968
			foreach ( $args['meta'] as $key => $value ) {
1969
				$item->update_meta_data( $key, $value );
1970
			}
1971
		}
1972
1973
        $item->save();
1974
1975
        if ( ! $inserting ) {
1976
            do_action( 'woocommerce_order_update_shipping', $this->get_id(), $item->get_order_item_id(), $args );
1977
        }
1978
1979
        return $item->get_order_item_id();
1980
    }
1981
1982
    /**
1983
     * Add a fee to the order.
1984
     * Order must be saved prior to adding items.
1985
     * @param object $fee
1986
     * @return int updated order item ID
1987
     */
1988
    public function add_fee( $fee ) {
1989
        $args = wp_parse_args( $args, array(
1990
            'name'      => $fee->name,
1991
            'tax_class' => $fee->taxable ? $fee->tax_class : 0,
1992
            'total'     => $fee->amount,
1993
            'total_tax' => $fee->tax,
1994
            'taxes'     => array(
1995
                'total' => $fee->tax_data
1996
            )
1997
        ) );
1998
        $item = new WC_Order_Item_Fee();
1999
        $item_id = $this->update_fee( $item, $args );
2000
2001
        do_action( 'woocommerce_order_add_fee', $this->get_id(), $item->get_order_item_id(), $fee );
2002
2003
        return $item_id;
2004
    }
2005
2006
    /**
2007
     * Update fee for order.
2008
     *
2009
     * Note this does not update order totals.
2010
     *
2011
     * @since 2.2
2012
     * @param object|int $item
2013
     * @param array $args
2014
     * @return int updated order item ID
2015
     */
2016
    public function update_fee( $item, $args ) {
2017
        if ( is_numeric( $item ) ) {
2018
            $item = $this->get_item( $item );
2019
        }
2020
2021
        if ( ! is_object( $product ) || ! $item->is_type( 'fee' ) ) {
2022
            return false;
2023
        }
2024
2025
        if ( ! $this->get_id() ) {
2026
            $this->save();
2027
        }
2028
2029
		$item->set_order_id( $this->get_id() );
2030
2031
        if ( ! $item->get_order_item_id() ) {
2032
            $inserting = true;
2033
        } else {
2034
            $inserting = false;
2035
        }
2036
2037
        if ( isset( $args['name'] ) ) {
2038
            $item->set_name( $args['name'] );
2039
        }
2040
2041
        if ( isset( $args['tax_class'] ) ) {
2042
            $item->set_tax_class( $args['tax_class'] );
2043
        }
2044
2045
        if ( isset( $args['total'] ) ) {
2046
            $item->set_total( $args['total'] );
2047
        }
2048
2049
        if ( isset( $args['total_tax'] ) ) {
2050
            $item->set_total_tax( $args['total_tax'] );
2051
        }
2052
2053
        if ( isset( $args['taxes'] ) ) {
2054
            $item->set_taxes( $args['taxes'] );
2055
        }
2056
2057
        $item->save();
2058
2059
        if ( ! $inserting ) {
2060
            do_action( 'woocommerce_order_update_fee', $this->get_id(), $item->get_order_item_id(), $args );
2061
        }
2062
2063
        return $item->get_order_item_id();
2064
    }
2065
2066
    /**
2067
     * Add a tax row to the order.
2068
     * Order must be saved prior to adding items.
2069
     * @since 2.2
2070
     * @param int tax_rate_id
2071
     * @return int updated order item ID
2072
     */
2073
    public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
2074
        if ( ! $code = WC_Tax::get_rate_code( $tax_rate_id ) ) {
2075
            return false;
2076
        }
2077
2078
        $args = wp_parse_args( $args, array(
2079
            'rate_code'          => $code,
2080
            'rate_id'            => $tax_rate_id,
2081
            'label'              => WC_Tax::get_rate_label( $tax_rate_id ),
2082
            'compound'           => WC_Tax::is_compound( $tax_rate_id ),
2083
            'tax_total'          => $tax_amount,
2084
            'shipping_tax_total' => $shipping_tax_amount
2085
        ) );
2086
        $item = new WC_Order_Item_Tax();
2087
        $item_id = $this->update_tax( $item, $args );
2088
2089
        do_action( 'woocommerce_order_add_tax', $this->get_id(), $item->get_order_item_id(), $tax_rate_id, $tax_amount, $shipping_tax_amount );
2090
2091
        return $item_id;
2092
    }
2093
2094
    /**
2095
     * Update tax line on order.
2096
     * Note this does not update order totals.
2097
     *
2098
     * @since 2.6
2099
     * @param object|int $item
2100
     * @param array $args
2101
     * @return int updated order item ID
2102
     */
2103
    public function update_tax( $item, $args ) {
2104
        if ( is_numeric( $item ) ) {
2105
            $item = $this->get_item( $item );
2106
        }
2107
2108
        if ( ! is_object( $product ) || ! $item->is_type( 'tax' ) ) {
2109
            return false;
2110
        }
2111
2112
        if ( ! $this->get_id() ) {
2113
            $this->save();
2114
        }
2115
2116
		$item->set_order_id( $this->get_id() );
2117
2118
        if ( ! $item->get_order_item_id() ) {
2119
            $inserting = true;
2120
        } else {
2121
            $inserting = false;
2122
        }
2123
2124
        if ( isset( $args['rate_code'] ) ) {
2125
            $item->set_rate_code( $args['rate_code'] );
2126
        }
2127
2128
        if ( isset( $args['rate_id'] ) ) {
2129
            $item->set_rate_id( $args['rate_id'] );
2130
        }
2131
2132
        if ( isset( $args['label'] ) ) {
2133
            $item->set_label( $args['label'] );
2134
        }
2135
2136
        if ( isset( $args['compound'] ) ) {
2137
            $item->set_compound( $args['compound'] );
2138
        }
2139
2140
        if ( isset( $args['tax_total'] ) ) {
2141
            $item->set_tax_total( $args['tax_total'] );
2142
        }
2143
2144
        if ( isset( $args['shipping_tax_total'] ) ) {
2145
            $item->set_shipping_tax_total( $args['shipping_tax_total'] );
2146
        }
2147
2148
        $item->save();
2149
2150
        if ( ! $inserting ) {
2151
            do_action( 'woocommerce_order_update_tax', $this->get_id(), $item->get_order_item_id(), $args );
2152
        }
2153
2154
        return $item->get_order_item_id();
2155
    }
2156
2157
	/**
2158
     * Update tax lines at order level by looking at the line item taxes themselves.
2159
     * @return bool success or fail.
2160
     */
2161
    public function update_taxes() {
2162
        $cart_taxes     = array();
2163
        $shipping_taxes = array();
2164
2165 View Code Duplication
        foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $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...
2166
            $taxes = $item->get_taxes();
2167
            if ( isset( $taxes['total'] ) ) {
2168
                foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
2169
                    if ( ! isset( $cart_taxes[ $tax_rate_id ] ) ) {
2170
                        $cart_taxes[ $tax_rate_id ] = 0;
2171
                    }
2172
                    $cart_taxes[ $tax_rate_id ] += $tax;
2173
                }
2174
            }
2175
        }
2176
2177 View Code Duplication
        foreach ( $this->get_items( array( 'shipping' ) ) as $item_id => $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...
2178
			$taxes = $item->get_taxes();
2179
            if ( isset( $taxes['total'] ) ) {
2180
                foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
2181
                    if ( ! isset( $shipping_taxes[ $tax_rate_id ] ) ) {
2182
                        $shipping_taxes[ $tax_rate_id ] = 0;
2183
                    }
2184
                    $shipping_taxes[ $tax_rate_id ] += $tax;
2185
                }
2186
            }
2187
        }
2188
2189
        // Remove old existing tax rows.
2190
        $this->remove_order_items( 'tax' );
2191
2192
        // Now merge to keep tax rows.
2193 View Code Duplication
        foreach ( array_keys( $cart_taxes + $shipping_taxes ) as $tax_rate_id ) {
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...
2194
            $this->add_tax( $tax_rate_id, isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
2195
        }
2196
2197
        // Save tax totals
2198
        $this->set_total( WC_Tax::round( array_sum( $shipping_taxes ) ), 'shipping_tax' );
2199
        $this->set_total( WC_Tax::round( array_sum( $cart_taxes ) ), 'tax' );
2200
2201
        return true;
2202
    }
2203
2204
    /*
2205
    |--------------------------------------------------------------------------
2206
    | Calculations.
2207
    |--------------------------------------------------------------------------
2208
    |
2209
    | These methods calculate order totals and taxes based on the current data.
2210
    |
2211
    */
2212
2213
    /**
2214
     * Calculate shipping total.
2215
     *
2216
     * @since 2.2
2217
     * @return float
2218
     */
2219
    public function calculate_shipping() {
2220
        $shipping_total = 0;
2221
2222
        foreach ( $this->get_shipping_methods() as $shipping ) {
2223
            $shipping_total += $shipping->get_total();
2224
        }
2225
2226
        $this->set_total( $shipping_total, 'shipping' );
2227
2228
        return $this->get_shipping_total();
2229
    }
2230
2231
    /**
2232
     * Calculate taxes for all line items and shipping, and store the totals and tax rows.
2233
     *
2234
     * Will use the base country unless customer addresses are set.
2235
     *
2236
     * @return bool success or fail.
2237
     */
2238
    public function calculate_taxes() {
2239
        $cart_tax     = 0;
2240
        $cart_taxes   = array();
2241
        $tax_based_on = get_option( 'woocommerce_tax_based_on' );
2242
2243
        if ( 'billing' === $tax_based_on ) {
2244
            $country  = $this->get_billing_country();
2245
            $state    = $this->get_billing_state();
2246
            $postcode = $this->get_billing_postcode();
2247
            $city     = $this->get_billing_city();
2248
        } elseif ( 'shipping' === $tax_based_on ) {
2249
            $country  = $this->get_shipping_country();
2250
            $state    = $this->get_shipping_state();
2251
            $postcode = $this->get_shipping_postcode();
2252
            $city     = $this->get_shipping_city();
2253
        }
2254
2255
        // Default to base
2256 View Code Duplication
        if ( 'base' === $tax_based_on || empty( $country ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2257
            $default  = wc_get_base_location();
2258
            $country  = $default['country'];
2259
            $state    = $default['state'];
2260
            $postcode = '';
2261
            $city     = '';
2262
        }
2263
2264
        // Get items
2265
        foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
2266
			$tax_class  = $item->get_tax_class();
2267
			$tax_status = $item->get_tax_status();
0 ignored issues
show
Unused Code introduced by
$tax_status is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2268
2269
            if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
2270
2271
                $tax_rates = WC_Tax::find_rates( array(
2272
                    'country'   => $country,
2273
                    'state'     => $state,
2274
                    'postcode'  => $postcode,
2275
                    'city'      => $city,
2276
                    'tax_class' => $tax_class
2277
                ) );
2278
2279
				$total     = $item->get_total();
2280
				$taxes     = WC_Tax::calc_tax( $total, $tax_rates, false );
2281
				$total_tax = max( 0, array_sum( $taxes ) );
2282
				$cart_tax += $total_tax;
2283
				$item->set_total_tax( $total_tax );
2284
2285
				if ( $item->is_type( 'line_item' ) ) {
2286
					$subtotal       = $item->get_subtotal();
2287
					$subtotal_taxes = WC_Tax::calc_tax( $subtotal, $tax_rates, false );
2288
					$subtotal_tax   = max( 0, array_sum( $subtotal_taxes ) );
2289
					$item->set_subtotal_tax( $subtotal_tax );
2290
					$item->set_taxes( array( 'total' => $taxes, 'subtotal' => $subtotal_taxes ) );
2291
				} else {
2292
					$item->set_taxes( array( 'total' => $taxes ) );
2293
				}
2294
2295
				$item->save(); //@todo store items to self, don't save right away
2296
2297
                // Sum the item taxes
2298
                foreach ( array_keys( $cart_taxes + $taxes ) as $key ) {
2299
                    $cart_taxes[ $key ] = ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $cart_taxes[ $key ] : 0 );
2300
                }
2301
            }
2302
        }
2303
2304
        // Now calculate shipping tax
2305
        $shipping_methods = $this->get_shipping_methods();
2306
2307
        if ( ! empty( $shipping_methods ) ) {
2308
            $matched_tax_rates = array();
2309
            $tax_rates         = WC_Tax::find_rates( array(
2310
                'country'   => $country,
2311
                'state'     => $state,
2312
                'postcode'  => $postcode,
2313
                'city'      => $city,
2314
                'tax_class' => ''
2315
            ) );
2316
2317 View Code Duplication
            if ( ! empty( $tax_rates ) ) {
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...
2318
                foreach ( $tax_rates as $key => $rate ) {
2319
                    if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) {
2320
                        $matched_tax_rates[ $key ] = $rate;
2321
                    }
2322
                }
2323
            }
2324
2325
            $shipping_taxes     = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates );
2326
            $shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) );
2327
        } else {
2328
            $shipping_taxes     = array();
2329
            $shipping_tax_total = 0;
2330
        }
2331
2332
        // Save tax totals
2333
        $this->set_total( $shipping_tax_total, 'shipping_tax' );
2334
        $this->set_total( $tax_total, 'tax' );
2335
2336
        // Tax rows
2337
        $this->remove_order_items( 'tax' );
2338
2339
        // Now merge to keep tax rows
2340 View Code Duplication
        foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) {
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...
2341
            $this->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
2342
        }
2343
2344
        return true;
2345
    }
2346
2347
    /**
2348
     * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
2349
     *
2350
     * @since 2.2
2351
     * @param  bool $and_taxes Calc taxes if true.
2352
     * @return float calculated grand total.
2353
     */
2354
    public function calculate_totals( $and_taxes = true ) {
2355
        $cart_subtotal     = 0;
2356
        $cart_total        = 0;
2357
        $fee_total         = 0;
2358
        $cart_subtotal_tax = 0;
2359
        $cart_total_tax    = 0;
2360
2361
        if ( $and_taxes && wc_tax_enabled() ) {
2362
            $this->calculate_taxes();
2363
        }
2364
2365
        // line items
2366
        foreach ( $this->get_items() as $item ) {
2367
            $cart_subtotal     += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 );
2368
            $cart_total        += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 );
2369
            $cart_subtotal_tax += wc_format_decimal( isset( $item['line_subtotal_tax'] ) ? $item['line_subtotal_tax'] : 0 );
2370
            $cart_total_tax    += wc_format_decimal( isset( $item['line_tax'] ) ? $item['line_tax'] : 0 );
2371
        }
2372
2373
        $this->calculate_shipping();
2374
2375
        foreach ( $this->get_fees() as $item ) {
2376
            $fee_total += $item['line_total'];
2377
        }
2378
2379
        $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' );
2380
        $this->set_total( $cart_subtotal_tax - $cart_total_tax, 'cart_discount_tax' );
2381
2382
        $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() );
2383
2384
        $this->set_total( $grand_total, 'total' );
2385
2386
        return $grand_total;
2387
    }
2388
2389
    /*
2390
    |--------------------------------------------------------------------------
2391
    | Total Getters
2392
    |--------------------------------------------------------------------------
2393
    |
2394
    | Methods for getting totals e.g. for display on the frontend.
2395
    |
2396
    */
2397
2398
    /**
2399
     * Get a product (either product or variation).
2400
     *
2401
     * @param object $item
2402
     * @return WC_Product|bool
2403
     */
2404
    public function get_product_from_item( $item ) {
2405
        if ( is_callable( array( $item, 'get_product' ) ) ) {
2406
            $product = $item->get_product();
2407
        } else {
2408
            $product = false;
2409
        }
2410
        return apply_filters( 'woocommerce_get_product_from_item', $product, $item, $this );
2411
    }
2412
2413
    /**
2414
     * Get item subtotal - this is the cost before discount.
2415
     *
2416
     * @param object $item
2417
     * @param bool $inc_tax (default: false).
2418
     * @param bool $round (default: true).
2419
     * @return float
2420
     */
2421 View Code Duplication
    public function get_item_subtotal( $item, $inc_tax = false, $round = 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...
2422
        $subtotal = 0;
2423
2424
        if ( is_callable( array( $item, 'get_subtotal' ) ) ) {
2425
            if ( $inc_tax ) {
2426
                $subtotal = ( $item->get_subtotal() + $item->get_subtotal_tax() ) / max( 1, $item->get_qty() );
2427
            } else {
2428
                $subtotal = ( $item->get_subtotal() / max( 1, $item->get_qty() ) );
2429
            }
2430
2431
            $subtotal = $round ? number_format( (float) $subtotal, wc_get_price_decimals(), '.', '' ) : $subtotal;
2432
        }
2433
2434
        return apply_filters( 'woocommerce_order_amount_item_subtotal', $subtotal, $this, $item, $inc_tax, $round );
2435
    }
2436
2437
    /**
2438
     * Get line subtotal - this is the cost before discount.
2439
     *
2440
     * @param object $item
2441
     * @param bool $inc_tax (default: false).
2442
     * @param bool $round (default: true).
2443
     * @return float
2444
     */
2445 View Code Duplication
    public function get_line_subtotal( $item, $inc_tax = false, $round = 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...
2446
        $subtotal = 0;
2447
2448
        if ( is_callable( array( $item, 'get_subtotal' ) ) ) {
2449
            if ( $inc_tax ) {
2450
                $subtotal = $item->get_subtotal() + $item->get_subtotal_tax();
2451
            } else {
2452
                $subtotal = $item->get_subtotal();
2453
            }
2454
2455
            $subtotal = $round ? round( $subtotal, wc_get_price_decimals() ) : $subtotal;
2456
        }
2457
2458
        return apply_filters( 'woocommerce_order_amount_line_subtotal', $subtotal, $this, $item, $inc_tax, $round );
2459
    }
2460
2461
    /**
2462
     * Calculate item cost - useful for gateways.
2463
     *
2464
     * @param object $item
2465
     * @param bool $inc_tax (default: false).
2466
     * @param bool $round (default: true).
2467
     * @return float
2468
     */
2469 View Code Duplication
    public function get_item_total( $item, $inc_tax = false, $round = 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...
2470
        $total = 0;
2471
2472
        if ( is_callable( array( $item, 'get_total' ) ) ) {
2473
            if ( $inc_tax ) {
2474
                $total = ( $item->get_total() + $item->get_total_tax() ) / max( 1, $item->get_qty() );
2475
            } else {
2476
                $total = $item->get_total() / max( 1, $item->get_qty() );
2477
            }
2478
2479
            $total = $round ? round( $total, wc_get_price_decimals() ) : $total;
2480
        }
2481
2482
        return apply_filters( 'woocommerce_order_amount_item_total', $total, $this, $item, $inc_tax, $round );
2483
    }
2484
2485
    /**
2486
     * Calculate line total - useful for gateways.
2487
     *
2488
     * @param object $item
2489
     * @param bool $inc_tax (default: false).
2490
     * @param bool $round (default: true).
2491
     * @return float
2492
     */
2493 View Code Duplication
    public function get_line_total( $item, $inc_tax = false, $round = 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...
2494
        $total = 0;
2495
2496
        if ( is_callable( array( $item, 'get_total' ) ) ) {
2497
            // Check if we need to add line tax to the line total.
2498
            $total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total();
2499
2500
            // Check if we need to round.
2501
            $total = $round ? round( $total, wc_get_price_decimals() ) : $total;
2502
        }
2503
2504
        return apply_filters( 'woocommerce_order_amount_line_total', $total, $this, $item, $inc_tax, $round );
2505
    }
2506
2507
    /**
2508
     * Get item tax - useful for gateways.
2509
     *
2510
     * @param mixed $item
2511
     * @param bool $round (default: true).
2512
     * @return float
2513
     */
2514
    public function get_item_tax( $item, $round = true ) {
2515
        $tax = 0;
2516
2517
        if ( is_callable( array( $item, 'get_total_tax' ) ) ) {
2518
            $tax = $item->get_total_tax() / max( 1, $item->get_qty() );
2519
            $tax = $round ? wc_round_tax_total( $tax ) : $tax;
2520
        }
2521
2522
        return apply_filters( 'woocommerce_order_amount_item_tax', $tax, $item, $round, $this );
2523
    }
2524
2525
    /**
2526
     * Get line tax - useful for gateways.
2527
     *
2528
     * @param mixed $item
2529
     * @return float
2530
     */
2531
    public function get_line_tax( $item ) {
2532
        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 );
2533
    }
2534
2535
    /**
2536
     * Gets line subtotal - formatted for display.
2537
     *
2538
     * @param array  $item
2539
     * @param string $tax_display
2540
     * @return string
2541
     */
2542
    public function get_formatted_line_subtotal( $item, $tax_display = '' ) {
2543
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2544
2545
        if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) {
2546
            return '';
2547
        }
2548
2549
        if ( 'excl' == $tax_display ) {
2550
            $ex_tax_label = $this->get_prices_include_tax() ? 1 : 0;
2551
2552
            $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_order_currency() ) );
0 ignored issues
show
Documentation introduced by
$item is of type array<string,?,{"line_su...ine_subtotal_tax":"?"}>, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2553
        } else {
2554
            $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array('currency' => $this->get_order_currency()) );
0 ignored issues
show
Documentation introduced by
$item is of type array<string,?,{"line_su...ine_subtotal_tax":"?"}>, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2555
        }
2556
2557
        return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this );
2558
    }
2559
2560
    /**
2561
     * Gets order total - formatted for display.
2562
     *
2563
     * @return string
2564
     */
2565
    public function get_formatted_order_total() {
2566
        $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_order_currency() ) );
2567
        return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this );
2568
    }
2569
2570
    /**
2571
     * Gets subtotal - subtotal is shown before discounts, but with localised taxes.
2572
     *
2573
     * @param bool $compound (default: false).
2574
     * @param string $tax_display (default: the tax_display_cart value).
2575
     * @return string
2576
     */
2577
    public function get_subtotal_to_display( $compound = false, $tax_display = '' ) {
2578
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2579
        $subtotal    = 0;
2580
2581
        if ( ! $compound ) {
2582
            foreach ( $this->get_items() as $item ) {
2583
                $subtotal += $item->get_subtotal();
2584
2585
                if ( 'incl' === $tax_display ) {
2586
                    $subtotal += $item->get_subtotal_tax();
2587
                }
2588
            }
2589
2590
            $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_order_currency() ) );
2591
2592
            if ( 'excl' === $tax_display && $this->get_prices_include_tax() ) {
2593
                $subtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>';
2594
            }
2595
2596
        } else {
2597
            if ( 'incl' === $tax_display ) {
2598
                return '';
2599
            }
2600
2601
            foreach ( $this->get_items() as $item ) {
2602
                $subtotal += $item->get_subtotal();
2603
            }
2604
2605
            // Add Shipping Costs.
2606
            $subtotal += $this->get_total_shipping();
2607
2608
            // Remove non-compound taxes.
2609
            foreach ( $this->get_taxes() as $tax ) {
2610
                if ( ! empty( $tax['compound'] ) ) {
2611
                    continue;
2612
                }
2613
                $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount'];
2614
            }
2615
2616
            // Remove discounts.
2617
            $subtotal = $subtotal - $this->get_total_discount();
2618
            $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_order_currency() ) );
2619
        }
2620
2621
        return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this );
2622
    }
2623
2624
    /**
2625
     * Gets shipping (formatted).
2626
     *
2627
     * @return string
2628
     */
2629
    public function get_shipping_to_display( $tax_display = '' ) {
2630
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2631
2632
        if ( $this->order_shipping != 0 ) {
2633
2634
            if ( $tax_display == 'excl' ) {
2635
2636
                // Show shipping excluding tax.
2637
                $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) );
2638
2639 View Code Duplication
                if ( $this->order_shipping_tax != 0 && $this->prices_include_tax ) {
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...
2640
                    $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', '&nbsp;<small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>', $this, $tax_display );
2641
                }
2642
2643
            } else {
2644
2645
                // Show shipping including tax.
2646
                $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) );
2647
2648 View Code Duplication
                if ( $this->order_shipping_tax != 0 && ! $this->prices_include_tax ) {
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...
2649
                    $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', '&nbsp;<small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>', $this, $tax_display );
2650
                }
2651
2652
            }
2653
2654
            $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_shipped_via', '&nbsp;<small class="shipped_via">' . sprintf( __( 'via %s', 'woocommerce' ), $this->get_shipping_method() ) . '</small>', $this );
2655
2656
        } elseif ( $this->get_shipping_method() ) {
2657
            $shipping = $this->get_shipping_method();
2658
        } else {
2659
            $shipping = __( 'Free!', 'woocommerce' );
2660
        }
2661
2662
        return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this );
2663
    }
2664
2665
    /**
2666
     * Get the discount amount (formatted).
2667
     * @since  2.3.0
2668
     * @return string
2669
     */
2670
    public function get_discount_to_display( $tax_display = '' ) {
2671
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2672
        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_order_currency() ) ), $this );
2673
    }
2674
2675
    /**
2676
     * Get totals for display on pages and in emails.
2677
     *
2678
     * @param mixed $tax_display
2679
     * @return array
2680
     */
2681
    public function get_order_item_totals( $tax_display = '' ) {
2682
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2683
        $total_rows  = array();
2684
2685
        if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) {
2686
            $total_rows['cart_subtotal'] = array(
2687
                'label' => __( 'Subtotal:', 'woocommerce' ),
2688
                'value'    => $subtotal
2689
            );
2690
        }
2691
2692
        if ( $this->get_total_discount() > 0 ) {
2693
            $total_rows['discount'] = array(
2694
                'label' => __( 'Discount:', 'woocommerce' ),
2695
                'value'    => '-' . $this->get_discount_to_display( $tax_display )
2696
            );
2697
        }
2698
2699
        if ( $this->get_shipping_method() ) {
2700
            $total_rows['shipping'] = array(
2701
                'label' => __( 'Shipping:', 'woocommerce' ),
2702
                'value'    => $this->get_shipping_to_display( $tax_display )
2703
            );
2704
        }
2705
2706
        if ( $fees = $this->get_fees() ) {
2707
            foreach ( $fees as $id => $fee ) {
2708
                if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', empty( $fee['line_total'] ) && empty( $fee['line_tax'] ), $id ) ) {
2709
                    continue;
2710
                }
2711
                $total_rows[ 'fee_' . $fee->get_order_item_id() ] = array(
2712
                    'label' => $fee->get_name() . ':',
2713
                    'value' => wc_price( 'excl' === $tax_display ? $fee->get_total() : $fee->get_total() + $fee->get_total_tax(), array('currency' => $this->get_order_currency()) )
2714
                );
2715
            }
2716
        }
2717
2718
        // Tax for tax exclusive prices.
2719
        if ( 'excl' === $tax_display ) {
2720
2721
            if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
2722
2723
                foreach ( $this->get_tax_totals() as $code => $tax ) {
2724
2725
                    $total_rows[ sanitize_title( $code ) ] = array(
2726
                        'label' => $tax->label . ':',
2727
                        'value'    => $tax->formatted_amount
2728
                    );
2729
                }
2730
2731
            } else {
2732
2733
                $total_rows['tax'] = array(
2734
                    'label' => WC()->countries->tax_or_vat() . ':',
2735
                    'value'    => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_order_currency() ) )
2736
                );
2737
            }
2738
        }
2739
2740
        if ( $this->get_total() > 0 && $this->get_payment_method_title() ) {
2741
            $total_rows['payment_method'] = array(
2742
                'label' => __( 'Payment Method:', 'woocommerce' ),
2743
                'value' => $this->get_payment_method_title()
2744
            );
2745
        }
2746
2747
        if ( $refunds = $this->get_refunds() ) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Abstract_Order as the method get_refunds() does only exist in the following sub-classes of WC_Abstract_Order: WC_Order. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

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

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

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

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

Available Fixes

  1. Change the type-hint for the parameter:

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

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

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
2748
            foreach ( $refunds as $id => $refund ) {
2749
                $total_rows[ 'refund_' . $id ] = array(
2750
                    'label' => $refund->get_refund_reason() ? $refund->get_refund_reason() : __( 'Refund', 'woocommerce' ) . ':',
2751
                    'value'    => wc_price( '-' . $refund->get_refund_amount(), array( 'currency' => $this->get_order_currency() ) )
2752
                );
2753
            }
2754
        }
2755
2756
        $total_rows['order_total'] = array(
2757
            'label' => __( 'Total:', 'woocommerce' ),
2758
            'value'    => $this->get_formatted_order_total( $tax_display )
0 ignored issues
show
Unused Code introduced by
The call to WC_Abstract_Order::get_formatted_order_total() has too many arguments starting with $tax_display.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
2759
        );
2760
2761
        return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this );
2762
    }
2763
2764
    /*
2765
    |--------------------------------------------------------------------------
2766
    | Conditionals
2767
    |--------------------------------------------------------------------------
2768
    |
2769
    | Checks if a condition is true or false.
2770
    |
2771
    */
2772
2773
    /**
2774
     * Checks the order status against a passed in status.
2775
     *
2776
     * @return bool
2777
     */
2778
    public function has_status( $status ) {
2779
        return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
2780
    }
2781
2782
    /**
2783
     * has_meta function for order items.
2784
     *
2785
     * @param string $order_item_id
2786
     * @return array of meta data.
2787
     */
2788
    public function has_meta( $order_item_id ) {
2789
        global $wpdb;
2790
2791
        return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
2792
            FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
2793
            ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
2794
    }
2795
2796
    /**
2797
     * Check whether this order has a specific shipping method or not.
2798
     *
2799
     * @param string $method_id
2800
     * @return bool
2801
     */
2802
    public function has_shipping_method( $method_id ) {
2803
        foreach ( $this->get_shipping_methods() as $shipping_method ) {
2804
            if ( $shipping_method->get_method_id() === $method_id ) {
2805
                return true;
2806
            }
2807
        }
2808
        return false;
2809
    }
2810
2811
    /**
2812
     * Check if an order key is valid.
2813
     *
2814
     * @param mixed $key
2815
     * @return bool
2816
     */
2817
    public function key_is_valid( $key ) {
2818
        return $key === $this->get_order_key();
2819
    }
2820
2821
    /**
2822
     * Returns true if the order contains a free product.
2823
     * @since 2.5.0
2824
     * @return bool
2825
     */
2826
    public function has_free_item() {
2827
        foreach ( $this->get_items() as $item ) {
2828
            if ( ! $item->get_total() ) {
2829
                return true;
2830
            }
2831
        }
2832
        return false;
2833
    }
2834
2835
    /*
2836
    |--------------------------------------------------------------------------
2837
    | Deprecated methods
2838
    |--------------------------------------------------------------------------
2839
    |
2840
    | Will be removed after 2 major releases, or 1 year.
2841
    |
2842
    */
2843
2844
    /**
2845
     * Magic __isset method for backwards compatibility.
2846
     * @param string $key
2847
     * @return bool
2848
     */
2849
    public function __isset( $key ) {
2850
        // Legacy properties which could be accessed directly in the past.
2851
        $legacy_props = array( 'completed_date', 'id', 'order_type', 'post', 'status', 'post_status', 'customer_note', 'customer_message', 'user_id', 'customer_user', 'prices_include_tax', 'tax_display_cart', 'display_totals_ex_tax', 'display_cart_ex_tax', 'order_date', 'modified_date', 'cart_discount', 'cart_discount_tax', 'order_shipping', 'order_shipping_tax', 'order_total', 'order_tax', 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode', 'billing_country', 'billing_phone', 'billing_email', 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode', 'shipping_country', 'customer_ip_address', 'customer_user_agent', 'payment_method_title', 'payment_method', 'order_currency' );
2852
        return $this->get_id() ? ( in_array( $key, $legacy_props ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) ) : false;
2853
    }
2854
2855
    /**
2856
     * Magic __get method for backwards compatibility.
2857
     * @param string $key
2858
     * @return mixed
2859
     */
2860
    public function __get( $key ) {
2861
        /**
2862
         * Maps legacy vars to new getters.
2863
         */
2864
        if ( 'completed_date' === $key ) {
2865
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2866
            return $this->get_date_completed();
2867
		} elseif ( 'paid_date' === $key ) {
2868
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2869
            return $this->get_date_paid();
2870
        } elseif ( 'modified_date' === $key ) {
2871
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2872
            return $this->get_date_modified();
2873
        } elseif ( 'order_date' === $key ) {
2874
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2875
            return $this->get_date_created();
2876
        } elseif ( 'id' === $key ) {
2877
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2878
            return $this->get_id();
2879
		} elseif ( 'post' === $key ) {
2880
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2881
            return get_post( $this->get_id() );
2882
		} elseif ( 'status' === $key || 'post_status' === $key ) {
2883
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2884
            return $this->get_status();
2885
		} elseif ( 'customer_message' === $key || 'customer_note' === $key ) {
2886
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2887
            return $this->get_customer_note();
2888
		} elseif ( in_array( $key, array( 'user_id', 'customer_user' ) ) ) {
2889
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2890
            return $this->get_customer_id();
2891
		} elseif ( 'tax_display_cart' === $key ) {
2892
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2893
			return get_option( 'woocommerce_tax_display_cart' );
2894
		} elseif ( 'display_totals_ex_tax' === $key ) {
2895
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2896
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
2897
		} elseif ( 'display_cart_ex_tax' === $key ) {
2898
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2899
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
2900
        } elseif ( 'cart_discount' === $key ) {
2901
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2902
			return $this->get_discount();
0 ignored issues
show
Bug introduced by
The method get_discount() does not exist on WC_Abstract_Order. Did you maybe mean get_discount_total()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
2903
        } elseif ( 'cart_discount_tax' === $key ) {
2904
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2905
			return $this->get_discount_tax();
2906
        } elseif ( 'order_tax' === $key ) {
2907
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2908
			return $this->get_cart_tax();
2909
        } elseif ( 'order_shipping_tax' === $key ) {
2910
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2911
            return $this->get_shipping_tax();
2912
        } elseif ( 'order_shipping' === $key ) {
2913
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2914
            return $this->get_shipping();
0 ignored issues
show
Bug introduced by
The method get_shipping() does not exist on WC_Abstract_Order. Did you maybe mean get_shipping_first_name()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
2915
        /**
2916
         * Map vars to getters with warning.
2917
         */
2918
	 	} elseif ( is_callable( array( $this, "get_{$key}" ) ) ) {
2919
			_doing_it_wrong( $key, 'Order properties should not be accessed directly Use get_' . $key . '().', '2.6' );
2920
            return $this->{"get_{$key}"}();
2921
        /**
2922
         * Handle post meta
2923
         */
2924
        } else {
2925
            _doing_it_wrong( $key, 'Meta should not be accessed directly. Use WC_Order::get_order_meta( $key )', '2.6' );
2926
			$value = get_post_meta( $this->get_id(), '_' . $key, true );
2927
		}
2928
2929
        return $value;
2930
    }
2931
2932
    /**
2933
     * Get order item meta.
2934
     * @deprecated 2.6.0
2935
     * @param mixed $order_item_id
2936
     * @param string $key (default: '')
2937
     * @param bool $single (default: false)
2938
     * @return array|string
2939
     */
2940
    public function get_item_meta( $order_item_id, $key = '', $single = false ) {
2941
        _deprecated_function( 'get_item_meta', '2.6', 'wc_get_order_item_meta' );
2942
        return get_metadata( 'order_item', $order_item_id, $key, $single );
2943
    }
2944
2945
    /**
2946
     * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
2947
     *
2948
     * @param mixed $order_item_id
2949
     * @return array of objects
2950
     */
2951
    public function get_item_meta_array( $order_item_id ) {
2952
        _deprecated_function( 'get_item_meta_array', '2.6', 'WC_Order_Item::get_meta_data()' );
2953
        $item = $this->get_item( $order_item_id );
2954
        return $item->get_meta_data();
2955
    }
2956
2957
    /**
2958
     * Expand item meta into the $item array.
2959
     * @deprecated 2.6.0 Item meta no longer expanded due to new order item
2960
     *        classes. This function now does nothing to avoid data breakage.
2961
     * @since 2.4.0
2962
     * @param array $item before expansion.
2963
     * @return array
2964
     */
2965
    public function expand_item_meta( $item ) {
2966
        _deprecated_function( 'expand_item_meta', '2.6', '' );
2967
        return $item;
2968
    }
2969
2970
	/**
2971
     * Load the order object. Called from the constructor.
2972
     * @deprecated 2.6.0 Logic moved to constructor
2973
     * @param int|object|WC_Order $order Order to init.
2974
     */
2975 View Code Duplication
    protected function init( $order ) {
1 ignored issue
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...
2976
		_deprecated_function( 'init', '2.6', 'Logic moved to constructor' );
2977
        if ( is_numeric( $order ) ) {
2978
            $this->read( $order );
2979
        } elseif ( $order instanceof WC_Order ) {
2980
            $this->read( absint( $order->get_id() ) );
2981
        } elseif ( isset( $order->ID ) ) {
2982
            $this->read( absint( $order->ID ) );
2983
        }
2984
    }
2985
2986
    /**
2987
     * Gets an order from the database.
2988
     * @deprecated 2.6
2989
     * @param int $id (default: 0).
2990
     * @return bool
2991
     */
2992 View Code Duplication
    public function get_order( $id = 0 ) {
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...
2993
        _deprecated_function( 'get_order', '2.6', 'read' );
2994
        if ( ! $id ) {
2995
            return false;
2996
        }
2997
        if ( $result = get_post( $id ) ) {
2998
            $this->populate( $result );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Abstract_Order::populate() has been deprecated with message: 2.6

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2999
            return true;
3000
        }
3001
        return false;
3002
    }
3003
3004
    /**
3005
     * Populates an order from the loaded post data.
3006
     * @deprecated 2.6
3007
     * @param mixed $result
3008
     */
3009
    public function populate( $result ) {
3010
        _deprecated_function( 'populate', '2.6', 'read' );
3011
        $this->read( $result->ID );
3012
    }
3013
3014
	/**
3015
     * Cancel the order and restore the cart (before payment).
3016
     * @deprecated 2.6.0 Moved to event handler.
3017
     * @param string $note (default: '') Optional note to add.
3018
     */
3019
    public function cancel_order( $note = '' ) {
3020
		_deprecated_function( 'cancel_order', '2.6', 'update_status' );
3021
        WC()->session->set( 'order_awaiting_payment', false );
3022
        $this->update_status( 'cancelled', $note );
3023
    }
3024
3025
	/**
3026
     * Record sales.
3027
     * @deprecated 2.6.0
3028
     */
3029
    public function record_product_sales() {
3030
		_deprecated_function( 'record_product_sales', '2.6', 'wc_update_total_sales_counts' );
3031
		wc_update_total_sales_counts( $this->get_id() );
3032
    }
3033
3034
	/**
3035
     * Increase applied coupon counts.
3036
     * @deprecated 2.6.0
3037
     */
3038
    public function increase_coupon_usage_counts() {
3039
		_deprecated_function( 'increase_coupon_usage_counts', '2.6', 'wc_update_coupon_usage_counts' );
3040
		wc_update_coupon_usage_counts( $this->get_id() );
3041
    }
3042
3043
    /**
3044
     * Decrease applied coupon counts.
3045
     * @deprecated 2.6.0
3046
     */
3047
    public function decrease_coupon_usage_counts() {
3048
		_deprecated_function( 'decrease_coupon_usage_counts', '2.6', 'wc_update_coupon_usage_counts' );
3049
		wc_update_coupon_usage_counts( $this->get_id() );
3050
    }
3051
3052
	/**
3053
     * Reduce stock levels for all line items in the order.
3054
	 * @deprecated 2.6.0
3055
     */
3056
    public function reduce_order_stock() {
3057
        _deprecated_function( 'reduce_order_stock', '2.6', 'wc_reduce_stock_levels' );
3058
		wc_reduce_stock_levels( $this->get_id() );
3059
    }
3060
3061
	/**
3062
     * Send the stock notifications.
3063
	 * @deprecated 2.6.0 No longer needs to be called directly.
3064
     */
3065
    public function send_stock_notifications( $product, $new_stock, $qty_ordered ) {
0 ignored issues
show
Unused Code introduced by
The parameter $product is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $new_stock is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $qty_ordered is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3066
        _deprecated_function( 'send_stock_notifications', '2.6' );
3067
    }
3068
3069
	/**
3070
	 * Output items for display in html emails.
3071
	 * @deprecated 2.6.0 Moved to template functions.
3072
	 * @param array $args Items args.
3073
	 * @return string
3074
	 */
3075
	public function email_order_items_table( $args = array() ) {
3076
		return wc_get_email_order_items( $this, $args );
0 ignored issues
show
Compatibility introduced by
$this of type object<WC_Abstract_Order> is not a sub-type of object<WC_Order>. It seems like you assume a child class of the class WC_Abstract_Order to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
3077
	}
3078
}
3079