Passed
Pull Request — master (#217)
by Patrik
02:57
created

wpinv-invoice-functions.php ➔ wpinv_mark_invoice_viewed()   D

Complexity

Conditions 18
Paths 27

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
nc 27
nop 0
dl 0
loc 34
rs 4.8666
c 0
b 0
f 0

How to fix   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 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( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
function wpinv_get_invoice_cart_id() {
15
    $wpinv_checkout = wpinv_get_checkout_session();
16
    
17
    if ( !empty( $wpinv_checkout['invoice_id'] ) ) {
18
        return $wpinv_checkout['invoice_id'];
19
    }
20
    
21
    return NULL;
22
}
23
24
function wpinv_insert_invoice( $invoice_data = array(), $wp_error = false ) {
25
    if ( empty( $invoice_data ) ) {
26
        return false;
27
    }
28
    
29
    if ( !( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) ) ) {
30
        return $wp_error ? new WP_Error( 'wpinv_invalid_items', __( 'Invoice must have atleast on item.', 'invoicing' ) ) : 0;
31
    }
32
    
33
    if ( empty( $invoice_data['user_id'] ) ) {
34
        $invoice_data['user_id'] = get_current_user_id();
35
    }
36
    
37
    $invoice_data['invoice_id'] = !empty( $invoice_data['invoice_id'] ) ? (int)$invoice_data['invoice_id'] : 0;
38
    
39
    if ( empty( $invoice_data['status'] ) ) {
40
        $invoice_data['status'] = 'wpi-pending';
41
    }
42
    
43
    if ( empty( $invoice_data['ip'] ) ) {
44
        $invoice_data['ip'] = wpinv_get_ip();
45
    }
46
47
    // default invoice args, note that status is checked for validity in wpinv_create_invoice()
48
    $default_args = array(
49
        'invoice_id'    => (int)$invoice_data['invoice_id'],
50
        'user_id'       => (int)$invoice_data['user_id'],
51
        'status'        => $invoice_data['status'],
52
    );
53
54
    $invoice = wpinv_create_invoice( $default_args, $invoice_data, true );
55
    if ( is_wp_error( $invoice ) ) {
56
        return $wp_error ? $invoice : 0;
57
    }
58
    
59
    if ( empty( $invoice_data['invoice_id'] ) ) {
60
        //$invoice->add_note( wp_sprintf( __( 'Invoice is created with status %s.', 'invoicing' ), wpinv_status_nicename( $invoice->status ) ) );
61
    }
62
    
63
    // User info
64
    $default_user_info = array(
65
        'user_id'               => '',
66
        'first_name'            => '',
67
        'last_name'             => '',
68
        'email'                 => '',
69
        'company'               => '',
70
        'phone'                 => '',
71
        'address'               => '',
72
        'city'                  => '',
73
        'country'               => wpinv_get_default_country(),
74
        'state'                 => wpinv_get_default_state(),
75
        'zip'                   => '',
76
        'vat_number'            => '',
77
        'vat_rate'              => '',
78
        'adddress_confirmed'    => '',
79
        'discount'              => array(),
80
    );
81
82
    if ( $user_id = (int)$invoice->get_user_id() ) {
83
        if ( $user_address = wpinv_get_user_address( $user_id ) ) {
84
            $default_user_info = wp_parse_args( $user_address, $default_user_info );
85
        }
86
    }
87
    
88
    if ( empty( $invoice_data['user_info'] ) ) {
89
        $invoice_data['user_info'] = array();
90
    }
91
    
92
    $user_info = wp_parse_args( $invoice_data['user_info'], $default_user_info );
93
    
94 View Code Duplication
    if ( empty( $user_info['first_name'] ) ) {
95
        $user_info['first_name'] = $default_user_info['first_name'];
96
        $user_info['last_name'] = $default_user_info['last_name'];
97
    }
98
    
99
    if ( empty( $user_info['country'] ) ) {
100
        $user_info['country'] = $default_user_info['country'];
101
        $user_info['state'] = $default_user_info['state'];
102
        $user_info['city'] = $default_user_info['city'];
103
        $user_info['address'] = $default_user_info['address'];
104
        $user_info['zip'] = $default_user_info['zip'];
105
        $user_info['phone'] = $default_user_info['phone'];
106
    }
107
    
108
    if ( !empty( $user_info['discount'] ) && !is_array( $user_info['discount'] ) ) {
109
        $user_info['discount'] = (array)$user_info['discount'];
110
    }
111
112
    // Payment details
113
    $payment_details = array();
114
    if ( !empty( $invoice_data['payment_details'] ) ) {
115
        $default_payment_details = array(
116
            'gateway'           => 'manual',
117
            'gateway_title'     => '',
118
            'currency'          => wpinv_get_default_country(),
119
            'transaction_id'    => '',
120
        );
121
        
122
        $payment_details = wp_parse_args( $invoice_data['payment_details'], $default_payment_details );
123
        
124
        if ( empty( $payment_details['gateway'] ) ) {
125
            $payment_details['gateway'] = 'manual';
126
        }
127
        
128
        if ( empty( $payment_details['currency'] ) ) {
129
            $payment_details['currency'] = wpinv_get_default_country();
130
        }
131
        
132
        if ( empty( $payment_details['gateway_title'] ) ) {
133
            $payment_details['gateway_title'] = wpinv_get_gateway_checkout_label( $payment_details['gateway'] );
134
        }
135
    }
136
    
137
    $invoice->set( 'status', ( !empty( $invoice_data['status'] ) ? $invoice_data['status'] : 'wpi-pending' ) );
138
    
139
    if ( !empty( $payment_details ) ) {
140
        $invoice->set( 'currency', $payment_details['currency'] );
141
        $invoice->set( 'gateway', $payment_details['gateway'] );
142
        $invoice->set( 'gateway_title', $payment_details['gateway_title'] );
143
        $invoice->set( 'transaction_id', $payment_details['transaction_id'] );
144
    }
145
    
146
    $invoice->set( 'user_info', $user_info );
147
    $invoice->set( 'first_name', $user_info['first_name'] );
148
    $invoice->set( 'last_name', $user_info['last_name'] );
149
    $invoice->set( 'address', $user_info['address'] );
150
    $invoice->set( 'company', $user_info['company'] );
151
    $invoice->set( 'vat_number', $user_info['vat_number'] );
152
    $invoice->set( 'phone', $user_info['phone'] );
153
    $invoice->set( 'city', $user_info['city'] );
154
    $invoice->set( 'country', $user_info['country'] );
155
    $invoice->set( 'state', $user_info['state'] );
156
    $invoice->set( 'zip', $user_info['zip'] );
157
    $invoice->set( 'discounts', $user_info['discount'] );
158
    $invoice->set( 'ip', ( !empty( $invoice_data['ip'] ) ? $invoice_data['ip'] : wpinv_get_ip() ) );
159
    $invoice->set( 'mode', ( wpinv_is_test_mode() ? 'test' : 'live' ) );
160
    $invoice->set( 'parent_invoice', ( !empty( $invoice_data['parent'] ) ? absint( $invoice_data['parent'] ) : '' ) );
161
    
162
    if ( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) ) {
163
        foreach ( $invoice_data['cart_details'] as $key => $item ) {
164
            $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
165
            $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
166
            $name           = !empty( $item['name'] ) ? $item['name'] : '';
167
            $item_price     = isset( $item['item_price'] ) ? $item['item_price'] : '';
168
            
169
            $post_item  = new WPInv_Item( $item_id );
170
            if ( !empty( $post_item ) ) {
171
                $name       = !empty( $name ) ? $name : $post_item->get_name();
172
                $item_price = $item_price !== '' ? $item_price : $post_item->get_price();
173
            } else {
174
                continue;
175
            }
176
            
177
            $args = array(
178
                'name'          => $name,
179
                'quantity'      => $quantity,
180
                'item_price'    => $item_price,
181
                'custom_price'  => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
182
                'tax'           => !empty( $item['tax'] ) ? $item['tax'] : 0.00,
183
                'discount'      => isset( $item['discount'] ) ? $item['discount'] : 0,
184
                'meta'          => isset( $item['meta'] ) ? $item['meta'] : array(),
185
                'fees'          => isset( $item['fees'] ) ? $item['fees'] : array(),
186
            );
187
188
            $invoice->add_item( $item_id, $args );
189
        }
190
    }
191
192
    $invoice->increase_tax( wpinv_get_cart_fee_tax() );
193
194
    if ( isset( $invoice_data['post_date'] ) ) {
195
        $invoice->set( 'date', $invoice_data['post_date'] );
196
    }
197
    
198
    // Invoice due date
199
    if ( isset( $invoice_data['due_date'] ) ) {
200
        $invoice->set( 'due_date', $invoice_data['due_date'] );
201
    }
202
    
203
    $invoice->save();
204
    
205
    // Add notes
206
    if ( !empty( $invoice_data['private_note'] ) ) {
207
        $invoice->add_note( $invoice_data['private_note'] );
208
    }
209
    if ( !empty( $invoice_data['user_note'] ) ) {
210
        $invoice->add_note( $invoice_data['user_note'], true );
211
    }
212
    
213
    do_action( 'wpinv_insert_invoice', $invoice->ID, $invoice_data );
214
215
    if ( ! empty( $invoice->ID ) ) {
216
        global $wpi_userID, $wpinv_ip_address_country;
217
        
218
        $checkout_session = wpinv_get_checkout_session();
219
        
220
        $data_session                   = array();
221
        $data_session['invoice_id']     = $invoice->ID;
222
        $data_session['cart_discounts'] = $invoice->get_discounts( true );
223
        
224
        wpinv_set_checkout_session( $data_session );
225
        
226
        $wpi_userID         = (int)$invoice->get_user_id();
227
        
228
        $_POST['country']   = !empty( $invoice->country ) ? $invoice->country : wpinv_get_default_country();
229
        $_POST['state']     = $invoice->state;
230
231
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
232
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
233
        
234
        $wpinv_ip_address_country = $invoice->country;
235
        
236
        $invoice = $invoice->recalculate_totals( true );
237
        
238
        wpinv_set_checkout_session( $checkout_session );
239
                    
240
        return $invoice;
241
    }
242
    
243 View Code Duplication
    if ( $wp_error ) {
244
        if ( is_wp_error( $invoice ) ) {
245
            return $invoice;
246
        } else {
247
            return new WP_Error( 'wpinv_insert_invoice_error', __( 'Error in insert invoice.', 'invoicing' ) );
248
        }
249
    } else {
250
        return 0;
251
    }
252
}
253
254
function wpinv_update_invoice( $invoice_data = array(), $wp_error = false ) {
255
    $invoice_ID = !empty( $invoice_data['ID'] ) ? absint( $invoice_data['ID'] ) : NULL;
256
257
    if ( !$invoice_ID ) {
258
        if ( $wp_error ) {
259
            return new WP_Error( 'invalid_invoice_id', __( 'Invalid invoice ID.', 'invoicing' ) );
260
        }
261
        return 0;
262
    }
263
264
    $invoice = wpinv_get_invoice( $invoice_ID );
265
266
    $recurring_item = $invoice->is_recurring() ? $invoice->get_recurring( true ) : NULL;
267
268
    if ( empty( $invoice->ID ) ) {
269
        if ( $wp_error ) {
270
            return new WP_Error( 'invalid_invoice', __( 'Invalid invoice.', 'invoicing' ) );
271
        }
272
        return 0;
273
    }
274
275
    if ( !$invoice->has_status( array( 'wpi-pending' ) ) ) {
276
        if ( $wp_error ) {
277
            return new WP_Error( 'invalid_invoice_status', __( 'Only invoice with pending payment is allowed to update.', 'invoicing' ) );
278
        }
279
        return 0;
280
    }
281
282
    // Invoice status
283
    if ( !empty( $invoice_data['status'] ) ) {
284
        $invoice->set( 'status', $invoice_data['status'] );
285
    }
286
287
    // Invoice date
288
    if ( !empty( $invoice_data['post_date'] ) ) {
289
        $invoice->set( 'date', $invoice_data['post_date'] );
290
    }
291
292
    // Invoice due date
293
    if ( isset( $invoice_data['due_date'] ) ) {
294
        $invoice->set( 'due_date', $invoice_data['due_date'] );
295
    }
296
297
    // Invoice IP address
298
    if ( !empty( $invoice_data['ip'] ) ) {
299
        $invoice->set( 'ip', $invoice_data['ip'] );
300
    }
301
    
302
    // User info
303
    if ( !empty( $invoice_data['user_info'] ) && is_array( $invoice_data['user_info'] ) ) {
304
        $user_info = wp_parse_args( $invoice_data['user_info'], $invoice->user_info );
305
306
        if ( $discounts = $invoice->get_discounts() ) {
307
            $set_discount = $discounts;
308
        } else {
309
            $set_discount = '';
310
        }
311
312
        // Manage discount
313
        if ( !empty( $invoice_data['user_info']['discount'] ) ) {
314
            // Remove discount
315
            if ( $invoice_data['user_info']['discount'] == 'none' ) {
316
                $set_discount = '';
317
            } else {
318
                $set_discount = $invoice_data['user_info']['discount'];
319
            }
320
321
            $invoice->set( 'discounts', $set_discount );
322
        }
323
324
        $user_info['discount'] = $set_discount;
325
326
        $invoice->set( 'user_info', $user_info );
327
    }
328
329
    if ( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) && $cart_details = $invoice_data['cart_details'] ) {
330
        $remove_items = !empty( $cart_details['remove_items'] ) && is_array( $cart_details['remove_items'] ) ? $cart_details['remove_items'] : array();
331
332
        if ( !empty( $remove_items[0]['id'] ) ) {
333
            foreach ( $remove_items as $item ) {
334
                $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
335
                $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
336
                if ( empty( $item_id ) ) {
337
                    continue;
338
                }
339
340
                foreach ( $invoice->cart_details as $cart_index => $cart_item ) {
341
                    if ( $item_id == $cart_item['id'] ) {
342
                        $args = array(
343
                            'id'         => $item_id,
344
                            'quantity'   => $quantity,
345
                            'cart_index' => $cart_index
346
                        );
347
348
                        $invoice->remove_item( $item_id, $args );
349
                        break;
350
                    }
351
                }
352
            }
353
        }
354
355
        $add_items = !empty( $cart_details['add_items'] ) && is_array( $cart_details['add_items'] ) ? $cart_details['add_items'] : array();
356
357
        if ( !empty( $add_items[0]['id'] ) ) {
358
            foreach ( $add_items as $item ) {
359
                $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
360
                $post_item      = new WPInv_Item( $item_id );
361
                if ( empty( $post_item ) ) {
362
                    continue;
363
                }
364
365
                $valid_item = true;
366 View Code Duplication
                if ( !empty( $recurring_item ) ) {
367
                    if ( $recurring_item->ID != $item_id ) {
368
                        $valid_item = false;
369
                    }
370
                } else if ( wpinv_is_recurring_item( $item_id ) ) {
371
                    $valid_item = false;
372
                }
373
                
374
                if ( !$valid_item ) {
375
                    if ( $wp_error ) {
376
                        return new WP_Error( 'invalid_invoice_item', __( 'You can not add item because recurring item must be paid individually!', 'invoicing' ) );
377
                    }
378
                    return 0;
379
                }
380
381
                $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
382
                $name           = !empty( $item['name'] ) ? $item['name'] : $post_item->get_name();
383
                $item_price     = isset( $item['item_price'] ) ? $item['item_price'] : $post_item->get_price();
384
385
                $args = array(
386
                    'name'          => $name,
387
                    'quantity'      => $quantity,
388
                    'item_price'    => $item_price,
389
                    'custom_price'  => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
390
                    'tax'           => !empty( $item['tax'] ) ? $item['tax'] : 0,
391
                    'discount'      => isset( $item['discount'] ) ? $item['discount'] : 0,
392
                    'meta'          => isset( $item['meta'] ) ? $item['meta'] : array(),
393
                    'fees'          => isset( $item['fees'] ) ? $item['fees'] : array(),
394
                );
395
396
                $invoice->add_item( $item_id, $args );
397
            }
398
        }
399
    }
400
    
401
    // Payment details
402
    if ( !empty( $invoice_data['payment_details'] ) && $payment_details = $invoice_data['payment_details'] ) {
403
        if ( !empty( $payment_details['gateway'] ) ) {
404
            $invoice->set( 'gateway', $payment_details['gateway'] );
405
        }
406
407
        if ( !empty( $payment_details['transaction_id'] ) ) {
408
            $invoice->set( 'transaction_id', $payment_details['transaction_id'] );
409
        }
410
    }
411
412
    do_action( 'wpinv_pre_update_invoice', $invoice->ID, $invoice_data );
413
414
    // Parent invoice
415
    if ( !empty( $invoice_data['parent'] ) ) {
416
        $invoice->set( 'parent_invoice', $invoice_data['parent'] );
417
    }
418
419
    // Save invoice data.
420
    $invoice->save();
421
    
422
    if ( empty( $invoice->ID ) || is_wp_error( $invoice ) ) {
423 View Code Duplication
        if ( $wp_error ) {
424
            if ( is_wp_error( $invoice ) ) {
425
                return $invoice;
426
            } else {
427
                return new WP_Error( 'wpinv_update_invoice_error', __( 'Error in update invoice.', 'invoicing' ) );
428
            }
429
        } else {
430
            return 0;
431
        }
432
    }
433
434
    // Add private note
435
    if ( !empty( $invoice_data['private_note'] ) ) {
436
        $invoice->add_note( $invoice_data['private_note'] );
437
    }
438
439
    // Add user note
440
    if ( !empty( $invoice_data['user_note'] ) ) {
441
        $invoice->add_note( $invoice_data['user_note'], true );
442
    }
443
444
    global $wpi_userID, $wpinv_ip_address_country;
445
446
    $checkout_session = wpinv_get_checkout_session();
447
448
    $data_session                   = array();
449
    $data_session['invoice_id']     = $invoice->ID;
450
    $data_session['cart_discounts'] = $invoice->get_discounts( true );
451
452
    wpinv_set_checkout_session( $data_session );
453
454
    $wpi_userID         = (int)$invoice->get_user_id();
455
456
    $_POST['country']   = !empty( $invoice->country ) ? $invoice->country : wpinv_get_default_country();
457
    $_POST['state']     = $invoice->state;
458
459
    $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
460
    $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
461
462
    $wpinv_ip_address_country = $invoice->country;
463
464
    $invoice = $invoice->recalculate_totals( true );
465
466
    do_action( 'wpinv_post_update_invoice', $invoice->ID, $invoice_data );
467
468
    wpinv_set_checkout_session( $checkout_session );
469
470
    return $invoice;
471
}
472
473
function wpinv_get_invoice( $invoice_id = 0, $cart = false ) {
474
    if ( $cart && empty( $invoice_id ) ) {
475
        $invoice_id = (int)wpinv_get_invoice_cart_id();
476
    }
477
478
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
479
480
    if ( ! empty( $invoice ) && ! empty( $invoice->ID ) ) {
481
        return $invoice;
482
    }
483
    
484
    return NULL;
485
}
486
487
function wpinv_get_invoice_cart( $invoice_id = 0 ) {
488
    return wpinv_get_invoice( $invoice_id, true );
489
}
490
491
function wpinv_get_invoice_description( $invoice_id = 0 ) {
492
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
493
    return $invoice->get_description();
494
}
495
496
function wpinv_get_invoice_currency_code( $invoice_id = 0 ) {
497
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
498
    return $invoice->get_currency();
499
}
500
501
function wpinv_get_payment_user_email( $invoice_id ) {
502
    $invoice = new WPInv_Invoice( $invoice_id );
503
    return $invoice->get_email();
504
}
505
506
function wpinv_get_user_id( $invoice_id ) {
507
    $invoice = new WPInv_Invoice( $invoice_id );
508
    return $invoice->get_user_id();
509
}
510
511
function wpinv_get_invoice_status( $invoice_id, $return_label = false ) {
512
    $invoice = new WPInv_Invoice( $invoice_id );
513
    
514
    return $invoice->get_status( $return_label );
515
}
516
517
function wpinv_get_payment_gateway( $invoice_id, $return_label = false ) {
518
    $invoice = new WPInv_Invoice( $invoice_id );
519
    
520
    return $invoice->get_gateway( $return_label );
0 ignored issues
show
Unused Code introduced by
The call to WPInv_Invoice::get_gateway() has too many arguments starting with $return_label.

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

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

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

Loading history...
521
}
522
523
function wpinv_get_payment_gateway_name( $invoice_id ) {
524
    $invoice = new WPInv_Invoice( $invoice_id );
525
    
526
    return $invoice->get_gateway_title();
527
}
528
529
function wpinv_get_payment_transaction_id( $invoice_id ) {
530
    $invoice = new WPInv_Invoice( $invoice_id );
531
    
532
    return $invoice->get_transaction_id();
533
}
534
535 View Code Duplication
function wpinv_get_id_by_transaction_id( $key ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
536
    global $wpdb;
537
538
    $invoice_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wpinv_transaction_id' AND meta_value = %s LIMIT 1", $key ) );
539
540
    if ( $invoice_id != NULL )
541
        return $invoice_id;
542
543
    return 0;
544
}
545
546
function wpinv_get_invoice_meta( $invoice_id = 0, $meta_key = '_wpinv_payment_meta', $single = true ) {
547
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
548
549
    return $invoice->get_meta( $meta_key, $single );
550
}
551
552
function wpinv_update_invoice_meta( $invoice_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
553
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
554
    
555
    return $invoice->update_meta( $meta_key, $meta_value, $prev_value );
556
}
557
558
function wpinv_get_items( $invoice_id = 0 ) {
559
    $invoice            = wpinv_get_invoice( $invoice_id );
560
    
561
    $items              = $invoice->get_items();
562
    $invoice_currency   = $invoice->get_currency();
563
564
    if ( !empty( $items ) && is_array( $items ) ) {
565 View Code Duplication
        foreach ( $items as $key => $item ) {
566
            $items[$key]['currency'] = $invoice_currency;
567
568
            if ( !isset( $cart_item['subtotal'] ) ) {
569
                $items[$key]['subtotal'] = $items[$key]['amount'] * 1;
570
            }
571
        }
572
    }
573
574
    return apply_filters( 'wpinv_get_items', $items, $invoice_id );
575
}
576
577
function wpinv_get_fees( $invoice_id = 0 ) {
578
    $invoice           = wpinv_get_invoice( $invoice_id );
579
    $fees              = $invoice->get_fees();
580
581
    return apply_filters( 'wpinv_get_fees', $fees, $invoice_id );
582
}
583
584
function wpinv_get_invoice_ip( $invoice_id ) {
585
    $invoice = new WPInv_Invoice( $invoice_id );
586
    return $invoice->get_ip();
587
}
588
589
function wpinv_get_invoice_user_info( $invoice_id ) {
590
    $invoice = new WPInv_Invoice( $invoice_id );
591
    return $invoice->get_user_info();
592
}
593
594
function wpinv_subtotal( $invoice_id = 0, $currency = false ) {
595
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
596
597
    return $invoice->get_subtotal( $currency );
598
}
599
600
function wpinv_tax( $invoice_id = 0, $currency = false ) {
601
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
602
603
    return $invoice->get_tax( $currency );
604
}
605
606
function wpinv_discount( $invoice_id = 0, $currency = false, $dash = false ) {
607
    $invoice = wpinv_get_invoice( $invoice_id );
608
609
    return $invoice->get_discount( $currency, $dash );
610
}
611
612
function wpinv_discount_code( $invoice_id = 0 ) {
613
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
614
615
    return $invoice->get_discount_code();
616
}
617
618
function wpinv_payment_total( $invoice_id = 0, $currency = false ) {
619
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
620
621
    return $invoice->get_total( $currency );
622
}
623
624
function wpinv_get_date_created( $invoice_id = 0, $format = '' ) {
625
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
626
627
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
628
    $date_created   = $invoice->get_created_date();
629
    $date_created   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_created ) ) : '';
630
631
    return $date_created;
632
}
633
634
function wpinv_get_invoice_date( $invoice_id = 0, $format = '', $default = true ) {
635
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
636
    
637
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
638
    $date_completed = $invoice->get_completed_date();
639
    $invoice_date   = $date_completed != '' && $date_completed != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_completed ) ) : '';
640
    if ( $invoice_date == '' && $default ) {
641
        $invoice_date   = wpinv_get_date_created( $invoice_id, $format );
642
    }
643
644
    return $invoice_date;
645
}
646
647
function wpinv_get_invoice_vat_number( $invoice_id = 0 ) {
648
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
649
    
650
    return $invoice->vat_number;
651
}
652
653
function wpinv_insert_payment_note( $invoice_id = 0, $note = '', $user_type = false, $added_by_user = false, $system = false ) {
654
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
655
656
    return $invoice->add_note( $note, $user_type, $added_by_user, $system );
657
}
658
659
function wpinv_get_invoice_notes( $invoice_id = 0, $type = '' ) {
660
    global $invoicing;
661
    
662
    if ( empty( $invoice_id ) ) {
663
        return NULL;
664
    }
665
    
666
    $notes = $invoicing->notes->get_invoice_notes( $invoice_id, $type );
667
    
668
    return apply_filters( 'wpinv_invoice_notes', $notes, $invoice_id, $type );
669
}
670
671
function wpinv_get_payment_key( $invoice_id = 0 ) {
672
	$invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
673
    return $invoice->get_key();
674
}
675
676
function wpinv_get_invoice_number( $invoice_id = 0 ) {
677
    $invoice = new WPInv_Invoice( $invoice_id );
0 ignored issues
show
Documentation introduced by
$invoice_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
678
    return $invoice->get_number();
679
}
680
681
function wpinv_get_cart_discountable_subtotal( $code_id ) {
682
    $cart_items = wpinv_get_cart_content_details();
683
    $items      = array();
684
685
    $excluded_items = wpinv_get_discount_excluded_items( $code_id );
686
687
    if( $cart_items ) {
688
689
        foreach( $cart_items as $item ) {
690
691
            if( ! in_array( $item['id'], $excluded_items ) ) {
692
                $items[] =  $item;
693
            }
694
        }
695
    }
696
697
    $subtotal = wpinv_get_cart_items_subtotal( $items );
698
699
    return apply_filters( 'wpinv_get_cart_discountable_subtotal', $subtotal );
700
}
701
702
function wpinv_get_cart_items_subtotal( $items ) {
703
    $subtotal = 0.00;
704
705
    if ( is_array( $items ) && ! empty( $items ) ) {
706
        $prices = wp_list_pluck( $items, 'subtotal' );
707
708
        if( is_array( $prices ) ) {
709
            $subtotal = array_sum( $prices );
710
        } else {
711
            $subtotal = 0.00;
712
        }
713
714
        if( $subtotal < 0 ) {
715
            $subtotal = 0.00;
716
        }
717
    }
718
719
    return apply_filters( 'wpinv_get_cart_items_subtotal', $subtotal );
720
}
721
722
function wpinv_get_cart_subtotal( $items = array() ) {
723
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
724
    $subtotal = wpinv_get_cart_items_subtotal( $items );
725
726
    return apply_filters( 'wpinv_get_cart_subtotal', $subtotal );
727
}
728
729
function wpinv_cart_subtotal( $items = array() ) {
730
    $price = wpinv_price( wpinv_format_amount( wpinv_get_cart_subtotal( $items ) ) );
731
732
    return $price;
733
}
734
735
function wpinv_get_cart_total( $items = array(), $discounts = false, $invoice = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $discounts is not used and could be removed.

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

Loading history...
736
    $subtotal  = (float)wpinv_get_cart_subtotal( $items );
737
    $discounts = (float)wpinv_get_cart_discounted_amount( $items );
738
    $cart_tax  = (float)wpinv_get_cart_tax( $items );
739
    $fees      = (float)wpinv_get_cart_fee_total();
740
    if ( !empty( $invoice ) && $invoice->is_free_trial() ) {
0 ignored issues
show
Bug introduced by
The method is_free_trial cannot be called on $invoice (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
741
        $total = 0;
742
    } else {
743
        $total     = $subtotal - $discounts + $cart_tax + $fees;
744
    }
745
746
    if ( $total < 0 ) {
747
        $total = 0.00;
748
    }
749
    
750
    $total = (float)apply_filters( 'wpinv_get_cart_total', $total, $items );
751
752
    return wpinv_sanitize_amount( $total );
753
}
754
755
function wpinv_cart_total( $cart_items = array(), $echo = true, $invoice = array() ) {
756
    global $cart_total;
757
    $total = wpinv_price( wpinv_format_amount( wpinv_get_cart_total( $cart_items, NULL, $invoice ) ) );
0 ignored issues
show
Documentation introduced by
NULL is of type null, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
758
    $total = apply_filters( 'wpinv_cart_total', $total, $cart_items, $invoice );
759
    
760
    $cart_total = $total;
761
762
    if ( !$echo ) {
763
        return $total;
764
    }
765
766
    echo $total;
767
}
768
769 View Code Duplication
function wpinv_get_cart_tax( $items = array() ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
770
    $cart_tax = 0;
771
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
772
773
    if ( $items ) {
774
        $taxes = wp_list_pluck( $items, 'tax' );
775
776
        if( is_array( $taxes ) ) {
777
            $cart_tax = array_sum( $taxes );
778
        }
779
    }
780
781
    $cart_tax += wpinv_get_cart_fee_tax();
782
783
    return apply_filters( 'wpinv_get_cart_tax', wpinv_sanitize_amount( $cart_tax ) );
784
}
785
786 View Code Duplication
function wpinv_cart_tax( $items = array(), $echo = false ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
787
    $cart_tax = wpinv_get_cart_tax( $items );
788
    $cart_tax = wpinv_price( wpinv_format_amount( $cart_tax ) );
789
790
    $tax = apply_filters( 'wpinv_cart_tax', $cart_tax, $items );
791
792
    if ( !$echo ) {
793
        return $tax;
794
    }
795
796
    echo $tax;
797
}
798
799
function wpinv_get_cart_discount_code( $items = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $items is not used and could be removed.

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

Loading history...
800
    $invoice = wpinv_get_invoice_cart();
801
    $cart_discount_code = !empty( $invoice ) ? $invoice->get_discount_code() : '';
802
    
803
    return apply_filters( 'wpinv_get_cart_discount_code', $cart_discount_code );
804
}
805
806
function wpinv_cart_discount_code( $items = array(), $echo = false ) {
807
    $cart_discount_code = wpinv_get_cart_discount_code( $items );
808
809
    if ( $cart_discount_code != '' ) {
810
        $cart_discount_code = ' (' . $cart_discount_code . ')';
811
    }
812
    
813
    $discount_code = apply_filters( 'wpinv_cart_discount_code', $cart_discount_code, $items );
814
815
    if ( !$echo ) {
816
        return $discount_code;
817
    }
818
819
    echo $discount_code;
820
}
821
822
function wpinv_get_cart_discount( $items = array() ) {
823
    $invoice = wpinv_get_invoice_cart();
824
    $cart_discount = !empty( $invoice ) ? $invoice->get_discount() : 0;
825
    
826
    return apply_filters( 'wpinv_get_cart_discount', wpinv_sanitize_amount( $cart_discount ), $items );
827
}
828
829 View Code Duplication
function wpinv_cart_discount( $items = array(), $echo = false ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
830
    $cart_discount = wpinv_get_cart_discount( $items );
831
    $cart_discount = wpinv_price( wpinv_format_amount( $cart_discount ) );
832
833
    $discount = apply_filters( 'wpinv_cart_discount', $cart_discount, $items );
834
835
    if ( !$echo ) {
836
        return $discount;
837
    }
838
839
    echo $discount;
840
}
841
842
function wpinv_get_cart_fees( $type = 'all', $item_id = 0 ) {
843
    $item = new WPInv_Item( $item_id );
0 ignored issues
show
Documentation introduced by
$item_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
844
    
845
    return $item->get_fees( $type, $item_id );
846
}
847
848
function wpinv_get_cart_fee_total() {
849
    $total  = 0;
850
    $fees = wpinv_get_cart_fees();
851
    
852
    if ( $fees ) {
853
        foreach ( $fees as $fee_id => $fee ) {
854
            $total += $fee['amount'];
855
        }
856
    }
857
858
    return apply_filters( 'wpinv_get_cart_fee_total', $total );
859
}
860
861
function wpinv_get_cart_fee_tax() {
862
    $tax  = 0;
863
    $fees = wpinv_get_cart_fees();
864
865
    if ( $fees ) {
866
        foreach ( $fees as $fee_id => $fee ) {
867
            if( ! empty( $fee['no_tax'] ) ) {
868
                continue;
869
            }
870
871
            $tax += wpinv_calculate_tax( $fee['amount'] );
872
        }
873
    }
874
875
    return apply_filters( 'wpinv_get_cart_fee_tax', $tax );
876
}
877
878
function wpinv_cart_has_recurring_item() {
879
    $cart_items = wpinv_get_cart_contents();
880
    
881
    if ( empty( $cart_items ) ) {
882
        return false;
883
    }
884
    
885
    $has_subscription = false;
886 View Code Duplication
    foreach( $cart_items as $cart_item ) {
887
        if ( !empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] )  ) {
888
            $has_subscription = true;
889
            break;
890
        }
891
    }
892
    
893
    return apply_filters( 'wpinv_cart_has_recurring_item', $has_subscription, $cart_items );
894
}
895
896
function wpinv_cart_has_free_trial() {
897
    $invoice = wpinv_get_invoice_cart();
898
    
899
    $free_trial = false;
900
    
901
    if ( !empty( $invoice ) && $invoice->is_free_trial() ) {
902
        $free_trial = true;
903
    }
904
    
905
    return apply_filters( 'wpinv_cart_has_free_trial', $free_trial, $invoice );
906
}
907
908
function wpinv_get_cart_contents() {
909
    $cart_details = wpinv_get_cart_details();
910
    
911
    return apply_filters( 'wpinv_get_cart_contents', $cart_details );
912
}
913
914
function wpinv_get_cart_content_details() {
915
    global $wpinv_euvat, $wpi_current_id, $wpi_item_id, $wpinv_is_last_cart_item, $wpinv_flat_discount_total;
916
    $cart_items = wpinv_get_cart_contents();
917
    
918
    if ( empty( $cart_items ) ) {
919
        return false;
920
    }
921
    $invoice = wpinv_get_invoice_cart();
922
	if ( empty( $invoice ) ) {
923
        return false;
924
    }
925
926
    $details = array();
927
    $length  = count( $cart_items ) - 1;
0 ignored issues
show
Unused Code introduced by
$length is not used, you could remove the assignment.

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

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

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

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

Loading history...
928
    
929
    if ( empty( $_POST['country'] ) ) {
930
        $_POST['country'] = $invoice->country;
931
    }
932
    if ( !isset( $_POST['state'] ) ) {
933
        $_POST['state'] = $invoice->state;
934
    }
935
936
    foreach( $cart_items as $key => $item ) {
937
        $item_id            = isset( $item['id'] ) ? sanitize_text_field( $item['id'] ) : '';
938
        if ( empty( $item_id ) ) {
939
            continue;
940
        }
941
        
942
        $wpi_current_id         = $invoice->ID;
943
        $wpi_item_id            = $item_id;
944
        
945
        if ( isset( $item['custom_price'] ) && $item['custom_price'] !== '' ) {
946
            $item_price = $item['custom_price'];
947
        } else {
948
            if ( isset( $item['item_price'] ) && $item['item_price'] !== '' && $item['item_price'] !== false ) {
949
                $item_price = $item['item_price'];
950
            } else {
951
                $item_price = wpinv_get_item_price( $item_id );
952
            }
953
        }
954
        $discount           = wpinv_get_cart_item_discount_amount( $item );
955
        $discount           = apply_filters( 'wpinv_get_cart_content_details_item_discount_amount', $discount, $item );
956
        $quantity           = wpinv_get_cart_item_quantity( $item );
957
        $fees               = wpinv_get_cart_fees( 'fee', $item_id );
958
        
959
        $subtotal           = $item_price * $quantity;
960
        $tax_rate           = wpinv_get_tax_rate( $_POST['country'], $_POST['state'], $wpi_item_id );
0 ignored issues
show
Documentation introduced by
$_POST['state'] is of type string, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
961
        $tax_class          = $wpinv_euvat->get_item_class( $item_id );
962
        $tax                = wpinv_get_cart_item_tax( $item_id, $subtotal - $discount );
963
        
964
        if ( wpinv_prices_include_tax() ) {
965
            $subtotal -= wpinv_round_amount( $tax );
966
        }
967
        
968
        $total              = $subtotal - $discount + $tax;
969
        
970
        // Do not allow totals to go negatve
971
        if( $total < 0 ) {
972
            $total = 0;
973
        }
974
        
975
        $details[ $key ]  = array(
976
            'id'                => $item_id,
977
            'name'              => !empty($item['name']) ? $item['name'] : get_the_title( $item_id ),
978
            'item_price'        => wpinv_round_amount( $item_price ),
979
            'custom_price'      => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
980
            'quantity'          => $quantity,
981
            'discount'          => wpinv_round_amount( $discount ),
982
            'subtotal'          => wpinv_round_amount( $subtotal ),
983
            'tax'               => wpinv_round_amount( $tax ),
984
            'price'             => wpinv_round_amount( $total ),
985
            'vat_rates_class'   => $tax_class,
986
            'vat_rate'          => $tax_rate,
987
            'meta'              => isset( $item['meta'] ) ? $item['meta'] : array(),
988
            'fees'              => $fees,
989
        );
990
        
991
        if ( $wpinv_is_last_cart_item ) {
992
            $wpinv_is_last_cart_item   = false;
993
            $wpinv_flat_discount_total = 0.00;
994
        }
995
    }
996
    
997
    return $details;
998
}
999
1000
function wpinv_get_cart_details( $invoice_id = 0 ) {
1001
    global $ajax_cart_details;
1002
1003
    $invoice      = wpinv_get_invoice_cart( $invoice_id );
1004
    $cart_details = $ajax_cart_details;
1005
    if ( empty( $cart_details ) && ! empty( $invoice->cart_details ) ) {
1006
        $cart_details = $invoice->cart_details;
1007
    }
1008
1009
    if ( ! empty( $cart_details ) && is_array( $cart_details ) ) {
1010
        $invoice_currency = ! empty( $invoice->currency ) ? $invoice->currency : wpinv_get_default_country();
1011
1012 View Code Duplication
        foreach ( $cart_details as $key => $cart_item ) {
1013
            $cart_details[ $key ]['currency'] = $invoice_currency;
1014
1015
            if ( ! isset( $cart_item['subtotal'] ) ) {
1016
                $cart_details[ $key ]['subtotal'] = $cart_item['price'];
1017
            }
1018
        }
1019
    }
1020
1021
    return apply_filters( 'wpinv_get_cart_details', $cart_details, $invoice_id );
1022
}
1023
1024
function wpinv_record_status_change( $invoice_id, $new_status, $old_status ) {
1025
    if ( 'wpi_invoice' != get_post_type( $invoice_id ) ) {
1026
        return;
1027
    }
1028
1029
    if ( ( $old_status == 'wpi-pending' && $new_status == 'draft' ) || ( $old_status == 'draft' && $new_status == 'wpi-pending' ) ) {
1030
        return;
1031
    }
1032
1033
    $invoice    = wpinv_get_invoice( $invoice_id );
1034
    
1035
    $old_status = wpinv_status_nicename( $old_status );
1036
    $new_status = wpinv_status_nicename( $new_status );
1037
1038
    $status_change = sprintf( __( 'Invoice status changed from %s to %s', 'invoicing' ), $old_status, $new_status );
1039
    
1040
    // Add note
1041
    return $invoice->add_note( $status_change, false, false, true );
1042
}
1043
add_action( 'wpinv_update_status', 'wpinv_record_status_change', 100, 3 );
1044
1045
function wpinv_complete_payment( $invoice_id, $new_status, $old_status ) {
1046
    global $wpi_has_free_trial;
1047
    
1048
    $wpi_has_free_trial = false;
1049
    
1050
    if ( $old_status == 'publish' ) {
1051
        return; // Make sure that payments are only paid once
1052
    }
1053
1054
    // Make sure the payment completion is only processed when new status is paid
1055
    if ( $new_status != 'publish' ) {
1056
        return;
1057
    }
1058
1059
    $invoice = new WPInv_Invoice( $invoice_id );
1060
    if ( empty( $invoice ) ) {
1061
        return;
1062
    }
1063
1064
    $wpi_has_free_trial = $invoice->is_free_trial();
1065
    $completed_date = $invoice->completed_date;
1066
    $cart_details   = $invoice->cart_details;
1067
1068
    do_action( 'wpinv_pre_complete_payment', $invoice_id );
1069
1070
    if ( is_array( $cart_details ) ) {
1071
        // Increase purchase count and earnings
1072
        foreach ( $cart_details as $cart_index => $item ) {
1073
            // Ensure these actions only run once, ever
1074
            if ( empty( $completed_date ) ) {
1075
                do_action( 'wpinv_complete_item_payment', $item['id'], $invoice_id, $item, $cart_index );
1076
            }
1077
        }
1078
    }
1079
    
1080
    // Check for discount codes and increment their use counts
1081
    if ( $discounts = $invoice->get_discounts( true ) ) {
1082
        if( ! empty( $discounts ) ) {
1083
            foreach( $discounts as $code ) {
1084
                wpinv_increase_discount_usage( $code );
1085
            }
1086
        }
1087
    }
1088
    
1089
    // Ensure this action only runs once ever
1090
    if( empty( $completed_date ) ) {
1091
        // Save the completed date
1092
        $invoice->set( 'completed_date', current_time( 'mysql', 0 ) );
1093
        $invoice->save();
1094
1095
        do_action( 'wpinv_complete_payment', $invoice_id );
1096
    }
1097
1098
    // Empty the shopping cart
1099
    wpinv_empty_cart();
1100
}
1101
add_action( 'wpinv_update_status', 'wpinv_complete_payment', 100, 3 );
1102
1103
function wpinv_update_payment_status( $invoice_id, $new_status = 'publish' ) {    
1104
    $invoice = !empty( $invoice_id ) && is_object( $invoice_id ) ? $invoice_id : wpinv_get_invoice( (int)$invoice_id );
1105
    
1106
    if ( empty( $invoice ) ) {
1107
        return false;
1108
    }
1109
    
1110
    return $invoice->update_status( $new_status );
1111
}
1112
1113
function wpinv_cart_has_fees( $type = 'all' ) {
1114
    return false;
1115
}
1116
1117
function wpinv_validate_checkout_fields() {    
1118
    // Check if there is $_POST
1119
    if ( empty( $_POST ) ) {
1120
        return false;
1121
    }
1122
    
1123
    // Start an array to collect valid data
1124
    $valid_data = array(
1125
        'gateway'          => wpinv_checkout_validate_gateway(), // Gateway fallback
1126
        'discount'         => wpinv_checkout_validate_discounts(), // Set default discount
1127
        'cc_info'          => wpinv_checkout_validate_cc() // Credit card info
1128
    );
1129
    
1130
    // Validate agree to terms
1131
    $page = wpinv_get_option( 'tandc_page' );
1132
    if(isset($page) && (int)$page > 0 && apply_filters( 'wpinv_checkout_show_terms', true )){
1133
        // Validate agree to terms
1134 View Code Duplication
        if ( ! isset( $_POST['wpi_terms'] ) || !$_POST['wpi_terms'] ) {
1135
            wpinv_set_error( 'accept_terms', apply_filters( 'wpinv_accept_terms_error_text', __( 'You must accept terms and conditions', 'invoicing' ) ) );
1136
        }
1137
    }
1138
    
1139
    $valid_data['invoice_user'] = wpinv_checkout_validate_invoice_user();
1140
    $valid_data['current_user'] = wpinv_checkout_validate_current_user();
1141
    
1142
    // Return collected data
1143
    return $valid_data;
1144
}
1145
1146
function wpinv_checkout_validate_gateway() {
1147
    $gateway = wpinv_get_default_gateway();
1148
    
1149
    $invoice = wpinv_get_invoice_cart();
1150
    $has_subscription = $invoice->is_recurring();
1151
    if ( empty( $invoice ) ) {
1152
        wpinv_set_error( 'invalid_invoice', __( 'Your cart is empty.', 'invoicing' ) );
1153
        return $gateway;
1154
    }
1155
1156
    // Check if a gateway value is present
1157
    if ( !empty( $_REQUEST['wpi-gateway'] ) ) {
1158
        $gateway = sanitize_text_field( $_REQUEST['wpi-gateway'] );
1159
1160
        if ( $invoice->is_free() ) {
1161
            $gateway = 'manual';
1162
        } elseif ( !wpinv_is_gateway_active( $gateway ) ) {
1163
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled', 'invoicing' ) );
1164
        } elseif ( $has_subscription && !wpinv_gateway_support_subscription( $gateway ) ) {
1165
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway doesnot support subscription payment', 'invoicing' ) );
1166
        }
1167
    }
1168
1169
    if ( $has_subscription && count( wpinv_get_cart_contents() ) > 1 ) {
1170
        wpinv_set_error( 'subscription_invalid', __( 'Only one subscription may be purchased through payment per checkout.', 'invoicing' ) );
1171
    }
1172
1173
    return $gateway;
1174
}
1175
1176
function wpinv_checkout_validate_discounts() {
1177
    global $wpi_cart;
1178
    
1179
    // Retrieve the discount stored in cookies
1180
    $discounts = wpinv_get_cart_discounts();
1181
    
1182
    $error = false;
1183
    // If we have discounts, loop through them
1184
    if ( ! empty( $discounts ) ) {
1185
        foreach ( $discounts as $discount ) {
1186
            // Check if valid
1187
            if (  !wpinv_is_discount_valid( $discount, (int)$wpi_cart->get_user_id() ) ) {
1188
                // Discount is not valid
1189
                $error = true;
1190
            }
1191
        }
1192
    } else {
1193
        // No discounts
1194
        return NULL;
1195
    }
1196
1197
    if ( $error && !wpinv_get_errors() ) {
1198
        wpinv_set_error( 'invalid_discount', __( 'Discount code you entered is invalid', 'invoicing' ) );
1199
    }
1200
1201
    return implode( ',', $discounts );
1202
}
1203
1204
function wpinv_checkout_validate_cc() {
1205
    $card_data = wpinv_checkout_get_cc_info();
1206
1207
    // Validate the card zip
1208
    if ( !empty( $card_data['wpinv_zip'] ) ) {
1209
        if ( !wpinv_checkout_validate_cc_zip( $card_data['wpinv_zip'], $card_data['wpinv_country'] ) ) {
1210
            wpinv_set_error( 'invalid_cc_zip', __( 'The zip / postcode you entered for your billing address is invalid', 'invoicing' ) );
1211
        }
1212
    }
1213
1214
    // This should validate card numbers at some point too
1215
    return $card_data;
1216
}
1217
1218
function wpinv_checkout_get_cc_info() {
1219
	$cc_info = array();
1220
	$cc_info['card_name']      = isset( $_POST['card_name'] )       ? sanitize_text_field( $_POST['card_name'] )       : '';
1221
	$cc_info['card_number']    = isset( $_POST['card_number'] )     ? sanitize_text_field( $_POST['card_number'] )     : '';
1222
	$cc_info['card_cvc']       = isset( $_POST['card_cvc'] )        ? sanitize_text_field( $_POST['card_cvc'] )        : '';
1223
	$cc_info['card_exp_month'] = isset( $_POST['card_exp_month'] )  ? sanitize_text_field( $_POST['card_exp_month'] )  : '';
1224
	$cc_info['card_exp_year']  = isset( $_POST['card_exp_year'] )   ? sanitize_text_field( $_POST['card_exp_year'] )   : '';
1225
	$cc_info['card_address']   = isset( $_POST['wpinv_address'] )  ? sanitize_text_field( $_POST['wpinv_address'] ) : '';
1226
	$cc_info['card_city']      = isset( $_POST['wpinv_city'] )     ? sanitize_text_field( $_POST['wpinv_city'] )    : '';
1227
	$cc_info['card_state']     = isset( $_POST['wpinv_state'] )    ? sanitize_text_field( $_POST['wpinv_state'] )   : '';
1228
	$cc_info['card_country']   = isset( $_POST['wpinv_country'] )  ? sanitize_text_field( $_POST['wpinv_country'] ) : '';
1229
	$cc_info['card_zip']       = isset( $_POST['wpinv_zip'] )      ? sanitize_text_field( $_POST['wpinv_zip'] )     : '';
1230
1231
	// Return cc info
1232
	return $cc_info;
1233
}
1234
1235
function wpinv_checkout_validate_cc_zip( $zip = 0, $country_code = '' ) {
1236
    $ret = false;
1237
1238
    if ( empty( $zip ) || empty( $country_code ) )
1239
        return $ret;
1240
1241
    $country_code = strtoupper( $country_code );
1242
1243
    $zip_regex = array(
1244
        "AD" => "AD\d{3}",
1245
        "AM" => "(37)?\d{4}",
1246
        "AR" => "^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$",
1247
        "AS" => "96799",
1248
        "AT" => "\d{4}",
1249
        "AU" => "^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$",
1250
        "AX" => "22\d{3}",
1251
        "AZ" => "\d{4}",
1252
        "BA" => "\d{5}",
1253
        "BB" => "(BB\d{5})?",
1254
        "BD" => "\d{4}",
1255
        "BE" => "^[1-9]{1}[0-9]{3}$",
1256
        "BG" => "\d{4}",
1257
        "BH" => "((1[0-2]|[2-9])\d{2})?",
1258
        "BM" => "[A-Z]{2}[ ]?[A-Z0-9]{2}",
1259
        "BN" => "[A-Z]{2}[ ]?\d{4}",
1260
        "BR" => "\d{5}[\-]?\d{3}",
1261
        "BY" => "\d{6}",
1262
        "CA" => "^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$",
1263
        "CC" => "6799",
1264
        "CH" => "^[1-9][0-9][0-9][0-9]$",
1265
        "CK" => "\d{4}",
1266
        "CL" => "\d{7}",
1267
        "CN" => "\d{6}",
1268
        "CR" => "\d{4,5}|\d{3}-\d{4}",
1269
        "CS" => "\d{5}",
1270
        "CV" => "\d{4}",
1271
        "CX" => "6798",
1272
        "CY" => "\d{4}",
1273
        "CZ" => "\d{3}[ ]?\d{2}",
1274
        "DE" => "\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b",
1275
        "DK" => "^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$",
1276
        "DO" => "\d{5}",
1277
        "DZ" => "\d{5}",
1278
        "EC" => "([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?",
1279
        "EE" => "\d{5}",
1280
        "EG" => "\d{5}",
1281
        "ES" => "^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$",
1282
        "ET" => "\d{4}",
1283
        "FI" => "\d{5}",
1284
        "FK" => "FIQQ 1ZZ",
1285
        "FM" => "(9694[1-4])([ \-]\d{4})?",
1286
        "FO" => "\d{3}",
1287
        "FR" => "^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$",
1288
        "GE" => "\d{4}",
1289
        "GF" => "9[78]3\d{2}",
1290
        "GL" => "39\d{2}",
1291
        "GN" => "\d{3}",
1292
        "GP" => "9[78][01]\d{2}",
1293
        "GR" => "\d{3}[ ]?\d{2}",
1294
        "GS" => "SIQQ 1ZZ",
1295
        "GT" => "\d{5}",
1296
        "GU" => "969[123]\d([ \-]\d{4})?",
1297
        "GW" => "\d{4}",
1298
        "HM" => "\d{4}",
1299
        "HN" => "(?:\d{5})?",
1300
        "HR" => "\d{5}",
1301
        "HT" => "\d{4}",
1302
        "HU" => "\d{4}",
1303
        "ID" => "\d{5}",
1304
        "IE" => "((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?",
1305
        "IL" => "\d{5}",
1306
        "IN"=> "^[1-9][0-9][0-9][0-9][0-9][0-9]$", //india
1307
        "IO" => "BBND 1ZZ",
1308
        "IQ" => "\d{5}",
1309
        "IS" => "\d{3}",
1310
        "IT" => "^(V-|I-)?[0-9]{5}$",
1311
        "JO" => "\d{5}",
1312
        "JP" => "\d{3}-\d{4}",
1313
        "KE" => "\d{5}",
1314
        "KG" => "\d{6}",
1315
        "KH" => "\d{5}",
1316
        "KR" => "\d{3}[\-]\d{3}",
1317
        "KW" => "\d{5}",
1318
        "KZ" => "\d{6}",
1319
        "LA" => "\d{5}",
1320
        "LB" => "(\d{4}([ ]?\d{4})?)?",
1321
        "LI" => "(948[5-9])|(949[0-7])",
1322
        "LK" => "\d{5}",
1323
        "LR" => "\d{4}",
1324
        "LS" => "\d{3}",
1325
        "LT" => "\d{5}",
1326
        "LU" => "\d{4}",
1327
        "LV" => "\d{4}",
1328
        "MA" => "\d{5}",
1329
        "MC" => "980\d{2}",
1330
        "MD" => "\d{4}",
1331
        "ME" => "8\d{4}",
1332
        "MG" => "\d{3}",
1333
        "MH" => "969[67]\d([ \-]\d{4})?",
1334
        "MK" => "\d{4}",
1335
        "MN" => "\d{6}",
1336
        "MP" => "9695[012]([ \-]\d{4})?",
1337
        "MQ" => "9[78]2\d{2}",
1338
        "MT" => "[A-Z]{3}[ ]?\d{2,4}",
1339
        "MU" => "(\d{3}[A-Z]{2}\d{3})?",
1340
        "MV" => "\d{5}",
1341
        "MX" => "\d{5}",
1342
        "MY" => "\d{5}",
1343
        "NC" => "988\d{2}",
1344
        "NE" => "\d{4}",
1345
        "NF" => "2899",
1346
        "NG" => "(\d{6})?",
1347
        "NI" => "((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?",
1348
        "NL" => "^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$",
1349
        "NO" => "\d{4}",
1350
        "NP" => "\d{5}",
1351
        "NZ" => "\d{4}",
1352
        "OM" => "(PC )?\d{3}",
1353
        "PF" => "987\d{2}",
1354
        "PG" => "\d{3}",
1355
        "PH" => "\d{4}",
1356
        "PK" => "\d{5}",
1357
        "PL" => "\d{2}-\d{3}",
1358
        "PM" => "9[78]5\d{2}",
1359
        "PN" => "PCRN 1ZZ",
1360
        "PR" => "00[679]\d{2}([ \-]\d{4})?",
1361
        "PT" => "\d{4}([\-]\d{3})?",
1362
        "PW" => "96940",
1363
        "PY" => "\d{4}",
1364
        "RE" => "9[78]4\d{2}",
1365
        "RO" => "\d{6}",
1366
        "RS" => "\d{5}",
1367
        "RU" => "\d{6}",
1368
        "SA" => "\d{5}",
1369
        "SE" => "^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$",
1370
        "SG" => "\d{6}",
1371
        "SH" => "(ASCN|STHL) 1ZZ",
1372
        "SI" => "\d{4}",
1373
        "SJ" => "\d{4}",
1374
        "SK" => "\d{3}[ ]?\d{2}",
1375
        "SM" => "4789\d",
1376
        "SN" => "\d{5}",
1377
        "SO" => "\d{5}",
1378
        "SZ" => "[HLMS]\d{3}",
1379
        "TC" => "TKCA 1ZZ",
1380
        "TH" => "\d{5}",
1381
        "TJ" => "\d{6}",
1382
        "TM" => "\d{6}",
1383
        "TN" => "\d{4}",
1384
        "TR" => "\d{5}",
1385
        "TW" => "\d{3}(\d{2})?",
1386
        "UA" => "\d{5}",
1387
        "UK" => "^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$",
1388
        "US" => "^\d{5}([\-]?\d{4})?$",
1389
        "UY" => "\d{5}",
1390
        "UZ" => "\d{6}",
1391
        "VA" => "00120",
1392
        "VE" => "\d{4}",
1393
        "VI" => "008(([0-4]\d)|(5[01]))([ \-]\d{4})?",
1394
        "WF" => "986\d{2}",
1395
        "YT" => "976\d{2}",
1396
        "YU" => "\d{5}",
1397
        "ZA" => "\d{4}",
1398
        "ZM" => "\d{5}"
1399
    );
1400
1401
    if ( ! isset ( $zip_regex[ $country_code ] ) || preg_match( "/" . $zip_regex[ $country_code ] . "/i", $zip ) )
1402
        $ret = true;
1403
1404
    return apply_filters( 'wpinv_is_zip_valid', $ret, $zip, $country_code );
1405
}
1406
1407
function wpinv_checkout_validate_agree_to_terms() {
1408
    // Validate agree to terms
1409 View Code Duplication
    if ( ! isset( $_POST['wpi_agree_to_terms'] ) || $_POST['wpi_agree_to_terms'] != 1 ) {
1410
        // User did not agree
1411
        wpinv_set_error( 'agree_to_terms', apply_filters( 'wpinv_agree_to_terms_text', __( 'You must agree to the terms of use', 'invoicing' ) ) );
1412
    }
1413
}
1414
1415
function wpinv_checkout_validate_invoice_user() {
1416
    global $wpi_cart, $user_ID;
1417
1418
    if(empty($wpi_cart)){
1419
        $wpi_cart = wpinv_get_invoice_cart();
1420
    }
1421
1422
    $invoice_user = (int)$wpi_cart->get_user_id();
1423
    $valid_user_data = array(
1424
        'user_id' => $invoice_user
1425
    );
1426
1427
    // If guest checkout allowed
1428
    if ( !wpinv_require_login_to_checkout() ) {
1429
        return $valid_user_data;
1430
    }
1431
    
1432
    // Verify there is a user_ID
1433
    if ( $user_ID == $invoice_user ) {
1434
        // Get the logged in user data
1435
        $user_data = get_userdata( $user_ID );
1436
        $required_fields  = wpinv_checkout_required_fields();
1437
1438
        // Loop through required fields and show error messages
1439
         if ( !empty( $required_fields ) ) {
1440
            foreach ( $required_fields as $field_name => $value ) {
1441
                if ( in_array( $value, $required_fields ) && empty( $_POST[ 'wpinv_' . $field_name ] ) ) {
1442
                    wpinv_set_error( $value['error_id'], $value['error_message'] );
1443
                }
1444
            }
1445
        }
1446
1447
        // Verify data
1448
        if ( $user_data ) {
1449
            // Collected logged in user data
1450
            $valid_user_data = array(
1451
                'user_id'     => $user_ID,
1452
                'email'       => isset( $_POST['wpinv_email'] ) ? sanitize_email( $_POST['wpinv_email'] ) : $user_data->user_email,
1453
                'first_name'  => isset( $_POST['wpinv_first_name'] ) && ! empty( $_POST['wpinv_first_name'] ) ? sanitize_text_field( $_POST['wpinv_first_name'] ) : $user_data->first_name,
1454
                'last_name'   => isset( $_POST['wpinv_last_name'] ) && ! empty( $_POST['wpinv_last_name']  ) ? sanitize_text_field( $_POST['wpinv_last_name']  ) : $user_data->last_name,
1455
            );
1456
1457
            if ( !empty( $_POST[ 'wpinv_email' ] ) && !is_email( $_POST[ 'wpinv_email' ] ) ) {
1458
                wpinv_set_error( 'invalid_email', __( 'Please enter a valid email address', 'invoicing' ) );
1459
            }
1460
        } else {
1461
            // Set invalid user error
1462
            wpinv_set_error( 'invalid_user', __( 'The user billing information is invalid', 'invoicing' ) );
1463
        }
1464
    } else {
1465
        // Set invalid user error
1466
        wpinv_set_error( 'invalid_user_id', __( 'The invalid invoice user id', 'invoicing' ) );
1467
    }
1468
1469
    // Return user data
1470
    return $valid_user_data;
1471
}
1472
1473
function wpinv_checkout_validate_current_user() {
1474
    global $wpi_cart;
1475
1476
    $data = array();
1477
    
1478
    if ( is_user_logged_in() ) {
1479
        if ( !wpinv_require_login_to_checkout() || ( wpinv_require_login_to_checkout() && (int)$wpi_cart->get_user_id() === (int)get_current_user_id() ) ) {
1480
            $data['user_id'] = (int)get_current_user_id();
1481
        } else {
1482
            wpinv_set_error( 'logged_in_only', __( 'You are not allowed to pay for this invoice', 'invoicing' ) );
1483
        }
1484
    } else {
1485
        // If guest checkout allowed
1486
        if ( !wpinv_require_login_to_checkout() ) {
1487
            $data['user_id'] = 0;
1488
        } else {
1489
            wpinv_set_error( 'logged_in_only', __( 'You must be logged in to pay for this invoice', 'invoicing' ) );
1490
        }
1491
    }
1492
1493
    return $data;
1494
}
1495
1496
function wpinv_checkout_form_get_user( $valid_data = array() ) {
1497
1498
    if ( !empty( $valid_data['current_user']['user_id'] ) ) {
1499
        $user = $valid_data['current_user'];
1500
    } else {
1501
        // Set the valid invoice user
1502
        $user = $valid_data['invoice_user'];
1503
    }
1504
1505
    // Verify invoice have an user
1506
    if ( false === $user || empty( $user ) ) {
1507
        return false;
1508
    }
1509
1510
    $address_fields = array(
1511
        'first_name',
1512
        'last_name',
1513
        'company',
1514
        'vat_number',
1515
        'phone',
1516
        'address',
1517
        'city',
1518
        'state',
1519
        'country',
1520
        'zip',
1521
    );
1522
    
1523
    foreach ( $address_fields as $field ) {
1524
        $user[$field]  = !empty( $_POST['wpinv_' . $field] ) ? sanitize_text_field( $_POST['wpinv_' . $field] ) : false;
1525
        
1526
        if ( !empty( $user['user_id'] ) && !empty( $valid_data['current_user']['user_id'] ) && $valid_data['current_user']['user_id'] == $valid_data['invoice_user']['user_id'] ) {
1527
            update_user_meta( $user['user_id'], '_wpinv_' . $field, $user[$field] );
1528
        }
1529
    }
1530
1531
    // Return valid user
1532
    return $user;
1533
}
1534
1535
function wpinv_set_checkout_session( $invoice_data = array() ) {
1536
    global $wpi_session;
1537
    
1538
    return $wpi_session->set( 'wpinv_checkout', $invoice_data );
1539
}
1540
1541
function wpinv_get_checkout_session() {
1542
	global $wpi_session;
1543
    
1544
    return $wpi_session->get( 'wpinv_checkout' );
1545
}
1546
1547
function wpinv_empty_cart() {
1548
    global $wpi_session;
1549
1550
    // Remove cart contents
1551
    $wpi_session->set( 'wpinv_checkout', NULL );
1552
1553
    // Remove all cart fees
1554
    $wpi_session->set( 'wpi_cart_fees', NULL );
1555
1556
    do_action( 'wpinv_empty_cart' );
1557
}
1558
1559
function wpinv_process_checkout() {
1560
    global $wpinv_euvat, $wpi_checkout_id, $wpi_cart;
1561
    
1562
    wpinv_clear_errors();
1563
    
1564
    $invoice = wpinv_get_invoice_cart();
1565
    if ( empty( $invoice ) ) {
1566
        return false;
1567
    }
1568
    
1569
    $wpi_cart = $invoice;
1570
    
1571
    $wpi_checkout_id = $invoice->ID;
1572
    
1573
    do_action( 'wpinv_pre_process_checkout' );
1574
    
1575
    if ( !wpinv_get_cart_contents() ) { // Make sure the cart isn't empty
1576
        $valid_data = false;
1577
        wpinv_set_error( 'empty_cart', __( 'Your cart is empty', 'invoicing' ) );
1578
    } else {
1579
        // Validate the form $_POST data
1580
        $valid_data = wpinv_validate_checkout_fields();
1581
        
1582
        // Allow themes and plugins to hook to errors
1583
        do_action( 'wpinv_checkout_error_checks', $valid_data, $_POST );
1584
    }
1585
    
1586
    $is_ajax    = defined( 'DOING_AJAX' ) && DOING_AJAX;
1587
    
1588
    // Validate the user
1589
    $user = wpinv_checkout_form_get_user( $valid_data );
0 ignored issues
show
Security Bug introduced by
It seems like $valid_data can also be of type false; however, wpinv_checkout_form_get_user() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
1590
1591
    // Let extensions validate fields after user is logged in if user has used login/registration form
1592
    do_action( 'wpinv_checkout_user_error_checks', $user, $valid_data, $_POST );
1593
    
1594
    if ( false === $valid_data || wpinv_get_errors() || ! $user ) {
1595
        if ( $is_ajax ) {
1596
            do_action( 'wpinv_ajax_checkout_errors' );
1597
            die();
1598
        } else {
1599
            return false;
1600
        }
1601
    }
1602
1603
    if ( $is_ajax ) {
1604
        // Save address fields.
1605
        $address_fields = array( 'first_name', 'last_name', 'phone', 'address', 'city', 'country', 'state', 'zip', 'company' );
1606 View Code Duplication
        foreach ( $address_fields as $field ) {
1607
            if ( isset( $user[$field] ) ) {
1608
                $invoice->set( $field, $user[$field] );
1609
            }
1610
1611
            $invoice->save();
1612
        }
1613
1614
        $response['success']            = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1615
        $response['data']['subtotal']   = $invoice->get_subtotal();
1616
        $response['data']['subtotalf']  = $invoice->get_subtotal( true );
1617
        $response['data']['discount']   = $invoice->get_discount();
1618
        $response['data']['discountf']  = $invoice->get_discount( true );
1619
        $response['data']['tax']        = $invoice->get_tax();
1620
        $response['data']['taxf']       = $invoice->get_tax( true );
1621
        $response['data']['total']      = $invoice->get_total();
1622
        $response['data']['totalf']     = $invoice->get_total( true );
1623
	    $response['data']['free']       = $invoice->is_free() && ( ! ( (float) $response['data']['total'] > 0 ) || $invoice->is_free_trial() ) ? true : false;
1624
1625
        wp_send_json( $response );
1626
    }
1627
    
1628
    $user_info = array(
1629
        'user_id'        => $user['user_id'],
1630
        'first_name'     => $user['first_name'],
1631
        'last_name'      => $user['last_name'],
1632
        'email'          => $invoice->get_email(),
1633
        'company'        => $user['company'],
1634
        'phone'          => $user['phone'],
1635
        'address'        => $user['address'],
1636
        'city'           => $user['city'],
1637
        'country'        => $user['country'],
1638
        'state'          => $user['state'],
1639
        'zip'            => $user['zip'],
1640
    );
1641
    
1642
    $cart_items = wpinv_get_cart_contents();
1643
    $discounts  = wpinv_get_cart_discounts();
1644
    
1645
    // Setup invoice information
1646
    $invoice_data = array(
1647
        'invoice_id'        => !empty( $invoice ) ? $invoice->ID : 0,
1648
        'items'             => $cart_items,
1649
        'cart_discounts'    => $discounts,
1650
        'fees'              => wpinv_get_cart_fees(),        // Any arbitrary fees that have been added to the cart
1651
        'subtotal'          => wpinv_get_cart_subtotal( $cart_items ),    // Amount before taxes and discounts
1652
        'discount'          => wpinv_get_cart_items_discount_amount( $cart_items, $discounts ), // Discounted amount
1653
        'tax'               => wpinv_get_cart_tax( $cart_items ),               // Taxed amount
1654
        'price'             => wpinv_get_cart_total( $cart_items, $discounts ),    // Amount after taxes
1655
        'invoice_key'       => $invoice->get_key() ? $invoice->get_key() : $invoice->generate_key(),
1656
        'user_email'        => $invoice->get_email(),
1657
        'date'              => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
1658
        'user_info'         => stripslashes_deep( $user_info ),
1659
        'post_data'         => $_POST,
1660
        'cart_details'      => $cart_items,
1661
        'gateway'           => $valid_data['gateway'],
1662
        'card_info'         => $valid_data['cc_info']
1663
    );
1664
    
1665
    $vat_info   = $wpinv_euvat->current_vat_data();
1666
    if ( is_array( $vat_info ) ) {
1667
        $invoice_data['user_info']['vat_number']        = $vat_info['number'];
1668
        $invoice_data['user_info']['vat_rate']          = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state']);
1669
        $invoice_data['user_info']['adddress_confirmed']    = isset($vat_info['adddress_confirmed']) ? $vat_info['adddress_confirmed'] : false;
1670
1671
        // Add the VAT rate to each item in the cart
1672
        foreach( $invoice_data['cart_details'] as $key => $item_data) {
1673
            $rate = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state'], $item_data['id']);
1674
            $invoice_data['cart_details'][$key]['vat_rate'] = wpinv_round_amount( $rate, 4 );
1675
        }
1676
    }
1677
    
1678
    // Save vat fields.
1679
    $address_fields = array( 'vat_number', 'vat_rate', 'adddress_confirmed' );
1680 View Code Duplication
    foreach ( $address_fields as $field ) {
1681
        if ( isset( $invoice_data['user_info'][$field] ) ) {
1682
            $invoice->set( $field, $invoice_data['user_info'][$field] );
1683
        }
1684
1685
        $invoice->save();
1686
    }
1687
1688
    // Add the user data for hooks
1689
    $valid_data['user'] = $user;
1690
    
1691
    // Allow themes and plugins to hook before the gateway
1692
    do_action( 'wpinv_checkout_before_gateway', $_POST, $user_info, $valid_data );
1693
    
1694
    // If the total amount in the cart is 0, send to the manual gateway. This emulates a free invoice
1695
    if ( !$invoice_data['price'] ) {
1696
        // Revert to manual
1697
        $invoice_data['gateway'] = 'manual';
1698
        $_POST['wpi-gateway'] = 'manual';
1699
    }
1700
    
1701
    // Allow the invoice data to be modified before it is sent to the gateway
1702
    $invoice_data = apply_filters( 'wpinv_data_before_gateway', $invoice_data, $valid_data );
1703
    
1704
    if ( $invoice_data['price'] && $invoice_data['gateway'] == 'manual' ) {
1705
        $mode = 'test';
1706
    } else {
1707
        $mode = wpinv_is_test_mode( $invoice_data['gateway'] ) ? 'test' : 'live';
1708
    }
1709
    
1710
    // Setup the data we're storing in the purchase session
1711
    $session_data = $invoice_data;
1712
    // Make sure credit card numbers are never stored in sessions
1713
    if ( !empty( $session_data['card_info']['card_number'] ) ) {
1714
        unset( $session_data['card_info']['card_number'] );
1715
    }
1716
    
1717
    // Used for showing item links to non logged-in users after purchase, and for other plugins needing purchase data.
1718
    wpinv_set_checkout_session( $invoice_data );
1719
    
1720
    // Set gateway
1721
    $invoice->update_meta( '_wpinv_gateway', $invoice_data['gateway'] );
1722
    $invoice->update_meta( '_wpinv_mode', $mode );
1723
    $invoice->update_meta( '_wpinv_checkout', date_i18n( 'Y-m-d H:i:s', current_time( 'timestamp' ) ) );
1724
    
1725
    do_action( 'wpinv_checkout_before_send_to_gateway', $invoice, $invoice_data );
1726
1727
    // Send info to the gateway for payment processing
1728
    wpinv_send_to_gateway( $invoice_data['gateway'], $invoice_data );
1729
    die();
1730
}
1731
add_action( 'wpinv_payment', 'wpinv_process_checkout' );
1732
1733
function wpinv_get_invoices( $args ) {
1734
    $args = wp_parse_args( $args, array(
1735
        'status'   => array_keys( wpinv_get_invoice_statuses() ),
1736
        'type'     => 'wpi_invoice',
1737
        'parent'   => null,
1738
        'user'     => null,
1739
        'email'    => '',
1740
        'limit'    => get_option( 'posts_per_page' ),
1741
        'offset'   => null,
1742
        'page'     => 1,
1743
        'exclude'  => array(),
1744
        'orderby'  => 'date',
1745
        'order'    => 'DESC',
1746
        'return'   => 'objects',
1747
        'paginate' => false,
1748
    ) );
1749
    
1750
    // Handle some BW compatibility arg names where wp_query args differ in naming.
1751
    $map_legacy = array(
1752
        'numberposts'    => 'limit',
1753
        'post_type'      => 'type',
1754
        'post_status'    => 'status',
1755
        'post_parent'    => 'parent',
1756
        'author'         => 'user',
1757
        'posts_per_page' => 'limit',
1758
        'paged'          => 'page',
1759
    );
1760
1761
    foreach ( $map_legacy as $from => $to ) {
1762
        if ( isset( $args[ $from ] ) ) {
1763
            $args[ $to ] = $args[ $from ];
1764
        }
1765
    }
1766
1767
    if ( get_query_var( 'paged' ) )
1768
        $args['page'] = get_query_var('paged');
1769
    else if ( get_query_var( 'page' ) )
1770
        $args['page'] = get_query_var( 'page' );
1771
    else if ( !empty( $args[ 'page' ] ) )
1772
        $args['page'] = $args[ 'page' ];
1773
    else
1774
        $args['page'] = 1;
1775
1776
    /**
1777
     * Generate WP_Query args. This logic will change if orders are moved to
1778
     * custom tables in the future.
1779
     */
1780
    $wp_query_args = array(
1781
        'post_type'      => 'wpi_invoice',
1782
        'post_status'    => $args['status'],
1783
        'posts_per_page' => $args['limit'],
1784
        'meta_query'     => array(),
1785
        'date_query'     => !empty( $args['date_query'] ) ? $args['date_query'] : array(),
1786
        'fields'         => 'ids',
1787
        'orderby'        => $args['orderby'],
1788
        'order'          => $args['order'],
1789
    );
1790
    
1791
    if ( !empty( $args['user'] ) ) {
1792
        $wp_query_args['author'] = absint( $args['user'] );
1793
    }
1794
1795
    if ( ! is_null( $args['parent'] ) ) {
1796
        $wp_query_args['post_parent'] = absint( $args['parent'] );
1797
    }
1798
1799
    if ( ! is_null( $args['offset'] ) ) {
1800
        $wp_query_args['offset'] = absint( $args['offset'] );
1801
    } else {
1802
        $wp_query_args['paged'] = absint( $args['page'] );
1803
    }
1804
1805
    if ( ! empty( $args['exclude'] ) ) {
1806
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
1807
    }
1808
1809
    if ( ! $args['paginate' ] ) {
1810
        $wp_query_args['no_found_rows'] = true;
1811
    }
1812
1813
    $wp_query_args = apply_filters('wpinv_get_invoices_args', $wp_query_args, $args);
1814
1815
    // Get results.
1816
    $invoices = new WP_Query( $wp_query_args );
1817
1818
    if ( 'objects' === $args['return'] ) {
1819
        $return = array_map( 'wpinv_get_invoice', $invoices->posts );
1820
    } elseif ( 'self' === $args['return'] ) {
1821
        return $invoices;
1822
    } else {
1823
        $return = $invoices->posts;
1824
    }
1825
1826
    if ( $args['paginate' ] ) {
1827
        return (object) array(
1828
            'invoices'      => $return,
1829
            'total'         => $invoices->found_posts,
1830
            'max_num_pages' => $invoices->max_num_pages,
1831
        );
1832
    } else {
1833
        return $return;
1834
    }
1835
}
1836
1837
function wpinv_get_user_invoices_columns() {
1838
    $columns = array(
1839
            'invoice-number'  => array( 'title' => __( 'ID', 'invoicing' ), 'class' => 'text-left' ),
1840
            'created-date'    => array( 'title' => __( 'Created Date', 'invoicing' ), 'class' => 'text-left' ),
1841
            'payment-date'    => array( 'title' => __( 'Payment Date', 'invoicing' ), 'class' => 'text-left' ),
1842
            'invoice-status'  => array( 'title' => __( 'Status', 'invoicing' ), 'class' => 'text-center' ),
1843
            'invoice-total'   => array( 'title' => __( 'Total', 'invoicing' ), 'class' => 'text-right' ),
1844
            'invoice-actions' => array( 'title' => '&nbsp;', 'class' => 'text-center' ),
1845
        );
1846
1847
    return apply_filters( 'wpinv_user_invoices_columns', $columns );
1848
}
1849
1850
function wpinv_payment_receipt( $atts, $content = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $content is not used and could be removed.

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

Loading history...
1851
    global $wpinv_receipt_args;
1852
1853
    $wpinv_receipt_args = shortcode_atts( array(
1854
        'error'           => __( 'Sorry, trouble retrieving payment receipt.', 'invoicing' ),
1855
        'price'           => true,
1856
        'discount'        => true,
1857
        'items'           => true,
1858
        'date'            => true,
1859
        'notes'           => true,
1860
        'invoice_key'     => false,
1861
        'payment_method'  => true,
1862
        'invoice_id'      => true
1863
    ), $atts, 'wpinv_receipt' );
1864
1865
    $session = wpinv_get_checkout_session();
1866
    if ( isset( $_GET['invoice_key'] ) ) {
1867
        $invoice_key = urldecode( $_GET['invoice_key'] );
1868
    } else if ( $session && isset( $session['invoice_key'] ) ) {
1869
        $invoice_key = $session['invoice_key'];
1870
    } elseif ( isset( $wpinv_receipt_args['invoice_key'] ) && $wpinv_receipt_args['invoice_key'] ) {
1871
        $invoice_key = $wpinv_receipt_args['invoice_key'];
1872
    } else if ( isset( $_GET['invoice-id'] ) ) {
1873
        $invoice_key = wpinv_get_payment_key( (int)$_GET['invoice-id'] );
1874
    }
1875
1876
    // No key found
1877
    if ( ! isset( $invoice_key ) ) {
1878
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1879
    }
1880
1881
    $invoice_id    = wpinv_get_invoice_id_by_key( $invoice_key );
0 ignored issues
show
Unused Code introduced by
$invoice_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
1882
    $user_can_view = wpinv_can_view_receipt( $invoice_key );
1883 View Code Duplication
    if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1884
        $invoice_id     = (int)$_GET['invoice-id'];
0 ignored issues
show
Unused Code introduced by
$invoice_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
1885
        $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1886
    }
1887
1888
    // Key was provided, but user is logged out. Offer them the ability to login and view the receipt
1889
    if ( ! $user_can_view && ! empty( $invoice_key ) && ! is_user_logged_in() ) {
1890
        // login redirect
1891
        return '<p class="alert alert-error">' . __( 'You are not allowed to access this section', 'invoicing' ) . '</p>';
1892
    }
1893
1894
    if ( ! apply_filters( 'wpinv_user_can_view_receipt', $user_can_view, $wpinv_receipt_args ) ) {
1895
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1896
    }
1897
1898
    ob_start();
1899
1900
    wpinv_get_template_part( 'wpinv-invoice-receipt' );
1901
1902
    $display = ob_get_clean();
1903
1904
    return $display;
1905
}
1906
1907 View Code Duplication
function wpinv_get_invoice_id_by_key( $key ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
1908
	global $wpdb;
1909
1910
	$invoice_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wpinv_key' AND meta_value = %s LIMIT 1", $key ) );
1911
1912
	if ( $invoice_id != NULL )
1913
		return $invoice_id;
1914
1915
	return 0;
1916
}
1917
1918
function wpinv_can_view_receipt( $invoice_key = '' ) {
1919
	$return = false;
1920
1921
	if ( empty( $invoice_key ) ) {
1922
		return $return;
1923
	}
1924
1925
	global $wpinv_receipt_args;
1926
1927
	$wpinv_receipt_args['id'] = wpinv_get_invoice_id_by_key( $invoice_key );
1928
	if ( isset( $_GET['invoice-id'] ) ) {
1929
		$wpinv_receipt_args['id'] = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? (int)$_GET['invoice-id'] : 0;
1930
	}
1931
1932
	if ( empty( $wpinv_receipt_args['id'] ) ) {
1933
		return $return;
1934
	}
1935
1936
	$invoice = wpinv_get_invoice( $wpinv_receipt_args['id'] );
1937
	if ( !( !empty( $invoice->ID ) && $invoice->get_key() === $invoice_key ) ) {
1938
		return $return;
1939
	}
1940
1941
	if ( is_user_logged_in() ) {
1942
		if ( (int)$invoice->get_user_id() === (int) get_current_user_id() ) {
1943
			$return = true;
1944
		}
1945
	}
1946
1947
	$session = wpinv_get_checkout_session();
1948
	if ( isset( $_GET['invoice_key'] ) || ( $session && isset( $session['invoice_key'] ) ) ) {
1949
		$check_key = isset( $_GET['invoice_key'] ) ? $_GET['invoice_key'] : $session['invoice_key'];
1950
1951
		if ( wpinv_require_login_to_checkout() ) {
1952
			$return = $return && $check_key === $invoice_key;
1953
		} else {
1954
			$return = $check_key === $invoice_key;
1955
		}
1956
	}
1957
1958
	return (bool) apply_filters( 'wpinv_can_view_receipt', $return, $invoice_key );
1959
}
1960
1961
function wpinv_pay_for_invoice() {
1962
    global $wpinv_euvat;
1963
    
1964
    if ( isset( $_GET['invoice_key'] ) ) {
1965
        $checkout_uri   = wpinv_get_checkout_uri();
1966
        $invoice_key    = sanitize_text_field( $_GET['invoice_key'] );
1967
        
1968
        if ( empty( $invoice_key ) ) {
1969
            wpinv_set_error( 'invalid_invoice', __( 'Invoice not found', 'invoicing' ) );
1970
            wp_redirect( $checkout_uri );
1971
            exit();
1972
        }
1973
        
1974
        do_action( 'wpinv_check_pay_for_invoice', $invoice_key );
1975
1976
        $invoice_id    = wpinv_get_invoice_id_by_key( $invoice_key );
1977
        $user_can_view = wpinv_can_view_receipt( $invoice_key );
1978 View Code Duplication
        if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1979
            $invoice_id     = (int)$_GET['invoice-id'];
1980
            $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1981
        }
1982
        
1983
        if ( $invoice_id && $user_can_view && ( $invoice = wpinv_get_invoice( $invoice_id ) ) ) {
1984
            if ( $invoice->needs_payment() ) {
1985
                $data                   = array();
1986
                $data['invoice_id']     = $invoice_id;
1987
                $data['cart_discounts'] = $invoice->get_discounts( true );
1988
                
1989
                wpinv_set_checkout_session( $data );
1990
                
1991
                if ( wpinv_get_option( 'vat_ip_country_default' ) ) {
1992
                    $_POST['country']   = $wpinv_euvat->get_country_by_ip();
1993
                    $_POST['state']     = $_POST['country'] == $invoice->country ? $invoice->state : '';
1994
                    
1995
                    wpinv_recalculate_tax( true );
1996
                }
1997
                
1998
            } else {
1999
                $checkout_uri = $invoice->get_view_url();
2000
            }
2001
        } else {
2002
            wpinv_set_error( 'invalid_invoice', __( 'You are not allowed to view this invoice', 'invoicing' ) );
2003
            
2004
            $checkout_uri = is_user_logged_in() ? wpinv_get_history_page_uri() : wp_login_url( get_permalink() );
2005
        }
2006
        
2007
        wp_safe_redirect( $checkout_uri );
2008
        exit();
2009
    }
2010
}
2011
add_action( 'wpinv_pay_for_invoice', 'wpinv_pay_for_invoice' );
2012
2013
function wpinv_handle_pay_via_invoice_link( $invoice_key ) {
2014
    if ( !empty( $invoice_key ) && !empty( $_REQUEST['_wpipay'] ) && !is_user_logged_in() && $invoice_id = wpinv_get_invoice_id_by_key( $invoice_key ) ) {
2015
        if ( $invoice = wpinv_get_invoice( $invoice_id ) ) {
2016
            $user_id = $invoice->get_user_id();
2017
            $secret = sanitize_text_field( $_GET['_wpipay'] );
2018
            
2019
            if ( $secret === md5( $user_id . '::' . $invoice->get_email() . '::' . $invoice_key ) ) { // valid invoice link
2020
                $redirect_to = remove_query_arg( '_wpipay', get_permalink() );
2021
                
2022
                wpinv_guest_redirect( $redirect_to, $user_id );
2023
                exit();
2024
            }
2025
        }
2026
    }
2027
}
2028
add_action( 'wpinv_check_pay_for_invoice', 'wpinv_handle_pay_via_invoice_link' );
2029
2030
function wpinv_set_payment_transaction_id( $invoice_id = 0, $transaction_id = '' ) {
2031
    $invoice_id = is_object( $invoice_id ) && !empty( $invoice_id->ID ) ? $invoice_id : $invoice_id;
2032
    
2033
    if ( empty( $invoice_id ) && $invoice_id > 0 ) {
2034
        return false;
2035
    }
2036
    
2037
    if ( empty( $transaction_id ) ) {
2038
        $transaction_id = $invoice_id;
2039
    }
2040
2041
    $transaction_id = apply_filters( 'wpinv_set_payment_transaction_id', $transaction_id, $invoice_id );
2042
    
2043
    return wpinv_update_invoice_meta( $invoice_id, '_wpinv_transaction_id', $transaction_id );
2044
}
2045
2046
function wpinv_invoice_status_label( $status, $status_display = '' ) {
2047
    if ( empty( $status_display ) ) {
2048
        $status_display = wpinv_status_nicename( $status );
2049
    }
2050
    
2051
    switch ( $status ) {
2052
        case 'publish' :
2053
        case 'wpi-renewal' :
2054
            $class = 'label-success';
2055
        break;
2056
        case 'wpi-pending' :
2057
            $class = 'label-primary';
2058
        break;
2059
        case 'wpi-processing' :
2060
            $class = 'label-warning';
2061
        break;
2062
        case 'wpi-onhold' :
2063
            $class = 'label-info';
2064
        break;
2065
        case 'wpi-cancelled' :
2066
        case 'wpi-failed' :
2067
            $class = 'label-danger';
2068
        break;
2069
        default:
2070
            $class = 'label-default';
2071
        break;
2072
    }
2073
    
2074
    $label = '<span class="label label-inv-' . $status . ' ' . $class . '">' . $status_display . '</span>';
2075
    
2076
    return apply_filters( 'wpinv_invoice_status_label', $label, $status, $status_display );
2077
}
2078
2079
function wpinv_format_invoice_number( $number, $type = '' ) {
2080
    $check = apply_filters( 'wpinv_pre_format_invoice_number', null, $number, $type );
2081
    if ( null !== $check ) {
2082
        return $check;
2083
    }
2084
2085
    if ( !empty( $number ) && !is_numeric( $number ) ) {
2086
        return $number;
2087
    }
2088
2089
    $padd  = wpinv_get_option( 'invoice_number_padd' );
2090
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2091
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2092
    
2093
    $padd = absint( $padd );
2094
    $formatted_number = absint( $number );
2095
    
2096
    if ( $padd > 0 ) {
2097
        $formatted_number = zeroise( $formatted_number, $padd );
2098
    }    
2099
2100
    $formatted_number = $prefix . $formatted_number . $postfix;
2101
2102
    return apply_filters( 'wpinv_format_invoice_number', $formatted_number, $number, $prefix, $postfix, $padd );
2103
}
2104
2105
function wpinv_get_next_invoice_number( $type = '' ) {
2106
    $check = apply_filters( 'wpinv_get_pre_next_invoice_number', null, $type );
2107
    if ( null !== $check ) {
2108
        return $check;
2109
    }
2110
    
2111
    if ( !wpinv_sequential_number_active() ) {
2112
        return false;
2113
    }
2114
2115
    $number = $last_number = get_option( 'wpinv_last_invoice_number', 0 );
2116
    $start  = wpinv_get_option( 'invoice_sequence_start', 1 );
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2117
    if ( !absint( $start ) > 0 ) {
2118
        $start = 1;
2119
    }
2120
    $increment_number = true;
2121
    $save_number = false;
2122
2123
    if ( !empty( $number ) && !is_numeric( $number ) && $number == wpinv_format_invoice_number( $number ) ) {
2124
        $number = wpinv_clean_invoice_number( $number );
2125
    }
2126
2127
    if ( empty( $number ) ) {
2128
        if ( !( $last_number === 0 || $last_number === '0' ) ) {
2129
            $last_invoice = wpinv_get_invoices( array( 'limit' => 1, 'order' => 'DESC', 'orderby' => 'ID', 'return' => 'posts', 'fields' => 'ids', 'status' => array_keys( wpinv_get_invoice_statuses( true, true ) ) ) );
2130
2131
            if ( !empty( $last_invoice[0] ) && $invoice_number = wpinv_get_invoice_number( $last_invoice[0] ) ) {
2132
                if ( is_numeric( $invoice_number ) ) {
2133
                    $number = $invoice_number;
2134
                } else {
2135
                    $number = wpinv_clean_invoice_number( $invoice_number );
2136
                }
2137
            }
2138
2139 View Code Duplication
            if ( empty( $number ) ) {
2140
                $increment_number = false;
2141
                $number = $start;
2142
                $save_number = ( $number - 1 );
2143
            } else {
2144
                $save_number = $number;
2145
            }
2146
        }
2147
    }
2148
2149 View Code Duplication
    if ( $start > $number ) {
2150
        $increment_number = false;
2151
        $number = $start;
2152
        $save_number = ( $number - 1 );
2153
    }
2154
2155
    if ( $save_number !== false ) {
2156
        update_option( 'wpinv_last_invoice_number', $save_number );
2157
    }
2158
    
2159
    $increment_number = apply_filters( 'wpinv_increment_payment_number', $increment_number, $number );
2160
2161
    if ( $increment_number ) {
2162
        $number++;
2163
    }
2164
2165
    return apply_filters( 'wpinv_get_next_invoice_number', $number );
2166
}
2167
2168
function wpinv_clean_invoice_number( $number, $type = '' ) {
2169
    $check = apply_filters( 'wpinv_pre_clean_invoice_number', null, $number, $type );
2170
    if ( null !== $check ) {
2171
        return $check;
2172
    }
2173
    
2174
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2175
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2176
2177
    $number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
2178
2179
    $length      = strlen( $number );
2180
    $postfix_pos = strrpos( $number, $postfix );
2181
    
2182
    if ( false !== $postfix_pos ) {
2183
        $number      = substr_replace( $number, '', $postfix_pos, $length );
2184
    }
2185
2186
    $number = intval( $number );
2187
2188
    return apply_filters( 'wpinv_clean_invoice_number', $number, $prefix, $postfix );
2189
}
2190
2191
function wpinv_save_number_post_saved( $post_ID, $post, $update ) {
2192
    global $wpdb;
2193
2194
    if ( !$update && !get_post_meta( $post_ID, '_wpinv_number', true ) ) {
2195
        wpinv_update_invoice_number( $post_ID, $post->post_status != 'auto-draft', $post->post_type );
2196
    }
2197
2198
    if ( !$update ) {
2199
        $wpdb->update( $wpdb->posts, array( 'post_name' => wpinv_generate_post_name( $post_ID ) ), array( 'ID' => $post_ID ) );
2200
        clean_post_cache( $post_ID );
2201
    }
2202
}
2203
add_action( 'save_post_wpi_invoice', 'wpinv_save_number_post_saved', 1, 3 );
2204
2205
function wpinv_save_number_post_updated( $post_ID, $post_after, $post_before ) {
2206
    if ( !empty( $post_after->post_type ) && $post_after->post_type == 'wpi_invoice' && $post_before->post_status == 'auto-draft' && $post_after->post_status != $post_before->post_status ) {
2207
        wpinv_update_invoice_number( $post_ID, true, $post_after->post_type );
2208
    }
2209
}
2210
add_action( 'post_updated', 'wpinv_save_number_post_updated', 1, 3 );
2211
2212
function wpinv_update_invoice_number( $post_ID, $save_sequential = false, $type = '' ) {
2213
    global $wpdb;
2214
    
2215
    $check = apply_filters( 'wpinv_pre_update_invoice_number', null, $post_ID, $save_sequential, $type );
2216
    if ( null !== $check ) {
2217
        return $check;
2218
    }
2219
2220
    if ( wpinv_sequential_number_active() ) {
2221
        $number = wpinv_get_next_invoice_number();
2222
2223
        if ( $save_sequential ) {
2224
            update_option( 'wpinv_last_invoice_number', $number );
2225
        }
2226
    } else {
2227
        $number = $post_ID;
2228
    }
2229
2230
    $number = wpinv_format_invoice_number( $number );
2231
2232
    update_post_meta( $post_ID, '_wpinv_number', $number );
2233
2234
    $wpdb->update( $wpdb->posts, array( 'post_title' => $number ), array( 'ID' => $post_ID ) );
2235
2236
    clean_post_cache( $post_ID );
2237
2238
    return $number;
2239
}
2240
2241
function wpinv_post_name_prefix( $post_type = 'wpi_invoice' ) {
2242
    return apply_filters( 'wpinv_post_name_prefix', 'inv-', $post_type );
2243
}
2244
2245
function wpinv_generate_post_name( $post_ID ) {
2246
    $prefix = wpinv_post_name_prefix( get_post_type( $post_ID ) );
2247
    $post_name = sanitize_title( $prefix . $post_ID );
2248
2249
    return apply_filters( 'wpinv_generate_post_name', $post_name, $post_ID, $prefix );
2250
}
2251
2252
function wpinv_is_invoice_viewed( $invoice_id ) {
2253
    if ( empty( $invoice_id ) ) {
2254
        return false;
2255
    }
2256
2257
    $viewed_meta = get_post_meta( $invoice_id, '_wpinv_is_viewed', true );
2258
2259
    return apply_filters( 'wpinv_is_invoice_viewed', 1 === (int)$viewed_meta, $invoice_id );
2260
}
2261
2262
function wpinv_mark_invoice_viewed() {
2263
2264
    if ( isset( $_GET['invoice_key'] ) || is_singular( 'wpi_invoice' ) || is_singular( 'wpi_quote' ) ) {
2265
        $invoice_key = isset( $_GET['invoice_key'] ) ? urldecode($_GET['invoice_key']) : '';
2266
	    global $post;
2267
2268
        if(!empty($invoice_key)){
2269
	        $invoice_id = wpinv_get_invoice_id_by_key($invoice_key);
2270
        } else if(!empty( $post ) && ($post->post_type == 'wpi_invoice' || $post->post_type == 'wpi_quote')) {
2271
			$invoice_id = $post->ID;
2272
        } else {
2273
        	return;
2274
        }
2275
2276
        $invoice = new WPInv_Invoice($invoice_id);
2277
2278
        if(!$invoice_id){
2279
            return;
2280
        }
2281
2282
	    if ( is_user_logged_in() ) {
2283
		    if ( (int)$invoice->get_user_id() === get_current_user_id() ) {
2284
			    update_post_meta($invoice_id,'_wpinv_is_viewed', 1);
2285
		    } else if ( !wpinv_require_login_to_checkout() && isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2286
			    update_post_meta($invoice_id,'_wpinv_is_viewed', 1);
2287
		    }
2288
	    } else {
2289
		    if ( !wpinv_require_login_to_checkout() && isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2290
			    update_post_meta($invoice_id,'_wpinv_is_viewed', 1);
2291
		    }
2292
	    }
2293
    }
2294
2295
}
2296
add_action( 'template_redirect', 'wpinv_mark_invoice_viewed' );
2297
2298
function wpinv_get_subscription( $invoice, $by_parent = false ) {
2299
    if ( empty( $invoice ) ) {
2300
        return false;
2301
    }
2302
    
2303
    if ( ! is_object( $invoice ) && is_scalar( $invoice ) ) {
2304
        $invoice = wpinv_get_invoice( $invoice );
2305
    }
2306
    
2307
    if ( !( is_object( $invoice ) && ! empty( $invoice->ID ) && $invoice->is_recurring() ) ) {
2308
        return false;
2309
    }
2310
    
2311
    $invoice_id = ! $by_parent && ! empty( $invoice->parent_invoice ) ? $invoice->parent_invoice : $invoice->ID;
2312
    
2313
    $subs_db    = new WPInv_Subscriptions_DB;
2314
    $subs       = $subs_db->get_subscriptions( array( 'parent_payment_id' => $invoice_id, 'number' => 1 ) );
2315
    
2316
    if ( ! empty( $subs ) ) {
2317
        return reset( $subs );
2318
    }
2319
    
2320
    return false;
2321
}
2322
2323
function wpinv_filter_posts_clauses( $clauses, $wp_query ) {
2324
    global $wpdb;
2325
2326
    if ( ! empty( $wp_query->query_vars['orderby'] ) && $wp_query->query_vars['orderby'] == 'invoice_date' ) {
2327
        if ( !empty( $clauses['join'] ) ) {
2328
            $clauses['join'] .= " ";
2329
        }
2330
2331
        if ( !empty( $clauses['fields'] ) ) {
2332
            $clauses['fields'] .= ", ";
2333
        }
2334
2335
        $clauses['join'] .= "LEFT JOIN {$wpdb->postmeta} ON ( {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_wpinv_completed_date' )";
2336
        $clauses['fields'] .= "IF( {$wpdb->postmeta}.meta_value, {$wpdb->postmeta}.meta_value, {$wpdb->posts}.post_date ) AS invoice_date";
2337
        $clauses['orderby'] = "invoice_date DESC, {$wpdb->posts}.post_date DESC, {$wpdb->posts}.ID DESC";
2338
    }
2339
2340
    return $clauses;
2341
}
2342
add_filter( 'posts_clauses', 'wpinv_filter_posts_clauses', 10, 2 );