wpinv_insert_invoice()   F
last analyzed

Complexity

Conditions 77
Paths 5029

Size

Total Lines 212
Code Lines 106

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 77
eloc 106
c 0
b 0
f 0
nc 5029
nop 2
dl 0
loc 212
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Contains invoice functions.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * Retrieves the current invoice.
13
 */
14
function getpaid_get_current_invoice_id() {
15
16
    // Ensure that we have an invoice key.
17
    if ( empty( $_GET['invoice_key'] ) ) {
18
        return 0;
19
    }
20
21
    // Retrieve an invoice using the key.
22
    $invoice = new WPInv_Invoice( sanitize_text_field( $_GET['invoice_key'] ) );
23
24
    // Compare the invoice key and the parsed key.
25
    if ( $invoice->get_id() != 0 && $invoice->get_key() == sanitize_text_field( $_GET['invoice_key'] ) ) {
26
        return $invoice->get_id();
27
    }
28
29
    return 0;
30
}
31
32
/**
33
 * Checks if the current user cna view an invoice.
34
 */
35
function wpinv_user_can_view_invoice( $invoice ) {
36
    $invoice = new WPInv_Invoice( $invoice );
37
38
    // Abort if the invoice does not exist.
39
    if ( 0 == $invoice->get_id() ) {
40
        return false;
41
    }
42
43
    // Don't allow trash, draft status
44
    if ( $invoice->is_draft() ) {
45
        return false;
46
    }
47
48
    // If users are not required to login to check out, compare the invoice keys.
49
    if ( ! wpinv_require_login_to_checkout() && isset( $_GET['invoice_key'] ) && sanitize_text_field( $_GET['invoice_key'] ) == $invoice->get_key() ) {
50
        return true;
51
    }
52
53
    // Always enable for admins..
54
    if ( wpinv_current_user_can( 'view_invoice', array( 'invoice' => $invoice ) ) || current_user_can( 'view_invoices', $invoice->get_id() ) ) { // Admin user
55
        return true;
56
    }
57
58
    // Else, ensure that this is their invoice.
59
    if ( is_user_logged_in() && $invoice->get_user_id() == get_current_user_id() ) {
60
        return true;
61
    }
62
63
    return apply_filters( 'wpinv_current_user_can_view_invoice', false, $invoice );
64
}
65
66
/**
67
 * Checks if the current user cna view an invoice receipt.
68
 */
69
function wpinv_can_view_receipt( $invoice ) {
70
	return (bool) apply_filters( 'wpinv_can_view_receipt', wpinv_user_can_view_invoice( $invoice ), $invoice );
71
}
72
73
/**
74
 * Returns an array of all invoice post types.
75
 *
76
 * @return array
77
 */
78
function getpaid_get_invoice_post_types() {
79
    $post_types = array(
80
        'wpi_quote'   => __( 'Quote', 'invoicing' ),
81
        'wpi_invoice' => __( 'Invoice', 'invoicing' ),
82
    );
83
84
    // Ensure the quotes addon is installed.
85
    if ( ! defined( 'WPINV_QUOTES_VERSION' ) ) {
86
        unset( $post_types['wpi_quote'] );
87
    }
88
89
    return apply_filters( 'getpaid_invoice_post_types', $post_types );
90
}
91
92
/**
93
 * Checks if this is an invocing post type.
94
 *
95
 *
96
 * @param string $post_type The post type to check for.
97
 */
98
function getpaid_is_invoice_post_type( $post_type ) {
99
	return is_scalar( $post_type ) && ! empty( $post_type ) && strpos( $post_type, 'wpi_' ) === 0 && array_key_exists( $post_type, getpaid_get_invoice_post_types() );
100
}
101
102
/**
103
 * Creates a new invoice.
104
 *
105
 * @param  array $data   An array of invoice properties.
106
 * @param  bool  $wp_error       Whether to return false or WP_Error on failure.
107
 * @return int|WP_Error|WPInv_Invoice The value 0 or WP_Error on failure. The WPInv_Invoice object on success.
108
 */
109
function wpinv_create_invoice( $data = array(), $deprecated = null, $wp_error = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $deprecated is not used and could be removed. ( Ignorable by Annotation )

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

109
function wpinv_create_invoice( $data = array(), /** @scrutinizer ignore-unused */ $deprecated = null, $wp_error = false ) {

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

Loading history...
110
    $data['invoice_id'] = 0;
111
    return wpinv_insert_invoice( $data, $wp_error );
112
}
113
114
/**
115
 * Updates an existing invoice.
116
 *
117
 * @param  array $data   An array of invoice properties.
118
 * @param  bool  $wp_error       Whether to return false or WP_Error on failure.
119
 * @return int|WP_Error|WPInv_Invoice The value 0 or WP_Error on failure. The WPInv_Invoice object on success.
120
 */
121
function wpinv_update_invoice( $data = array(), $wp_error = false ) {
122
123
    // Backwards compatibility.
124
    if ( ! empty( $data['ID'] ) ) {
125
        $data['invoice_id'] = $data['ID'];
126
    }
127
128
    // Do we have an invoice id?
129
    if ( empty( $data['invoice_id'] ) ) {
130
        return $wp_error ? new WP_Error( 'invalid_invoice_id', __( 'Invalid invoice ID.', 'invoicing' ) ) : 0;
131
    }
132
133
    // Retrieve the invoice.
134
    $invoice = wpinv_get_invoice( $data['invoice_id'] );
135
136
    // And abort if it does not exist.
137
    if ( empty( $invoice ) ) {
138
        return $wp_error ? new WP_Error( 'missing_invoice', __( 'Invoice not found.', 'invoicing' ) ) : 0;
139
    }
140
141
    // Do not update totals for paid / refunded invoices.
142
    if ( $invoice->is_paid() || $invoice->is_refunded() ) {
143
144
        if ( ! empty( $data['items'] ) || ! empty( $data['cart_details'] ) ) {
145
            return $wp_error ? new WP_Error( 'paid_invoice', __( 'You can not update cart items for invoices that have already been paid for.', 'invoicing' ) ) : 0;
146
        }
147
}
148
149
    return wpinv_insert_invoice( $data, $wp_error );
150
151
}
152
153
/**
154
 * Create/Update an invoice
155
 *
156
 * @param  array $data   An array of invoice properties.
157
 * @param  bool  $wp_error       Whether to return false or WP_Error on failure.
158
 * @return int|WP_Error|WPInv_Invoice The value 0 or WP_Error on failure. The WPInv_Invoice object on success.
159
 */
160
function wpinv_insert_invoice( $data = array(), $wp_error = false ) {
161
162
    // Ensure that we have invoice data.
163
    if ( empty( $data ) ) {
164
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type WPInv_Invoice|WP_Error|integer.
Loading history...
165
    }
166
167
    // The invoice id will be provided when updating an invoice.
168
    $data['invoice_id'] = ! empty( $data['invoice_id'] ) ? (int) $data['invoice_id'] : false;
169
170
    // Retrieve the invoice.
171
    $invoice = new WPInv_Invoice( $data['invoice_id'] );
172
173
    // Do we have an error?
174
    if ( ! empty( $invoice->last_error ) ) {
175
        return $wp_error ? new WP_Error( 'invalid_invoice_id', $invoice->last_error ) : 0;
176
    }
177
178
    // Backwards compatibility (billing address).
179
    if ( ! empty( $data['user_info'] ) ) {
180
181
        foreach ( $data['user_info'] as $key => $value ) {
182
183
            if ( $key == 'discounts' ) {
184
                $value = (array) $value;
185
                $data['discount_code'] = empty( $value ) ? null : $value[0];
186
            } else {
187
                $data[ $key ] = $value;
188
            }
189
}
190
}
191
192
    // Backwards compatibility.
193
    if ( ! empty( $data['payment_details'] ) ) {
194
195
        foreach ( $data['payment_details'] as $key => $value ) {
196
            $data[ $key ] = $value;
197
        }
198
}
199
200
    // Set up the owner of the invoice.
201
    $user_id = ! empty( $data['user_id'] ) ? wpinv_clean( $data['user_id'] ) : get_current_user_id();
202
203
    // Make sure the user exists.
204
    if ( ! get_userdata( $user_id ) ) {
205
        return $wp_error ? new WP_Error( 'wpinv_invalid_user', __( 'There is no user with that ID.', 'invoicing' ) ) : 0;
206
    }
207
208
    $address = wpinv_get_user_address( $user_id );
209
210
    foreach ( $address as $key => $value ) {
211
212
        if ( $value == '' ) {
213
            $address[ $key ] = null;
214
        } else {
215
            $address[ $key ] = wpinv_clean( $value );
216
        }
217
}
218
219
    // Load new data.
220
    $invoice->set_props(
221
        array(
222
223
            // Basic info.
224
            'template'          => isset( $data['template'] ) ? wpinv_clean( $data['template'] ) : null,
225
            'email_cc'          => isset( $data['email_cc'] ) ? wpinv_clean( $data['email_cc'] ) : null,
226
            'date_created'      => isset( $data['created_date'] ) ? wpinv_clean( $data['created_date'] ) : null,
227
            'due_date'          => isset( $data['due_date'] ) ? wpinv_clean( $data['due_date'] ) : null,
228
            'date_completed'    => isset( $data['date_completed'] ) ? wpinv_clean( $data['date_completed'] ) : null,
229
            'number'            => isset( $data['number'] ) ? wpinv_clean( $data['number'] ) : null,
230
            'key'               => isset( $data['key'] ) ? wpinv_clean( $data['key'] ) : null,
231
            'status'            => isset( $data['status'] ) ? wpinv_clean( $data['status'] ) : null,
232
            'post_type'         => isset( $data['post_type'] ) ? wpinv_clean( $data['post_type'] ) : null,
233
            'user_ip'           => isset( $data['ip'] ) ? wpinv_clean( $data['ip'] ) : wpinv_get_ip(),
234
            'parent_id'         => isset( $data['parent'] ) ? intval( $data['parent'] ) : null,
235
            'mode'              => isset( $data['mode'] ) ? wpinv_clean( $data['mode'] ) : null,
236
            'description'       => isset( $data['description'] ) ? wp_kses_post( $data['description'] ) : null,
237
238
            // Payment info.
239
            'disable_taxes'     => ! empty( $data['disable_taxes'] ),
240
            'currency'          => isset( $data['currency'] ) ? wpinv_clean( $data['currency'] ) : wpinv_get_currency(),
241
            'gateway'           => isset( $data['gateway'] ) ? wpinv_clean( $data['gateway'] ) : null,
242
            'transaction_id'    => isset( $data['transaction_id'] ) ? wpinv_clean( $data['transaction_id'] ) : null,
243
            'discount_code'     => isset( $data['discount_code'] ) ? wpinv_clean( $data['discount_code'] ) : null,
244
            'payment_form'      => isset( $data['payment_form'] ) ? intval( $data['payment_form'] ) : null,
245
            'submission_id'     => isset( $data['submission_id'] ) ? wpinv_clean( $data['submission_id'] ) : null,
246
            'subscription_id'   => isset( $data['subscription_id'] ) ? wpinv_clean( $data['subscription_id'] ) : null,
247
            'is_viewed'         => isset( $data['is_viewed'] ) ? wpinv_clean( $data['is_viewed'] ) : null,
248
            'fees'              => isset( $data['fees'] ) ? wpinv_clean( $data['fees'] ) : null,
249
            'discounts'         => isset( $data['discounts'] ) ? wpinv_clean( $data['discounts'] ) : null,
250
            'taxes'             => isset( $data['taxes'] ) ? wpinv_clean( $data['taxes'] ) : null,
251
252
            // Billing details.
253
            'user_id'           => $data['user_id'],
254
            'first_name'        => isset( $data['first_name'] ) ? wpinv_clean( $data['first_name'] ) : $address['first_name'],
255
            'last_name'         => isset( $data['last_name'] ) ? wpinv_clean( $data['last_name'] ) : $address['last_name'],
256
            'address'           => isset( $data['address'] ) ? wpinv_clean( $data['address'] ) : $address['address'],
257
            'vat_number'        => isset( $data['vat_number'] ) ? wpinv_clean( $data['vat_number'] ) : $address['vat_number'],
258
            'company'           => isset( $data['company'] ) ? wpinv_clean( $data['company'] ) : $address['company'],
259
            'zip'               => isset( $data['zip'] ) ? wpinv_clean( $data['zip'] ) : $address['zip'],
260
            'state'             => isset( $data['state'] ) ? wpinv_clean( $data['state'] ) : $address['state'],
261
            'city'              => isset( $data['city'] ) ? wpinv_clean( $data['city'] ) : $address['city'],
262
            'country'           => isset( $data['country'] ) ? wpinv_clean( $data['country'] ) : $address['country'],
263
            'phone'             => isset( $data['phone'] ) ? wpinv_clean( $data['phone'] ) : $address['phone'],
264
            'address_confirmed' => ! empty( $data['address_confirmed'] ),
265
266
        )
267
    );
268
269
    // Backwards compatibililty.
270
    if ( ! empty( $data['cart_details'] ) && is_array( $data['cart_details'] ) ) {
271
        $data['items'] = array();
272
273
        foreach ( $data['cart_details'] as $_item ) {
274
275
            // Ensure that we have an item id.
276
            if ( empty( $_item['id'] ) ) {
277
                continue;
278
            }
279
280
            // Retrieve the item.
281
            $item = new GetPaid_Form_Item( $_item['id'] );
282
283
            // Ensure that it is purchasable.
284
            if ( ! $item->can_purchase() ) {
285
                continue;
286
            }
287
288
            // Set quantity.
289
            if ( ! empty( $_item['quantity'] ) && is_numeric( $_item['quantity'] ) ) {
290
                $item->set_quantity( $_item['quantity'] );
291
            }
292
293
            // Set price.
294
            if ( isset( $_item['item_price'] ) ) {
295
                $item->set_price( $_item['item_price'] );
296
            }
297
298
            if ( isset( $_item['custom_price'] ) ) {
299
                $item->set_price( $_item['custom_price'] );
300
            }
301
302
            // Set name.
303
            if ( ! empty( $_item['name'] ) ) {
304
                $item->set_name( $_item['name'] );
305
            }
306
307
            // Set description.
308
            if ( isset( $_item['description'] ) ) {
309
                $item->set_custom_description( $_item['description'] );
310
            }
311
312
            // Set meta.
313
            if ( isset( $_item['meta'] ) && is_array( $_item['meta'] ) ) {
314
315
                $item->set_item_meta( $_item['meta'] );
316
317
                if ( isset( $_item['meta']['description'] ) ) {
318
                    $item->set_custom_description( $_item['meta']['description'] );
319
                }
320
            }
321
322
            $data['items'][] = $item;
323
324
        }
325
    }
326
327
    // Add invoice items.
328
    if ( ! empty( $data['items'] ) && is_array( $data['items'] ) ) {
329
330
        $invoice->set_items( array() );
331
332
        foreach ( $data['items'] as $item ) {
333
334
            if ( is_object( $item ) && is_a( $item, 'GetPaid_Form_Item' ) && $item->can_purchase() ) {
335
                $invoice->add_item( $item );
336
            }
337
}
338
}
339
340
    // Save the invoice.
341
    $invoice->recalculate_total();
342
    $invoice->save();
343
344
    if ( ! $invoice->get_id() ) {
345
        return $wp_error ? new WP_Error( 'wpinv_insert_invoice_error', __( 'An error occured when saving your invoice.', 'invoicing' ) ) : 0;
346
    }
347
348
    // Add private note.
349
    if ( ! empty( $data['private_note'] ) ) {
350
        $invoice->add_note( $data['private_note'] );
351
    }
352
353
    // User notes.
354
    if ( ! empty( $data['user_note'] ) ) {
355
        $invoice->add_note( $data['user_note'], true );
356
    }
357
358
    // Created via.
359
    if ( isset( $data['created_via'] ) ) {
360
        update_post_meta( $invoice->get_id(), 'wpinv_created_via', $data['created_via'] );
361
    }
362
363
    // Backwards compatiblity.
364
    if ( $invoice->is_quote() ) {
365
366
        if ( isset( $data['valid_until'] ) ) {
367
            update_post_meta( $invoice->get_id(), 'wpinv_quote_valid_until', $data['valid_until'] );
368
        }
369
}
370
371
    return $invoice;
372
}
373
374
/**
375
 * Retrieves an invoice.
376
 *
377
 * @param int|string|object|WPInv_Invoice|WPInv_Legacy_Invoice|WP_Post $invoice Invoice id, key, transaction id, number or object.
378
 * @param $bool $deprecated
0 ignored issues
show
Documentation Bug introduced by
The doc comment $bool at position 0 could not be parsed: Unknown type name '$bool' at position 0 in $bool.
Loading history...
379
 * @return WPInv_Invoice|null
380
 */
381
function wpinv_get_invoice( $invoice = 0, $deprecated = false ) {
382
383
    // If we are retrieving the invoice from the cart...
384
    if ( $deprecated && empty( $invoice ) ) {
385
        $invoice = (int) getpaid_get_current_invoice_id();
386
    }
387
388
    // Retrieve the invoice.
389
    if ( ! is_a( $invoice, 'WPInv_Invoice' ) ) {
390
        $invoice = new WPInv_Invoice( $invoice );
391
    }
392
393
    // Check if it exists.
394
    if ( $invoice->exists() ) {
395
        return $invoice;
396
    }
397
398
    return null;
399
}
400
401
/**
402
 * Retrieves several invoices.
403
 *
404
 * @param array $args Args to search for.
405
 * @return WPInv_Invoice[]|int[]|object
406
 */
407
function wpinv_get_invoices( $args ) {
408
409
    // Prepare args.
410
    $args = wp_parse_args(
411
        $args,
412
        array(
413
            'status' => array_keys( wpinv_get_invoice_statuses() ),
414
            'type'   => 'wpi_invoice',
415
            'limit'  => get_option( 'posts_per_page' ),
416
            'return' => 'objects',
417
        )
418
    );
419
420
    // Map params to wp_query params.
421
    $map_legacy = array(
422
        'numberposts'    => 'limit',
423
        'post_type'      => 'type',
424
        'post_status'    => 'status',
425
        'post_parent'    => 'parent',
426
        'author'         => 'user',
427
        'posts_per_page' => 'limit',
428
        'paged'          => 'page',
429
        'post__not_in'   => 'exclude',
430
        'post__in'       => 'include',
431
    );
432
433
    foreach ( $map_legacy as $to => $from ) {
434
        if ( isset( $args[ $from ] ) ) {
435
            $args[ $to ] = $args[ $from ];
436
            unset( $args[ $from ] );
437
        }
438
    }
439
440
    // Backwards compatibility.
441
    if ( ! empty( $args['email'] ) && empty( $args['user'] ) ) {
442
        $args['user'] = $args['email'];
443
        unset( $args['email'] );
444
    }
445
446
    // Handle cases where the user is set as an email.
447
    if ( ! empty( $args['author'] ) && is_email( $args['author'] ) ) {
448
        $user = get_user_by( 'email', $args['user'] );
449
450
        if ( $user ) {
451
            $args['author'] = $user->user_email;
452
        }
453
}
454
455
    // We only want invoice ids.
456
    $args['fields'] = 'ids';
457
458
    // Show all posts.
459
    $paginate = true;
460
    if ( isset( $args['paginate'] ) ) {
461
462
        $paginate = $args['paginate'];
463
        $args['no_found_rows'] = empty( $args['paginate'] );
464
        unset( $args['paginate'] );
465
466
    }
467
468
    // Whether to return objects or fields.
469
    $return = $args['return'];
470
    unset( $args['return'] );
471
472
    // Get invoices.
473
    $invoices = new WP_Query( apply_filters( 'wpinv_get_invoices_args', $args ) );
474
475
    // Prepare the results.
476
    if ( 'objects' === $return ) {
477
        $results = array_map( 'wpinv_get_invoice', $invoices->posts );
478
    } elseif ( 'self' === $return ) {
479
        return $invoices;
480
    } else {
481
        $results = $invoices->posts;
482
    }
483
484
    if ( $paginate ) {
485
        return (object) array(
486
            'invoices'      => $results,
487
            'total'         => $invoices->found_posts,
488
            'max_num_pages' => $invoices->max_num_pages,
489
        );
490
    }
491
492
    return $results;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $results returns an array which contains values of type WP_Post which are incompatible with the documented value type WPInv_Invoice|integer.
Loading history...
493
494
}
495
496
/**
497
 * Retrieves an invoice's id from a transaction id.
498
 *
499
 * @param string $transaction_id The transaction id to check.
500
 * @return int Invoice id on success or 0 on failure
501
 */
502
function wpinv_get_id_by_transaction_id( $transaction_id ) {
503
    return WPInv_Invoice::get_invoice_id_by_field( $transaction_id, 'transaction_id' );
504
}
505
506
/**
507
 * Retrieves an invoice's id from the invoice number.
508
 *
509
 * @param string $invoice_number The invoice number to check.
510
 * @return int Invoice id on success or 0 on failure
511
 */
512
function wpinv_get_id_by_invoice_number( $invoice_number ) {
513
    return WPInv_Invoice::get_invoice_id_by_field( $invoice_number, 'number' );
514
}
515
516
/**
517
 * Retrieves an invoice's id from the invoice key.
518
 *
519
 * @param string $invoice_key The invoice key to check.
520
 * @return int Invoice id on success or 0 on failure
521
 */
522
function wpinv_get_invoice_id_by_key( $invoice_key ) {
523
    return WPInv_Invoice::get_invoice_id_by_field( $invoice_key, 'key' );
524
}
525
526
/**
527
 * Retrieves an invoice's notes.
528
 *
529
 * @param int|string|object|WPInv_Invoice|WPInv_Legacy_Invoice|WP_Post $invoice Invoice id, key, transaction id, number or object.
530
 * @param string $type Optionally filter by type i.e customer|system
531
 * @return array|null
532
 */
533
function wpinv_get_invoice_notes( $invoice = 0, $type = '' ) {
534
535
    // Prepare the invoice.
536
    $invoice = wpinv_get_invoice( $invoice );
537
    if ( empty( $invoice ) ) {
538
        return null;
539
    }
540
541
    // Fetch notes.
542
    $notes = getpaid_notes()->get_invoice_notes( $invoice->get_id(), $type );
543
544
    // Filter the notes.
545
    return apply_filters( 'wpinv_invoice_notes', $notes, $invoice->get_id(), $type );
546
}
547
548
/**
549
 * Returns an array of columns to display on the invoices page.
550
 *
551
 * @param string $post_type
552
 */
553
function wpinv_get_user_invoices_columns( $post_type = 'wpi_invoice' ) {
554
555
    $label   = getpaid_get_post_type_label( $post_type, false );
556
    $label   = empty( $label ) ? __( 'Invoice', 'invoicing' ) : sanitize_text_field( $label );
557
    $columns = array(
558
559
		'invoice-number'  => array(
560
			'title' => $label,
561
			'class' => 'text-left',
562
		),
563
564
		'created-date'    => array(
565
			'title' => __( 'Created Date', 'invoicing' ),
566
			'class' => 'text-left',
567
		),
568
569
		'payment-date'    => array(
570
			'title' => __( 'Payment Date', 'invoicing' ),
571
			'class' => 'text-left',
572
		),
573
574
		'invoice-status'  => array(
575
			'title' => __( 'Status', 'invoicing' ),
576
			'class' => 'text-center',
577
		),
578
579
		'invoice-total'   => array(
580
			'title' => __( 'Total', 'invoicing' ),
581
			'class' => 'text-right',
582
		),
583
584
		'invoice-actions' => array(
585
			'title' => '&nbsp;',
586
			'class' => 'text-center',
587
		),
588
589
	);
590
591
    return apply_filters( 'wpinv_user_invoices_columns', $columns, $post_type );
592
}
593
594
/**
595
 * Displays the invoice receipt.
596
 */
597
function wpinv_payment_receipt() {
598
599
    // Find the invoice.
600
    $invoice_id = getpaid_get_current_invoice_id();
601
    $invoice = new WPInv_Invoice( $invoice_id );
602
603
    // Abort if non was found.
604
    if ( empty( $invoice_id ) || $invoice->is_draft() ) {
605
606
        return aui()->alert(
607
            array(
608
                'type'    => 'warning',
609
                'content' => __( 'We could not find your invoice', 'invoicing' ),
610
            )
611
        );
612
613
    }
614
615
    // Can the user view this invoice?
616
    if ( ! wpinv_can_view_receipt( $invoice_id ) ) {
617
618
        return aui()->alert(
619
            array(
620
                'type'    => 'warning',
621
                'content' => __( 'You are not allowed to view this receipt', 'invoicing' ),
622
            )
623
        );
624
625
    }
626
627
    // Load the template.
628
    return wpinv_get_template_html( 'invoice-receipt.php', compact( 'invoice' ) );
629
630
}
631
632
/**
633
 * Displays the invoice history.
634
 */
635
function getpaid_invoice_history( $user_id = 0, $post_type = 'wpi_invoice' ) {
636
637
    // Ensure that we have a user id.
638
    if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
639
        $user_id = get_current_user_id();
640
    }
641
642
    $label = getpaid_get_post_type_label( $post_type );
643
    $label = empty( $label ) ? __( 'Invoices', 'invoicing' ) : sanitize_text_field( $label );
644
645
    // View user id.
646
    if ( empty( $user_id ) ) {
647
648
        return aui()->alert(
649
            array(
650
                'type'    => 'warning',
651
                'content' => sprintf(
652
                    __( 'You must be logged in to view your %s.', 'invoicing' ),
653
                    strtolower( $label )
654
                ),
655
            )
656
        );
657
658
    }
659
660
    // Fetch invoices.
661
    $invoices = wpinv_get_invoices(
662
        array(
663
            'page'     => ( get_query_var( 'paged' ) ) ? absint( get_query_var( 'paged' ) ) : 1,
664
            'user'     => $user_id,
665
            'paginate' => true,
666
            'type'     => $post_type,
667
            'status'   => array_keys( wpinv_get_invoice_statuses( false, false, $post_type ) ),
668
        )
669
    );
670
671
    if ( empty( $invoices->total ) ) {
672
673
        return aui()->alert(
674
            array(
675
                'type'    => 'info',
676
                'content' => sprintf(
677
                    __( 'No %s found.', 'invoicing' ),
678
                    strtolower( $label )
679
                ),
680
            )
681
        );
682
683
    }
684
685
    // Load the template.
686
    return wpinv_get_template_html( 'invoice-history.php', compact( 'invoices', 'post_type' ) );
687
688
}
689
690
/**
691
 * Formats an invoice number given an invoice type.
692
 */
693
function wpinv_format_invoice_number( $number, $type = '' ) {
694
695
    // Allow other plugins to overide this.
696
    $check = apply_filters( 'wpinv_pre_format_invoice_number', null, $number, $type );
697
    if ( null !== $check ) {
698
        return $check;
699
    }
700
701
    // Ensure that we have a numeric number.
702
    if ( ! is_numeric( $number ) ) {
703
        return $number;
704
    }
705
706
    // Format the number.
707
    $padd             = absint( (int) wpinv_get_option( 'invoice_number_padd', 5 ) );
708
    $prefix           = sanitize_text_field( (string) wpinv_get_option( 'invoice_number_prefix', 'INV-' ) );
709
    $prefix           = sanitize_text_field( apply_filters( 'getpaid_invoice_type_prefix', $prefix, $type ) );
710
    $postfix          = sanitize_text_field( (string) wpinv_get_option( 'invoice_number_postfix' ) );
711
    $postfix          = sanitize_text_field( apply_filters( 'getpaid_invoice_type_postfix', $postfix, $type ) );
712
    $formatted_number = zeroise( absint( $number ), $padd );
713
714
    // Add the prefix and post fix.
715
    $formatted_number = $prefix . $formatted_number . $postfix;
716
717
    return apply_filters( 'wpinv_format_invoice_number', $formatted_number, $number, $prefix, $postfix, $padd );
718
}
719
720
/**
721
 * Returns the next invoice number.
722
 *
723
 * @param string $type.
724
 * @return int|null|bool
725
 */
726
function wpinv_get_next_invoice_number( $type = '' ) {
727
728
    // Allow plugins to overide this.
729
    $check = apply_filters( 'wpinv_get_pre_next_invoice_number', null, $type );
730
    if ( null !== $check ) {
731
        return $check;
732
    }
733
734
    // Ensure sequential invoice numbers is active.
735
    if ( ! wpinv_sequential_number_active() ) {
736
        return false;
737
    }
738
739
    // Retrieve the current number and the start number.
740
    $number = (int) get_option( 'wpinv_last_invoice_number', 0 );
741
    $start  = absint( (int) wpinv_get_option( 'invoice_sequence_start', 1 ) );
742
743
    // Ensure that we are starting at a positive integer.
744
    $start  = max( $start, 1 );
745
746
    // If this is the first invoice, use the start number.
747
    $number = max( $start, $number );
748
749
    // Format the invoice number.
750
    $formatted_number = wpinv_format_invoice_number( $number, $type );
751
752
    // Ensure that this number is unique.
753
    $invoice_id = WPInv_Invoice::get_invoice_id_by_field( $formatted_number, 'number' );
754
755
    // We found a match. Nice.
756
    if ( empty( $invoice_id ) ) {
757
        update_option( 'wpinv_last_invoice_number', $number );
758
        return apply_filters( 'wpinv_get_next_invoice_number', $number );
759
    }
760
761
    update_option( 'wpinv_last_invoice_number', $number + 1 );
762
    return wpinv_get_next_invoice_number( $type );
763
764
}
765
766
/**
767
 * The prefix used for invoice paths.
768
 */
769
function wpinv_post_name_prefix( $post_type = 'wpi_invoice' ) {
770
    return apply_filters( 'wpinv_post_name_prefix', 'inv-', $post_type );
771
}
772
773
function wpinv_generate_post_name( $post_ID ) {
774
    $prefix = wpinv_post_name_prefix( get_post_type( $post_ID ) );
775
    $post_name = sanitize_title( $prefix . $post_ID );
776
777
    return apply_filters( 'wpinv_generate_post_name', $post_name, $post_ID, $prefix );
778
}
779
780
/**
781
 * Checks if an invoice was viewed by the customer.
782
 *
783
 * @param int|string|object|WPInv_Invoice|WPInv_Legacy_Invoice|WP_Post $invoice Invoice id, key, transaction id, number or object.
784
 */
785
function wpinv_is_invoice_viewed( $invoice ) {
786
    $invoice = new WPInv_Invoice( $invoice );
787
    return (bool) $invoice->get_is_viewed();
788
}
789
790
/**
791
 * Marks an invoice as viewed.
792
 *
793
 * @param int|string|object|WPInv_Invoice|WPInv_Legacy_Invoice|WP_Post $invoice Invoice id, key, transaction id, number or object.
794
 */
795
function getpaid_maybe_mark_invoice_as_viewed( $invoice ) {
796
    $invoice = new WPInv_Invoice( $invoice );
797
798
    if ( get_current_user_id() == $invoice->get_user_id() && ! $invoice->get_is_viewed() ) {
799
        $invoice->set_is_viewed( true );
800
        $invoice->save();
801
    }
802
803
}
804
add_action( 'wpinv_invoice_print_before_display', 'getpaid_maybe_mark_invoice_as_viewed' );
805
add_action( 'wpinv_before_receipt', 'getpaid_maybe_mark_invoice_as_viewed' );
806
807
/**
808
 * Processes an invoice refund.
809
 *
810
 * @param WPInv_Invoice $invoice
811
 * @param array $status_transition
812
 * @todo: descrease customer/store earnings
813
 */
814
function getpaid_maybe_process_refund( $invoice, $status_transition ) {
815
816
    if ( empty( $status_transition['from'] ) || ! in_array( $status_transition['from'], array( 'publish', 'wpi-processing', 'wpi-renewal' ) ) ) {
817
        return;
818
    }
819
820
    $discount_code = $invoice->get_discount_code();
821
    if ( ! empty( $discount_code ) ) {
822
        $discount = wpinv_get_discount_obj( $discount_code );
823
824
        if ( $discount->exists() ) {
825
            $discount->increase_usage( -1 );
826
        }
827
}
828
829
    do_action( 'wpinv_pre_refund_invoice', $invoice, $invoice->get_id() );
830
    do_action( 'wpinv_refund_invoice', $invoice, $invoice->get_id() );
831
    do_action( 'wpinv_post_refund_invoice', $invoice, $invoice->get_id() );
832
}
833
add_action( 'getpaid_invoice_status_wpi-refunded', 'getpaid_maybe_process_refund', 10, 2 );
834
835
836
/**
837
 * Processes invoice payments.
838
 *
839
 * @param int $invoice_id
840
 */
841
function getpaid_process_invoice_payment( $invoice_id ) {
842
843
    // Fetch the invoice.
844
    $invoice = new WPInv_Invoice( $invoice_id );
845
846
    // We only want to do this once.
847
    if ( 1 == get_post_meta( $invoice->get_id(), 'wpinv_processed_payment', true ) ) {
848
        return;
849
    }
850
851
    update_post_meta( $invoice->get_id(), 'wpinv_processed_payment', 1 );
852
853
    // Fires when processing a payment.
854
    do_action( 'getpaid_process_payment', $invoice );
855
856
    // Fire an action for each invoice item.
857
    foreach ( $invoice->get_items() as $item ) {
858
        do_action( 'getpaid_process_item_payment', $item, $invoice );
859
    }
860
861
    // Increase discount usage.
862
    $discount_code = $invoice->get_discount_code();
863
    if ( ! empty( $discount_code ) && ! $invoice->is_renewal() ) {
864
        $discount = wpinv_get_discount_obj( $discount_code );
865
866
        if ( $discount->exists() ) {
867
            $discount->increase_usage();
868
        }
869
}
870
871
    // Record reverse vat.
872
    if ( 'invoice' === $invoice->get_type() && wpinv_use_taxes() && ! $invoice->get_disable_taxes() ) {
873
874
        $taxes = $invoice->get_total_tax();
875
        if ( empty( $taxes ) && GetPaid_Payment_Form_Submission_Taxes::is_eu_transaction( $invoice->get_country() ) ) {
876
            $invoice->add_note( __( 'VAT was reverse charged', 'invoicing' ), false, false, true );
877
        }
878
}
879
880
}
881
add_action( 'getpaid_invoice_payment_status_changed', 'getpaid_process_invoice_payment' );
882
883
/**
884
 * Returns an array of invoice item columns
885
 *
886
 * @param int|WPInv_Invoice $invoice
887
 * @return array
888
 */
889
function getpaid_invoice_item_columns( $invoice ) {
890
891
    // Prepare the invoice.
892
    $invoice = new WPInv_Invoice( $invoice );
893
894
    // Abort if there is no invoice.
895
    if ( 0 == $invoice->get_id() ) {
896
        return array();
897
    }
898
899
    // Line item columns.
900
    $columns = apply_filters(
901
        'getpaid_invoice_item_columns',
902
        array(
903
            'name'     => __( 'Item', 'invoicing' ),
904
            'price'    => __( 'Price', 'invoicing' ),
905
            'tax_rate' => __( 'Tax Rate', 'invoicing' ),
906
            'quantity' => __( 'Quantity', 'invoicing' ),
907
            'subtotal' => __( 'Item Subtotal', 'invoicing' ),
908
        ),
909
        $invoice
910
    );
911
912
    // Quantities.
913
    if ( isset( $columns['quantity'] ) ) {
914
915
        if ( 'hours' == $invoice->get_template() ) {
916
            $columns['quantity'] = __( 'Hours', 'invoicing' );
917
        }
918
919
        if ( ! wpinv_item_quantities_enabled() || 'amount' == $invoice->get_template() ) {
920
            unset( $columns['quantity'] );
921
        }
922
    }
923
924
    // Price.
925
    if ( isset( $columns['price'] ) ) {
926
927
        if ( 'amount' == $invoice->get_template() ) {
928
            $columns['price'] = __( 'Amount', 'invoicing' );
929
        }
930
931
        if ( 'hours' == $invoice->get_template() ) {
932
            $columns['price'] = __( 'Rate', 'invoicing' );
933
        }
934
}
935
936
    // Sub total.
937
    if ( isset( $columns['subtotal'] ) ) {
938
939
        if ( 'amount' == $invoice->get_template() ) {
940
            unset( $columns['subtotal'] );
941
        }
942
}
943
944
    // Tax rates.
945
    if ( isset( $columns['tax_rate'] ) ) {
946
947
        if ( 0 == $invoice->get_total_tax() ) {
948
            unset( $columns['tax_rate'] );
949
        }
950
    }
951
952
    return $columns;
953
}
954
955
/**
956
 * Returns an array of invoice totals rows
957
 *
958
 * @param int|WPInv_Invoice $invoice
959
 * @return array
960
 */
961
function getpaid_invoice_totals_rows( $invoice ) {
962
963
    // Prepare the invoice.
964
    $invoice = new WPInv_Invoice( $invoice );
965
966
    // Abort if there is no invoice.
967
    if ( 0 == $invoice->get_id() ) {
968
        return array();
969
    }
970
971
    $totals = apply_filters(
972
        'getpaid_invoice_totals_rows',
973
        array(
974
            'subtotal' => __( 'Subtotal', 'invoicing' ),
975
            'shipping' => __( 'Shipping', 'invoicing' ),
976
            'tax'      => __( 'Tax', 'invoicing' ),
977
            'fee'      => __( 'Fee', 'invoicing' ),
978
            'discount' => __( 'Discount', 'invoicing' ),
979
            'total'    => __( 'Total', 'invoicing' ),
980
        ),
981
        $invoice
982
    );
983
984
    if ( ! $invoice->has_shipping() ) {
985
        unset( $totals['shipping'] );
986
    }
987
988
    if ( ( $invoice->get_disable_taxes() || ! wpinv_use_taxes() ) && isset( $totals['tax'] ) ) {
989
        unset( $totals['tax'] );
990
    }
991
992
    // If we have taxes, display individual taxes.
993
    if ( isset( $totals['tax'] ) && wpinv_display_individual_tax_rates() ) {
994
995
        $new_totals = array();
996
        foreach ( $totals as $key => $label ) {
997
998
            if ( 'tax' !== $key ) {
999
                $new_totals[ $key ] = $label;
1000
                continue;
1001
            }
1002
1003
            $taxes = array_keys( $invoice->get_taxes() );
1004
            if ( ! empty( $taxes ) ) {
1005
1006
                foreach ( $taxes as $tax ) {
1007
                    $new_totals[ 'tax__' . $tax ] = $tax;
1008
                }
1009
            }
1010
        }
1011
1012
        $totals = $new_totals;
1013
    }
1014
1015
    if ( 0 == $invoice->get_total_fees() && isset( $totals['fee'] ) ) {
1016
        unset( $totals['fee'] );
1017
    }
1018
1019
    if ( 0 == $invoice->get_total_discount() && isset( $totals['discount'] ) ) {
1020
        unset( $totals['discount'] );
1021
    }
1022
1023
    return $totals;
1024
}
1025
1026
/**
1027
 * This function is called whenever an invoice is created.
1028
 *
1029
 * @param WPInv_Invoice $invoice
1030
 */
1031
function getpaid_new_invoice( $invoice ) {
1032
1033
    if ( ! $invoice->get_status() ) {
1034
        return;
1035
    }
1036
1037
    // Add an invoice created note.
1038
    $invoice->add_note(
1039
        sprintf(
1040
            __( '%1$s created with the status "%2$s".', 'invoicing' ),
1041
            ucfirst( $invoice->get_invoice_quote_type() ),
1042
            wpinv_status_nicename( $invoice->get_status(), $invoice )
1043
        )
1044
    );
1045
1046
}
1047
add_action( 'getpaid_new_invoice', 'getpaid_new_invoice' );
1048
1049
/**
1050
 * This function updates invoice caches.
1051
 *
1052
 * @param WPInv_Invoice $invoice
1053
 */
1054
function getpaid_update_invoice_caches( $invoice ) {
1055
1056
    // Cache invoice number.
1057
    wp_cache_set( $invoice->get_number(), $invoice->get_id(), 'getpaid_invoice_numbers_to_invoice_ids' );
1058
1059
    // Cache invoice key.
1060
    wp_cache_set( $invoice->get_key(), $invoice->get_id(), 'getpaid_invoice_keys_to_invoice_ids' );
1061
1062
    // (Maybe) cache transaction id.
1063
    $transaction_id = $invoice->get_transaction_id();
1064
1065
    if ( ! empty( $transaction_id ) ) {
1066
        wp_cache_set( $transaction_id, $invoice->get_id(), 'getpaid_invoice_transaction_ids_to_invoice_ids' );
1067
    }
1068
1069
}
1070
add_action( 'getpaid_new_invoice', 'getpaid_update_invoice_caches', 5 );
1071
add_action( 'getpaid_update_invoice', 'getpaid_update_invoice_caches', 5 );
1072
1073
/**
1074
 * Duplicates an invoice.
1075
 *
1076
 * Please note that this function does not save the duplicated invoice.
1077
 *
1078
 * @param  WPInv_Invoice $old_invoice The invoice to duplicate
1079
 * @return WPInv_Invoice The new invoice.
1080
 */
1081
function getpaid_duplicate_invoice( $old_invoice ) {
1082
1083
    // Create the new invoice.
1084
    $invoice = new WPInv_Invoice();
1085
    $invoice->set_props(
1086
        array(
1087
1088
            // Basic info.
1089
            'template'          => $old_invoice->get_template(),
1090
            'email_cc'          => $old_invoice->get_email_cc(),
1091
            'post_type'         => $old_invoice->get_post_type(),
1092
            'user_ip'           => $old_invoice->get_user_ip(),
1093
            'parent_id'         => $old_invoice->get_parent_id(),
1094
            'mode'              => $old_invoice->get_mode(),
1095
            'description'       => $old_invoice->get_description(),
1096
            'created_via'       => $old_invoice->get_created_via(),
1097
            'status'            => $old_invoice->get_default_status(),
1098
1099
            // Payment info.
1100
            'disable_taxes'     => $old_invoice->get_disable_taxes(),
1101
            'currency'          => $old_invoice->get_currency(),
1102
            'gateway'           => $old_invoice->get_gateway(),
1103
            'discount_code'     => $old_invoice->get_discount_code(),
1104
            'payment_form'      => $old_invoice->get_payment_form(),
1105
            'submission_id'     => $old_invoice->get_submission_id(),
1106
            'subscription_id'   => $old_invoice->get_subscription_id(),
1107
            'fees'              => $old_invoice->get_fees(),
1108
            'discounts'         => $old_invoice->get_discounts(),
1109
            'taxes'             => $old_invoice->get_taxes(),
1110
            'items'             => $old_invoice->get_items(),
1111
1112
            // Billing details.
1113
            'user_id'           => $old_invoice->get_user_id(),
1114
            'first_name'        => $old_invoice->get_first_name(),
1115
            'last_name'         => $old_invoice->get_last_name(),
1116
            'address'           => $old_invoice->get_address(),
1117
            'vat_number'        => $old_invoice->get_vat_number(),
1118
            'company'           => $old_invoice->get_company(),
1119
            'zip'               => $old_invoice->get_zip(),
1120
            'state'             => $old_invoice->get_state(),
1121
            'city'              => $old_invoice->get_city(),
1122
            'country'           => $old_invoice->get_country(),
1123
            'phone'             => $old_invoice->get_phone(),
1124
            'address_confirmed' => $old_invoice->get_address_confirmed(),
1125
1126
        )
1127
    );
1128
1129
    // Recalculate totals.
1130
    $invoice->recalculate_total();
1131
1132
    return $invoice;
1133
}
1134
1135
/**
1136
 * Retrieves invoice meta fields.
1137
 *
1138
 * @param WPInv_Invoice $invoice
1139
 * @return array
1140
 */
1141
function getpaid_get_invoice_meta( $invoice ) {
1142
1143
    // Load the invoice meta.
1144
    $meta = array(
1145
1146
        'number'         => array(
1147
            'label' => sprintf(
1148
                __( '%s Number', 'invoicing' ),
1149
                ucfirst( $invoice->get_invoice_quote_type() )
1150
            ),
1151
            'value' => sanitize_text_field( $invoice->get_number() ),
1152
        ),
1153
1154
        'status'         => array(
1155
            'label' => sprintf(
1156
                __( '%s Status', 'invoicing' ),
1157
                ucfirst( $invoice->get_invoice_quote_type() )
1158
            ),
1159
            'value' => $invoice->get_status_label_html(),
1160
        ),
1161
1162
        'date'           => array(
1163
            'label' => sprintf(
1164
                __( '%s Date', 'invoicing' ),
1165
                ucfirst( $invoice->get_invoice_quote_type() )
1166
            ),
1167
            'value' => getpaid_format_date( $invoice->get_created_date() ),
1168
        ),
1169
1170
        'date_paid'      => array(
1171
            'label' => __( 'Paid On', 'invoicing' ),
1172
            'value' => getpaid_format_date( $invoice->get_completed_date() ),
1173
        ),
1174
1175
        'gateway'        => array(
1176
            'label' => __( 'Payment Method', 'invoicing' ),
1177
            'value' => sanitize_text_field( $invoice->get_gateway_title() ),
1178
        ),
1179
1180
        'transaction_id' => array(
1181
            'label' => __( 'Transaction ID', 'invoicing' ),
1182
            'value' => sanitize_text_field( $invoice->get_transaction_id() ),
1183
        ),
1184
1185
        'due_date'       => array(
1186
            'label' => __( 'Due Date', 'invoicing' ),
1187
            'value' => getpaid_format_date( $invoice->get_due_date() ),
1188
        ),
1189
1190
        'vat_number'     => array(
1191
            'label' => __( 'VAT Number', 'invoicing' ),
1192
            'value' => sanitize_text_field( $invoice->get_vat_number() ),
1193
        ),
1194
1195
    );
1196
1197
    $additional_meta = get_post_meta( $invoice->get_id(), 'additional_meta_data', true );
1198
1199
    if ( ! empty( $additional_meta ) ) {
1200
1201
        foreach ( $additional_meta as $label => $value ) {
1202
            $meta[ sanitize_key( $label ) ] = array(
1203
                'label' => esc_html( $label ),
1204
                'value' => esc_html( $value ),
1205
            );
1206
        }
1207
}
1208
    // If it is not paid, remove the date of payment.
1209
    if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) {
1210
        unset( $meta['date_paid'] );
1211
        unset( $meta['transaction_id'] );
1212
    }
1213
1214
    if ( ! $invoice->is_paid() || 'none' == $invoice->get_gateway() ) {
1215
        unset( $meta['gateway'] );
1216
    }
1217
1218
    // Only display the due date if due dates are enabled.
1219
    if ( ! $invoice->needs_payment() || ! wpinv_get_option( 'overdue_active' ) ) {
1220
        unset( $meta['due_date'] );
1221
    }
1222
1223
    // Only display the vat number if taxes are enabled.
1224
    if ( ! wpinv_use_taxes() ) {
1225
        unset( $meta['vat_number'] );
1226
    }
1227
1228
    // Link to the parent invoice.
1229
    if ( $invoice->get_parent_id() > 0 ) {
1230
1231
        $meta['parent'] = array(
1232
1233
            'label' => sprintf(
1234
                __( 'Parent %s', 'invoicing' ),
1235
                ucfirst( $invoice->get_invoice_quote_type() )
1236
            ),
1237
1238
            'value' => wpinv_invoice_link( $invoice->get_parent_id() ),
1239
1240
        );
1241
1242
    }
1243
1244
    if ( $invoice->is_recurring() ) {
1245
1246
        $subscription = getpaid_get_invoice_subscriptions( $invoice );
1247
        if ( ! empty( $subscription ) && ! is_array( $subscription ) && $subscription->exists() ) {
1248
1249
            // Display the renewal date.
1250
            if ( $subscription->is_active() && 'cancelled' != $subscription->get_status() ) {
1251
1252
                $meta['renewal_date'] = array(
1253
                    'label' => __( 'Renews On', 'invoicing' ),
1254
                    'value' => getpaid_format_date( $subscription->get_expiration() ) .
1255
                    sprintf(
1256
                        ' <a class="small" href="%s">%s<a>',
1257
                        $subscription->get_view_url(),
1258
                        __( '(View Subscription)', 'invoicing' )
1259
                    ),
1260
                );
1261
1262
            }
1263
1264
            if ( $invoice->is_parent() ) {
1265
1266
                // Display the recurring amount.
1267
                $meta['recurring_total'] = array(
1268
1269
                    'label' => __( 'Recurring Amount', 'invoicing' ),
1270
                    'value' => wpinv_price( $subscription->get_recurring_amount(), $invoice->get_currency() ),
1271
1272
                );
1273
1274
            }
1275
        }
1276
    }
1277
1278
    // Add the invoice total to the meta.
1279
    $meta['invoice_total'] = array(
1280
1281
        'label' => __( 'Total Amount', 'invoicing' ),
1282
        'value' => wpinv_price( $invoice->get_total(), $invoice->get_currency() ),
1283
1284
    );
1285
1286
    // Provide a way for third party plugins to filter the meta.
1287
    $meta = apply_filters( 'getpaid_invoice_meta_data', $meta, $invoice );
1288
1289
    return $meta;
1290
1291
}
1292
1293
/**
1294
 * Returns an array of valid invoice status classes.
1295
 *
1296
 * @return array
1297
 */
1298
function getpaid_get_invoice_status_classes() {
1299
1300
	return apply_filters(
1301
		'getpaid_get_invoice_status_classes',
1302
		array(
1303
            'wpi-quote-declined' => 'bg-danger',
1304
            'wpi-failed'         => 'bg-danger',
1305
			'wpi-processing'     => 'bg-info',
1306
			'wpi-onhold'         => 'bg-warning text-dark',
1307
			'wpi-quote-accepted' => 'bg-success',
1308
			'publish'            => 'bg-success',
1309
			'wpi-renewal'        => 'bg-primary',
1310
            'wpi-cancelled'      => 'bg-secondary',
1311
            'wpi-pending'        => 'bg-dark text-white',
1312
            'wpi-quote-pending'  => 'bg-dark text-white',
1313
            'wpi-refunded'       => 'bg-secondary',
1314
		)
1315
	);
1316
1317
}
1318
1319
/**
1320
 * Returns an invoice's tax rate percentage.
1321
 *
1322
 * @param WPInv_Invoice $invoice
1323
 * @param GetPaid_Form_Item $item
1324
 * @return float
1325
 */
1326
function getpaid_get_invoice_tax_rate( $invoice, $item ) {
1327
1328
    $rates   = getpaid_get_item_tax_rates( $item, $invoice->get_country(), $invoice->get_state() );
1329
	$rates   = getpaid_filter_item_tax_rates( $item, $rates );
1330
    $rates   = wp_list_pluck( $rates, 'rate' );
1331
1332
    return array_sum( $rates );
1333
1334
}
1335