WPInv_Legacy_Invoice::increase_tax()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
9
// MUST have WordPress.
10
if ( ! defined( 'WPINC' ) ) {
11
    exit;
12
}
13
14
/**
15
 * This class is used to migrate invoices to the new store.
16
 */
17
final class WPInv_Legacy_Invoice {
18
19
    /**
20
     * Invoice id.
21
     */
22
    public $ID  = 0;
23
24
    /**
25
     * The title of the invoice. Usually the invoice number.
26
     */
27
    public $title;
28
29
    /**
30
     * The post type - either wpi_quote or wpi_invoice
31
     */
32
    public $post_type;
33
34
    /**
35
     * An array of pending changes.
36
     */
37
    public $pending;
38
39
    /**
40
     * An array of invoice items.
41
     */
42
    public $items = array();
43
44
    /**
45
     * Information on the invoice client.
46
     */
47
    public $user_info = array();
48
49
    /**
50
     * Payment information for the invoice.
51
     */
52
    public $payment_meta = array();
53
54
    /**
55
     * Whether this invoice exists in the db or not.
56
     */
57
    public $new = false;
58
59
    /**
60
     * The invoice number.
61
     */
62
    public $number = '';
63
64
    /**
65
     * Whether an actual payment occurred (live) or the transaction
66
     * happened in a sandbox environment (test).
67
     */
68
    public $mode = 'live';
69
70
    /**
71
     * A unique key for this invoice.
72
     */
73
    public $key = '';
74
75
    /**
76
     * The invoice total.
77
     */
78
    public $total = 0.00;
79
80
    /**
81
     * The invoice subtotal.
82
     */
83
    public $subtotal = 0;
84
85
    /**
86
     * 1 to disable taxes and 0 otherwise.
87
     */
88
    public $disable_taxes = 0;
89
90
    /**
91
     * Total tax for this invoice.
92
     */
93
    public $tax = 0;
94
95
    /**
96
     * Other fees for the invoice.
97
     */
98
    public $fees = array();
99
100
    /**
101
     * Total amount of the fees.
102
     */
103
    public $fees_total = 0;
104
105
    /**
106
     * A comma separated array of discount codes.
107
     */
108
    public $discounts = '';
109
110
    /**
111
     * Total discount.
112
     */
113
    public $discount = 0;
114
115
    /**
116
     * Main discount code.
117
     */
118
    public $discount_code = 0;
119
120
    /**
121
     * The date the invoice was created.
122
     */
123
    public $date = '';
124
125
    /**
126
     * The date that the invoice will be due.
127
     */
128
    public $due_date = '';
129
130
    /**
131
     * The date the invoice was paid for.
132
     */
133
    public $completed_date = '';
134
135
    /**
136
     * The invoice status.
137
     */
138
    public $status      = 'wpi-pending';
139
140
    /**
141
     * Same as self::$status.
142
     */
143
    public $post_status = 'wpi-pending';
144
145
    /**
146
     * The old invoice status (used when transitioning statuses).
147
     */
148
    public $old_status = '';
149
150
    /**
151
     * A human readable status name.
152
     */
153
    public $status_nicename = '';
154
155
    /**
156
     * The user id of the invoice client.
157
     */
158
    public $user_id = 0;
159
160
    /**
161
     * The first name of the invoice client.
162
     */
163
    public $first_name = '';
164
165
    /**
166
     * The last name of the invoice client.
167
     */
168
    public $last_name = '';
169
170
    /**
171
     * The email address of the invoice client.
172
     */
173
    public $email = '';
174
175
    /**
176
     * The phone number of the invoice client.
177
     */
178
    public $phone = '';
179
180
    /**
181
     * The street address of the invoice client.
182
     */
183
    public $address = '';
184
185
    /**
186
     * The city of the invoice client.
187
     */
188
    public $city = '';
189
190
    /**
191
     * The country of the invoice client.
192
     */
193
    public $country = '';
194
195
    /**
196
     * The state of the invoice client.
197
     */
198
    public $state = '';
199
200
    /**
201
     * The postal code of the invoice client.
202
     */
203
    public $zip = '';
204
205
    /**
206
     * The transaction id of the invoice.
207
     */
208
    public $transaction_id = '';
209
210
    /**
211
     * The ip address of the invoice client.
212
     */
213
    public $ip = '';
214
215
    /**
216
     * The gateway used to pay the invoice.
217
     */
218
    public $gateway = '';
219
220
    /**
221
     * The title of the gateway used to pay for the invoice.
222
     */
223
    public $gateway_title = '';
224
225
    /**
226
     * The currency of the invoice.
227
     */
228
    public $currency = '';
229
230
    /**
231
     * The cart details of the invoice.
232
     */
233
    public $cart_details = array();
234
235
    /**
236
     * The company of the client.
237
     */
238
    public $company = '';
239
240
    /**
241
     * The vat number of the client.
242
     */
243
    public $vat_number = '';
244
245
    /**
246
     * The vat rate used on the invoice.
247
     */
248
    public $vat_rate = '';
249
250
    /**
251
     * Whether or not the client confirmed the address
252
     */
253
    public $adddress_confirmed = '';
254
255
    /**
256
     * The full name of the client.
257
     */
258
    public $full_name = '';
259
260
    /**
261
     * The parent invoice id of this invoice.
262
     */
263
    public $parent_invoice = 0;
264
265
    public function __construct( $invoice_id = false ) {
266
        if ( empty( $invoice_id ) ) {
267
            return false;
268
        }
269
270
        $this->setup_invoice( $invoice_id );
271
    }
272
273
    public function get( $key ) {
274
        if ( method_exists( $this, 'get_' . $key ) ) {
275
            $value = call_user_func( array( $this, 'get_' . $key ) );
276
        } else {
277
            $value = $this->$key;
278
        }
279
280
        return $value;
281
    }
282
283
    public function set( $key, $value ) {
284
        $ignore = array( 'items', 'cart_details', 'fees', '_ID' );
285
286
        if ( $key === 'status' ) {
287
            $this->old_status = $this->status;
288
        }
289
290
        if ( ! in_array( $key, $ignore ) ) {
291
            $this->pending[ $key ] = $value;
292
        }
293
294
        if ( '_ID' !== $key ) {
295
            $this->$key = $value;
296
        }
297
    }
298
299
    public function _isset( $name ) {
300
        if ( property_exists( $this, $name ) ) {
301
            return false === empty( $this->$name );
302
        } else {
303
            return null;
304
        }
305
    }
306
307
    private function setup_invoice( $invoice_id ) {
308
        $this->pending = array();
309
310
        $invoice = get_post( $invoice_id );
311
312
        if ( ! $invoice || is_wp_error( $invoice ) ) {
0 ignored issues
show
introduced by
$invoice is of type WP_Post, thus it always evaluated to true.
Loading history...
313
            return false;
314
        }
315
316
        do_action( 'wpinv_pre_setup_invoice', $this, $invoice_id );
317
318
        // Primary Identifier
319
        $this->ID              = absint( $invoice_id );
320
        $this->post_type       = $invoice->post_type;
321
322
        // We have a payment, get the generic payment_meta item to reduce calls to it
323
        $this->payment_meta    = $this->get_meta();
324
        $this->date            = $invoice->post_date;
325
        $this->due_date        = $this->setup_due_date();
326
        $this->completed_date  = $this->setup_completed_date();
327
        $this->status          = $invoice->post_status;
328
329
        if ( 'future' == $this->status ) {
330
            $this->status = 'publish';
331
        }
332
333
        $this->post_status     = $this->status;
334
        $this->mode            = $this->setup_mode();
335
        $this->parent_invoice  = $invoice->post_parent;
336
        $this->post_name       = $this->setup_post_name( $invoice );
0 ignored issues
show
Bug Best Practice introduced by
The property post_name does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug introduced by
Are you sure the assignment to $this->post_name is correct as $this->setup_post_name($invoice) targeting WPInv_Legacy_Invoice::setup_post_name() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
337
        $this->status_nicename = $this->setup_status_nicename( $invoice->post_status );
338
339
        // Items
340
        $this->fees            = $this->setup_fees();
341
        $this->cart_details    = $this->setup_cart_details();
342
        $this->items           = $this->setup_items();
343
344
        // Currency Based
345
        $this->total           = $this->setup_total();
346
        $this->disable_taxes   = $this->setup_is_taxable();
347
        $this->tax             = $this->setup_tax();
348
        $this->fees_total      = $this->get_fees_total();
349
        $this->subtotal        = $this->setup_subtotal();
350
        $this->currency        = $this->setup_currency();
351
352
        // Gateway based
353
        $this->gateway         = $this->setup_gateway();
354
        $this->gateway_title   = $this->setup_gateway_title();
355
        $this->transaction_id  = $this->setup_transaction_id();
356
357
        // User based
358
        $this->ip              = $this->setup_ip();
359
        $this->user_id         = ! empty( $invoice->post_author ) ? $invoice->post_author : get_current_user_id();///$this->setup_user_id();
360
        $this->email           = get_the_author_meta( 'email', $this->user_id );
0 ignored issues
show
Bug introduced by
It seems like $this->user_id can also be of type string; however, parameter $user_id of get_the_author_meta() does only seem to accept false|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

360
        $this->email           = get_the_author_meta( 'email', /** @scrutinizer ignore-type */ $this->user_id );
Loading history...
361
362
        $this->user_info       = $this->setup_user_info();
363
364
        $this->first_name      = $this->user_info['first_name'];
365
        $this->last_name       = $this->user_info['last_name'];
366
        $this->company         = $this->user_info['company'];
367
        $this->vat_number      = $this->user_info['vat_number'];
368
        $this->vat_rate        = $this->user_info['vat_rate'];
369
        $this->adddress_confirmed  = $this->user_info['adddress_confirmed'];
370
        $this->address         = $this->user_info['address'];
371
        $this->city            = $this->user_info['city'];
372
        $this->country         = $this->user_info['country'];
373
        $this->state           = $this->user_info['state'];
374
        $this->zip             = $this->user_info['zip'];
375
        $this->phone           = $this->user_info['phone'];
376
377
        $this->discounts       = $this->user_info['discount'];
378
            $this->discount        = $this->setup_discount();
379
            $this->discount_code   = $this->setup_discount_code();
380
381
        // Other Identifiers
382
        $this->key             = $this->setup_invoice_key();
383
        $this->number          = $this->setup_invoice_number();
384
        $this->title           = ! empty( $invoice->post_title ) ? $invoice->post_title : $this->number;
385
386
        $this->full_name       = trim( $this->first_name . ' ' . $this->last_name );
387
388
        // Allow extensions to add items to this object via hook
389
        do_action( 'wpinv_setup_invoice', $this, $invoice_id );
390
391
        return true;
392
    }
393
394
    private function setup_status_nicename( $status ) {
395
        return $status;
396
    }
397
398
    private function setup_post_name( $post ) {
399
        $this->post_name = $post->post_name;
0 ignored issues
show
Bug Best Practice introduced by
The property post_name does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
400
    }
401
402
    private function setup_due_date() {
403
        $due_date = $this->get_meta( '_wpinv_due_date' );
404
405
        if ( empty( $due_date ) ) {
406
            $overdue_time = strtotime( $this->date ) + ( DAY_IN_SECONDS * absint( wpinv_get_option( 'overdue_days', 0 ) ) );
407
            $due_date = date_i18n( 'Y-m-d', $overdue_time );
408
        } elseif ( $due_date == 'none' ) {
409
            $due_date = '';
410
        }
411
412
        return $due_date;
413
    }
414
415
    private function setup_completed_date() {
416
        $invoice = get_post( $this->ID );
417
418
        if ( 'wpi-pending' == $invoice->post_status || 'preapproved' == $invoice->post_status ) {
419
            return false; // This invoice was never paid
420
        }
421
422
        $date = ( $date = $this->get_meta( '_wpinv_completed_date', true ) ) ? $date : $invoice->modified_date;
423
424
        return $date;
425
    }
426
427
    private function setup_cart_details() {
428
        $cart_details = isset( $this->payment_meta['cart_details'] ) ? maybe_unserialize( $this->payment_meta['cart_details'] ) : array();
429
        return $cart_details;
430
    }
431
432
    public function array_convert() {
433
        return get_object_vars( $this );
434
    }
435
436
    private function setup_items() {
437
        $items = isset( $this->payment_meta['items'] ) ? maybe_unserialize( $this->payment_meta['items'] ) : array();
438
        return $items;
439
    }
440
441
    private function setup_fees() {
442
        $payment_fees = isset( $this->payment_meta['fees'] ) ? $this->payment_meta['fees'] : array();
443
        return $payment_fees;
444
    }
445
446
    private function setup_currency() {
447
        $currency = isset( $this->payment_meta['currency'] ) ? $this->payment_meta['currency'] : apply_filters( 'wpinv_currency_default', wpinv_get_currency(), $this );
448
        return $currency;
449
    }
450
451
    private function setup_discount() {
452
        //$discount = $this->get_meta( '_wpinv_discount', true );
453
        $discount = (float)$this->subtotal - ( (float)$this->total - (float)$this->tax - (float)$this->fees_total );
454
        if ( $discount < 0 ) {
455
            $discount = 0;
456
        }
457
        $discount = wpinv_round_amount( $discount );
458
459
        return $discount;
460
    }
461
462
    private function setup_discount_code() {
463
        $discount_code = ! empty( $this->discounts ) ? $this->discounts : $this->get_meta( '_wpinv_discount_code', true );
464
        return $discount_code;
465
    }
466
467
    private function setup_tax() {
468
469
        $tax = $this->get_meta( '_wpinv_tax', true );
470
471
        // We don't have tax as it's own meta and no meta was passed
472
        if ( '' === $tax ) {
473
            $tax = isset( $this->payment_meta['tax'] ) ? $this->payment_meta['tax'] : 0;
474
        }
475
476
        if ( $tax < 0 || ! $this->is_taxable() ) {
477
            $tax = 0;
478
        }
479
480
        return $tax;
481
    }
482
483
    /**
484
     * If taxes are enabled, allow users to enable/disable taxes per invoice.
485
     */
486
    private function setup_is_taxable() {
487
        return (int) $this->get_meta( '_wpinv_disable_taxes', true );
488
    }
489
490
    private function setup_subtotal() {
491
        $subtotal     = 0;
492
        $cart_details = $this->cart_details;
493
494
        if ( is_array( $cart_details ) ) {
0 ignored issues
show
introduced by
The condition is_array($cart_details) is always true.
Loading history...
495
            foreach ( $cart_details as $item ) {
496
                if ( isset( $item['subtotal'] ) ) {
497
                    $subtotal += $item['subtotal'];
498
                }
499
            }
500
        } else {
501
            $subtotal  = $this->total;
502
            $tax       = wpinv_use_taxes() ? $this->tax : 0;
503
            $subtotal -= $tax;
504
        }
505
506
        return $subtotal;
507
    }
508
509
    private function setup_discounts() {
510
        $discounts = ! empty( $this->payment_meta['user_info']['discount'] ) ? $this->payment_meta['user_info']['discount'] : array();
511
        return $discounts;
512
    }
513
514
    private function setup_total() {
515
        $amount = $this->get_meta( '_wpinv_total', true );
516
517
        if ( empty( $amount ) && '0.00' != $amount ) {
518
            $meta   = $this->get_meta( '_wpinv_payment_meta', true );
519
            $meta   = maybe_unserialize( $meta );
0 ignored issues
show
Bug introduced by
It seems like $meta can also be of type array and array; however, parameter $data of maybe_unserialize() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

519
            $meta   = maybe_unserialize( /** @scrutinizer ignore-type */ $meta );
Loading history...
520
521
            if ( isset( $meta['amount'] ) ) {
522
                $amount = $meta['amount'];
523
            }
524
        }
525
526
        if ( $amount < 0 ) {
527
            $amount = 0;
528
        }
529
530
        return $amount;
531
    }
532
533
    private function setup_mode() {
534
        return $this->get_meta( '_wpinv_mode' );
535
    }
536
537
    private function setup_gateway() {
538
        $gateway = $this->get_meta( '_wpinv_gateway' );
539
540
        if ( empty( $gateway ) && 'publish' === $this->status ) {
541
            $gateway = 'manual';
542
        }
543
544
        return $gateway;
545
    }
546
547
    private function setup_gateway_title() {
548
        $gateway_title = wpinv_get_gateway_checkout_label( $this->gateway );
549
        return $gateway_title;
550
    }
551
552
    private function setup_transaction_id() {
553
        $transaction_id = $this->get_meta( '_wpinv_transaction_id' );
554
555
        if ( empty( $transaction_id ) || (int) $transaction_id === (int) $this->ID ) {
556
            $gateway        = $this->gateway;
557
            $transaction_id = apply_filters( 'wpinv_get_invoice_transaction_id-' . $gateway, $this->ID );
558
        }
559
560
        return $transaction_id;
561
    }
562
563
    private function setup_ip() {
564
        $ip = $this->get_meta( '_wpinv_user_ip' );
565
        return $ip;
566
    }
567
568
    ///private function setup_user_id() {
569
        ///$user_id = $this->get_meta( '_wpinv_user_id' );
570
        ///return $user_id;
571
    ///}
572
573
    private function setup_first_name() {
574
        $first_name = $this->get_meta( '_wpinv_first_name' );
575
        return $first_name;
576
    }
577
578
    private function setup_last_name() {
579
        $last_name = $this->get_meta( '_wpinv_last_name' );
580
        return $last_name;
581
    }
582
583
    private function setup_company() {
584
        $company = $this->get_meta( '_wpinv_company' );
585
        return $company;
586
    }
587
588
    private function setup_vat_number() {
589
        $vat_number = $this->get_meta( '_wpinv_vat_number' );
590
        return $vat_number;
591
    }
592
593
    private function setup_vat_rate() {
594
        $vat_rate = $this->get_meta( '_wpinv_vat_rate' );
595
        return $vat_rate;
596
    }
597
598
    private function setup_adddress_confirmed() {
599
        $adddress_confirmed = $this->get_meta( '_wpinv_adddress_confirmed' );
600
        return $adddress_confirmed;
601
    }
602
603
    private function setup_phone() {
604
        $phone = $this->get_meta( '_wpinv_phone' );
605
        return $phone;
606
    }
607
608
    private function setup_address() {
609
        $address = $this->get_meta( '_wpinv_address', true );
610
        return $address;
611
    }
612
613
    private function setup_city() {
614
        $city = $this->get_meta( '_wpinv_city', true );
615
        return $city;
616
    }
617
618
    private function setup_country() {
619
        $country = $this->get_meta( '_wpinv_country', true );
620
        return $country;
621
    }
622
623
    private function setup_state() {
624
        $state = $this->get_meta( '_wpinv_state', true );
625
        return $state;
626
    }
627
628
    private function setup_zip() {
629
        $zip = $this->get_meta( '_wpinv_zip', true );
630
        return $zip;
631
    }
632
633
    private function setup_user_info() {
634
        $defaults = array(
635
            'user_id'            => $this->user_id,
636
            'first_name'         => $this->first_name,
637
            'last_name'          => $this->last_name,
638
            'email'              => get_the_author_meta( 'email', $this->user_id ),
639
            'phone'              => $this->phone,
640
            'address'            => $this->address,
641
            'city'               => $this->city,
642
            'country'            => $this->country,
643
            'state'              => $this->state,
644
            'zip'                => $this->zip,
645
            'company'            => $this->company,
646
            'vat_number'         => $this->vat_number,
647
            'vat_rate'           => $this->vat_rate,
648
            'adddress_confirmed' => $this->adddress_confirmed,
649
            'discount'           => $this->discounts,
650
        );
651
652
        $user_info = array();
653
        if ( isset( $this->payment_meta['user_info'] ) ) {
654
            $user_info = maybe_unserialize( $this->payment_meta['user_info'] );
655
656
            if ( ! empty( $user_info ) && isset( $user_info['user_id'] ) && $post = get_post( $this->ID ) ) {
657
                $this->user_id = $post->post_author;
658
                $this->email = get_the_author_meta( 'email', $this->user_id );
0 ignored issues
show
Bug introduced by
$this->user_id of type string is incompatible with the type false|integer expected by parameter $user_id of get_the_author_meta(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

658
                $this->email = get_the_author_meta( 'email', /** @scrutinizer ignore-type */ $this->user_id );
Loading history...
659
660
                $user_info['user_id'] = $this->user_id;
661
                $user_info['email'] = $this->email;
662
                $this->payment_meta['user_id'] = $this->user_id;
663
                $this->payment_meta['email'] = $this->email;
664
            }
665
        }
666
667
        $user_info    = wp_parse_args( $user_info, $defaults );
668
669
        // Get the user, but only if it's been created
670
        $user = get_userdata( $this->user_id );
671
672
        if ( ! empty( $user ) && $user->ID > 0 ) {
673
            if ( empty( $user_info ) ) {
674
                $user_info = array(
675
                    'user_id'    => $user->ID,
676
                    'first_name' => $user->first_name,
677
                    'last_name'  => $user->last_name,
678
                    'email'      => $user->user_email,
679
                    'discount'   => '',
680
                );
681
            } else {
682
                foreach ( $user_info as $key => $value ) {
683
                    if ( ! empty( $value ) ) {
684
                        continue;
685
                    }
686
687
                    switch ( $key ) {
688
                        case 'user_id':
689
                            $user_info[ $key ] = $user->ID;
690
                            break;
691
                        case 'first_name':
692
                            $user_info[ $key ] = $user->first_name;
693
                            break;
694
                        case 'last_name':
695
                            $user_info[ $key ] = $user->last_name;
696
                            break;
697
                        case 'email':
698
                            $user_info[ $key ] = $user->user_email;
699
                            break;
700
                    }
701
                }
702
            }
703
        }
704
705
        return $user_info;
706
    }
707
708
    private function setup_invoice_key() {
709
        $key = $this->get_meta( '_wpinv_key', true );
710
711
        return $key;
712
    }
713
714
    private function setup_invoice_number() {
715
        $number = $this->get_meta( '_wpinv_number', true );
716
717
        if ( ! $number ) {
718
            $number = $this->ID;
719
720
            if ( $this->status == 'auto-draft' ) {
721
                if ( wpinv_sequential_number_active( $this->post_type ) ) {
722
                    $next_number = wpinv_get_next_invoice_number( $this->post_type );
723
                    $number      = $next_number;
724
                }
725
            }
726
727
            $number = wpinv_format_invoice_number( $number, $this->post_type );
728
        }
729
730
        return $number;
731
    }
732
733
    public function save() {}
734
735
    public function add_fee( $args ) {
736
        $default_args = array(
737
            'label'   => '',
738
            'amount'  => 0,
739
            'type'    => 'fee',
740
            'id'      => '',
741
            'no_tax'  => false,
742
            'item_id' => 0,
743
        );
744
745
        $fee = wp_parse_args( $args, $default_args );
746
747
        if ( empty( $fee['label'] ) ) {
748
            return false;
749
        }
750
751
        $fee['id']  = sanitize_title( $fee['label'] );
752
753
        $this->fees[]               = $fee;
754
755
        $added_fee               = $fee;
756
        $added_fee['action']     = 'add';
757
        $this->pending['fees'][] = $added_fee;
758
        reset( $this->fees );
759
760
        $this->increase_fees( $fee['amount'] );
761
        return true;
762
    }
763
764
    public function remove_fee( $key ) {
765
        $removed = false;
766
767
        if ( is_numeric( $key ) ) {
768
            $removed = $this->remove_fee_by( 'index', $key );
769
        }
770
771
        return $removed;
772
    }
773
774
    public function remove_fee_by( $key, $value, $global = false ) {
775
        $allowed_fee_keys = apply_filters(
776
            'wpinv_fee_keys',
777
            array(
778
				'index',
779
				'label',
780
				'amount',
781
				'type',
782
            )
783
        );
784
785
        if ( ! in_array( $key, $allowed_fee_keys ) ) {
786
            return false;
787
        }
788
789
        $removed = false;
790
        if ( 'index' === $key && array_key_exists( $value, $this->fees ) ) {
791
            $removed_fee             = $this->fees[ $value ];
792
            $removed_fee['action']   = 'remove';
793
            $this->pending['fees'][] = $removed_fee;
794
795
            $this->decrease_fees( $removed_fee['amount'] );
796
797
            unset( $this->fees[ $value ] );
798
            $removed = true;
799
        } elseif ( 'index' !== $key ) {
800
            foreach ( $this->fees as $index => $fee ) {
801
                if ( isset( $fee[ $key ] ) && $fee[ $key ] == $value ) {
802
                    $removed_fee             = $fee;
803
                    $removed_fee['action']   = 'remove';
804
                    $this->pending['fees'][] = $removed_fee;
805
806
                    $this->decrease_fees( $removed_fee['amount'] );
807
808
                    unset( $this->fees[ $index ] );
809
                    $removed = true;
810
811
                    if ( false === $global ) {
812
                        break;
813
                    }
814
                }
815
            }
816
        }
817
818
        if ( true === $removed ) {
819
            $this->fees = array_values( $this->fees );
820
        }
821
822
        return $removed;
823
    }
824
825
826
827
    public function add_note( $note = '', $customer_type = false, $added_by_user = false, $system = false ) {
828
        // Bail if no note specified
829
        if ( ! $note ) {
830
            return false;
831
        }
832
833
        if ( empty( $this->ID ) ) {
834
            return false;
835
        }
836
837
        if ( ( ( is_user_logged_in() && wpinv_current_user_can_manage_invoicing() ) || $added_by_user ) && ! $system ) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_user_logged_in() && ...d_by_user) && ! $system, Probably Intended Meaning: is_user_logged_in() && w...d_by_user && ! $system)
Loading history...
838
            $user                 = get_user_by( 'id', get_current_user_id() );
839
            $comment_author       = $user->display_name;
840
            $comment_author_email = $user->user_email;
841
        } else {
842
            $comment_author       = 'System';
843
            $comment_author_email = 'system@';
844
            $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com';
845
            $comment_author_email = sanitize_email( $comment_author_email );
846
        }
847
848
        do_action( 'wpinv_pre_insert_invoice_note', $this->ID, $note, $customer_type );
849
850
        $note_id = wp_insert_comment(
851
            wp_filter_comment(
852
                array(
853
					'comment_post_ID'      => $this->ID,
854
					'comment_content'      => $note,
855
					'comment_agent'        => 'WPInvoicing',
856
					'user_id'              => is_admin() ? get_current_user_id() : 0,
857
					'comment_date'         => current_time( 'mysql' ),
858
					'comment_date_gmt'     => current_time( 'mysql', 1 ),
859
					'comment_approved'     => 1,
860
					'comment_parent'       => 0,
861
					'comment_author'       => $comment_author,
862
					'comment_author_IP'    => wpinv_get_ip(),
863
					'comment_author_url'   => '',
864
					'comment_author_email' => $comment_author_email,
865
					'comment_type'         => 'wpinv_note',
866
                )
867
            )
868
        );
869
870
        do_action( 'wpinv_insert_payment_note', $note_id, $this->ID, $note );
871
872
        if ( $customer_type ) {
873
            add_comment_meta( $note_id, '_wpi_customer_note', 1 );
0 ignored issues
show
Bug introduced by
It seems like $note_id can also be of type false; however, parameter $comment_id of add_comment_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

873
            add_comment_meta( /** @scrutinizer ignore-type */ $note_id, '_wpi_customer_note', 1 );
Loading history...
874
875
            do_action(
876
                'wpinv_new_customer_note',
877
                array(
878
					'invoice_id' => $this->ID,
879
					'user_note'  => $note,
880
                )
881
            );
882
        }
883
884
        return $note_id;
885
    }
886
887
    private function increase_subtotal( $amount = 0.00 ) {
888
        $amount          = (float) $amount;
889
        $this->subtotal += $amount;
890
        $this->subtotal  = wpinv_round_amount( $this->subtotal );
891
892
        $this->recalculate_total();
893
    }
894
895
    private function decrease_subtotal( $amount = 0.00 ) {
896
        $amount          = (float) $amount;
897
        $this->subtotal -= $amount;
898
        $this->subtotal  = wpinv_round_amount( $this->subtotal );
899
900
        if ( $this->subtotal < 0 ) {
901
            $this->subtotal = 0;
902
        }
903
904
        $this->recalculate_total();
905
    }
906
907
    private function increase_fees( $amount = 0.00 ) {
908
        $amount            = (float)$amount;
909
        $this->fees_total += $amount;
910
        $this->fees_total  = wpinv_round_amount( $this->fees_total );
911
912
        $this->recalculate_total();
913
    }
914
915
    private function decrease_fees( $amount = 0.00 ) {
916
        $amount            = (float) $amount;
917
        $this->fees_total -= $amount;
918
        $this->fees_total  = wpinv_round_amount( $this->fees_total );
919
920
        if ( $this->fees_total < 0 ) {
921
            $this->fees_total = 0;
922
        }
923
924
        $this->recalculate_total();
925
    }
926
927
    public function recalculate_total() {
928
        global $wpi_nosave;
929
930
        $this->total = $this->subtotal + $this->tax + $this->fees_total;
931
        $this->total = wpinv_round_amount( $this->total );
932
933
        do_action( 'wpinv_invoice_recalculate_total', $this, $wpi_nosave );
934
    }
935
936
    public function increase_tax( $amount = 0.00 ) {
937
        $amount       = (float) $amount;
938
        $this->tax   += $amount;
939
940
        $this->recalculate_total();
941
    }
942
943
    public function decrease_tax( $amount = 0.00 ) {
944
        $amount     = (float) $amount;
945
        $this->tax -= $amount;
946
947
        if ( $this->tax < 0 ) {
948
            $this->tax = 0;
949
        }
950
951
        $this->recalculate_total();
952
    }
953
954
    public function update_status( $new_status = false, $note = '', $manual = false ) {
955
        $old_status = ! empty( $this->old_status ) ? $this->old_status : get_post_status( $this->ID );
956
957
        if ( $old_status === $new_status && in_array( $new_status, array_keys( wpinv_get_invoice_statuses( true ) ) ) ) {
958
            return false; // Don't permit status changes that aren't changes
959
        }
960
961
        $do_change = apply_filters( 'wpinv_should_update_invoice_status', true, $this->ID, $new_status, $old_status );
962
        $updated = false;
963
964
        if ( $do_change ) {
965
            do_action( 'wpinv_before_invoice_status_change', $this->ID, $new_status, $old_status );
966
967
            $update_post_data                   = array();
968
            $update_post_data['ID']             = $this->ID;
969
            $update_post_data['post_status']    = $new_status;
970
            $update_post_data['edit_date']      = current_time( 'mysql', 0 );
971
            $update_post_data['edit_date_gmt']  = current_time( 'mysql', 1 );
972
973
            $update_post_data = apply_filters( 'wpinv_update_invoice_status_fields', $update_post_data, $this->ID );
974
975
            $updated = wp_update_post( $update_post_data );
976
977
            // Status was changed.
978
            do_action( 'wpinv_status_' . $new_status, $this->ID, $old_status );
979
            do_action( 'wpinv_status_' . $old_status . '_to_' . $new_status, $this->ID, $old_status );
0 ignored issues
show
Bug introduced by
Are you sure $old_status of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

979
            do_action( 'wpinv_status_' . /** @scrutinizer ignore-type */ $old_status . '_to_' . $new_status, $this->ID, $old_status );
Loading history...
980
            do_action( 'wpinv_update_status', $this->ID, $new_status, $old_status );
981
        }
982
983
        return $updated;
984
    }
985
986
    public function refund() {
987
        $this->old_status        = $this->status;
988
        $this->status            = 'wpi-refunded';
989
        $this->pending['status'] = $this->status;
990
991
        $this->save();
992
    }
993
994
    public function update_meta() {}
995
996
    // get data
997
    public function get_meta( $meta_key = '_wpinv_payment_meta', $single = true ) {
998
        $meta = get_post_meta( $this->ID, $meta_key, $single );
999
1000
        if ( $meta_key === '_wpinv_payment_meta' ) {
1001
1002
            if ( ! is_array( $meta ) ) {
1003
$meta = array();} // we need this to be an array so make sure it is.
1004
1005
            if ( empty( $meta['key'] ) ) {
1006
                $meta['key'] = $this->setup_invoice_key();
1007
            }
1008
1009
            if ( empty( $meta['date'] ) ) {
1010
                $meta['date'] = get_post_field( 'post_date', $this->ID );
1011
            }
1012
        }
1013
1014
        $meta = apply_filters( 'wpinv_get_invoice_meta_' . $meta_key, $meta, $this->ID );
1015
1016
        return apply_filters( 'wpinv_get_invoice_meta', $meta, $this->ID, $meta_key );
1017
    }
1018
1019
    public function get_description() {
1020
        $post = get_post( $this->ID );
1021
1022
        $description = ! empty( $post ) ? $post->post_content : '';
1023
        return apply_filters( 'wpinv_get_description', $description, $this->ID, $this );
1024
    }
1025
1026
    public function get_status( $nicename = false ) {
1027
        if ( ! $nicename ) {
1028
            $status = $this->status;
1029
        } else {
1030
            $status = $this->status_nicename;
1031
        }
1032
1033
        return apply_filters( 'wpinv_get_status', $status, $nicename, $this->ID, $this );
1034
    }
1035
1036
    public function get_cart_details() {
1037
        return apply_filters( 'wpinv_cart_details', $this->cart_details, $this->ID, $this );
1038
    }
1039
1040
    public function get_subtotal( $currency = false ) {
1041
        $subtotal = wpinv_round_amount( $this->subtotal );
1042
1043
        if ( $currency ) {
1044
            $subtotal = wpinv_price( wpinv_format_amount( $subtotal, null, ! $currency ), $this->get_currency() );
0 ignored issues
show
Bug introduced by
wpinv_format_amount($subtotal, null, ! $currency) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1044
            $subtotal = wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( $subtotal, null, ! $currency ), $this->get_currency() );
Loading history...
1045
        }
1046
1047
        return apply_filters( 'wpinv_get_invoice_subtotal', $subtotal, $this->ID, $this, $currency );
1048
    }
1049
1050
    public function get_total( $currency = false ) {
1051
        if ( $this->is_free_trial() ) {
1052
            $total = wpinv_round_amount( 0 );
1053
        } else {
1054
            $total = wpinv_round_amount( $this->total );
1055
        }
1056
        if ( $currency ) {
1057
            $total = wpinv_price( wpinv_format_amount( $total, null, ! $currency ), $this->get_currency() );
0 ignored issues
show
Bug introduced by
wpinv_format_amount($total, null, ! $currency) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1057
            $total = wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( $total, null, ! $currency ), $this->get_currency() );
Loading history...
1058
        }
1059
1060
        return apply_filters( 'wpinv_get_invoice_total', $total, $this->ID, $this, $currency );
1061
    }
1062
1063
    public function get_recurring_details() {}
1064
1065
    public function get_final_tax( $currency = false ) {
1066
        $final_total = wpinv_round_amount( $this->tax );
1067
        if ( $currency ) {
1068
            $final_total = wpinv_price( wpinv_format_amount( $final_total, null, ! $currency ), $this->get_currency() );
0 ignored issues
show
Bug introduced by
wpinv_format_amount($fin...tal, null, ! $currency) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1068
            $final_total = wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( $final_total, null, ! $currency ), $this->get_currency() );
Loading history...
1069
        }
1070
1071
        return apply_filters( 'wpinv_get_invoice_final_total', $final_total, $this, $currency );
1072
    }
1073
1074
    public function get_discounts( $array = false ) {
1075
        $discounts = $this->discounts;
1076
        if ( $array && $discounts ) {
1077
            $discounts = explode( ',', $discounts );
1078
        }
1079
        return apply_filters( 'wpinv_payment_discounts', $discounts, $this->ID, $this, $array );
1080
    }
1081
1082
    public function get_discount( $currency = false, $dash = false ) {
1083
        if ( ! empty( $this->discounts ) ) {
1084
            global $ajax_cart_details;
1085
            $ajax_cart_details = $this->get_cart_details();
1086
1087
            if ( ! empty( $ajax_cart_details ) && count( $ajax_cart_details ) == count( $this->items ) ) {
1088
                $cart_items = $ajax_cart_details;
1089
            } else {
1090
                $cart_items = $this->items;
1091
            }
1092
1093
            $this->discount = wpinv_get_cart_items_discount_amount( $cart_items, $this->discounts );
0 ignored issues
show
Unused Code introduced by
The call to wpinv_get_cart_items_discount_amount() has too many arguments starting with $cart_items. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1093
            $this->discount = /** @scrutinizer ignore-call */ wpinv_get_cart_items_discount_amount( $cart_items, $this->discounts );

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. Please note the @ignore annotation hint above.

Loading history...
Deprecated Code introduced by
The function wpinv_get_cart_items_discount_amount() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1093
            $this->discount = /** @scrutinizer ignore-deprecated */ wpinv_get_cart_items_discount_amount( $cart_items, $this->discounts );
Loading history...
1094
        }
1095
        $discount   = wpinv_round_amount( $this->discount );
1096
        $dash       = $dash && $discount > 0 ? '&ndash;' : '';
1097
1098
        if ( $currency ) {
1099
            $discount = wpinv_price( wpinv_format_amount( $discount, null, ! $currency ), $this->get_currency() );
0 ignored issues
show
Bug introduced by
wpinv_format_amount($discount, null, ! $currency) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1099
            $discount = wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( $discount, null, ! $currency ), $this->get_currency() );
Loading history...
1100
        }
1101
1102
        $discount   = $dash . $discount;
1103
1104
        return apply_filters( 'wpinv_get_invoice_discount', $discount, $this->ID, $this, $currency, $dash );
1105
    }
1106
1107
    public function get_discount_code() {
1108
        return $this->discount_code;
1109
    }
1110
1111
    // Checks if the invoice is taxable. Does not check if taxes are enabled on the site.
1112
    public function is_taxable() {
1113
        return (int) $this->disable_taxes === 0;
1114
    }
1115
1116
    public function get_tax( $currency = false ) {
1117
        $tax = wpinv_round_amount( $this->tax );
1118
1119
        if ( $currency ) {
1120
            $tax = wpinv_price( wpinv_format_amount( $tax, null, ! $currency ), $this->get_currency() );
0 ignored issues
show
Bug introduced by
wpinv_format_amount($tax, null, ! $currency) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1120
            $tax = wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( $tax, null, ! $currency ), $this->get_currency() );
Loading history...
1121
        }
1122
1123
        if ( ! $this->is_taxable() ) {
1124
            $tax = wpinv_round_amount( 0.00 );
1125
        }
1126
1127
        return apply_filters( 'wpinv_get_invoice_tax', $tax, $this->ID, $this, $currency );
1128
    }
1129
1130
    public function get_fees( $type = 'all' ) {
1131
        $fees    = array();
1132
1133
        if ( ! empty( $this->fees ) && is_array( $this->fees ) ) {
1134
            foreach ( $this->fees as $fee ) {
1135
                if ( 'all' != $type && ! empty( $fee['type'] ) && $type != $fee['type'] ) {
1136
                    continue;
1137
                }
1138
1139
                $fee['label'] = stripslashes( $fee['label'] );
1140
                $fee['amount_display'] = wpinv_price( $fee['amount'], $this->get_currency() );
1141
                $fees[]    = $fee;
1142
            }
1143
        }
1144
1145
        return apply_filters( 'wpinv_get_invoice_fees', $fees, $this->ID, $this );
1146
    }
1147
1148
    public function get_fees_total() {
1149
        $fees_total = (float) 0.00;
1150
1151
        $payment_fees = isset( $this->payment_meta['fees'] ) ? $this->payment_meta['fees'] : array();
1152
        if ( ! empty( $payment_fees ) ) {
1153
            foreach ( $payment_fees as $fee ) {
1154
                $fees_total += (float) $fee['amount'];
1155
            }
1156
        }
1157
1158
        return apply_filters( 'wpinv_get_invoice_fees_total', $fees_total, $this->ID, $this );
1159
1160
    }
1161
1162
    public function get_user_id() {
1163
        return apply_filters( 'wpinv_user_id', $this->user_id, $this->ID, $this );
1164
    }
1165
1166
    public function get_first_name() {
1167
        return apply_filters( 'wpinv_first_name', $this->first_name, $this->ID, $this );
1168
    }
1169
1170
    public function get_last_name() {
1171
        return apply_filters( 'wpinv_last_name', $this->last_name, $this->ID, $this );
1172
    }
1173
1174
    public function get_user_full_name() {
1175
        return apply_filters( 'wpinv_user_full_name', $this->full_name, $this->ID, $this );
1176
    }
1177
1178
    public function get_user_info() {
1179
        return apply_filters( 'wpinv_user_info', $this->user_info, $this->ID, $this );
1180
    }
1181
1182
    public function get_email() {
1183
        return apply_filters( 'wpinv_user_email', $this->email, $this->ID, $this );
1184
    }
1185
1186
    public function get_address() {
1187
        return apply_filters( 'wpinv_address', $this->address, $this->ID, $this );
1188
    }
1189
1190
    public function get_phone() {
1191
        return apply_filters( 'wpinv_phone', $this->phone, $this->ID, $this );
1192
    }
1193
1194
    public function get_number() {
1195
        return apply_filters( 'wpinv_number', $this->number, $this->ID, $this );
1196
    }
1197
1198
    public function get_items() {
1199
        return apply_filters( 'wpinv_payment_meta_items', $this->items, $this->ID, $this );
1200
    }
1201
1202
    public function get_key() {
1203
        return apply_filters( 'wpinv_key', $this->key, $this->ID, $this );
1204
    }
1205
1206
    public function get_transaction_id() {
1207
        return apply_filters( 'wpinv_get_invoice_transaction_id', $this->transaction_id, $this->ID, $this );
1208
    }
1209
1210
    public function get_gateway() {
1211
        return apply_filters( 'wpinv_gateway', $this->gateway, $this->ID, $this );
1212
    }
1213
1214
    public function get_gateway_title() {}
1215
1216
    public function get_currency() {
1217
        return apply_filters( 'wpinv_currency_code', $this->currency, $this->ID, $this );
1218
    }
1219
1220
    public function get_created_date() {
1221
        return apply_filters( 'wpinv_created_date', $this->date, $this->ID, $this );
1222
    }
1223
1224
    public function get_due_date( $display = false ) {
1225
        $due_date = apply_filters( 'wpinv_due_date', $this->due_date, $this->ID, $this );
1226
1227
        if ( ! $display ) {
1228
            return $due_date;
1229
        }
1230
1231
        return getpaid_format_date( $this->due_date );
1232
    }
1233
1234
    public function get_completed_date() {
1235
        return apply_filters( 'wpinv_completed_date', $this->completed_date, $this->ID, $this );
1236
    }
1237
1238
    public function get_invoice_date( $formatted = true ) {
1239
        $date_completed = $this->completed_date;
1240
        $invoice_date   = $date_completed != '' && $date_completed != '0000-00-00 00:00:00' ? $date_completed : '';
1241
1242
        if ( $invoice_date == '' ) {
1243
            $date_created   = $this->date;
1244
            $invoice_date   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? $date_created : '';
1245
        }
1246
1247
        if ( $formatted && $invoice_date ) {
1248
            $invoice_date   = getpaid_format_date( $invoice_date );
1249
        }
1250
1251
        return apply_filters( 'wpinv_get_invoice_date', $invoice_date, $formatted, $this->ID, $this );
1252
    }
1253
1254
    public function get_ip() {
1255
        return apply_filters( 'wpinv_user_ip', $this->ip, $this->ID, $this );
1256
    }
1257
1258
    public function has_status( $status ) {
1259
        return apply_filters( 'wpinv_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
1260
    }
1261
1262
    public function add_item() {}
1263
1264
    public function remove_item() {}
1265
1266
    public function update_items() {}
1267
1268
    public function recalculate_totals() {}
1269
1270
    public function needs_payment() {}
1271
1272
    public function get_checkout_payment_url() {}
1273
1274
    public function get_view_url() {}
1275
1276
    public function generate_key( $string = '' ) {
1277
        $auth_key  = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
1278
        return strtolower( md5( $string . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'wpinv', true ) ) );  // Unique key
1279
    }
1280
1281
    public function is_recurring() {
1282
        if ( empty( $this->cart_details ) ) {
1283
            return false;
1284
        }
1285
1286
        $has_subscription = false;
1287
        foreach ( $this->cart_details as $cart_item ) {
1288
            if ( ! empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] ) ) {
1289
                $has_subscription = true;
1290
                break;
1291
            }
1292
        }
1293
1294
        if ( count( $this->cart_details ) > 1 ) {
1295
            $has_subscription = false;
1296
        }
1297
1298
        return apply_filters( 'wpinv_invoice_has_recurring_item', $has_subscription, $this->cart_details );
1299
    }
1300
1301
    public function is_free_trial() {
1302
        $is_free_trial = false;
1303
1304
        if ( $this->is_parent() && $item = $this->get_recurring( true ) ) {
1305
            if ( ! empty( $item ) && $item->has_free_trial() ) {
1306
                $is_free_trial = true;
1307
            }
1308
        }
1309
1310
        return apply_filters( 'wpinv_invoice_is_free_trial', $is_free_trial, $this->cart_details, $this );
1311
    }
1312
1313
    public function is_initial_free() {}
1314
1315
    public function get_recurring( $object = false ) {
1316
        $item = null;
1317
1318
        if ( empty( $this->cart_details ) ) {
1319
            return $item;
1320
        }
1321
1322
        foreach ( $this->cart_details as $cart_item ) {
1323
            if ( ! empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] ) ) {
1324
                $item = $cart_item['id'];
1325
                break;
1326
            }
1327
        }
1328
1329
        if ( $object ) {
1330
            $item = $item ? new WPInv_Item( $item ) : null;
1331
1332
            apply_filters( 'wpinv_invoice_get_recurring_item', $item, $this );
1333
        }
1334
1335
        return apply_filters( 'wpinv_invoice_get_recurring_item_id', $item, $this );
1336
    }
1337
1338
    public function get_subscription_name() {}
1339
1340
    public function get_subscription_id() {}
1341
1342
    public function is_parent() {
1343
        return ! empty( $this->parent_invoice );
1344
    }
1345
1346
    public function is_renewal() {}
1347
1348
    public function get_parent_payment() {}
1349
1350
    public function is_paid() {}
1351
1352
    public function is_quote() {}
1353
1354
    public function is_refunded() {}
1355
1356
    public function is_free() {
1357
        $total = (float) wpinv_round_amount( $this->get_total() );
1358
        return $total > 0 && ! $this->is_recurring();
1359
    }
1360
1361
    public function has_vat() {}
1362
1363
    public function refresh_item_ids() {}
1364
1365
    public function get_invoice_quote_type() {}
1366
1367
}
1368