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

WC_Abstract_Order::get_order_number()   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 0
1
<?php
2
/**
3
 * Abstract Order
4
 *
5
 * Handles order data and database interaction.
6
 *
7
 * @class       WC_Abstract_Order
8
 * @version     2.6.0
9
 * @package     WooCommerce/Classes
10
 * @category    Class
11
 * @author      WooThemes
12
 *
13
 * @todo check date formats are bw compat and consistant
14
 */
15
abstract class WC_Abstract_Order {
16
17
    /**
18
     * Stores data about status changes so relevant hooks can be fired.
19
     * @var bool|array
20
     */
21
    protected $_status_transition = false;
22
23
    /**
24
     * Data array, with defaults.
25
     *
26
     * @todo when migrating to custom tables, these will be columns
27
     * @since 2.6.0
28
     * @var array
29
     */
30
    protected $_data = array(
31
		'order_id'             => 0,
32
        'parent_id'            => 0,
33
		'status'               => '',
34
        /**
35
         * @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
36
         * The order type for shop_order_refund is refund.
37
         * Why do we need two separate variables? This should be unified, especially once this is in a custom table and post_type is redundent.
38
         * Switching to 'shop_order', and then using this value in the order factory instead of post_type. @thenbrent might have feedback on this.
39
         */
40
		'order_type'           => 'shop_order',
41
		'order_key'            => '',
42
		'order_currency'       => '',
43
		'date_created'         => '',
44
		'date_modified'        => '',
45
		'customer_id'          => 0,
46
		'billing_first_name'   => '',
47
		'billing_last_name'    => '',
48
		'billing_company'      => '',
49
		'billing_address_1'    => '',
50
		'billing_address_2'    => '',
51
		'billing_city'         => '',
52
		'billing_state'        => '',
53
		'billing_postcode'     => '',
54
		'billing_country'      => '',
55
		'billing_email'        => '',
56
		'billing_phone'        => '',
57
		'shipping_first_name'  => '',
58
		'shipping_last_name'   => '',
59
		'shipping_company'     => '',
60
		'shipping_address_1'   => '',
61
		'shipping_address_2'   => '',
62
		'shipping_city'        => '',
63
		'shipping_state'       => '',
64
		'shipping_postcode'    => '',
65
		'shipping_country'     => '',
66
		'discount_total'       => 0,
67
		'discount_tax'         => 0,
68
		'shipping_total'       => 0,
69
		'shipping_tax'         => 0,
70
		'cart_tax'             => 0, // cart_tax is the new name for the legacy 'order_tax' which is the tax for items only, not shipping.
71
		'order_total'          => 0,
72
		'order_tax'            => 0, // Sum of all taxes.
73
74
		// These will be meta when moving to custom data
75
		'payment_method'       => '',
76
		'payment_method_title' => '',
77
		'transaction_id'       => '',
78
		'customer_ip_address'  => '',
79
		'customer_user_agent'  => '',
80
		'created_via'          => '',
81
		'order_version'        => '',
82
		'prices_include_tax'   => false,
83
		'customer_note'        => '',
84
		'date_completed'       => '',
85
		'date_paid'            => '',
86
87
		// These will remain as order items @todo
88
		'line_items'           => array(),
89
		'tax_lines'            => array(),
90
		'shipping_lines'       => array(),
91
		'fees'                 => array(),
92
		'fee_lines'            => array(),
93
		'coupon_lines'         => array()
94
    );
95
96
    /**
97
     * Get the order if ID is passed, otherwise the order is new and empty.
98
     * This class should NOT be instantiated, but the get_order function or new WC_Order_Factory.
99
     * should be used. It is possible, but the aforementioned are preferred and are the only.
100
     * methods that will be maintained going forward.
101
     *
102
     * @param  int|object|WC_Order $order Order to init.
103
     */
104 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...
105
		if ( is_numeric( $order ) ) {
106
            $this->read( $order );
107
        } elseif ( $order instanceof WC_Order ) {
108
            $this->read( absint( $order->get_order_id() ) );
109
        } elseif ( ! empty( $order->ID ) ) {
110
            $this->read( absint( $order->ID ) );
111
        }
112
    }
113
114
    /**
115
     * Change data to JSON format.
116
     * @return string Data in JSON format.
117
     */
118
    public function __toString() {
119
        return json_encode( $this->get_data() );
120
    }
121
122
    public function add_meta_data(){} // @todo
123
    public function get_meta_data(){} // @todo
124
    public function get_order_meta( $key ){} // @todo
0 ignored issues
show
Unused Code introduced by
The parameter $key 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...
125
126
    /*
127
    |--------------------------------------------------------------------------
128
    | Getters
129
    |--------------------------------------------------------------------------
130
    |
131
    | Methods for getting data from the order object.
132
    |
133
    */
134
135
    /**
136
     * Get all class data in array format.
137
     * @since 2.6.0
138
     * @access protected
139
     * @return array
140
     */
141
    protected function get_data() {
142
        return $this->_data;
143
    }
144
145
    /**
146
     * Get order ID.
147
     * @since 2.6.0
148
     * @return integer
149
     */
150
    public function get_order_id() {
151
        return absint( $this->_data['order_id'] );
152
    }
153
154
    /**
155
     * Get parent order ID.
156
     * @since 2.6.0
157
     * @return integer
158
     */
159
    public function get_parent_id() {
160
        return absint( $this->_data['parent_id'] );
161
    }
162
163
    /**
164
     * get_order_number function.
165
     *
166
     * Gets the order number for display (by default, order ID).
167
     *
168
     * @return string
169
     */
170
    public function get_order_number() {
171
        return apply_filters( 'woocommerce_order_number', $this->get_order_id(), $this );
172
    }
173
174
    /**
175
     * Get order key.
176
     * @since 2.6.0
177
     * @return string
178
     */
179
    public function get_order_key() {
180
        return $this->_data['order_key'];
181
    }
182
183
    /**
184
     * Gets order currency.
185
     * @return string
186
     */
187
    public function get_order_currency() {
188
        return apply_filters( 'woocommerce_get_order_currency', $this->_data['order_currency'], $this );
189
    }
190
191
    /**
192
     * Get Order Type
193
     * @return string
194
     */
195
    public function get_order_type() {
196
        return $this->_data['order_type'];
197
    }
198
199
    /**
200
     * Get date_created
201
     * @return string
202
     */
203
    public function get_date_created() {
204
        return $this->_data['date_created'];
205
    }
206
207
    /**
208
     * Get date_modified
209
     * @return string
210
     */
211
    public function get_date_modified() {
212
        return $this->_data['date_modified'];
213
    }
214
215
    /**
216
     * Get date_completed
217
     * @return string
218
     */
219
    public function get_date_completed() {
220
        return $this->_data['date_completed'];
221
    }
222
223
	/**
224
     * Get date_paid
225
     * @return string
226
     */
227
    public function get_date_paid() {
228
        return $this->_data['date_paid'];
229
    }
230
231
    /**
232
     * Get customer_id
233
     * @return int
234
     */
235
    public function get_customer_id() {
236
        return absint( $this->_data['customer_id'] );
237
    }
238
239
    /**
240
     * Get billing_first_name
241
     * @return string
242
     */
243
    public function get_billing_first_name() {
244
        return $this->_data['billing_first_name'];
245
    }
246
247
    /**
248
     * Get billing_last_name
249
     * @return string
250
     */
251
    public function get_billing_last_name() {
252
        return $this->_data['billing_last_name'];
253
    }
254
255
    /**
256
     * Get billing_company
257
     * @return string
258
     */
259
    public function get_billing_company() {
260
        return $this->_data['billing_company'];
261
    }
262
263
    /**
264
     * Get billing_address_1
265
     * @return string
266
     */
267
    public function get_billing_address_1() {
268
        return $this->_data['billing_address_1'];
269
    }
270
271
    /**
272
     * Get billing_address_2
273
     * @return string $value
274
     */
275
    public function get_billing_address_2() {
276
        return $this->_data['billing_address_2'];
277
    }
278
279
    /**
280
     * Get billing_city
281
     * @return string $value
282
     */
283
    public function get_billing_city() {
284
        return $this->_data['billing_city'];
285
    }
286
287
    /**
288
     * Get billing_state
289
     * @return string
290
     */
291
    public function get_billing_state() {
292
        return $this->_data['billing_state'];
293
    }
294
295
    /**
296
     * Get billing_postcode
297
     * @return string
298
     */
299
    public function get_billing_postcode() {
300
        return $this->_data['billing_postcode'];
301
    }
302
303
    /**
304
     * Get billing_country
305
     * @return string
306
     */
307
    public function get_billing_country() {
308
        return $this->_data['billing_country'];
309
    }
310
311
    /**
312
     * Get billing_email
313
     * @return string
314
     */
315
    public function get_billing_email() {
316
        return sanitize_email( $this->_data['billing_email'] );
317
    }
318
319
    /**
320
     * Get billing_phone
321
     * @return string
322
     */
323
    public function get_billing_phone() {
324
        return $this->_data['billing_phone'];
325
    }
326
327
    /**
328
     * Get shipping_first_name
329
     * @return string
330
     */
331
    public function get_shipping_first_name() {
332
        return $this->_data['shipping_first_name'];
333
    }
334
335
    /**
336
     * Get shipping_last_name
337
     * @return string
338
     */
339
    public function get_shipping_last_name() {
340
         return $this->_data['shipping_last_name'];
341
    }
342
343
    /**
344
     * Get shipping_company
345
     * @return string
346
     */
347
    public function get_shipping_company() {
348
        return $this->_data['shipping_company'];
349
    }
350
351
    /**
352
     * Get shipping_address_1
353
     * @return string
354
     */
355
    public function get_shipping_address_1() {
356
        return $this->_data['shipping_address_1'];
357
    }
358
359
    /**
360
     * Get shipping_address_2
361
     * @return string
362
     */
363
    public function get_shipping_address_2() {
364
        return $this->_data['shipping_address_2'];
365
    }
366
367
    /**
368
     * Get shipping_city
369
     * @return string
370
     */
371
    public function get_shipping_city() {
372
        return $this->_data['shipping_city'];
373
    }
374
375
    /**
376
     * Get shipping_state
377
     * @return string
378
     */
379
    public function get_shipping_state() {
380
        return $this->_data['shipping_state'];
381
    }
382
383
    /**
384
     * Get shipping_postcode
385
     * @return string
386
     */
387
    public function get_shipping_postcode() {
388
        return $this->_data['shipping_postcode'];
389
    }
390
391
    /**
392
     * Get shipping_country
393
     * @return string
394
     */
395
    public function get_shipping_country() {
396
        return $this->_data['shipping_country'];
397
    }
398
399
    /**
400
     * Get the payment method.
401
     * @return string
402
     */
403
    public function get_payment_method() {
404
        return $this->_data['payment_method'];
405
    }
406
407
    /**
408
     * Get payment_method_title
409
     * @return string
410
     */
411
    public function get_payment_method_title() {
412
        return $this->_data['payment_method_title'];
413
    }
414
415
    /**
416
     * Get transaction_id
417
     * @return string
418
     */
419
    public function get_transaction_id() {
420
        return $this->_data['transaction_id'];
421
    }
422
423
    /**
424
     * Get customer_ip_address
425
     * @return string
426
     */
427
    public function get_customer_ip_address() {
428
        return $this->_data['customer_ip_address'];
429
    }
430
431
    /**
432
     * Get customer_user_agent
433
     * @return string
434
     */
435
    public function get_customer_user_agent() {
436
        return $this->_data['customer_user_agent'];
437
    }
438
439
    /**
440
     * Get created_via
441
     * @return string
442
     */
443
    public function get_created_via() {
444
        return $this->_data['created_via'];
445
    }
446
447
    /**
448
     * Get order_version
449
     * @return string
450
     */
451
    public function get_order_version() {
452
        return $this->_data['order_version'];
453
    }
454
455
    /**
456
     * Get prices_include_tax
457
     * @return bool
458
     */
459
    public function get_prices_include_tax() {
460
        return (bool) $this->_data['prices_include_tax'];
461
    }
462
463
    /**
464
     * Get customer_note
465
     * @return string
466
     */
467
    public function get_customer_note() {
468
        return $this->_data['customer_note'];
469
    }
470
471
    /**
472
     * Returns the requested address in raw, non-formatted way.
473
     * @since  2.4.0
474
     * @param  string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
475
     * @return array The stored address after filter.
476
     */
477
    public function get_address( $type = 'billing' ) {
478
        if ( 'billing' === $type ) {
479
            $address = array(
480
                'first_name' => $this->get_billing_first_name(),
481
                'last_name'  => $this->get_billing_last_name(),
482
                'company'    => $this->get_billing_company(),
483
                'address_1'  => $this->get_billing_address_1(),
484
                'address_2'  => $this->get_billing_address_2(),
485
                'city'       => $this->get_billing_city(),
486
                'state'      => $this->get_billing_state(),
487
                'postcode'   => $this->get_billing_postcode(),
488
                'country'    => $this->get_billing_country(),
489
                'email'      => $this->get_billing_email(),
490
                'phone'      => $this->get_billing_phone()
491
            );
492
        } else {
493
            $address = array(
494
                'first_name' => $this->get_shipping_first_name(),
495
                'last_name'  => $this->get_shipping_last_name(),
496
                'company'    => $this->get_shipping_company(),
497
                'address_1'  => $this->get_shipping_address_1(),
498
                'address_2'  => $this->get_shipping_address_2(),
499
                'city'       => $this->get_shipping_city(),
500
                'state'      => $this->get_shipping_state(),
501
                'postcode'   => $this->get_shipping_postcode(),
502
                'country'    => $this->get_shipping_country()
503
            );
504
        }
505
        return apply_filters( 'woocommerce_get_order_address', $address, $type, $this );
506
    }
507
508
    /**
509
     * Return the order statuses without wc- internal prefix.
510
     * @return string
511
     */
512
    public function get_status() {
513
        return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->_data['status'], 0, 3 ) ? substr( $this->_data['status'], 3 ) : $this->_data['status'], $this );
514
    }
515
516
    /**
517
     * Alias for get_customer_id().
518
     * @since  2.2
519
     * @return int
520
     */
521
    public function get_user_id() {
522
        return $this->get_customer_id();
523
    }
524
525
    /**
526
     * Get the user associated with the order. False for guests.
527
     *
528
     * @since  2.2
529
     * @return WP_User|false
530
     */
531
    public function get_user() {
532
        return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
533
    }
534
535
    /**
536
     * Get a formatted billing address for the order.
537
     * @return string
538
     */
539
    public function get_formatted_billing_address() {
540
        return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this ) );
541
    }
542
543
    /**
544
     * Get a formatted shipping address for the order.
545
     * @return string
546
     */
547
    public function get_formatted_shipping_address() {
548
        if ( $this->get_shipping_address_1() || $this->get_shipping_address_2() ) {
549
            return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_shipping_address', $this->get_address( 'shipping' ), $this ) );
550
        } else {
551
            return '';
552
        }
553
    }
554
555
    /**
556
     * Get a formatted shipping address for the order.
557
     *
558
     * @return string
559
     */
560
    public function get_shipping_address_map_url() {
561
        $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', array(
562
            'address_1' => $this->get_shipping_address_1(),
563
            'address_2' => $this->get_shipping_address_2(),
564
            'city'      => $this->get_shipping_city(),
565
            'state'     => $this->get_shipping_state(),
566
            'postcode'  => $this->get_shipping_postcode(),
567
            'country'   => $this->get_shipping_country()
568
        ), $this );
569
        return apply_filters( 'woocommerce_shipping_address_map_url', 'http://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this );
570
    }
571
572
    /**
573
     * Get a formatted billing full name.
574
     *
575
     * @since 2.4.0
576
     *
577
     * @return string
578
     */
579
    public function get_formatted_billing_full_name() {
580
        return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ),  $this->get_billing_first_name(), $this->get_billing_last_name() );
581
    }
582
583
    /**
584
     * Get a formatted shipping full name.
585
     *
586
     * @since 2.4.0
587
     *
588
     * @return string
589
     */
590
    public function get_formatted_shipping_full_name() {
591
        return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ),  $this->get_shipping_first_name(), $this->get_shipping_last_name() );
592
    }
593
594
    /**
595
     * Get discount_total
596
     * @return string
597
     */
598
    public function get_discount_total() {
599
        $discount_total = wc_format_decimal( $this->_data['discount_total'] );
600
601
        // Backwards compatible total calculation - totals were not stored consistently in old versions.
602
        if ( ( ! $this->get_order_version() || version_compare( $this->get_order_version(), '2.3.7', '<' ) ) && $this->get_prices_include_tax() ) {
603
            $discount_total = $discount_total - $this->get_discount_tax();
604
        }
605
606
        return $discount_total;
607
    }
608
609
    /**
610
     * Get discount_tax
611
     * @return string
612
     */
613
    public function get_discount_tax() {
614
        return wc_format_decimal( $this->_data['discount_tax'] );
615
    }
616
617
    /**
618
     * Get shipping_total
619
     * woocommerce_order_amount_total_shipping filter has been removed to avoid
620
     * these values being modified and then saved back to the DB. There are
621
     * other, later hooks available to change totals on display. e.g.
622
     * woocommerce_get_order_item_totals.
623
     * @return string
624
     */
625
    public function get_shipping_total() {
626
        return wc_format_decimal( $this->_data['shipping_total'] );
627
    }
628
629
    /**
630
     * Gets cart tax amount.
631
     *
632
     * @since 2.6.0 woocommerce_order_amount_cart_tax filter has been removed to avoid
633
     * these values being modified and then saved back to the DB or used in
634
     * calculations. There are other, later hooks available to change totals on
635
     * display. e.g. woocommerce_get_order_item_totals.
636
     * @return float
637
     */
638
    public function get_cart_tax() {
639
        return wc_format_decimal( $this->_data['cart_tax'] );
640
    }
641
642
    /**
643
     * Get shipping_tax.
644
     *
645
     * @since 2.6.0 woocommerce_order_amount_shipping_tax filter has been removed to avoid
646
     * these values being modified and then saved back to the DB or used in
647
     * calculations. There are other, later hooks available to change totals on
648
     * display. e.g. woocommerce_get_order_item_totals.
649
     * @return string
650
     */
651
    public function get_shipping_tax() {
652
        return wc_format_decimal( $this->_data['shipping_tax'] );
653
    }
654
655
    /**
656
     * Order tax is the sum of all taxes.
657
     * @return string
658
     */
659
    public function get_order_tax() {
660
        return wc_round_tax_total( $this->_data['order_tax'] );
661
    }
662
663
    /**
664
     * Get the stored order total. Includes taxes and everything else.
665
     * @return string
666
     */
667
    public function get_order_total() {
668
        return wc_format_decimal( $this->_data['order_total'], wc_get_price_decimals() );
669
    }
670
671
    /**
672
     * Gets the total discount amount.
673
     * @param  bool $ex_tax Show discount excl any tax.
674
     * @return float
675
     */
676
    public function get_total_discount( $ex_tax = true ) {
677
        if ( $ex_tax ) {
678
            $total_discount = $this->get_discount_total();
679
        } else {
680
            $total_discount = $this->get_discount_total() + $this->get_discount_tax();
681
        }
682
        return apply_filters( 'woocommerce_order_amount_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this );
683
    }
684
685
    /**
686
     * Get total tax amount. Alias for get_order_tax().
687
     *
688
     * @since 2.6.0 woocommerce_order_amount_total_tax filter has been removed to avoid
689
     * these values being modified and then saved back to the DB. There are
690
     * other, later hooks available to change totals on display. e.g.
691
     * woocommerce_get_order_item_totals.
692
     * @return float
693
     */
694
    public function get_total_tax() {
695
        return $this->get_order_tax();
696
    }
697
698
    /**
699
     * Gets shipping total. Alias of WC_Order::get_shipping_total().
700
     *
701
     * @since 2.6.0 woocommerce_order_amount_total_shipping filter has been removed to avoid
702
     * these values being modified and then saved back to the DB or used in
703
     * calculations. There are other, later hooks available to change totals on
704
     * display. e.g. woocommerce_get_order_item_totals.
705
     * @return float
706
     */
707
    public function get_total_shipping() {
708
        return $this->get_shipping_total();
709
    }
710
711
    /**
712
     * Gets order grand total. incl. taxes. Used in gateways. Filtered.
713
     * @return float
714
     */
715
    public function get_total() {
716
        return apply_filters( 'woocommerce_order_amount_total', $this->get_order_total(), $this );
717
    }
718
719
    /**
720
     * Gets order subtotal.
721
     * @return float
722
     */
723
    public function get_subtotal() {
724
        $subtotal = 0;
725
726
        foreach ( $this->get_items() as $item ) {
727
            $subtotal += isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0;
728
        }
729
730
        return apply_filters( 'woocommerce_order_amount_subtotal', (double) $subtotal, $this );
731
    }
732
733
    /**
734
     * Get taxes, merged by code, formatted ready for output.
735
     *
736
     * @return array
737
     */
738
    public function get_tax_totals() {
739
        $tax_totals = array();
740
741
        foreach ( $this->get_items( 'tax' ) as $key => $tax ) {
742
            $code = $tax[ 'name' ];
743
744 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...
745
                $tax_totals[ $code ] = new stdClass();
746
                $tax_totals[ $code ]->amount = 0;
747
            }
748
749
            $tax_totals[ $code ]->id                = $key;
750
            $tax_totals[ $code ]->rate_id           = $tax['rate_id'];
751
            $tax_totals[ $code ]->is_compound       = $tax[ 'compound' ];
752
            $tax_totals[ $code ]->label             = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
753
            $tax_totals[ $code ]->amount           += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
754
            $tax_totals[ $code ]->formatted_amount  = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) );
755
        }
756
757
        return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this );
758
    }
759
760
    /**
761
     * Gets formatted shipping method title.
762
     * @return string
763
     */
764
    public function get_shipping_method() {
765
        $names = array();
766
        foreach ( $this->get_shipping_methods() as $shipping_method ) {
767
            $names[] = $shipping_method->get_name();
768
        }
769
        return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $names ), $this );
770
    }
771
772
    /*
773
    |--------------------------------------------------------------------------
774
    | Setters
775
    |--------------------------------------------------------------------------
776
    |
777
    | Functions for setting order data. These should not update anything in the
778
    | database itself and should only change what is stored in the class
779
    | object. However, for backwards compatibility pre 2.6.0 some of these
780
    | setters may handle both.
781
    |
782
    */
783
784
    /**
785
     * Set order ID.
786
     * @since 2.6.0
787
     * @param int $value
788
     */
789
    public function set_order_id( $value ) {
790
        $this->_data['order_id'] = absint( $value );
791
    }
792
793
    /**
794
     * Set parent order ID.
795
     * @since 2.6.0
796
     * @param int $value
797
     */
798
    public function set_parent_id( $value ) {
799
        $this->_data['parent_id'] = absint( $value );
800
    }
801
802
    /**
803
     * Set order status.
804
     * @since 2.6.0
805
     * @param string $new_status Status to change the order to. No internal wc- prefix is required.
806
     * @param string $note (default: '') Optional note to add.
807
     * @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...
808
     */
809
    public function set_status( $new_status, $note = '', $manual_update = false ) {
810
        // Remove prefixes and standardize
811
        $current_status = $this->get_status();
812
        $new_status     = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status;
813
814
        if ( in_array( 'wc-' . $new_status, array_keys( wc_get_order_statuses() ) ) && $new_status !== $current_status ) {
815
            if ( ! empty( $current_status ) ) {
816
                $this->_status_transition = array(
817
                    'original' => ! empty( $this->_status_transition['original'] ) ? $this->_status_transition['original'] : $current_status,
818
                    'note'     => $note ? $note : '',
819
                    'manual'   => (bool) $manual_update
820
                );
821
				if ( 'completed' === $new_status ) {
822
					$this->set_date_completed( current_time( 'timestamp' ) );
823
				}
824
            }
825
            $this->_data['status'] = 'wc-' . $new_status;
826
        }
827
    }
828
829
	/**
830
     * Updates status of order immediately.
831
     * @uses WC_Order::set_status()
832
     */
833
    public function update_status( $new_status, $note = '', $manual = false ) {
834
        if ( ! $this->get_order_id() ) {
835
            return false;
836
        }
837
		$this->set_status( $new_status, $note, $manual );
838
		$this->save();
839
        return true;
840
    }
841
842
    /**
843
     * Set Order Type
844
     * @param string $value
845
     */
846
    public function set_order_type( $value ) {
847
        $this->_data['order_type'] = $value;
848
    }
849
850
    /**
851
     * Set order_key
852
     * @param string $value
853
     */
854
    public function set_order_key( $value ) {
855
        $this->_data['order_key'] = $value;
856
    }
857
858
    /**
859
     * Set order_currency
860
     * @param string $value
861
     */
862
    public function set_order_currency( $value ) {
863
        $this->_data['order_currency'] = $value;
864
    }
865
866
    /**
867
     * Set date_created
868
     * @param string $timestamp Timestamp
869
     */
870
    public function set_date_created( $timestamp ) {
871
        $this->_data['date_created'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
872
    }
873
874
    /**
875
     * Set date_modified
876
     * @param string $timestamp
877
     */
878
    public function set_date_modified( $timestamp ) {
879
        $this->_data['date_modified'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
880
    }
881
882
    /**
883
     * Set date_completed
884
     * @param string $timestamp
885
     */
886
    public function set_date_completed( $timestamp ) {
887
        $this->_data['date_completed'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
888
    }
889
890
	/**
891
     * Set date_paid
892
     * @param string $timestamp
893
     */
894
    public function set_date_paid( $timestamp ) {
895
        $this->_data['date_paid'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
896
    }
897
898
    /**
899
     * Set customer_id
900
     * @param int $value
901
     */
902
    public function set_customer_id( $value ) {
903
        $this->_data['customer_id'] = absint( $value );
904
    }
905
906
    /**
907
     * Set billing_first_name
908
     * @param string $value
909
     */
910
    public function set_billing_first_name( $value ) {
911
        $this->_data['billing_first_name'] = $value;
912
    }
913
914
    /**
915
     * Set billing_last_name
916
     * @param string $value
917
     */
918
    public function set_billing_last_name( $value ) {
919
        $this->_data['billing_last_name'] = $value;
920
    }
921
922
    /**
923
     * Set billing_company
924
     * @param string $value
925
     */
926
    public function set_billing_company( $value ) {
927
        $this->_data['billing_company'] = $value;
928
    }
929
930
    /**
931
     * Set billing_address_1
932
     * @param string $value
933
     */
934
    public function set_billing_address_1( $value ) {
935
        $this->_data['billing_address_1'] = $value;
936
    }
937
938
    /**
939
     * Set billing_address_2
940
     * @param string $value
941
     */
942
    public function set_billing_address_2( $value ) {
943
        $this->_data['billing_address_2'] = $value;
944
    }
945
946
    /**
947
     * Set billing_city
948
     * @param string $value
949
     */
950
    public function set_billing_city( $value ) {
951
        $this->_data['billing_city'] = $value;
952
    }
953
954
    /**
955
     * Set billing_state
956
     * @param string $value
957
     */
958
    public function set_billing_state( $value ) {
959
        $this->_data['billing_state'] = $value;
960
    }
961
962
    /**
963
     * Set billing_postcode
964
     * @param string $value
965
     */
966
    public function set_billing_postcode( $value ) {
967
        $this->_data['billing_postcode'] = $value;
968
    }
969
970
    /**
971
     * Set billing_country
972
     * @param string $value
973
     */
974
    public function set_billing_country( $value ) {
975
        $this->_data['billing_country'] = $value;
976
    }
977
978
    /**
979
     * Set billing_email
980
     * @param string $value
981
     */
982
    public function set_billing_email( $value ) {
983
		$value = sanitize_email( $value );
984
        $this->_data['billing_email'] = is_email( $value ) ? $value : '';
985
    }
986
987
    /**
988
     * Set billing_phone
989
     * @param string $value
990
     */
991
    public function set_billing_phone( $value ) {
992
        $this->_data['billing_phone'] = $value;
993
    }
994
995
    /**
996
     * Set shipping_first_name
997
     * @param string $value
998
     */
999
    public function set_shipping_first_name( $value ) {
1000
        $this->_data['shipping_first_name'] = $value;
1001
    }
1002
1003
    /**
1004
     * Set shipping_last_name
1005
     * @param string $value
1006
     */
1007
    public function set_shipping_last_name( $value ) {
1008
        $this->_data['shipping_last_name'] = $value;
1009
    }
1010
1011
    /**
1012
     * Set shipping_company
1013
     * @param string $value
1014
     */
1015
    public function set_shipping_company( $value ) {
1016
        $this->_data['shipping_company'] = $value;
1017
    }
1018
1019
    /**
1020
     * Set shipping_address_1
1021
     * @param string $value
1022
     */
1023
    public function set_shipping_address_1( $value ) {
1024
        $this->_data['shipping_address_1'] = $value;
1025
    }
1026
1027
    /**
1028
     * Set shipping_address_2
1029
     * @param string $value
1030
     */
1031
    public function set_shipping_address_2( $value ) {
1032
        $this->_data['shipping_address_2'] = $value;
1033
    }
1034
1035
    /**
1036
     * Set shipping_city
1037
     * @param string $value
1038
     */
1039
    public function set_shipping_city( $value ) {
1040
        $this->_data['shipping_city'] = $value;
1041
    }
1042
1043
    /**
1044
     * Set shipping_state
1045
     * @param string $value
1046
     */
1047
    public function set_shipping_state( $value ) {
1048
        $this->_data['shipping_state'] = $value;
1049
    }
1050
1051
    /**
1052
     * Set shipping_postcode
1053
     * @param string $value
1054
     */
1055
    public function set_shipping_postcode( $value ) {
1056
        $this->_data['shipping_postcode'] = $value;
1057
    }
1058
1059
    /**
1060
     * Set shipping_country
1061
     * @param string $value
1062
     */
1063
    public function set_shipping_country( $value ) {
1064
        $this->_data['shipping_country'] = $value;
1065
    }
1066
1067
    /**
1068
     * Set discount_total
1069
     * @param string $value
1070
     */
1071
    public function set_discount_total( $value ) {
1072
        $this->_data['discount_total'] = wc_format_decimal( $value );
1073
    }
1074
1075
    /**
1076
     * Set discount_tax
1077
     * @param string $value
1078
     */
1079
    public function set_discount_tax( $value ) {
1080
        $this->_data['discount_tax'] = wc_format_decimal( $value );
1081
    }
1082
1083
    /**
1084
     * Set shipping_total
1085
     * @param string $value
1086
     */
1087
    public function set_shipping_total( $value ) {
1088
        $this->_data['shipping_total'] = wc_format_decimal( $value );
1089
    }
1090
1091
    /**
1092
     * Set shipping_tax
1093
     * @param string $value
1094
     */
1095
    public function set_shipping_tax( $value ) {
1096
        $this->_data['shipping_tax'] = wc_format_decimal( $value );
1097
        $this->set_order_tax( $this->get_cart_tax() + $this->get_shipping_tax() );
1098
    }
1099
1100
    /**
1101
     * Set cart tax
1102
     * @param string $value
1103
     */
1104
    public function set_cart_tax( $value ) {
1105
        $this->_data['cart_tax'] = wc_format_decimal( $value );
1106
        $this->set_order_tax( $this->get_cart_tax() + $this->get_shipping_tax() );
1107
    }
1108
1109
    /**
1110
     * Sets order tax (sum of cart and shipping tax). Used internaly only.
1111
     * @access protected
1112
     * @param string $value
1113
     */
1114
    protected function set_order_tax( $value ) {
1115
        $this->_data['order_tax'] = wc_format_decimal( $value );
1116
    }
1117
1118
    /**
1119
     * Set order_total
1120
     * @param string $value
1121
     */
1122
    public function set_order_total( $value ) {
1123
        $this->_data['order_total'] = wc_format_decimal( $value, wc_get_price_decimals() );
1124
    }
1125
1126
    /**
1127
     * Set the payment method ID.
1128
     * @since 2.2.0
1129
     * @param string $value Supports WC_Payment_Gateway for bw compatibility with < 2.6
1130
     */
1131
    public function set_payment_method( $value ) {
1132
        if ( is_object( $value ) ) {
1133
            update_post_meta( $this->get_order_id(), '_payment_method', $value->id );
1134
            update_post_meta( $this->get_order_id(), '_payment_method_title', $value->get_title() );
1135
            $this->set_payment_method( $value->id );
1136
            $this->set_payment_method_title( $value->get_title() );
1137
        } else {
1138
            $this->_data['payment_method'] = $value;
1139
        }
1140
    }
1141
1142
    /**
1143
     * Set payment_method_title
1144
     * @param string $value
1145
     */
1146
    public function set_payment_method_title( $value ) {
1147
        $this->_data['payment_method_title'] = $value;
1148
    }
1149
1150
    /**
1151
     * Set transaction_id
1152
     * @param string $value
1153
     */
1154
    public function set_transaction_id( $value ) {
1155
        $this->_data['transaction_id'] = $value;
1156
    }
1157
1158
    /**
1159
     * Set customer_ip_address
1160
     * @param string $value
1161
     */
1162
    public function set_customer_ip_address( $value ) {
1163
        $this->_data['customer_ip_address'] = $value;
1164
    }
1165
1166
    /**
1167
     * Set customer_user_agent
1168
     * @param string $value
1169
     */
1170
    public function set_customer_user_agent( $value ) {
1171
        $this->_data['customer_user_agent'] = $value;
1172
    }
1173
1174
    /**
1175
     * Set created_via
1176
     * @param string $value
1177
     */
1178
    public function set_created_via( $value ) {
1179
        $this->_data['created_via'] = $value;
1180
    }
1181
1182
    /**
1183
     * Set order_version
1184
     * @param string $value
1185
     */
1186
    public function set_order_version( $value ) {
1187
        $this->_data['order_version'] = $value;
1188
    }
1189
1190
    /**
1191
     * Set prices_include_tax
1192
     * @param bool $value
1193
     */
1194
    public function set_prices_include_tax( $value ) {
1195
        $this->_data['prices_include_tax'] = (bool) $value;
1196
    }
1197
1198
    /**
1199
     * Set customer_note
1200
     * @param string $value
1201
     */
1202
    public function set_customer_note( $value ) {
1203
        $this->_data['customer_note'] = $value;
1204
    }
1205
1206
    /**
1207
     * Set the customer address.
1208
     * @since 2.2.0
1209
     * @param array $address Address data.
1210
     * @param string $type billing or shipping.
1211
     */
1212
    public function set_address( $address, $type = 'billing' ) {
1213
        foreach ( $address as $key => $value ) {
1214
            update_post_meta( $this->get_order_id(), "_{$type}_" . $key, $value );
1215
            if ( method_exists( $this, "set_{$type}_{$key}" ) ) {
1216
                $this->{"set_{$type}_{$key}"}( $value );
1217
            }
1218
        }
1219
    }
1220
1221
    /**
1222
     * Set an order total.
1223
     * @since 2.2.0
1224
     * @param float $amount
1225
     * @param string $total_type
1226
     * @return bool
1227
     */
1228
    public function set_total( $amount, $total_type = 'total' ) {
1229
        if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
1230
            return false;
1231
        }
1232
1233
        switch ( $total_type ) {
1234
            case 'total' :
1235
                $amount = wc_format_decimal( $amount, wc_get_price_decimals() );
1236
                $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 1235 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...
1237
                update_post_meta( $this->get_order_id(), '_order_total', $amount );
1238
                break;
1239
            case 'cart_discount' :
1240
                $amount = wc_format_decimal( $amount );
1241
                $this->set_discount_total( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1240 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...
1242
                update_post_meta( $this->get_order_id(), '_cart_discount', $amount );
1243
                break;
1244
            case 'cart_discount_tax' :
1245
                $amount = wc_format_decimal( $amount );
1246
                $this->set_discount_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1245 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...
1247
                update_post_meta( $this->get_order_id(), '_cart_discount_tax', $amount );
1248
                break;
1249
            case 'shipping' :
1250
                $amount = wc_format_decimal( $amount );
1251
                $this->set_shipping_total( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1250 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...
1252
                update_post_meta( $this->get_order_id(), '_order_shipping', $amount );
1253
                break;
1254
            case 'shipping_tax' :
1255
                $amount = wc_format_decimal( $amount );
1256
                $this->set_shipping_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1255 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...
1257
                update_post_meta( $this->get_order_id(), '_order_shipping_tax', $amount );
1258
                break;
1259
            case 'tax' :
1260
                $amount = wc_format_decimal( $amount );
1261
                $this->set_cart_tax( $amount );
1 ignored issue
show
Bug introduced by
It seems like $amount defined by wc_format_decimal($amount) on line 1260 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...
1262
                update_post_meta( $this->get_order_id(), '_order_tax', $amount );
1263
                break;
1264
        }
1265
1266
        return true;
1267
    }
1268
1269
    /*
1270
    |--------------------------------------------------------------------------
1271
    | CRUD methods
1272
    |--------------------------------------------------------------------------
1273
    |
1274
    | Methods which create, read, update and delete orders from the database.
1275
    | Written in abstract fashion so that the way orders are stored can be
1276
    | changed more easily in the future.
1277
    |
1278
    | A save method is included for convenience (chooses update or create based
1279
    | on if the order exists yet).
1280
    |
1281
    */
1282
1283
    /**
1284
     * Insert data into the database.
1285
     * @since 2.6.0
1286
     * @access protected
1287
     */
1288
    protected function create() {
1289
        // Set random key
1290
        $this->set_order_key( uniqid( 'order_' ) );
1291
1292
        $order_id = wp_insert_post( apply_filters( 'woocommerce_new_order_data', array(
1293
            'post_type'     => $this->get_order_type(),
1294
            'post_status'   => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
1295
            'ping_status'   => 'closed',
1296
            'post_author'   => 1,
1297
            'post_title'    => sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ),
1298
            'post_password' => $this->get_order_key(),
1299
            'post_parent'   => $this->get_parent_id()
1300
        ) ), true );
1301
1302
        if ( $order_id ) {
1303
            $this->set_order_id( $order_id );
1304
1305
            // Set meta data
1306
            update_post_meta( $order_id, '_billing_first_name', $this->get_billing_first_name() );
1307
            update_post_meta( $order_id, '_billing_last_name', $this->get_billing_last_name() );
1308
            update_post_meta( $order_id, '_billing_company', $this->get_billing_company() );
1309
            update_post_meta( $order_id, '_billing_address_1', $this->get_billing_address_1() );
1310
            update_post_meta( $order_id, '_billing_address_2', $this->get_billing_address_2() );
1311
            update_post_meta( $order_id, '_billing_city', $this->get_billing_city() );
1312
            update_post_meta( $order_id, '_billing_state', $this->get_billing_state() );
1313
            update_post_meta( $order_id, '_billing_postcode', $this->get_billing_postcode() );
1314
            update_post_meta( $order_id, '_billing_country', $this->get_billing_country() );
1315
            update_post_meta( $order_id, '_billing_email', $this->get_billing_email() );
1316
            update_post_meta( $order_id, '_billing_phone', $this->get_billing_phone() );
1317
            update_post_meta( $order_id, '_shipping_first_name', $this->get_shipping_first_name() );
1318
            update_post_meta( $order_id, '_shipping_last_name', $this->get_shipping_last_name() );
1319
            update_post_meta( $order_id, '_shipping_company', $this->get_shipping_company() );
1320
            update_post_meta( $order_id, '_shipping_address_1', $this->get_shipping_address_1() );
1321
            update_post_meta( $order_id, '_shipping_address_2', $this->get_shipping_address_2() );
1322
            update_post_meta( $order_id, '_shipping_city', $this->get_shipping_city() );
1323
            update_post_meta( $order_id, '_shipping_state', $this->get_shipping_state() );
1324
            update_post_meta( $order_id, '_shipping_postcode', $this->get_shipping_postcode() );
1325
            update_post_meta( $order_id, '_shipping_country', $this->get_shipping_country() );
1326
            update_post_meta( $order_id, '_payment_method', $this->get_payment_method() );
1327
            update_post_meta( $order_id, '_payment_method_title', $this->get_payment_method_title() );
1328
            update_post_meta( $order_id, '_transaction_id', $this->get_transaction_id() );
1329
            update_post_meta( $order_id, '_customer_user', $this->get_customer_id() );
1330
            update_post_meta( $order_id, '_customer_ip_address', $this->get_customer_ip_address() );
1331
            update_post_meta( $order_id, '_customer_user_agent', $this->get_customer_user_agent() );
1332
            update_post_meta( $order_id, '_created_via', $this->get_created_via() );
1333
            update_post_meta( $order_id, '_order_version', $this->get_order_version() );
1334
            update_post_meta( $order_id, '_prices_include_tax', $this->get_prices_include_tax() );
1335
            update_post_meta( $order_id, '_completed_date', $this->get_date_completed() );
1336
			update_post_meta( $order_id, '_paid_date', $this->get_date_paid() );
1337
            update_post_meta( $order_id, '_order_currency', $this->get_order_currency() );
1338
            update_post_meta( $order_id, '_order_key', $this->get_order_key() );
1339
            update_post_meta( $order_id, '_cart_discount', $this->get_discount_total() );
1340
            update_post_meta( $order_id, '_cart_discount_tax', $this->get_discount_tax() );
1341
            update_post_meta( $order_id, '_order_shipping', $this->get_shipping_total() );
1342
            update_post_meta( $order_id, '_order_shipping_tax', $this->get_shipping_tax() );
1343
            update_post_meta( $order_id, '_order_tax', $this->get_cart_tax() );
1344
            update_post_meta( $order_id, '_order_total', $this->get_order_total() );
1345
        }
1346
    }
1347
1348
    /**
1349
     * Read from the database.
1350
     * @since 2.6.0
1351
     * @access protected
1352
     * @param int $id ID of object to read.
1353
     */
1354
    protected function read( $id ) {
1355
        $post_object = get_post( $id );
1356
        $order_id    = absint( $post_object->ID );
1357
1358
        // Map standard post data
1359
        $this->set_order_id( $order_id );
1360
        $this->set_date_created( $post_object->post_date );
1361
        $this->set_date_modified( $post_object->post_modified );
1362
        $this->set_status( $post_object->post_status );
1363
        $this->set_customer_note( $post_object->post_excerpt );
1364
1365
        // Map meta data
1366
        $this->set_customer_id( get_post_meta( $order_id, '_customer_user', true ) );
1367
        $this->set_order_key( get_post_meta( $order_id, '_order_key', true ) );
1368
        $this->set_order_currency( get_post_meta( $order_id, '_order_currency', true ) );
1369
        $this->set_billing_first_name( get_post_meta( $order_id, '_billing_first_name', true ) );
1370
        $this->set_billing_last_name( get_post_meta( $order_id, '_billing_last_name', true ) );
1371
        $this->set_billing_company( get_post_meta( $order_id, '_billing_company', true ) );
1372
        $this->set_billing_address_1( get_post_meta( $order_id, '_billing_address_1', true ) );
1373
        $this->set_billing_address_2( get_post_meta( $order_id, '_billing_address_2', true ) );
1374
        $this->set_billing_city( get_post_meta( $order_id, '_billing_city', true ) );
1375
        $this->set_billing_state( get_post_meta( $order_id, '_billing_state', true ) );
1376
        $this->set_billing_postcode( get_post_meta( $order_id, '_billing_postcode', true ) );
1377
        $this->set_billing_country( get_post_meta( $order_id, '_billing_country', true ) );
1378
        $this->set_billing_email( get_post_meta( $order_id, 'billing_email', true ) );
1379
        $this->set_billing_phone( get_post_meta( $order_id, '_billing_phone', true ) );
1380
        $this->set_shipping_first_name( get_post_meta( $order_id, '_shipping_first_name', true ) );
1381
        $this->set_shipping_last_name( get_post_meta( $order_id, '_shipping_last_name', true ) );
1382
        $this->set_shipping_company( get_post_meta( $order_id, '_shipping_company', true ) );
1383
        $this->set_shipping_address_1( get_post_meta( $order_id, '_shipping_address_1', true ) );
1384
        $this->set_shipping_address_2( get_post_meta( $order_id, '_shipping_address_2', true ) );
1385
        $this->set_shipping_city( get_post_meta( $order_id, '_shipping_city', true ) );
1386
        $this->set_shipping_state( get_post_meta( $order_id, '_shipping_state', true ) );
1387
        $this->set_shipping_postcode( get_post_meta( $order_id, '_shipping_postcode', true ) );
1388
        $this->set_shipping_country( get_post_meta( $order_id, '_shipping_country', true ) );
1389
        $this->set_payment_method( get_post_meta( $order_id, '_payment_method', true ) );
1390
        $this->set_payment_method_title( get_post_meta( $order_id, '_payment_method_title', true ) );
1391
        $this->set_transaction_id( get_post_meta( $order_id, '_transaction_id', true ) );
1392
        $this->set_customer_ip_address( get_post_meta( $order_id, '_customer_ip_address', true ) );
1393
        $this->set_customer_user_agent(get_post_meta( $order_id, '_customer_user_agent', true ) );
1394
        $this->set_created_via( get_post_meta( $order_id, '_created_via', true ) );
1395
        $this->set_order_version( get_post_meta( $order_id, '_order_version', true ) );
1396
        $this->set_prices_include_tax( get_post_meta( $order_id, '_prices_include_tax', true ) );
1397
        $this->set_date_completed( get_post_meta( $order_id, '_completed_date', true ) );
1398
		$this->set_date_paid( get_post_meta( $order_id, '_paid_date', true ) );
1399
1400
        // Map totals
1401
        $this->set_discount_total( get_post_meta( $order_id, '_cart_discount', true ) );
1402
        $this->set_discount_tax( get_post_meta( $order_id, '_cart_discount_tax', true ) );
1403
        $this->set_shipping_total( get_post_meta( $order_id, '_order_shipping', true ) );
1404
        $this->set_shipping_tax( get_post_meta( $order_id, '_order_shipping_tax', true ) );
1405
        $this->set_cart_tax( get_post_meta( $order_id, '_order_tax', true ) );
1406
        $this->set_order_total( get_post_meta( $order_id, '_order_total', true ) );
1407
1408
        // Map user data
1409
        if ( empty( $this->get_billing_email() ) && ( $user = $this->get_user() ) ) {
1410
            $this->set_billing_email( $user->user_email );
1411
        }
1412
1413
        // Orders store the state of prices including tax when created.
1414
        $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' );
1415
    }
1416
1417
    /**
1418
     * Update data in the database.
1419
     * @since 2.6.0
1420
     * @access protected
1421
     */
1422
    protected function update() {
1423
        global $wpdb;
1424
1425
        $order_id = $this->get_order_id();
1426
1427
        $wpdb->update(
1428
            $wpdb->posts,
1429
            array(
1430
                'post_date'     => date( 'Y-m-d H:i:s', $this->get_date_created() ),
1431
                'post_date_gmt' => get_gmt_from_date( date( 'Y-m-d H:i:s', $this->get_date_created() ) ),
1432
                'post_status'   => 'wc-' . ( $this->get_status() ? $this->get_status() : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
1433
                'post_parent'   => $this->get_parent_id()
1434
            ),
1435
            array(
1436
                'ID' => $order_id
1437
            )
1438
        );
1439
1440
        // Update meta data
1441
        update_post_meta( $order_id, '_billing_first_name', $this->get_billing_first_name() );
1442
        update_post_meta( $order_id, '_billing_last_name', $this->get_billing_last_name() );
1443
        update_post_meta( $order_id, '_billing_company', $this->get_billing_company() );
1444
        update_post_meta( $order_id, '_billing_address_1', $this->get_billing_address_1() );
1445
        update_post_meta( $order_id, '_billing_address_2', $this->get_billing_address_2() );
1446
        update_post_meta( $order_id, '_billing_city', $this->get_billing_city() );
1447
        update_post_meta( $order_id, '_billing_state', $this->get_billing_state() );
1448
        update_post_meta( $order_id, '_billing_postcode', $this->get_billing_postcode() );
1449
        update_post_meta( $order_id, '_billing_country', $this->get_billing_country() );
1450
        update_post_meta( $order_id, '_billing_email', $this->get_billing_email() );
1451
        update_post_meta( $order_id, '_billing_phone', $this->get_billing_phone() );
1452
        update_post_meta( $order_id, '_shipping_first_name', $this->get_shipping_first_name() );
1453
        update_post_meta( $order_id, '_shipping_last_name', $this->get_shipping_last_name() );
1454
        update_post_meta( $order_id, '_shipping_company', $this->get_shipping_company() );
1455
        update_post_meta( $order_id, '_shipping_address_1', $this->get_shipping_address_1() );
1456
        update_post_meta( $order_id, '_shipping_address_2', $this->get_shipping_address_2() );
1457
        update_post_meta( $order_id, '_shipping_city', $this->get_shipping_city() );
1458
        update_post_meta( $order_id, '_shipping_state', $this->get_shipping_state() );
1459
        update_post_meta( $order_id, '_shipping_postcode', $this->get_shipping_postcode() );
1460
        update_post_meta( $order_id, '_shipping_country', $this->get_shipping_country() );
1461
        update_post_meta( $order_id, '_payment_method', $this->get_payment_method() );
1462
        update_post_meta( $order_id, '_payment_method_title', $this->get_payment_method_title() );
1463
        update_post_meta( $order_id, '_transaction_id', $this->get_transaction_id() );
1464
        update_post_meta( $order_id, '_customer_user', $this->get_customer_id() );
1465
        update_post_meta( $order_id, '_customer_ip_address', $this->get_customer_ip_address() );
1466
        update_post_meta( $order_id, '_customer_user_agent', $this->get_customer_user_agent() );
1467
        update_post_meta( $order_id, '_created_via', $this->get_created_via() );
1468
        update_post_meta( $order_id, '_order_version', $this->get_order_version() );
1469
        update_post_meta( $order_id, '_prices_include_tax', $this->get_prices_include_tax() );
1470
        update_post_meta( $order_id, '_order_currency', $this->get_order_currency() );
1471
        update_post_meta( $order_id, '_order_key', $this->get_order_key() );
1472
        update_post_meta( $order_id, '_cart_discount', $this->get_discount_total() );
1473
        update_post_meta( $order_id, '_cart_discount_tax', $this->get_discount_tax() );
1474
        update_post_meta( $order_id, '_order_shipping', $this->get_shipping_total() );
1475
        update_post_meta( $order_id, '_order_shipping_tax', $this->get_shipping_tax() );
1476
        update_post_meta( $order_id, '_order_tax', $this->get_cart_tax() );
1477
        update_post_meta( $order_id, '_order_total', $this->get_order_total() );
1478
1479
        if ( $this->_status_transition ) {
1480
            if ( ! empty( $this->_status_transition['original'] ) ) {
1481
                $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() ) );
1482
1483
                do_action( 'woocommerce_order_status_' . $this->_status_transition['original'] . '_to_' . $this->get_status(), $this->get_order_id() );
1484
                do_action( 'woocommerce_order_status_changed', $this->get_order_id(), $this->_status_transition['original'], $this->get_status() );
1485
            } else {
1486
                $transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $this->get_status() ) );
1487
            }
1488
1489
            do_action( 'woocommerce_order_status_' . $this->get_status(), $this->get_order_id() );
1490
1491
            // Note the transition occured
1492
            $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...
1493
1494
            // This has ran, so reset status transition variable
1495
            $this->_status_transition = false;
1496
        }
1497
    }
1498
1499
    /**
1500
     * Delete data from the database.
1501
     * @since 2.6.0
1502
     * @access protected
1503
     */
1504
    protected function delete() {
1505
        wp_delete_post( $this->get_order_id() );
1506
    }
1507
1508
    /**
1509
     * Save data to the database.
1510
     * @since 2.6.0
1511
     * @access protected
1512
     */
1513
    public function save() {
1514
        if ( ! $this->get_order_id() ) {
1515
            $this->create();
1516
        } else {
1517
            $this->update();
1518
        }
1519
        wc_delete_shop_order_transients( $this->get_order_id() );
1520
    }
1521
1522
    /*
1523
    |--------------------------------------------------------------------------
1524
    | Order Item Handling
1525
    |--------------------------------------------------------------------------
1526
    |
1527
    | Order items are used for products, taxes, shipping, and fees within
1528
    | each order.
1529
    |
1530
    */
1531
1532
    /**
1533
     * Return an array of items/products within this order.
1534
     *
1535
     * @param string|array $type Types of line items to get (array or string).
1536
     * @return Array of WC_Order_item
1537
     */
1538
    public function get_items( $type = 'line_item' ) {
1539
        global $wpdb;
1540
1541
        $type            = ! is_array( $type ) ? array( $type ) : $type;
1542
        $items           = array();
1543
        $get_items_sql   = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d ", $this->get_order_id() );
1544
        $get_items_sql  .= "AND order_item_type IN ( '" . implode( "','", array_map( 'esc_sql', $type ) ) . "' ) ORDER BY order_item_id;";
1545
        $raw_items       = $wpdb->get_results( $get_items_sql );
1546
1547
        foreach ( $raw_items as $item ) {
1548
            $item                                = $this->get_item( $item );
1549
            $items[ $item->get_order_item_id() ] = $item;
1550
        }
1551
1552
        return apply_filters( 'woocommerce_order_get_items', $items, $this );
1553
    }
1554
1555
    /**
1556
     * Get an order item object, based on it's type.
1557
     * @param  int $item_id
1558
     * @return WC_Order_Item
1559
     */
1560
    public function get_item( $item_id ) {
1561
        return WC_Order_Factory::get_order_item( $item_id );
1562
    }
1563
1564
    /**
1565
     * Display meta data belonging to an item. @todo
1566
     * @param  array $item
1567
     */
1568
    public function display_item_meta( $item ) {
1569
        $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...
1570
        $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 1569 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...
1571
        $item_meta->display();
1572
    }
1573
1574
    /**
1575
     * Return an array of fees within this order.
1576
     *
1577
     * @return array
1578
     */
1579
    public function get_fees() {
1580
        return $this->get_items( 'fee' );
1581
    }
1582
1583
    /**
1584
     * Return an array of taxes within this order.
1585
     *
1586
     * @return array
1587
     */
1588
    public function get_taxes() {
1589
        return $this->get_items( 'tax' );
1590
    }
1591
1592
    /**
1593
     * Return an array of shipping costs within this order.
1594
     *
1595
     * @return array
1596
     */
1597
    public function get_shipping_methods() {
1598
        return $this->get_items( 'shipping' );
1599
    }
1600
1601
    /**
1602
     * Get coupon codes only.
1603
     *
1604
     * @return array
1605
     */
1606
    public function get_used_coupons() {
1607
        return array_map( 'trim', wp_list_pluck( $this->get_items( 'coupon' ), 'name' ) );
1608
    }
1609
1610
    /**
1611
     * Gets the count of order items of a certain type.
1612
     *
1613
     * @param string $item_type
1614
     * @return string
1615
     */
1616
    public function get_item_count( $item_type = '' ) {
1617
        if ( empty( $item_type ) ) {
1618
            $item_type = array( 'line_item' );
1619
        }
1620
        if ( ! is_array( $item_type ) ) {
1621
            $item_type = array( $item_type );
1622
        }
1623
1624
        $items = $this->get_items( $item_type );
1625
        $count = 0;
1626
1627
        foreach ( $items as $item ) {
1628
            $count += $item->get_qty();
1629
        }
1630
1631
        return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this );
1632
    }
1633
1634
    /**
1635
     * Remove all line items (products, coupons, shipping, taxes) from the order.
1636
     *
1637
     * @param string $type Order item type. Default null.
1638
     */
1639
    public function remove_order_items( $type = null ) {
1640
        global $wpdb;
1641
1642
        if ( ! empty( $type ) ) {
1643
            $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_order_id(), $type ) );
1644
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->get_order_id(), $type ) );
1645
        } else {
1646
            $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_order_id() ) );
1647
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->get_order_id() ) );
1648
        }
1649
    }
1650
1651
    /**
1652
     * Add a product line item to the order.
1653
     * Order must be saved prior to adding items.
1654
     *
1655
     * @since 2.2
1656
     * @param \WC_Product $product
1657
     * @param int $qty Line item quantity.
1658
     * @param array $args
1659
     * @return int updated order item ID
1660
     */
1661
    public function add_product( $product, $qty = 1, $args = array() ) {
1662
        $args = wp_parse_args( $args, array(
1663
            'name'         => $product->get_title(),
1664
            'qty'          => absint( $qty ),
1665
            'tax_class'    => $product->get_tax_class(),
1666
            'product_id'   => $product->id,
1667
            'variation_id' => isset( $product->variation_id ) ? $product->variation_id : 0,
1668
            'variation'    => array(),
1669
            'subtotal'     => $product->get_price_excluding_tax( $qty ),
1670
            'subtotal_tax' => 0,
1671
            'total'        => $product->get_price_excluding_tax( $qty ),
1672
            'total_tax'    => 0,
1673
            'taxes'        => array(
1674
                'subtotal' => array(),
1675
                'total'    => array()
1676
            )
1677
        ) );
1678
        $item = new WC_Order_Item_Product();
1679
        $item_id = $this->update_product( $item, $product, $args );
1680
1681
		do_action( 'woocommerce_order_add_product', $this->get_order_id(), $item->get_order_item_id(), $product, $qty, $args );
1682
1683
		return $item_id;
1684
    }
1685
1686
    /**
1687
     * Update a line item for the order.
1688
     *
1689
     * Note this does not update order totals.
1690
     *
1691
     * @since 2.2
1692
     * @param object|int $item order item ID or item object.
1693
     * @param WC_Product $product
1694
     * @param array $args data to update.
1695
     * @return int updated order item ID
1696
     */
1697
    public function update_product( $item, $product, $args ) {
1698
        if ( is_numeric( $item ) ) {
1699
            $item = $this->get_item( $item );
1700
        }
1701
1702
        if ( ! is_object( $product ) || ! $item->is_type( 'line_item' ) ) {
1703
            return false;
1704
        }
1705
1706
        if ( ! $this->get_order_id() ) {
1707
            $this->save();
1708
        }
1709
1710
		$item->set_order_id( $this->get_order_id() );
1711
1712
        if ( ! $item->get_order_item_id() ) {
1713
            $inserting = true;
1714
        } else {
1715
            $inserting = false;
1716
        }
1717
1718
        if ( isset( $args['name'] ) ) {
1719
            $item->set_name( $args['name'] );
1720
        }
1721
1722
        if ( isset( $args['qty'] ) ) {
1723
            $item->set_qty( $args['qty'] );
1724
1725
            if ( $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
1726
                $item->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ), true );
1727
            }
1728
1729
            $item->set_line_subtotal( $product->get_price_excluding_tax( $args['qty'] ) );
1730
            $item->set_line_total( $product->get_price_excluding_tax( $args['qty'] ) );
1731
        }
1732
1733
        if ( isset( $args['tax_class'] ) ) {
1734
            $item->set_tax_class( $args['tax_class'] );
1735
        }
1736
1737
        if ( isset( $args['product_id'] ) ) {
1738
            $item->set_product_id( $args['product_id'] );
1739
        }
1740
1741
        if ( isset( $args['variation_id'] ) ) {
1742
            $item->set_variation_id( $args['variation_id'] );
1743
        }
1744
1745
        if ( isset( $args['variation'] ) && is_array( $args['variation'] ) ) {
1746
            foreach ( $args['variation'] as $key => $value ) {
1747
                $item->add_meta_data( str_replace( 'attribute_', '', $key ), $value, true );
1748
            }
1749
        }
1750
1751
        if ( isset( $args['totals'] ) ) {
1752
            // BW compatibility with old args
1753
            if ( isset( $args['totals']['subtotal'] ) ) {
1754
                $args['subtotal'] = $args['totals']['subtotal'];
1755
            }
1756
            if ( isset( $args['totals']['total'] ) ) {
1757
                $args['total'] = $args['totals']['total'];
1758
            }
1759
            if ( isset( $args['totals']['subtotal_tax'] ) ) {
1760
                $args['subtotal_tax'] = $args['totals']['subtotal_tax'];
1761
            }
1762
            if ( isset( $args['totals']['tax'] ) ) {
1763
                $args['total_tax'] = $args['totals']['tax'];
1764
            }
1765
            if ( isset( $args['totals']['tax_data'] ) ) {
1766
                $args['taxes'] = $args['totals']['tax_data'];
1767
            }
1768
        }
1769
1770
        if ( isset( $args['subtotal'] ) ) {
1771
            $item->set_subtotal( $args['subtotal'] );
1772
        }
1773
        if ( isset( $args['total'] ) ) {
1774
            $item->set_total( $args['total'] );
1775
        }
1776
        if ( isset( $args['subtotal_tax'] ) ) {
1777
            $item->set_line_subtotal_tax( $args['subtotal_tax'] );
1778
        }
1779
        if ( isset( $args['total_tax'] ) ) {
1780
            $item->set_total_tax( $args['total_tax'] );
1781
        }
1782
        if ( isset( $args['taxes'] ) ) {
1783
            $item->set_taxes( $args['taxes'] );
1784
        }
1785
1786
        $item->save();
1787
1788
        if ( ! $inserting ) {
1789
            do_action( 'woocommerce_order_edit_product', $this->get_order_id(), $item->get_order_item_id(), $args, $product );
1790
        }
1791
1792
        return $item->get_order_item_id();
1793
    }
1794
1795
    /**
1796
     * Add coupon code to the order.
1797
     * Order must be saved prior to adding items.
1798
     *
1799
     * @param string $code
1800
     * @param int $discount_amount
1801
     * @param int $discount_amount_tax "Discounted" tax - used for tax inclusive prices.
1802
     * @return int updated order item ID
1803
     */
1804
    public function add_coupon( $code, $discount_amount = 0, $discount_amount_tax = 0 ) {
1805
        $args = wp_parse_args( $args, array(
1806
            'code'                => $code,
1807
            'discount_amount'     => $discount_amount,
1808
            'discount_amount_tax' => $discount_amount_tax
1809
        ) );
1810
        $item = new WC_Order_Item_Coupon();
1811
        $item_id = $this->update_coupon( $item, $args );
1812
1813
		do_action( 'woocommerce_order_add_coupon', $this->get_order_id(), $item->get_order_item_id(), $code, $discount_amount, $discount_amount_tax );
1814
1815
		return $item_id;
1816
    }
1817
1818
    /**
1819
     * Update coupon for order. Note this does not update order totals.
1820
     * @since 2.2
1821
     * @param object|int $item
1822
     * @param array $args
1823
     * @return int updated order item ID
1824
     */
1825
    public function update_coupon( $item, $args ) {
1826
        if ( is_numeric( $item ) ) {
1827
            $item = $this->get_item( $item );
1828
        }
1829
1830
        if ( ! is_object( $product ) || ! $item->is_type( 'coupon' ) ) {
1831
            return false;
1832
        }
1833
1834
        if ( ! $this->get_order_id() ) {
1835
            $this->save();
1836
        }
1837
1838
		$item->set_order_id( $this->get_order_id() );
1839
1840
        if ( ! $item->get_order_item_id() ) {
1841
            $inserting = true;
1842
        } else {
1843
            $inserting = false;
1844
        }
1845
1846
        if ( isset( $args['code'] ) ) {
1847
            $item->set_coupon_code( $args['code'] );
1848
        }
1849
        if ( isset( $args['discount_amount'] ) ) {
1850
            $item->set_discount_amount( $args['discount_amount'] );
1851
        }
1852
        if ( isset( $args['discount_amount_tax'] ) ) {
1853
            $item->set_discount_amount_tax( $args['discount_amount_tax'] );
1854
        }
1855
1856
        $item->save();
1857
1858
        if ( ! $inserting ) {
1859
            do_action( 'woocommerce_order_update_coupon', $this->get_order_id(), $item->get_order_item_id(), $args );
1860
        }
1861
1862
        return $item->get_order_item_id();
1863
    }
1864
1865
    /**
1866
     * Add a shipping row to the order.
1867
     * Order must be saved prior to adding items.
1868
     *
1869
     * @param WC_Shipping_Rate shipping_rate
1870
     * @return int updated order item ID
1871
     */
1872
    public function add_shipping( $shipping_rate ) {
1873
        $args = wp_parse_args( $args, array(
1874
            'method_title' => $shipping_rate->label,
1875
            'method_id'    => $shipping_rate->id,
1876
            'cost'         => wc_format_decimal( $shipping_rate->cost ),
1877
            'taxes'        => $shipping_rate->taxes,
1878
            'meta'         => $shipping_rate->get_meta_data(),
1879
        ) );
1880
1881
        $item = new WC_Order_Item_Shipping();
1882
        $item_id = $this->update_shipping( $item, $args );
1883
1884
		do_action( 'woocommerce_order_add_shipping', $this->get_order_id(), $item->get_order_item_id(), $shipping_rate );
1885
1886
		return $item_id;
1887
    }
1888
1889
    /**
1890
     * Update shipping method for order.
1891
     *
1892
     * Note this does not update the order total.
1893
     *
1894
     * @since 2.2
1895
     * @param object|int $item
1896
     * @param array $args
1897
     * @return int updated order item ID
1898
     */
1899
    public function update_shipping( $item, $args ) {
1900
        if ( is_numeric( $item ) ) {
1901
            $item = $this->get_item( $item );
1902
        }
1903
1904
        if ( ! is_object( $product ) || ! $item->is_type( 'shipping' ) ) {
1905
            return false;
1906
        }
1907
1908
        if ( ! $this->get_order_id() ) {
1909
            $this->save();
1910
        }
1911
1912
		$item->set_order_id( $this->get_order_id() );
1913
1914
        if ( ! $item->get_order_item_id() ) {
1915
            $inserting = true;
1916
        } else {
1917
            $inserting = false;
1918
        }
1919
1920
        if ( isset( $args['method_title'] ) ) {
1921
            $item->set_method_title( $args['method_title'] );
1922
        }
1923
1924
        if ( isset( $args['method_id'] ) ) {
1925
            $item->set_method_id( $args['method_id'] );
1926
        }
1927
1928
        if ( isset( $args['cost'] ) ) {
1929
            // Get old cost before updating
1930
            $old_cost = $item->get_cost();
1931
1932
            // Update
1933
            $item->set_cost( $args['cost'] );
1934
1935
            // Update total
1936
            $this->set_total( $this->get_total_shipping() - wc_format_decimal( $old_cost ) + $item->get_cost(), 'shipping' );
1937
        }
1938
1939
        if ( isset( $args['taxes'] ) && is_array( $args['taxes'] ) ) {
1940
            $item->set_taxes( $args['taxes'] );
1941
        }
1942
1943
        if ( isset( $args['meta'] ) && is_array( $args['meta'] ) ) {
1944
			foreach ( $args['meta'] as $key => $value ) {
1945
				$item->update_meta_data( $key, $value );
1946
			}
1947
		}
1948
1949
        $item->save();
1950
1951
        if ( ! $inserting ) {
1952
            do_action( 'woocommerce_order_update_shipping', $this->get_order_id(), $item->get_order_item_id(), $args );
1953
        }
1954
1955
        return $item->get_order_item_id();
1956
    }
1957
1958
    /**
1959
     * Add a fee to the order.
1960
     * Order must be saved prior to adding items.
1961
     * @param object $fee
1962
     * @return int updated order item ID
1963
     */
1964
    public function add_fee( $fee ) {
1965
        $args = wp_parse_args( $args, array(
1966
            'name'      => $fee->name,
1967
            'tax_class' => $fee->taxable ? $fee->tax_class : 0,
1968
            'total'     => $fee->amount,
1969
            'total_tax' => $fee->tax,
1970
            'taxes'     => array(
1971
                'total' => $fee->tax_data
1972
            )
1973
        ) );
1974
        $item = new WC_Order_Item_Fee();
1975
        $item_id = $this->update_fee( $item, $args );
1976
1977
        do_action( 'woocommerce_order_add_fee', $this->get_order_id(), $item->get_order_item_id(), $fee );
1978
1979
        return $item_id;
1980
    }
1981
1982
    /**
1983
     * Update fee for order.
1984
     *
1985
     * Note this does not update order totals.
1986
     *
1987
     * @since 2.2
1988
     * @param object|int $item
1989
     * @param array $args
1990
     * @return int updated order item ID
1991
     */
1992
    public function update_fee( $item, $args ) {
1993
        if ( is_numeric( $item ) ) {
1994
            $item = $this->get_item( $item );
1995
        }
1996
1997
        if ( ! is_object( $product ) || ! $item->is_type( 'fee' ) ) {
1998
            return false;
1999
        }
2000
2001
        if ( ! $this->get_order_id() ) {
2002
            $this->save();
2003
        }
2004
2005
		$item->set_order_id( $this->get_order_id() );
2006
2007
        if ( ! $item->get_order_item_id() ) {
2008
            $inserting = true;
2009
        } else {
2010
            $inserting = false;
2011
        }
2012
2013
        if ( isset( $args['name'] ) ) {
2014
            $item->set_name( $args['name'] );
2015
        }
2016
2017
        if ( isset( $args['tax_class'] ) ) {
2018
            $item->set_tax_class( $args['tax_class'] );
2019
        }
2020
2021
        if ( isset( $args['total'] ) ) {
2022
            $item->set_total( $args['total'] );
2023
        }
2024
2025
        if ( isset( $args['total_tax'] ) ) {
2026
            $item->set_total_tax( $args['total_tax'] );
2027
        }
2028
2029
        if ( isset( $args['taxes'] ) ) {
2030
            $item->set_taxes( $args['taxes'] );
2031
        }
2032
2033
        $item->save();
2034
2035
        if ( ! $inserting ) {
2036
            do_action( 'woocommerce_order_update_fee', $this->get_order_id(), $item->get_order_item_id(), $args );
2037
        }
2038
2039
        return $item->get_order_item_id();
2040
    }
2041
2042
    /**
2043
     * Add a tax row to the order.
2044
     * Order must be saved prior to adding items.
2045
     * @since 2.2
2046
     * @param int tax_rate_id
2047
     * @return int updated order item ID
2048
     */
2049
    public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
2050
        if ( ! $code = WC_Tax::get_rate_code( $tax_rate_id ) ) {
2051
            return false;
2052
        }
2053
2054
        $args = wp_parse_args( $args, array(
2055
            'rate_code'          => $code,
2056
            'rate_id'            => $tax_rate_id,
2057
            'label'              => WC_Tax::get_rate_label( $tax_rate_id ),
2058
            'compound'           => WC_Tax::is_compound( $tax_rate_id ),
2059
            'tax_total'          => $tax_amount,
2060
            'shipping_tax_total' => $shipping_tax_amount
2061
        ) );
2062
        $item = new WC_Order_Item_Tax();
2063
        $item_id = $this->update_tax( $item, $args );
2064
2065
        do_action( 'woocommerce_order_add_tax', $this->get_order_id(), $item->get_order_item_id(), $tax_rate_id, $tax_amount, $shipping_tax_amount );
2066
2067
        return $item_id;
2068
    }
2069
2070
    /**
2071
     * Update tax line on order.
2072
     * Note this does not update order totals.
2073
     *
2074
     * @since 2.6
2075
     * @param object|int $item
2076
     * @param array $args
2077
     * @return int updated order item ID
2078
     */
2079
    public function update_tax( $item, $args ) {
2080
        if ( is_numeric( $item ) ) {
2081
            $item = $this->get_item( $item );
2082
        }
2083
2084
        if ( ! is_object( $product ) || ! $item->is_type( 'tax' ) ) {
2085
            return false;
2086
        }
2087
2088
        if ( ! $this->get_order_id() ) {
2089
            $this->save();
2090
        }
2091
2092
		$item->set_order_id( $this->get_order_id() );
2093
2094
        if ( ! $item->get_order_item_id() ) {
2095
            $inserting = true;
2096
        } else {
2097
            $inserting = false;
2098
        }
2099
2100
        if ( isset( $args['rate_code'] ) ) {
2101
            $item->set_rate_code( $args['rate_code'] );
2102
        }
2103
2104
        if ( isset( $args['rate_id'] ) ) {
2105
            $item->set_rate_id( $args['rate_id'] );
2106
        }
2107
2108
        if ( isset( $args['label'] ) ) {
2109
            $item->set_label( $args['label'] );
2110
        }
2111
2112
        if ( isset( $args['compound'] ) ) {
2113
            $item->set_compound( $args['compound'] );
2114
        }
2115
2116
        if ( isset( $args['tax_total'] ) ) {
2117
            $item->set_tax_total( $args['tax_total'] );
2118
        }
2119
2120
        if ( isset( $args['shipping_tax_total'] ) ) {
2121
            $item->set_shipping_tax_total( $args['shipping_tax_total'] );
2122
        }
2123
2124
        $item->save();
2125
2126
        if ( ! $inserting ) {
2127
            do_action( 'woocommerce_order_update_tax', $this->get_order_id(), $item->get_order_item_id(), $args );
2128
        }
2129
2130
        return $item->get_order_item_id();
2131
    }
2132
2133
	/**
2134
     * Update tax lines at order level by looking at the line item taxes themselves.
2135
     * @return bool success or fail.
2136
     */
2137
    public function update_taxes() {
2138
        $cart_taxes     = array();
2139
        $shipping_taxes = array();
2140
2141 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...
2142
            $taxes = $item->get_taxes();
2143
            if ( isset( $taxes['total'] ) ) {
2144
                foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
2145
                    if ( ! isset( $cart_taxes[ $tax_rate_id ] ) ) {
2146
                        $cart_taxes[ $tax_rate_id ] = 0;
2147
                    }
2148
                    $cart_taxes[ $tax_rate_id ] += $tax;
2149
                }
2150
            }
2151
        }
2152
2153 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...
2154
			$taxes = $item->get_taxes();
2155
            if ( isset( $taxes['total'] ) ) {
2156
                foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
2157
                    if ( ! isset( $shipping_taxes[ $tax_rate_id ] ) ) {
2158
                        $shipping_taxes[ $tax_rate_id ] = 0;
2159
                    }
2160
                    $shipping_taxes[ $tax_rate_id ] += $tax;
2161
                }
2162
            }
2163
        }
2164
2165
        // Remove old existing tax rows.
2166
        $this->remove_order_items( 'tax' );
2167
2168
        // Now merge to keep tax rows.
2169 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...
2170
            $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 );
2171
        }
2172
2173
        // Save tax totals
2174
        $this->set_total( WC_Tax::round( array_sum( $shipping_taxes ) ), 'shipping_tax' );
2175
        $this->set_total( WC_Tax::round( array_sum( $cart_taxes ) ), 'tax' );
2176
2177
        return true;
2178
    }
2179
2180
    /*
2181
    |--------------------------------------------------------------------------
2182
    | Calculations.
2183
    |--------------------------------------------------------------------------
2184
    |
2185
    | These methods calculate order totals and taxes based on the current data.
2186
    |
2187
    */
2188
2189
    /**
2190
     * Calculate shipping total.
2191
     *
2192
     * @since 2.2
2193
     * @return float
2194
     */
2195
    public function calculate_shipping() {
2196
        $shipping_total = 0;
2197
2198
        foreach ( $this->get_shipping_methods() as $shipping ) {
2199
            $shipping_total += $shipping->get_total();
2200
        }
2201
2202
        $this->set_total( $shipping_total, 'shipping' );
2203
2204
        return $this->get_shipping_total();
2205
    }
2206
2207
    /**
2208
     * Calculate taxes for all line items and shipping, and store the totals and tax rows.
2209
     *
2210
     * Will use the base country unless customer addresses are set.
2211
     *
2212
     * @return bool success or fail.
2213
     */
2214
    public function calculate_taxes() {
2215
        $cart_tax     = 0;
2216
        $cart_taxes   = array();
2217
        $tax_based_on = get_option( 'woocommerce_tax_based_on' );
2218
2219
        if ( 'billing' === $tax_based_on ) {
2220
            $country  = $this->get_billing_country();
2221
            $state    = $this->get_billing_state();
2222
            $postcode = $this->get_billing_postcode();
2223
            $city     = $this->get_billing_city();
2224
        } elseif ( 'shipping' === $tax_based_on ) {
2225
            $country  = $this->get_shipping_country();
2226
            $state    = $this->get_shipping_state();
2227
            $postcode = $this->get_shipping_postcode();
2228
            $city     = $this->get_shipping_city();
2229
        }
2230
2231
        // Default to base
2232 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...
2233
            $default  = wc_get_base_location();
2234
            $country  = $default['country'];
2235
            $state    = $default['state'];
2236
            $postcode = '';
2237
            $city     = '';
2238
        }
2239
2240
        // Get items
2241
        foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
2242
			$tax_class  = $item->get_tax_class();
2243
			$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...
2244
2245
            if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
2246
2247
                $tax_rates = WC_Tax::find_rates( array(
2248
                    'country'   => $country,
2249
                    'state'     => $state,
2250
                    'postcode'  => $postcode,
2251
                    'city'      => $city,
2252
                    'tax_class' => $tax_class
2253
                ) );
2254
2255
				$total     = $item->get_total();
2256
				$taxes     = WC_Tax::calc_tax( $total, $tax_rates, false );
2257
				$total_tax = max( 0, array_sum( $taxes ) );
2258
				$cart_tax += $total_tax;
2259
				$item->set_total_tax( $total_tax );
2260
2261
				if ( $item->is_type( 'line_item' ) ) {
2262
					$subtotal       = $item->get_subtotal();
2263
					$subtotal_taxes = WC_Tax::calc_tax( $subtotal, $tax_rates, false );
2264
					$subtotal_tax   = max( 0, array_sum( $subtotal_taxes ) );
2265
					$item->set_subtotal_tax( $subtotal_tax );
2266
					$item->set_taxes( array( 'total' => $taxes, 'subtotal' => $subtotal_taxes ) );
2267
				} else {
2268
					$item->set_taxes( array( 'total' => $taxes ) );
2269
				}
2270
2271
				$item->save(); //@todo store items to self, don't save right away
2272
2273
                // Sum the item taxes
2274
                foreach ( array_keys( $cart_taxes + $taxes ) as $key ) {
2275
                    $cart_taxes[ $key ] = ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $cart_taxes[ $key ] : 0 );
2276
                }
2277
            }
2278
        }
2279
2280
        // Now calculate shipping tax
2281
        $shipping_methods = $this->get_shipping_methods();
2282
2283
        if ( ! empty( $shipping_methods ) ) {
2284
            $matched_tax_rates = array();
2285
            $tax_rates         = WC_Tax::find_rates( array(
2286
                'country'   => $country,
2287
                'state'     => $state,
2288
                'postcode'  => $postcode,
2289
                'city'      => $city,
2290
                'tax_class' => ''
2291
            ) );
2292
2293 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...
2294
                foreach ( $tax_rates as $key => $rate ) {
2295
                    if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) {
2296
                        $matched_tax_rates[ $key ] = $rate;
2297
                    }
2298
                }
2299
            }
2300
2301
            $shipping_taxes     = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates );
2302
            $shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) );
2303
        } else {
2304
            $shipping_taxes     = array();
2305
            $shipping_tax_total = 0;
2306
        }
2307
2308
        // Save tax totals
2309
        $this->set_total( $shipping_tax_total, 'shipping_tax' );
2310
        $this->set_total( $tax_total, 'tax' );
2311
2312
        // Tax rows
2313
        $this->remove_order_items( 'tax' );
2314
2315
        // Now merge to keep tax rows
2316 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...
2317
            $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 );
2318
        }
2319
2320
        return true;
2321
    }
2322
2323
    /**
2324
     * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
2325
     *
2326
     * @since 2.2
2327
     * @param  bool $and_taxes Calc taxes if true.
2328
     * @return float calculated grand total.
2329
     */
2330
    public function calculate_totals( $and_taxes = true ) {
2331
        $cart_subtotal     = 0;
2332
        $cart_total        = 0;
2333
        $fee_total         = 0;
2334
        $cart_subtotal_tax = 0;
2335
        $cart_total_tax    = 0;
2336
2337
        if ( $and_taxes && wc_tax_enabled() ) {
2338
            $this->calculate_taxes();
2339
        }
2340
2341
        // line items
2342
        foreach ( $this->get_items() as $item ) {
2343
            $cart_subtotal     += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 );
2344
            $cart_total        += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 );
2345
            $cart_subtotal_tax += wc_format_decimal( isset( $item['line_subtotal_tax'] ) ? $item['line_subtotal_tax'] : 0 );
2346
            $cart_total_tax    += wc_format_decimal( isset( $item['line_tax'] ) ? $item['line_tax'] : 0 );
2347
        }
2348
2349
        $this->calculate_shipping();
2350
2351
        foreach ( $this->get_fees() as $item ) {
2352
            $fee_total += $item['line_total'];
2353
        }
2354
2355
        $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' );
2356
        $this->set_total( $cart_subtotal_tax - $cart_total_tax, 'cart_discount_tax' );
2357
2358
        $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() );
2359
2360
        $this->set_total( $grand_total, 'total' );
2361
2362
        return $grand_total;
2363
    }
2364
2365
    /*
2366
    |--------------------------------------------------------------------------
2367
    | Total Getters
2368
    |--------------------------------------------------------------------------
2369
    |
2370
    | Methods for getting totals e.g. for display on the frontend.
2371
    |
2372
    */
2373
2374
    /**
2375
     * Get a product (either product or variation).
2376
     *
2377
     * @param object $item
2378
     * @return WC_Product|bool
2379
     */
2380
    public function get_product_from_item( $item ) {
2381
        if ( is_callable( array( $item, 'get_product' ) ) ) {
2382
            $product = $item->get_product();
2383
        } else {
2384
            $product = false;
2385
        }
2386
        return apply_filters( 'woocommerce_get_product_from_item', $product, $item, $this );
2387
    }
2388
2389
    /**
2390
     * Get item subtotal - this is the cost before discount.
2391
     *
2392
     * @param object $item
2393
     * @param bool $inc_tax (default: false).
2394
     * @param bool $round (default: true).
2395
     * @return float
2396
     */
2397 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...
2398
        $subtotal = 0;
2399
2400
        if ( is_callable( array( $item, 'get_subtotal' ) ) ) {
2401
            if ( $inc_tax ) {
2402
                $subtotal = ( $item->get_subtotal() + $item->get_subtotal_tax() ) / max( 1, $item->get_qty() );
2403
            } else {
2404
                $subtotal = ( $item->get_subtotal() / max( 1, $item->get_qty() ) );
2405
            }
2406
2407
            $subtotal = $round ? number_format( (float) $subtotal, wc_get_price_decimals(), '.', '' ) : $subtotal;
2408
        }
2409
2410
        return apply_filters( 'woocommerce_order_amount_item_subtotal', $subtotal, $this, $item, $inc_tax, $round );
2411
    }
2412
2413
    /**
2414
     * Get line 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_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...
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();
2427
            } else {
2428
                $subtotal = $item->get_subtotal();
2429
            }
2430
2431
            $subtotal = $round ? round( $subtotal, wc_get_price_decimals() ) : $subtotal;
2432
        }
2433
2434
        return apply_filters( 'woocommerce_order_amount_line_subtotal', $subtotal, $this, $item, $inc_tax, $round );
2435
    }
2436
2437
    /**
2438
     * Calculate item cost - useful for gateways.
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_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...
2446
        $total = 0;
2447
2448
        if ( is_callable( array( $item, 'get_total' ) ) ) {
2449
            if ( $inc_tax ) {
2450
                $total = ( $item->get_total() + $item->get_total_tax() ) / max( 1, $item->get_qty() );
2451
            } else {
2452
                $total = $item->get_total() / max( 1, $item->get_qty() );
2453
            }
2454
2455
            $total = $round ? round( $total, wc_get_price_decimals() ) : $total;
2456
        }
2457
2458
        return apply_filters( 'woocommerce_order_amount_item_total', $total, $this, $item, $inc_tax, $round );
2459
    }
2460
2461
    /**
2462
     * Calculate line total - 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_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...
2470
        $total = 0;
2471
2472
        if ( is_callable( array( $item, 'get_total' ) ) ) {
2473
            // Check if we need to add line tax to the line total.
2474
            $total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total();
2475
2476
            // Check if we need to round.
2477
            $total = $round ? round( $total, wc_get_price_decimals() ) : $total;
2478
        }
2479
2480
        return apply_filters( 'woocommerce_order_amount_line_total', $total, $this, $item, $inc_tax, $round );
2481
    }
2482
2483
    /**
2484
     * Get item tax - useful for gateways.
2485
     *
2486
     * @param mixed $item
2487
     * @param bool $round (default: true).
2488
     * @return float
2489
     */
2490
    public function get_item_tax( $item, $round = true ) {
2491
        $tax = 0;
2492
2493
        if ( is_callable( array( $item, 'get_total_tax' ) ) ) {
2494
            $tax = $item->get_total_tax() / max( 1, $item->get_qty() );
2495
            $tax = $round ? wc_round_tax_total( $tax ) : $tax;
2496
        }
2497
2498
        return apply_filters( 'woocommerce_order_amount_item_tax', $tax, $item, $round, $this );
2499
    }
2500
2501
    /**
2502
     * Get line tax - useful for gateways.
2503
     *
2504
     * @param mixed $item
2505
     * @return float
2506
     */
2507
    public function get_line_tax( $item ) {
2508
        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 );
2509
    }
2510
2511
    /**
2512
     * Gets line subtotal - formatted for display.
2513
     *
2514
     * @param array  $item
2515
     * @param string $tax_display
2516
     * @return string
2517
     */
2518
    public function get_formatted_line_subtotal( $item, $tax_display = '' ) {
2519
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2520
2521
        if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) {
2522
            return '';
2523
        }
2524
2525
        if ( 'excl' == $tax_display ) {
2526
            $ex_tax_label = $this->get_prices_include_tax() ? 1 : 0;
2527
2528
            $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...
2529
        } else {
2530
            $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...
2531
        }
2532
2533
        return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this );
2534
    }
2535
2536
    /**
2537
     * Gets order total - formatted for display.
2538
     *
2539
     * @return string
2540
     */
2541
    public function get_formatted_order_total() {
2542
        $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_order_currency() ) );
2543
        return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this );
2544
    }
2545
2546
    /**
2547
     * Gets subtotal - subtotal is shown before discounts, but with localised taxes.
2548
     *
2549
     * @param bool $compound (default: false).
2550
     * @param string $tax_display (default: the tax_display_cart value).
2551
     * @return string
2552
     */
2553
    public function get_subtotal_to_display( $compound = false, $tax_display = '' ) {
2554
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2555
        $subtotal    = 0;
2556
2557
        if ( ! $compound ) {
2558
            foreach ( $this->get_items() as $item ) {
2559
                $subtotal += $item->get_subtotal();
2560
2561
                if ( 'incl' === $tax_display ) {
2562
                    $subtotal += $item->get_subtotal_tax();
2563
                }
2564
            }
2565
2566
            $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_order_currency() ) );
2567
2568
            if ( 'excl' === $tax_display && $this->get_prices_include_tax() ) {
2569
                $subtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>';
2570
            }
2571
2572
        } else {
2573
            if ( 'incl' === $tax_display ) {
2574
                return '';
2575
            }
2576
2577
            foreach ( $this->get_items() as $item ) {
2578
                $subtotal += $item->get_subtotal();
2579
            }
2580
2581
            // Add Shipping Costs.
2582
            $subtotal += $this->get_total_shipping();
2583
2584
            // Remove non-compound taxes.
2585
            foreach ( $this->get_taxes() as $tax ) {
2586
                if ( ! empty( $tax['compound'] ) ) {
2587
                    continue;
2588
                }
2589
                $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount'];
2590
            }
2591
2592
            // Remove discounts.
2593
            $subtotal = $subtotal - $this->get_total_discount();
2594
            $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_order_currency() ) );
2595
        }
2596
2597
        return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this );
2598
    }
2599
2600
    /**
2601
     * Gets shipping (formatted).
2602
     *
2603
     * @return string
2604
     */
2605
    public function get_shipping_to_display( $tax_display = '' ) {
2606
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2607
2608
        if ( $this->order_shipping != 0 ) {
2609
2610
            if ( $tax_display == 'excl' ) {
2611
2612
                // Show shipping excluding tax.
2613
                $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) );
2614
2615 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...
2616
                    $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 );
2617
                }
2618
2619
            } else {
2620
2621
                // Show shipping including tax.
2622
                $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) );
2623
2624 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...
2625
                    $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 );
2626
                }
2627
2628
            }
2629
2630
            $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 );
2631
2632
        } elseif ( $this->get_shipping_method() ) {
2633
            $shipping = $this->get_shipping_method();
2634
        } else {
2635
            $shipping = __( 'Free!', 'woocommerce' );
2636
        }
2637
2638
        return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this );
2639
    }
2640
2641
    /**
2642
     * Get the discount amount (formatted).
2643
     * @since  2.3.0
2644
     * @return string
2645
     */
2646
    public function get_discount_to_display( $tax_display = '' ) {
2647
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2648
        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 );
2649
    }
2650
2651
    /**
2652
     * Get totals for display on pages and in emails.
2653
     *
2654
     * @param mixed $tax_display
2655
     * @return array
2656
     */
2657
    public function get_order_item_totals( $tax_display = '' ) {
2658
        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
2659
        $total_rows  = array();
2660
2661
        if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) {
2662
            $total_rows['cart_subtotal'] = array(
2663
                'label' => __( 'Subtotal:', 'woocommerce' ),
2664
                'value'    => $subtotal
2665
            );
2666
        }
2667
2668
        if ( $this->get_total_discount() > 0 ) {
2669
            $total_rows['discount'] = array(
2670
                'label' => __( 'Discount:', 'woocommerce' ),
2671
                'value'    => '-' . $this->get_discount_to_display( $tax_display )
2672
            );
2673
        }
2674
2675
        if ( $this->get_shipping_method() ) {
2676
            $total_rows['shipping'] = array(
2677
                'label' => __( 'Shipping:', 'woocommerce' ),
2678
                'value'    => $this->get_shipping_to_display( $tax_display )
2679
            );
2680
        }
2681
2682
        if ( $fees = $this->get_fees() ) {
2683
            foreach ( $fees as $id => $fee ) {
2684
                if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', empty( $fee['line_total'] ) && empty( $fee['line_tax'] ), $id ) ) {
2685
                    continue;
2686
                }
2687
                $total_rows[ 'fee_' . $fee->get_order_item_id() ] = array(
2688
                    'label' => $fee->get_name() . ':',
2689
                    'value' => wc_price( 'excl' === $tax_display ? $fee->get_total() : $fee->get_total() + $fee->get_total_tax(), array('currency' => $this->get_order_currency()) )
2690
                );
2691
            }
2692
        }
2693
2694
        // Tax for tax exclusive prices.
2695
        if ( 'excl' === $tax_display ) {
2696
2697
            if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
2698
2699
                foreach ( $this->get_tax_totals() as $code => $tax ) {
2700
2701
                    $total_rows[ sanitize_title( $code ) ] = array(
2702
                        'label' => $tax->label . ':',
2703
                        'value'    => $tax->formatted_amount
2704
                    );
2705
                }
2706
2707
            } else {
2708
2709
                $total_rows['tax'] = array(
2710
                    'label' => WC()->countries->tax_or_vat() . ':',
2711
                    'value'    => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_order_currency() ) )
2712
                );
2713
            }
2714
        }
2715
2716
        if ( $this->get_total() > 0 && $this->get_payment_method_title() ) {
2717
            $total_rows['payment_method'] = array(
2718
                'label' => __( 'Payment Method:', 'woocommerce' ),
2719
                'value' => $this->get_payment_method_title()
2720
            );
2721
        }
2722
2723
        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...
2724
            foreach ( $refunds as $id => $refund ) {
2725
                $total_rows[ 'refund_' . $id ] = array(
2726
                    'label' => $refund->get_refund_reason() ? $refund->get_refund_reason() : __( 'Refund', 'woocommerce' ) . ':',
2727
                    'value'    => wc_price( '-' . $refund->get_refund_amount(), array( 'currency' => $this->get_order_currency() ) )
2728
                );
2729
            }
2730
        }
2731
2732
        $total_rows['order_total'] = array(
2733
            'label' => __( 'Total:', 'woocommerce' ),
2734
            '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...
2735
        );
2736
2737
        return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this );
2738
    }
2739
2740
    /*
2741
    |--------------------------------------------------------------------------
2742
    | Conditionals
2743
    |--------------------------------------------------------------------------
2744
    |
2745
    | Checks if a condition is true or false.
2746
    |
2747
    */
2748
2749
    /**
2750
     * Checks the order status against a passed in status.
2751
     *
2752
     * @return bool
2753
     */
2754
    public function has_status( $status ) {
2755
        return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
2756
    }
2757
2758
    /**
2759
     * has_meta function for order items.
2760
     *
2761
     * @param string $order_item_id
2762
     * @return array of meta data.
2763
     */
2764
    public function has_meta( $order_item_id ) {
2765
        global $wpdb;
2766
2767
        return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
2768
            FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
2769
            ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
2770
    }
2771
2772
    /**
2773
     * Check whether this order has a specific shipping method or not.
2774
     *
2775
     * @param string $method_id
2776
     * @return bool
2777
     */
2778
    public function has_shipping_method( $method_id ) {
2779
        foreach ( $this->get_shipping_methods() as $shipping_method ) {
2780
            if ( $shipping_method->get_method_id() === $method_id ) {
2781
                return true;
2782
            }
2783
        }
2784
        return false;
2785
    }
2786
2787
    /**
2788
     * Check if an order key is valid.
2789
     *
2790
     * @param mixed $key
2791
     * @return bool
2792
     */
2793
    public function key_is_valid( $key ) {
2794
        return $key === $this->get_order_key();
2795
    }
2796
2797
    /**
2798
     * Returns true if the order contains a free product.
2799
     * @since 2.5.0
2800
     * @return bool
2801
     */
2802
    public function has_free_item() {
2803
        foreach ( $this->get_items() as $item ) {
2804
            if ( ! $item->get_total() ) {
2805
                return true;
2806
            }
2807
        }
2808
        return false;
2809
    }
2810
2811
    /*
2812
    |--------------------------------------------------------------------------
2813
    | Deprecated methods
2814
    |--------------------------------------------------------------------------
2815
    |
2816
    | Will be removed after 2 major releases, or 1 year.
2817
    |
2818
    */
2819
2820
    /**
2821
     * Magic __isset method for backwards compatibility.
2822
     * @param string $key
2823
     * @return bool
2824
     */
2825
    public function __isset( $key ) {
2826
        // Legacy properties which could be accessed directly in the past.
2827
        $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' );
2828
        return $this->get_order_id() ? ( in_array( $key, $legacy_props ) || metadata_exists( 'post', $this->get_order_id(), '_' . $key ) ) : false;
2829
    }
2830
2831
    /**
2832
     * Magic __get method for backwards compatibility.
2833
     * @param string $key
2834
     * @return mixed
2835
     */
2836
    public function __get( $key ) {
2837
        /**
2838
         * Maps legacy vars to new getters.
2839
         */
2840
        if ( 'completed_date' === $key ) {
2841
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2842
            return $this->get_date_completed();
2843
		} elseif ( 'paid_date' === $key ) {
2844
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2845
            return $this->get_date_paid();
2846
        } elseif ( 'modified_date' === $key ) {
2847
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2848
            return $this->get_date_modified();
2849
        } elseif ( 'order_date' === $key ) {
2850
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2851
            return $this->get_date_created();
2852
        } elseif ( 'id' === $key ) {
2853
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2854
            return $this->get_order_id();
2855
		} elseif ( 'post' === $key ) {
2856
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2857
            return get_post( $this->get_order_id() );
2858
		} elseif ( 'status' === $key || 'post_status' === $key ) {
2859
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2860
            return $this->get_status();
2861
		} elseif ( 'customer_message' === $key || 'customer_note' === $key ) {
2862
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2863
            return $this->get_customer_note();
2864
		} elseif ( in_array( $key, array( 'user_id', 'customer_user' ) ) ) {
2865
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2866
            return $this->get_customer_id();
2867
		} elseif ( 'tax_display_cart' === $key ) {
2868
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2869
			return get_option( 'woocommerce_tax_display_cart' );
2870
		} elseif ( 'display_totals_ex_tax' === $key ) {
2871
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2872
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
2873
		} elseif ( 'display_cart_ex_tax' === $key ) {
2874
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2875
			return 'excl' === get_option( 'woocommerce_tax_display_cart' );
2876
        } elseif ( 'cart_discount' === $key ) {
2877
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2878
			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...
2879
        } elseif ( 'cart_discount_tax' === $key ) {
2880
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2881
			return $this->get_discount_tax();
2882
        } elseif ( 'order_tax' === $key ) {
2883
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2884
			return $this->get_cart_tax();
2885
        } elseif ( 'order_shipping_tax' === $key ) {
2886
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2887
            return $this->get_shipping_tax();
2888
        } elseif ( 'order_shipping' === $key ) {
2889
            _doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.6' );
2890
            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...
2891
        /**
2892
         * Map vars to getters with warning.
2893
         */
2894
	 	} elseif ( is_callable( array( $this, "get_{$key}" ) ) ) {
2895
			_doing_it_wrong( $key, 'Order properties should not be accessed directly Use get_' . $key . '().', '2.6' );
2896
            return $this->{"get_{$key}"}();
2897
        /**
2898
         * Handle post meta
2899
         */
2900
        } else {
2901
            _doing_it_wrong( $key, 'Meta should not be accessed directly. Use WC_Order::get_order_meta( $key )', '2.6' );
2902
			$value = get_post_meta( $this->get_order_id(), '_' . $key, true );
2903
		}
2904
2905
        return $value;
2906
    }
2907
2908
    /**
2909
     * Get order item meta.
2910
     * @deprecated 2.6.0
2911
     * @param mixed $order_item_id
2912
     * @param string $key (default: '')
2913
     * @param bool $single (default: false)
2914
     * @return array|string
2915
     */
2916
    public function get_item_meta( $order_item_id, $key = '', $single = false ) {
2917
        _deprecated_function( 'get_item_meta', '2.6', 'wc_get_order_item_meta' );
2918
        return get_metadata( 'order_item', $order_item_id, $key, $single );
2919
    }
2920
2921
    /**
2922
     * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
2923
     *
2924
     * @param mixed $order_item_id
2925
     * @return array of objects
2926
     */
2927
    public function get_item_meta_array( $order_item_id ) {
2928
        _deprecated_function( 'get_item_meta_array', '2.6', 'WC_Order_Item::get_meta_data()' );
2929
        $item = $this->get_item( $order_item_id );
2930
        return $item->get_meta_data();
2931
    }
2932
2933
    /**
2934
     * Expand item meta into the $item array.
2935
     * @deprecated 2.6.0 Item meta no longer expanded due to new order item
2936
     *        classes. This function now does nothing to avoid data breakage.
2937
     * @since 2.4.0
2938
     * @param array $item before expansion.
2939
     * @return array
2940
     */
2941
    public function expand_item_meta( $item ) {
2942
        _deprecated_function( 'expand_item_meta', '2.6', '' );
2943
        return $item;
2944
    }
2945
2946
	/**
2947
     * Load the order object. Called from the constructor.
2948
     * @deprecated 2.6.0 Logic moved to constructor
2949
     * @param int|object|WC_Order $order Order to init.
2950
     */
2951 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...
2952
		_deprecated_function( 'init', '2.6', 'Logic moved to constructor' );
2953
        if ( is_numeric( $order ) ) {
2954
            $this->read( $order );
2955
        } elseif ( $order instanceof WC_Order ) {
2956
            $this->read( absint( $order->get_order_id() ) );
2957
        } elseif ( isset( $order->ID ) ) {
2958
            $this->read( absint( $order->ID ) );
2959
        }
2960
    }
2961
2962
    /**
2963
     * Gets an order from the database.
2964
     * @deprecated 2.6
2965
     * @param int $id (default: 0).
2966
     * @return bool
2967
     */
2968
    public function get_order( $id = 0 ) {
2969
        _deprecated_function( 'get_order', '2.6', 'read' );
2970
        if ( ! $id ) {
2971
            return false;
2972
        }
2973
        if ( $result = get_post( $id ) ) {
2974
            $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...
2975
            return true;
2976
        }
2977
        return false;
2978
    }
2979
2980
    /**
2981
     * Populates an order from the loaded post data.
2982
     * @deprecated 2.6
2983
     * @param mixed $result
2984
     */
2985
    public function populate( $result ) {
2986
        _deprecated_function( 'populate', '2.6', 'read' );
2987
        $this->read( $result->ID );
2988
    }
2989
2990
	/**
2991
     * Cancel the order and restore the cart (before payment).
2992
     * @deprecated 2.6.0 Moved to event handler.
2993
     * @param string $note (default: '') Optional note to add.
2994
     */
2995
    public function cancel_order( $note = '' ) {
2996
		_deprecated_function( 'cancel_order', '2.6', 'update_status' );
2997
        WC()->session->set( 'order_awaiting_payment', false );
2998
        $this->update_status( 'cancelled', $note );
2999
    }
3000
3001
	/**
3002
     * Record sales.
3003
     * @deprecated 2.6.0
3004
     */
3005
    public function record_product_sales() {
3006
		_deprecated_function( 'record_product_sales', '2.6', 'wc_update_total_sales_counts' );
3007
		wc_update_total_sales_counts( $this->get_order_id() );
3008
    }
3009
3010
	/**
3011
     * Increase applied coupon counts.
3012
     * @deprecated 2.6.0
3013
     */
3014
    public function increase_coupon_usage_counts() {
3015
		_deprecated_function( 'increase_coupon_usage_counts', '2.6', 'wc_update_coupon_usage_counts' );
3016
		wc_update_coupon_usage_counts( $this->get_order_id() );
3017
    }
3018
3019
    /**
3020
     * Decrease applied coupon counts.
3021
     * @deprecated 2.6.0
3022
     */
3023
    public function decrease_coupon_usage_counts() {
3024
		_deprecated_function( 'decrease_coupon_usage_counts', '2.6', 'wc_update_coupon_usage_counts' );
3025
		wc_update_coupon_usage_counts( $this->get_order_id() );
3026
    }
3027
3028
	/**
3029
     * Reduce stock levels for all line items in the order.
3030
	 * @deprecated 2.6.0
3031
     */
3032
    public function reduce_order_stock() {
3033
        _deprecated_function( 'reduce_order_stock', '2.6', 'wc_reduce_stock_levels' );
3034
		wc_reduce_stock_levels( $this->get_order_id() );
3035
    }
3036
3037
	/**
3038
     * Send the stock notifications.
3039
	 * @deprecated 2.6.0 No longer needs to be called directly.
3040
     */
3041
    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...
3042
        _deprecated_function( 'send_stock_notifications', '2.6' );
3043
    }
3044
3045
	/**
3046
	 * Output items for display in html emails.
3047
	 * @deprecated 2.6.0 Moved to template functions.
3048
	 * @param array $args Items args.
3049
	 * @return string
3050
	 */
3051
	public function email_order_items_table( $args = array() ) {
3052
		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...
3053
	}
3054
}
3055