Passed
Pull Request — master (#126)
by Kiran
03:46
created

wpinv-invoice-functions.php ➔ wpinv_get_subscription()   C

Complexity

Conditions 9
Paths 11

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 13
nc 11
nop 1
dl 0
loc 24
rs 5.3563
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( '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 ) ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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
    return $invoice;
480
}
481
482
function wpinv_get_invoice_cart( $invoice_id = 0 ) {
483
    return wpinv_get_invoice( $invoice_id, true );
484
}
485
486
function wpinv_get_invoice_description( $invoice_id = 0 ) {
487
    $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...
488
    return $invoice->get_description();
489
}
490
491
function wpinv_get_invoice_currency_code( $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_currency();
494
}
495
496
function wpinv_get_payment_user_email( $invoice_id ) {
497
    $invoice = new WPInv_Invoice( $invoice_id );
498
    return $invoice->get_email();
499
}
500
501
function wpinv_get_user_id( $invoice_id ) {
502
    $invoice = new WPInv_Invoice( $invoice_id );
503
    return $invoice->get_user_id();
504
}
505
506
function wpinv_get_invoice_status( $invoice_id, $return_label = false ) {
507
    $invoice = new WPInv_Invoice( $invoice_id );
508
    
509
    return $invoice->get_status( $return_label );
510
}
511
512
function wpinv_get_payment_gateway( $invoice_id, $return_label = false ) {
513
    $invoice = new WPInv_Invoice( $invoice_id );
514
    
515
    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...
516
}
517
518
function wpinv_get_payment_gateway_name( $invoice_id ) {
519
    $invoice = new WPInv_Invoice( $invoice_id );
520
    
521
    return $invoice->get_gateway_title();
522
}
523
524
function wpinv_get_payment_transaction_id( $invoice_id ) {
525
    $invoice = new WPInv_Invoice( $invoice_id );
526
    
527
    return $invoice->get_transaction_id();
528
}
529
530 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...
531
    global $wpdb;
532
533
    $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 ) );
534
535
    if ( $invoice_id != NULL )
536
        return $invoice_id;
537
538
    return 0;
539
}
540
541
function wpinv_get_invoice_meta( $invoice_id = 0, $meta_key = '_wpinv_payment_meta', $single = true ) {
542
    $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...
543
544
    return $invoice->get_meta( $meta_key, $single );
545
}
546
547
function wpinv_update_invoice_meta( $invoice_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
548
    $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...
549
    
550
    return $invoice->update_meta( $meta_key, $meta_value, $prev_value );
551
}
552
553
function wpinv_get_items( $invoice_id = 0 ) {
554
    $invoice            = wpinv_get_invoice( $invoice_id );
555
    
556
    $items              = $invoice->get_items();
557
    $invoice_currency   = $invoice->get_currency();
558
559 View Code Duplication
    if ( !empty( $items ) && is_array( $items ) ) {
560
        foreach ( $items as $key => $item ) {
561
            $items[$key]['currency'] = $invoice_currency;
562
563
            if ( !isset( $cart_item['subtotal'] ) ) {
564
                $items[$key]['subtotal'] = $items[$key]['amount'] * 1;
565
            }
566
        }
567
    }
568
569
    return apply_filters( 'wpinv_get_items', $items, $invoice_id );
570
}
571
572
function wpinv_get_fees( $invoice_id = 0 ) {
573
    $invoice           = wpinv_get_invoice( $invoice_id );
574
    $fees              = $invoice->get_fees();
575
576
    return apply_filters( 'wpinv_get_fees', $fees, $invoice_id );
577
}
578
579
function wpinv_get_invoice_ip( $invoice_id ) {
580
    $invoice = new WPInv_Invoice( $invoice_id );
581
    return $invoice->get_ip();
582
}
583
584
function wpinv_get_invoice_user_info( $invoice_id ) {
585
    $invoice = new WPInv_Invoice( $invoice_id );
586
    return $invoice->get_user_info();
587
}
588
589
function wpinv_subtotal( $invoice_id = 0, $currency = false ) {
590
    $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...
591
592
    return $invoice->get_subtotal( $currency );
593
}
594
595
function wpinv_tax( $invoice_id = 0, $currency = false ) {
596
    $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...
597
598
    return $invoice->get_tax( $currency );
599
}
600
601
function wpinv_discount( $invoice_id = 0, $currency = false, $dash = false ) {
602
    $invoice = wpinv_get_invoice( $invoice_id );
603
604
    return $invoice->get_discount( $currency, $dash );
605
}
606
607
function wpinv_discount_code( $invoice_id = 0 ) {
608
    $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...
609
610
    return $invoice->get_discount_code();
611
}
612
613
function wpinv_payment_total( $invoice_id = 0, $currency = false ) {
614
    $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...
615
616
    return $invoice->get_total( $currency );
617
}
618
619
function wpinv_get_date_created( $invoice_id = 0, $format = '' ) {
620
    $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...
621
622
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
623
    $date_created   = $invoice->get_created_date();
624
    $date_created   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_created ) ) : '';
625
626
    return $date_created;
627
}
628
629
function wpinv_get_invoice_date( $invoice_id = 0, $format = '', $default = true ) {
630
    $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...
631
    
632
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
633
    $date_completed = $invoice->get_completed_date();
634
    $invoice_date   = $date_completed != '' && $date_completed != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_completed ) ) : '';
635
    if ( $invoice_date == '' && $default ) {
636
        $invoice_date   = wpinv_get_date_created( $invoice_id, $format );
637
    }
638
639
    return $invoice_date;
640
}
641
642
function wpinv_get_invoice_vat_number( $invoice_id = 0 ) {
643
    $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...
644
    
645
    return $invoice->vat_number;
646
}
647
648
function wpinv_insert_payment_note( $invoice_id = 0, $note = '', $user_type = false, $added_by_user = false, $system = false ) {
649
    $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...
650
651
    return $invoice->add_note( $note, $user_type, $added_by_user, $system );
652
}
653
654
function wpinv_get_invoice_notes( $invoice_id = 0, $type = '' ) {
655
    global $invoicing;
656
    
657
    if ( empty( $invoice_id ) ) {
658
        return NULL;
659
    }
660
    
661
    $notes = $invoicing->notes->get_invoice_notes( $invoice_id, $type );
662
    
663
    return apply_filters( 'wpinv_invoice_notes', $notes, $invoice_id, $type );
664
}
665
666
function wpinv_get_payment_key( $invoice_id = 0 ) {
667
	$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...
668
    return $invoice->get_key();
669
}
670
671
function wpinv_get_invoice_number( $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_number();
674
}
675
676
function wpinv_get_cart_discountable_subtotal( $code_id ) {
677
    $cart_items = wpinv_get_cart_content_details();
678
    $items      = array();
679
680
    $excluded_items = wpinv_get_discount_excluded_items( $code_id );
681
682
    if( $cart_items ) {
683
684
        foreach( $cart_items as $item ) {
685
686
            if( ! in_array( $item['id'], $excluded_items ) ) {
687
                $items[] =  $item;
688
            }
689
        }
690
    }
691
692
    $subtotal = wpinv_get_cart_items_subtotal( $items );
693
694
    return apply_filters( 'wpinv_get_cart_discountable_subtotal', $subtotal );
695
}
696
697
function wpinv_get_cart_items_subtotal( $items ) {
698
    $subtotal = 0.00;
699
700
    if ( is_array( $items ) && ! empty( $items ) ) {
701
        $prices = wp_list_pluck( $items, 'subtotal' );
702
703
        if( is_array( $prices ) ) {
704
            $subtotal = array_sum( $prices );
705
        } else {
706
            $subtotal = 0.00;
707
        }
708
709
        if( $subtotal < 0 ) {
710
            $subtotal = 0.00;
711
        }
712
    }
713
714
    return apply_filters( 'wpinv_get_cart_items_subtotal', $subtotal );
715
}
716
717
function wpinv_get_cart_subtotal( $items = array() ) {
718
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
719
    $subtotal = wpinv_get_cart_items_subtotal( $items );
720
721
    return apply_filters( 'wpinv_get_cart_subtotal', $subtotal );
722
}
723
724
function wpinv_cart_subtotal( $items = array() ) {
725
    $price = wpinv_price( wpinv_format_amount( wpinv_get_cart_subtotal( $items ) ) );
726
727
    return $price;
728
}
729
730
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...
731
    $subtotal  = (float)wpinv_get_cart_subtotal( $items );
732
    $discounts = (float)wpinv_get_cart_discounted_amount( $items );
733
    $cart_tax  = (float)wpinv_get_cart_tax( $items );
734
    $fees      = (float)wpinv_get_cart_fee_total();
735
    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...
736
        $total = 0;
737
    } else {
738
        $total     = $subtotal - $discounts + $cart_tax + $fees;
739
    }
740
741
    if ( $total < 0 ) {
742
        $total = 0.00;
743
    }
744
    
745
    $total = (float)apply_filters( 'wpinv_get_cart_total', $total, $items );
746
747
    return wpinv_sanitize_amount( $total );
748
}
749
750
function wpinv_cart_total( $cart_items = array(), $echo = true, $invoice = array() ) {
751
    global $cart_total;
752
    $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...
753
    $total = apply_filters( 'wpinv_cart_total', $total, $cart_items, $invoice );
754
    
755
    $cart_total = $total;
756
757
    if ( !$echo ) {
758
        return $total;
759
    }
760
761
    echo $total;
762
}
763
764 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...
765
    $cart_tax = 0;
766
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
767
768
    if ( $items ) {
769
        $taxes = wp_list_pluck( $items, 'tax' );
770
771
        if( is_array( $taxes ) ) {
772
            $cart_tax = array_sum( $taxes );
773
        }
774
    }
775
776
    $cart_tax += wpinv_get_cart_fee_tax();
777
778
    return apply_filters( 'wpinv_get_cart_tax', wpinv_sanitize_amount( $cart_tax ) );
779
}
780
781 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...
782
    $cart_tax = wpinv_get_cart_tax( $items );
783
    $cart_tax = wpinv_price( wpinv_format_amount( $cart_tax ) );
784
785
    $tax = apply_filters( 'wpinv_cart_tax', $cart_tax, $items );
786
787
    if ( !$echo ) {
788
        return $tax;
789
    }
790
791
    echo $tax;
792
}
793
794
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...
795
    $invoice = wpinv_get_invoice_cart();
796
    $cart_discount_code = !empty( $invoice ) ? $invoice->get_discount_code() : '';
797
    
798
    return apply_filters( 'wpinv_get_cart_discount_code', $cart_discount_code );
799
}
800
801
function wpinv_cart_discount_code( $items = array(), $echo = false ) {
802
    $cart_discount_code = wpinv_get_cart_discount_code( $items );
803
804
    if ( $cart_discount_code != '' ) {
805
        $cart_discount_code = ' (' . $cart_discount_code . ')';
806
    }
807
    
808
    $discount_code = apply_filters( 'wpinv_cart_discount_code', $cart_discount_code, $items );
809
810
    if ( !$echo ) {
811
        return $discount_code;
812
    }
813
814
    echo $discount_code;
815
}
816
817
function wpinv_get_cart_discount( $items = array() ) {
818
    $invoice = wpinv_get_invoice_cart();
819
    $cart_discount = !empty( $invoice ) ? $invoice->get_discount() : 0;
820
    
821
    return apply_filters( 'wpinv_get_cart_discount', wpinv_sanitize_amount( $cart_discount ), $items );
822
}
823
824 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...
825
    $cart_discount = wpinv_get_cart_discount( $items );
826
    $cart_discount = wpinv_price( wpinv_format_amount( $cart_discount ) );
827
828
    $discount = apply_filters( 'wpinv_cart_discount', $cart_discount, $items );
829
830
    if ( !$echo ) {
831
        return $discount;
832
    }
833
834
    echo $discount;
835
}
836
837
function wpinv_get_cart_fees( $type = 'all', $item_id = 0 ) {
838
    $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...
839
    
840
    return $item->get_fees( $type, $item_id );
841
}
842
843
function wpinv_get_cart_fee_total() {
844
    $total  = 0;
845
    $fees = wpinv_get_cart_fees();
846
    
847
    if ( $fees ) {
848
        foreach ( $fees as $fee_id => $fee ) {
849
            $total += $fee['amount'];
850
        }
851
    }
852
853
    return apply_filters( 'wpinv_get_cart_fee_total', $total );
854
}
855
856
function wpinv_get_cart_fee_tax() {
857
    $tax  = 0;
858
    $fees = wpinv_get_cart_fees();
859
860
    if ( $fees ) {
861
        foreach ( $fees as $fee_id => $fee ) {
862
            if( ! empty( $fee['no_tax'] ) ) {
863
                continue;
864
            }
865
866
            $tax += wpinv_calculate_tax( $fee['amount'] );
867
        }
868
    }
869
870
    return apply_filters( 'wpinv_get_cart_fee_tax', $tax );
871
}
872
873
function wpinv_cart_has_recurring_item() {
874
    $cart_items = wpinv_get_cart_contents();
875
    
876
    if ( empty( $cart_items ) ) {
877
        return false;
878
    }
879
    
880
    $has_subscription = false;
881 View Code Duplication
    foreach( $cart_items as $cart_item ) {
882
        if ( !empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] )  ) {
883
            $has_subscription = true;
884
            break;
885
        }
886
    }
887
    
888
    return apply_filters( 'wpinv_cart_has_recurring_item', $has_subscription, $cart_items );
889
}
890
891
function wpinv_cart_has_free_trial() {
892
    $invoice = wpinv_get_invoice_cart();
893
    
894
    $free_trial = false;
895
    
896
    if ( !empty( $invoice ) && $invoice->is_free_trial() ) {
897
        $free_trial = true;
898
    }
899
    
900
    return apply_filters( 'wpinv_cart_has_free_trial', $free_trial, $invoice );
901
}
902
903
function wpinv_get_cart_contents() {
904
    $cart_details = wpinv_get_cart_details();
905
    
906
    return apply_filters( 'wpinv_get_cart_contents', $cart_details );
907
}
908
909
function wpinv_get_cart_content_details() {
910
    global $wpinv_euvat, $wpi_current_id, $wpi_item_id, $wpinv_is_last_cart_item, $wpinv_flat_discount_total;
911
    $cart_items = wpinv_get_cart_contents();
912
    
913
    if ( empty( $cart_items ) ) {
914
        return false;
915
    }
916
    $invoice = wpinv_get_invoice_cart();
917
918
    $details = array();
919
    $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...
920
    
921
    if ( empty( $_POST['country'] ) ) {
922
        $_POST['country'] = $invoice->country;
923
    }
924
    if ( !isset( $_POST['state'] ) ) {
925
        $_POST['state'] = $invoice->state;
926
    }
927
928
    foreach( $cart_items as $key => $item ) {
929
        $item_id            = isset( $item['id'] ) ? sanitize_text_field( $item['id'] ) : '';
930
        if ( empty( $item_id ) ) {
931
            continue;
932
        }
933
        
934
        $wpi_current_id         = $invoice->ID;
935
        $wpi_item_id            = $item_id;
936
        
937
        if ( isset( $item['custom_price'] ) && $item['custom_price'] !== '' ) {
938
            $item_price = $item['custom_price'];
939
        } else {
940
            if ( isset( $item['item_price'] ) && $item['item_price'] !== '' && $item['item_price'] !== false ) {
941
                $item_price = $item['item_price'];
942
            } else {
943
                $item_price = wpinv_get_item_price( $item_id );
944
            }
945
        }
946
        $discount           = wpinv_get_cart_item_discount_amount( $item );
947
        $discount           = apply_filters( 'wpinv_get_cart_content_details_item_discount_amount', $discount, $item );
948
        $quantity           = wpinv_get_cart_item_quantity( $item );
949
        $fees               = wpinv_get_cart_fees( 'fee', $item_id );
950
        
951
        $subtotal           = $item_price * $quantity;
952
        $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...
953
        $tax_class          = $wpinv_euvat->get_item_class( $item_id );
954
        $tax                = wpinv_get_cart_item_tax( $item_id, $subtotal - $discount );
955
        
956
        if ( wpinv_prices_include_tax() ) {
957
            $subtotal -= wpinv_round_amount( $tax );
958
        }
959
        
960
        $total              = $subtotal - $discount + $tax;
961
        
962
        // Do not allow totals to go negatve
963
        if( $total < 0 ) {
964
            $total = 0;
965
        }
966
        
967
        $details[ $key ]  = array(
968
            'id'                => $item_id,
969
            'name'              => !empty($item['name']) ? $item['name'] : get_the_title( $item_id ),
970
            'item_price'        => wpinv_round_amount( $item_price ),
971
            'custom_price'      => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
972
            'quantity'          => $quantity,
973
            'discount'          => wpinv_round_amount( $discount ),
974
            'subtotal'          => wpinv_round_amount( $subtotal ),
975
            'tax'               => wpinv_round_amount( $tax ),
976
            'price'             => wpinv_round_amount( $total ),
977
            'vat_rates_class'   => $tax_class,
978
            'vat_rate'          => $tax_rate,
979
            'meta'              => isset( $item['meta'] ) ? $item['meta'] : array(),
980
            'fees'              => $fees,
981
        );
982
        
983
        if ( $wpinv_is_last_cart_item ) {
984
            $wpinv_is_last_cart_item   = false;
985
            $wpinv_flat_discount_total = 0.00;
986
        }
987
    }
988
    
989
    return $details;
990
}
991
992
function wpinv_get_cart_details( $invoice_id = 0 ) {
993
    global $ajax_cart_details;
994
995
    $invoice      = wpinv_get_invoice_cart( $invoice_id );
996
    $cart_details = !empty( $ajax_cart_details ) ? $ajax_cart_details : $invoice->cart_details;
997
998
    $invoice_currency = $invoice->currency;
999
1000 View Code Duplication
    if ( ! empty( $cart_details ) && is_array( $cart_details ) ) {
1001
        foreach ( $cart_details as $key => $cart_item ) {
1002
            $cart_details[ $key ]['currency'] = $invoice_currency;
1003
1004
            if ( ! isset( $cart_item['subtotal'] ) ) {
1005
                $cart_details[ $key ]['subtotal'] = $cart_item['price'];
1006
            }
1007
        }
1008
    }
1009
1010
    return apply_filters( 'wpinv_get_cart_details', $cart_details, $invoice_id );
1011
}
1012
1013
function wpinv_record_status_change( $invoice_id, $new_status, $old_status ) {
1014
    if ( 'wpi_invoice' != get_post_type( $invoice_id ) ) {
1015
        return;
1016
    }
1017
1018
    $invoice    = wpinv_get_invoice( $invoice_id );
1019
    
1020
    $old_status = wpinv_status_nicename( $old_status );
1021
    $new_status = wpinv_status_nicename( $new_status );
1022
1023
    $status_change = sprintf( __( 'Invoice status changed from %s to %s', 'invoicing' ), $old_status, $new_status );
1024
    
1025
    // Add note
1026
    return $invoice->add_note( $status_change, false, false, true );
1027
}
1028
add_action( 'wpinv_update_status', 'wpinv_record_status_change', 100, 3 );
1029
1030
function wpinv_complete_payment( $invoice_id, $new_status, $old_status ) {
1031
    global $wpi_has_free_trial;
1032
    
1033
    $wpi_has_free_trial = false;
1034
    
1035
    if ( $old_status == 'publish' ) {
1036
        return; // Make sure that payments are only paid once
1037
    }
1038
1039
    // Make sure the payment completion is only processed when new status is paid
1040
    if ( $new_status != 'publish' ) {
1041
        return;
1042
    }
1043
1044
    $invoice = new WPInv_Invoice( $invoice_id );
1045
    if ( empty( $invoice ) ) {
1046
        return;
1047
    }
1048
1049
    $wpi_has_free_trial = $invoice->is_free_trial();
1050
    $completed_date = $invoice->completed_date;
1051
    $cart_details   = $invoice->cart_details;
1052
1053
    do_action( 'wpinv_pre_complete_payment', $invoice_id );
1054
1055
    if ( is_array( $cart_details ) ) {
1056
        // Increase purchase count and earnings
1057
        foreach ( $cart_details as $cart_index => $item ) {
1058
            // Ensure these actions only run once, ever
1059
            if ( empty( $completed_date ) ) {
1060
                do_action( 'wpinv_complete_item_payment', $item['id'], $invoice_id, $item, $cart_index );
1061
            }
1062
        }
1063
    }
1064
    
1065
    // Check for discount codes and increment their use counts
1066
    if ( $discounts = $invoice->get_discounts( true ) ) {
1067
        if( ! empty( $discounts ) ) {
1068
            foreach( $discounts as $code ) {
1069
                wpinv_increase_discount_usage( $code );
1070
            }
1071
        }
1072
    }
1073
    
1074
    // Ensure this action only runs once ever
1075
    if( empty( $completed_date ) ) {
1076
        // Save the completed date
1077
        $invoice->set( 'completed_date', current_time( 'mysql', 0 ) );
1078
        $invoice->save();
1079
1080
        do_action( 'wpinv_complete_payment', $invoice_id );
1081
    }
1082
1083
    // Empty the shopping cart
1084
    wpinv_empty_cart();
1085
}
1086
add_action( 'wpinv_update_status', 'wpinv_complete_payment', 100, 3 );
1087
1088
function wpinv_update_payment_status( $invoice_id, $new_status = 'publish' ) {    
1089
    $invoice = !empty( $invoice_id ) && is_object( $invoice_id ) ? $invoice_id : wpinv_get_invoice( (int)$invoice_id );
1090
    
1091
    if ( empty( $invoice ) ) {
1092
        return false;
1093
    }
1094
    
1095
    return $invoice->update_status( $new_status );
1096
}
1097
1098
function wpinv_cart_has_fees( $type = 'all' ) {
1099
    return false;
1100
}
1101
1102
function wpinv_validate_checkout_fields() {    
1103
    // Check if there is $_POST
1104
    if ( empty( $_POST ) ) {
1105
        return false;
1106
    }
1107
    
1108
    // Start an array to collect valid data
1109
    $valid_data = array(
1110
        'gateway'          => wpinv_checkout_validate_gateway(), // Gateway fallback
1111
        'discount'         => wpinv_checkout_validate_discounts(), // Set default discount
1112
        'cc_info'          => wpinv_checkout_validate_cc() // Credit card info
1113
    );
1114
    
1115
    // Validate agree to terms
1116
    if ( wpinv_get_option( 'show_agree_to_terms', false ) ) {
1117
        wpinv_checkout_validate_agree_to_terms();
1118
    }
1119
    
1120
    $valid_data['invoice_user'] = wpinv_checkout_validate_invoice_user();
1121
    $valid_data['current_user'] = wpinv_checkout_validate_current_user();
1122
    
1123
    // Return collected data
1124
    return $valid_data;
1125
}
1126
1127
function wpinv_checkout_validate_gateway() {
1128
    $gateway = wpinv_get_default_gateway();
1129
    
1130
    $invoice = wpinv_get_invoice_cart();
1131
    $has_subscription = $invoice->is_recurring();
1132
    if ( empty( $invoice ) ) {
1133
        wpinv_set_error( 'invalid_invoice', __( 'Your cart is empty.', 'invoicing' ) );
1134
        return $gateway;
1135
    }
1136
1137
    // Check if a gateway value is present
1138
    if ( !empty( $_REQUEST['wpi-gateway'] ) ) {
1139
        $gateway = sanitize_text_field( $_REQUEST['wpi-gateway'] );
1140
1141
        if ( $invoice->is_free() ) {
1142
            $gateway = 'manual';
1143
        } elseif ( !wpinv_is_gateway_active( $gateway ) ) {
1144
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled', 'invoicing' ) );
1145
        } elseif ( $has_subscription && !wpinv_gateway_support_subscription( $gateway ) ) {
1146
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway doesnot support subscription payment', 'invoicing' ) );
1147
        }
1148
    }
1149
1150
    if ( $has_subscription && count( wpinv_get_cart_contents() ) > 1 ) {
1151
        wpinv_set_error( 'subscription_invalid', __( 'Only one subscription may be purchased through payment per checkout.', 'invoicing' ) );
1152
    }
1153
1154
    return $gateway;
1155
}
1156
1157
function wpinv_checkout_validate_discounts() {
1158
    global $wpi_cart;
1159
    
1160
    // Retrieve the discount stored in cookies
1161
    $discounts = wpinv_get_cart_discounts();
1162
    
1163
    $error = false;
1164
    // If we have discounts, loop through them
1165
    if ( ! empty( $discounts ) ) {
1166
        foreach ( $discounts as $discount ) {
1167
            // Check if valid
1168
            if (  !wpinv_is_discount_valid( $discount, (int)$wpi_cart->get_user_id() ) ) {
1169
                // Discount is not valid
1170
                $error = true;
1171
            }
1172
        }
1173
    } else {
1174
        // No discounts
1175
        return NULL;
1176
    }
1177
1178
    if ( $error && !wpinv_get_errors() ) {
1179
        wpinv_set_error( 'invalid_discount', __( 'Discount code you entered is invalid', 'invoicing' ) );
1180
    }
1181
1182
    return implode( ',', $discounts );
1183
}
1184
1185
function wpinv_checkout_validate_cc() {
1186
    $card_data = wpinv_checkout_get_cc_info();
1187
1188
    // Validate the card zip
1189
    if ( !empty( $card_data['wpinv_zip'] ) ) {
1190
        if ( !wpinv_checkout_validate_cc_zip( $card_data['wpinv_zip'], $card_data['wpinv_country'] ) ) {
1191
            wpinv_set_error( 'invalid_cc_zip', __( 'The zip / postcode you entered for your billing address is invalid', 'invoicing' ) );
1192
        }
1193
    }
1194
1195
    // This should validate card numbers at some point too
1196
    return $card_data;
1197
}
1198
1199
function wpinv_checkout_get_cc_info() {
1200
	$cc_info = array();
1201
	$cc_info['card_name']      = isset( $_POST['card_name'] )       ? sanitize_text_field( $_POST['card_name'] )       : '';
1202
	$cc_info['card_number']    = isset( $_POST['card_number'] )     ? sanitize_text_field( $_POST['card_number'] )     : '';
1203
	$cc_info['card_cvc']       = isset( $_POST['card_cvc'] )        ? sanitize_text_field( $_POST['card_cvc'] )        : '';
1204
	$cc_info['card_exp_month'] = isset( $_POST['card_exp_month'] )  ? sanitize_text_field( $_POST['card_exp_month'] )  : '';
1205
	$cc_info['card_exp_year']  = isset( $_POST['card_exp_year'] )   ? sanitize_text_field( $_POST['card_exp_year'] )   : '';
1206
	$cc_info['card_address']   = isset( $_POST['wpinv_address'] )  ? sanitize_text_field( $_POST['wpinv_address'] ) : '';
1207
	$cc_info['card_city']      = isset( $_POST['wpinv_city'] )     ? sanitize_text_field( $_POST['wpinv_city'] )    : '';
1208
	$cc_info['card_state']     = isset( $_POST['wpinv_state'] )    ? sanitize_text_field( $_POST['wpinv_state'] )   : '';
1209
	$cc_info['card_country']   = isset( $_POST['wpinv_country'] )  ? sanitize_text_field( $_POST['wpinv_country'] ) : '';
1210
	$cc_info['card_zip']       = isset( $_POST['wpinv_zip'] )      ? sanitize_text_field( $_POST['wpinv_zip'] )     : '';
1211
1212
	// Return cc info
1213
	return $cc_info;
1214
}
1215
1216
function wpinv_checkout_validate_cc_zip( $zip = 0, $country_code = '' ) {
1217
    $ret = false;
1218
1219
    if ( empty( $zip ) || empty( $country_code ) )
1220
        return $ret;
1221
1222
    $country_code = strtoupper( $country_code );
1223
1224
    $zip_regex = array(
1225
        "AD" => "AD\d{3}",
1226
        "AM" => "(37)?\d{4}",
1227
        "AR" => "^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$",
1228
        "AS" => "96799",
1229
        "AT" => "\d{4}",
1230
        "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})$",
1231
        "AX" => "22\d{3}",
1232
        "AZ" => "\d{4}",
1233
        "BA" => "\d{5}",
1234
        "BB" => "(BB\d{5})?",
1235
        "BD" => "\d{4}",
1236
        "BE" => "^[1-9]{1}[0-9]{3}$",
1237
        "BG" => "\d{4}",
1238
        "BH" => "((1[0-2]|[2-9])\d{2})?",
1239
        "BM" => "[A-Z]{2}[ ]?[A-Z0-9]{2}",
1240
        "BN" => "[A-Z]{2}[ ]?\d{4}",
1241
        "BR" => "\d{5}[\-]?\d{3}",
1242
        "BY" => "\d{6}",
1243
        "CA" => "^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$",
1244
        "CC" => "6799",
1245
        "CH" => "^[1-9][0-9][0-9][0-9]$",
1246
        "CK" => "\d{4}",
1247
        "CL" => "\d{7}",
1248
        "CN" => "\d{6}",
1249
        "CR" => "\d{4,5}|\d{3}-\d{4}",
1250
        "CS" => "\d{5}",
1251
        "CV" => "\d{4}",
1252
        "CX" => "6798",
1253
        "CY" => "\d{4}",
1254
        "CZ" => "\d{3}[ ]?\d{2}",
1255
        "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",
1256
        "DK" => "^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$",
1257
        "DO" => "\d{5}",
1258
        "DZ" => "\d{5}",
1259
        "EC" => "([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?",
1260
        "EE" => "\d{5}",
1261
        "EG" => "\d{5}",
1262
        "ES" => "^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$",
1263
        "ET" => "\d{4}",
1264
        "FI" => "\d{5}",
1265
        "FK" => "FIQQ 1ZZ",
1266
        "FM" => "(9694[1-4])([ \-]\d{4})?",
1267
        "FO" => "\d{3}",
1268
        "FR" => "^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$",
1269
        "GE" => "\d{4}",
1270
        "GF" => "9[78]3\d{2}",
1271
        "GL" => "39\d{2}",
1272
        "GN" => "\d{3}",
1273
        "GP" => "9[78][01]\d{2}",
1274
        "GR" => "\d{3}[ ]?\d{2}",
1275
        "GS" => "SIQQ 1ZZ",
1276
        "GT" => "\d{5}",
1277
        "GU" => "969[123]\d([ \-]\d{4})?",
1278
        "GW" => "\d{4}",
1279
        "HM" => "\d{4}",
1280
        "HN" => "(?:\d{5})?",
1281
        "HR" => "\d{5}",
1282
        "HT" => "\d{4}",
1283
        "HU" => "\d{4}",
1284
        "ID" => "\d{5}",
1285
        "IE" => "((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?",
1286
        "IL" => "\d{5}",
1287
        "IN"=> "^[1-9][0-9][0-9][0-9][0-9][0-9]$", //india
1288
        "IO" => "BBND 1ZZ",
1289
        "IQ" => "\d{5}",
1290
        "IS" => "\d{3}",
1291
        "IT" => "^(V-|I-)?[0-9]{5}$",
1292
        "JO" => "\d{5}",
1293
        "JP" => "\d{3}-\d{4}",
1294
        "KE" => "\d{5}",
1295
        "KG" => "\d{6}",
1296
        "KH" => "\d{5}",
1297
        "KR" => "\d{3}[\-]\d{3}",
1298
        "KW" => "\d{5}",
1299
        "KZ" => "\d{6}",
1300
        "LA" => "\d{5}",
1301
        "LB" => "(\d{4}([ ]?\d{4})?)?",
1302
        "LI" => "(948[5-9])|(949[0-7])",
1303
        "LK" => "\d{5}",
1304
        "LR" => "\d{4}",
1305
        "LS" => "\d{3}",
1306
        "LT" => "\d{5}",
1307
        "LU" => "\d{4}",
1308
        "LV" => "\d{4}",
1309
        "MA" => "\d{5}",
1310
        "MC" => "980\d{2}",
1311
        "MD" => "\d{4}",
1312
        "ME" => "8\d{4}",
1313
        "MG" => "\d{3}",
1314
        "MH" => "969[67]\d([ \-]\d{4})?",
1315
        "MK" => "\d{4}",
1316
        "MN" => "\d{6}",
1317
        "MP" => "9695[012]([ \-]\d{4})?",
1318
        "MQ" => "9[78]2\d{2}",
1319
        "MT" => "[A-Z]{3}[ ]?\d{2,4}",
1320
        "MU" => "(\d{3}[A-Z]{2}\d{3})?",
1321
        "MV" => "\d{5}",
1322
        "MX" => "\d{5}",
1323
        "MY" => "\d{5}",
1324
        "NC" => "988\d{2}",
1325
        "NE" => "\d{4}",
1326
        "NF" => "2899",
1327
        "NG" => "(\d{6})?",
1328
        "NI" => "((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?",
1329
        "NL" => "^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$",
1330
        "NO" => "\d{4}",
1331
        "NP" => "\d{5}",
1332
        "NZ" => "\d{4}",
1333
        "OM" => "(PC )?\d{3}",
1334
        "PF" => "987\d{2}",
1335
        "PG" => "\d{3}",
1336
        "PH" => "\d{4}",
1337
        "PK" => "\d{5}",
1338
        "PL" => "\d{2}-\d{3}",
1339
        "PM" => "9[78]5\d{2}",
1340
        "PN" => "PCRN 1ZZ",
1341
        "PR" => "00[679]\d{2}([ \-]\d{4})?",
1342
        "PT" => "\d{4}([\-]\d{3})?",
1343
        "PW" => "96940",
1344
        "PY" => "\d{4}",
1345
        "RE" => "9[78]4\d{2}",
1346
        "RO" => "\d{6}",
1347
        "RS" => "\d{5}",
1348
        "RU" => "\d{6}",
1349
        "SA" => "\d{5}",
1350
        "SE" => "^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$",
1351
        "SG" => "\d{6}",
1352
        "SH" => "(ASCN|STHL) 1ZZ",
1353
        "SI" => "\d{4}",
1354
        "SJ" => "\d{4}",
1355
        "SK" => "\d{3}[ ]?\d{2}",
1356
        "SM" => "4789\d",
1357
        "SN" => "\d{5}",
1358
        "SO" => "\d{5}",
1359
        "SZ" => "[HLMS]\d{3}",
1360
        "TC" => "TKCA 1ZZ",
1361
        "TH" => "\d{5}",
1362
        "TJ" => "\d{6}",
1363
        "TM" => "\d{6}",
1364
        "TN" => "\d{4}",
1365
        "TR" => "\d{5}",
1366
        "TW" => "\d{3}(\d{2})?",
1367
        "UA" => "\d{5}",
1368
        "UK" => "^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$",
1369
        "US" => "^\d{5}([\-]?\d{4})?$",
1370
        "UY" => "\d{5}",
1371
        "UZ" => "\d{6}",
1372
        "VA" => "00120",
1373
        "VE" => "\d{4}",
1374
        "VI" => "008(([0-4]\d)|(5[01]))([ \-]\d{4})?",
1375
        "WF" => "986\d{2}",
1376
        "YT" => "976\d{2}",
1377
        "YU" => "\d{5}",
1378
        "ZA" => "\d{4}",
1379
        "ZM" => "\d{5}"
1380
    );
1381
1382
    if ( ! isset ( $zip_regex[ $country_code ] ) || preg_match( "/" . $zip_regex[ $country_code ] . "/i", $zip ) )
1383
        $ret = true;
1384
1385
    return apply_filters( 'wpinv_is_zip_valid', $ret, $zip, $country_code );
1386
}
1387
1388
function wpinv_checkout_validate_agree_to_terms() {
1389
    // Validate agree to terms
1390
    if ( ! isset( $_POST['wpi_agree_to_terms'] ) || $_POST['wpi_agree_to_terms'] != 1 ) {
1391
        // User did not agree
1392
        wpinv_set_error( 'agree_to_terms', apply_filters( 'wpinv_agree_to_terms_text', __( 'You must agree to the terms of use', 'invoicing' ) ) );
1393
    }
1394
}
1395
1396
function wpinv_checkout_validate_invoice_user() {
1397
    global $wpi_cart;
1398
    
1399
    $valid_user_data = array(
1400
        'user_id' => -1
1401
    );
1402
    
1403
    // Verify there is a user_ID
1404
    if ( $user_ID = (int)$wpi_cart->get_user_id() ) {
1405
        // Get the logged in user data
1406
        $user_data = get_userdata( $user_ID );
1407
        $required_fields  = wpinv_checkout_required_fields();
1408
1409
        // Loop through required fields and show error messages
1410
         if ( !empty( $required_fields ) ) {
1411
            foreach ( $required_fields as $field_name => $value ) {
1412
                if ( in_array( $value, $required_fields ) && empty( $_POST[ 'wpinv_' . $field_name ] ) ) {
1413
                    wpinv_set_error( $value['error_id'], $value['error_message'] );
1414
                }
1415
            }
1416
        }
1417
1418
        // Verify data
1419
        if ( $user_data ) {
1420
            // Collected logged in user data
1421
            $valid_user_data = array(
1422
                'user_id'     => $user_ID,
1423
                'email'       => isset( $_POST['wpinv_email'] ) ? sanitize_email( $_POST['wpinv_email'] ) : $user_data->user_email,
1424
                'first_name'  => isset( $_POST['wpinv_first_name'] ) && ! empty( $_POST['wpinv_first_name'] ) ? sanitize_text_field( $_POST['wpinv_first_name'] ) : $user_data->first_name,
1425
                'last_name'   => isset( $_POST['wpinv_last_name'] ) && ! empty( $_POST['wpinv_last_name']  ) ? sanitize_text_field( $_POST['wpinv_last_name']  ) : $user_data->last_name,
1426
            );
1427
1428
            if ( !empty( $_POST[ 'wpinv_email' ] ) && !is_email( $_POST[ 'wpinv_email' ] ) ) {
1429
                wpinv_set_error( 'invalid_email', __( 'Please enter a valid email address', 'invoicing' ) );
1430
            }
1431
        } else {
1432
            // Set invalid user error
1433
            wpinv_set_error( 'invalid_user', __( 'The user billing information is invalid', 'invoicing' ) );
1434
        }
1435
    } else {
1436
        // Set invalid user error
1437
        wpinv_set_error( 'invalid_user_id', __( 'The invalid invoice user id', 'invoicing' ) );
1438
    }
1439
1440
    // Return user data
1441
    return $valid_user_data;
1442
}
1443
1444
function wpinv_checkout_validate_current_user() {
1445
    global $wpi_cart;
1446
1447
    $data = array();
1448
    
1449
    if ( is_user_logged_in() ) {
1450
        if ( !wpinv_require_login_to_checkout() || ( wpinv_require_login_to_checkout() && (int)$wpi_cart->get_user_id() === (int)get_current_user_id() ) ) {
1451
            $data['user_id'] = (int)get_current_user_id();
1452
        } else {
1453
            wpinv_set_error( 'logged_in_only', __( 'You are not allowed to pay for this invoice', 'invoicing' ) );
1454
        }
1455
    } else {
1456
        // If guest checkout allowed
1457
        if ( !wpinv_require_login_to_checkout() ) {
1458
            $data['user_id'] = 0;
1459
        } else {
1460
            wpinv_set_error( 'logged_in_only', __( 'You must be logged in to pay for this invoice', 'invoicing' ) );
1461
        }
1462
    }
1463
1464
    return $data;
1465
}
1466
1467
function wpinv_checkout_form_get_user( $valid_data = array() ) {
1468
    // Initialize user
1469
    $user    = false;
0 ignored issues
show
Unused Code introduced by
$user 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...
1470
    $is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
0 ignored issues
show
Unused Code introduced by
$is_ajax 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...
1471
1472
    if ( empty( $valid_data['current_user'] ) ) {
1473
        $user = false;
1474
    } else {
1475
        // Set the valid invoice user
1476
        $user = $valid_data['invoice_user'];
1477
    }
1478
1479
    // Verify invoice have an user
1480
    if ( false === $user || empty( $user ) ) {
1481
        return false;
1482
    }
1483
1484
    $address_fields = array(
1485
        'first_name',
1486
        'last_name',
1487
        'company',
1488
        'vat_number',
1489
        'phone',
1490
        'address',
1491
        'city',
1492
        'state',
1493
        'country',
1494
        'zip',
1495
    );
1496
    
1497
    foreach ( $address_fields as $field ) {
1498
        $user[$field]  = !empty( $_POST['wpinv_' . $field] ) ? sanitize_text_field( $_POST['wpinv_' . $field] ) : false;
1499
        
1500
        if ( !empty( $user['user_id'] ) && !empty( $valid_data['current_user']['user_id'] ) && $valid_data['current_user']['user_id'] == $user['user_id'] ) {
1501
            update_user_meta( $user['user_id'], '_wpinv_' . $field, $user[$field] );
1502
        }
1503
    }
1504
1505
    // Return valid user
1506
    return $user;
1507
}
1508
1509
function wpinv_set_checkout_session( $invoice_data = array() ) {
1510
    global $wpi_session;
1511
    
1512
    return $wpi_session->set( 'wpinv_checkout', $invoice_data );
1513
}
1514
1515
function wpinv_get_checkout_session() {
1516
	global $wpi_session;
1517
    
1518
    return $wpi_session->get( 'wpinv_checkout' );
1519
}
1520
1521
function wpinv_empty_cart() {
1522
    global $wpi_session;
1523
1524
    // Remove cart contents
1525
    $wpi_session->set( 'wpinv_checkout', NULL );
1526
1527
    // Remove all cart fees
1528
    $wpi_session->set( 'wpi_cart_fees', NULL );
1529
1530
    do_action( 'wpinv_empty_cart' );
1531
}
1532
1533
function wpinv_process_checkout() {
1534
    global $wpinv_euvat, $wpi_checkout_id, $wpi_cart;
1535
    
1536
    wpinv_clear_errors();
1537
    
1538
    $invoice = wpinv_get_invoice_cart();
1539
    $wpi_cart = $invoice;
1540
    
1541
    $wpi_checkout_id = $invoice->ID;
1542
    
1543
    do_action( 'wpinv_pre_process_checkout' );
1544
    
1545
    if ( !wpinv_get_cart_contents() ) { // Make sure the cart isn't empty
1546
        $valid_data = false;
1547
        wpinv_set_error( 'empty_cart', __( 'Your cart is empty', 'invoicing' ) );
1548
    } else {
1549
        // Validate the form $_POST data
1550
        $valid_data = wpinv_validate_checkout_fields();
1551
        
1552
        // Allow themes and plugins to hook to errors
1553
        do_action( 'wpinv_checkout_error_checks', $valid_data, $_POST );
1554
    }
1555
    
1556
    $is_ajax    = defined( 'DOING_AJAX' ) && DOING_AJAX;
1557
    
1558
    // Validate the user
1559
    $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...
1560
1561
    // Let extensions validate fields after user is logged in if user has used login/registration form
1562
    do_action( 'wpinv_checkout_user_error_checks', $user, $valid_data, $_POST );
1563
    
1564
    if ( false === $valid_data || wpinv_get_errors() || ! $user ) {
1565
        if ( $is_ajax ) {
1566
            do_action( 'wpinv_ajax_checkout_errors' );
1567
            die();
1568
        } else {
1569
            return false;
1570
        }
1571
    }
1572
1573
    if ( $is_ajax ) {
1574
        // Save address fields.
1575
        $address_fields = array( 'first_name', 'last_name', 'phone', 'address', 'city', 'country', 'state', 'zip', 'company' );
1576 View Code Duplication
        foreach ( $address_fields as $field ) {
1577
            if ( isset( $user[$field] ) ) {
1578
                $invoice->set( $field, $user[$field] );
1579
            }
1580
            
1581
            $invoice->save();
1582
        }
1583
1584
        $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...
1585
        $response['data']['subtotal']   = $invoice->get_subtotal();
1586
        $response['data']['subtotalf']  = $invoice->get_subtotal( true );
1587
        $response['data']['discount']   = $invoice->get_discount();
1588
        $response['data']['discountf']  = $invoice->get_discount( true );
1589
        $response['data']['tax']        = $invoice->get_tax();
1590
        $response['data']['taxf']       = $invoice->get_tax( true );
1591
        $response['data']['total']      = $invoice->get_total();
1592
        $response['data']['totalf']     = $invoice->get_total( true );
1593
        
1594
        wp_send_json( $response );
1595
    }
1596
    
1597
    $user_info = array(
1598
        'user_id'        => $user['user_id'],
1599
        'first_name'     => $user['first_name'],
1600
        'last_name'      => $user['last_name'],
1601
        'email'          => $user['email'],
1602
        'company'        => $user['company'],
1603
        'phone'          => $user['phone'],
1604
        'address'        => $user['address'],
1605
        'city'           => $user['city'],
1606
        'country'        => $user['country'],
1607
        'state'          => $user['state'],
1608
        'zip'            => $user['zip'],
1609
    );
1610
    
1611
    $cart_items = wpinv_get_cart_contents();
1612
    $discounts  = wpinv_get_cart_discounts();
1613
    
1614
    // Setup invoice information
1615
    $invoice_data = array(
1616
        'invoice_id'        => !empty( $invoice ) ? $invoice->ID : 0,
1617
        'items'             => $cart_items,
1618
        'cart_discounts'    => $discounts,
1619
        'fees'              => wpinv_get_cart_fees(),        // Any arbitrary fees that have been added to the cart
1620
        'subtotal'          => wpinv_get_cart_subtotal( $cart_items ),    // Amount before taxes and discounts
1621
        'discount'          => wpinv_get_cart_items_discount_amount( $cart_items, $discounts ), // Discounted amount
1622
        'tax'               => wpinv_get_cart_tax( $cart_items ),               // Taxed amount
1623
        'price'             => wpinv_get_cart_total( $cart_items, $discounts ),    // Amount after taxes
1624
        'invoice_key'       => $invoice->get_key() ? $invoice->get_key() : $invoice->generate_key(),
1625
        'user_email'        => $user['email'],
1626
        'date'              => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
1627
        'user_info'         => stripslashes_deep( $user_info ),
1628
        'post_data'         => $_POST,
1629
        'cart_details'      => $cart_items,
1630
        'gateway'           => $valid_data['gateway'],
1631
        'card_info'         => $valid_data['cc_info']
1632
    );
1633
    
1634
    $vat_info   = $wpinv_euvat->current_vat_data();
1635
    if ( is_array( $vat_info ) ) {
1636
        $invoice_data['user_info']['vat_number']        = $vat_info['number'];
1637
        $invoice_data['user_info']['vat_rate']          = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state']);
1638
        $invoice_data['user_info']['adddress_confirmed']    = isset($vat_info['adddress_confirmed']) ? $vat_info['adddress_confirmed'] : false;
1639
1640
        // Add the VAT rate to each item in the cart
1641
        foreach( $invoice_data['cart_details'] as $key => $item_data) {
1642
            $rate = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state'], $item_data['id']);
1643
            $invoice_data['cart_details'][$key]['vat_rate'] = wpinv_round_amount( $rate, 4 );
1644
        }
1645
    }
1646
    
1647
    // Save vat fields.
1648
    $address_fields = array( 'vat_number', 'vat_rate', 'adddress_confirmed' );
1649 View Code Duplication
    foreach ( $address_fields as $field ) {
1650
        if ( isset( $invoice_data['user_info'][$field] ) ) {
1651
            $invoice->set( $field, $invoice_data['user_info'][$field] );
1652
        }
1653
        
1654
        $invoice->save();
1655
    }
1656
1657
    // Add the user data for hooks
1658
    $valid_data['user'] = $user;
1659
    
1660
    // Allow themes and plugins to hook before the gateway
1661
    do_action( 'wpinv_checkout_before_gateway', $_POST, $user_info, $valid_data );
1662
    
1663
    // If the total amount in the cart is 0, send to the manual gateway. This emulates a free invoice
1664
    if ( !$invoice_data['price'] ) {
1665
        // Revert to manual
1666
        $invoice_data['gateway'] = 'manual';
1667
        $_POST['wpi-gateway'] = 'manual';
1668
    }
1669
    
1670
    // Allow the invoice data to be modified before it is sent to the gateway
1671
    $invoice_data = apply_filters( 'wpinv_data_before_gateway', $invoice_data, $valid_data );
1672
    
1673
    // Setup the data we're storing in the purchase session
1674
    $session_data = $invoice_data;
1675
    // Make sure credit card numbers are never stored in sessions
1676
    if ( !empty( $session_data['card_info']['card_number'] ) ) {
1677
        unset( $session_data['card_info']['card_number'] );
1678
    }
1679
    
1680
    // Used for showing item links to non logged-in users after purchase, and for other plugins needing purchase data.
1681
    wpinv_set_checkout_session( $invoice_data );
1682
    
1683
    // Set gateway
1684
    $invoice->update_meta( '_wpinv_gateway', $invoice_data['gateway'] );
1685
    $invoice->update_meta( '_wpinv_mode', ( wpinv_is_test_mode( $invoice_data['gateway'] ) ? 'test' : 'live' ) );
1686
    $invoice->update_meta( '_wpinv_checkout', true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

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...
1687
    
1688
    do_action( 'wpinv_checkout_before_send_to_gateway', $invoice, $invoice_data );
1689
1690
    // Send info to the gateway for payment processing
1691
    wpinv_send_to_gateway( $invoice_data['gateway'], $invoice_data );
1692
    die();
1693
}
1694
add_action( 'wpinv_payment', 'wpinv_process_checkout' );
1695
1696
function wpinv_get_invoices( $args ) {
1697
    $args = wp_parse_args( $args, array(
1698
        'status'   => array_keys( wpinv_get_invoice_statuses() ),
1699
        'type'     => 'wpi_invoice',
1700
        'parent'   => null,
1701
        'user'     => null,
1702
        'email'    => '',
1703
        'limit'    => get_option( 'posts_per_page' ),
1704
        'offset'   => null,
1705
        'page'     => 1,
1706
        'exclude'  => array(),
1707
        'orderby'  => 'date',
1708
        'order'    => 'DESC',
1709
        'return'   => 'objects',
1710
        'paginate' => false,
1711
    ) );
1712
    
1713
    // Handle some BW compatibility arg names where wp_query args differ in naming.
1714
    $map_legacy = array(
1715
        'numberposts'    => 'limit',
1716
        'post_type'      => 'type',
1717
        'post_status'    => 'status',
1718
        'post_parent'    => 'parent',
1719
        'author'         => 'user',
1720
        'posts_per_page' => 'limit',
1721
        'paged'          => 'page',
1722
    );
1723
1724
    foreach ( $map_legacy as $from => $to ) {
1725
        if ( isset( $args[ $from ] ) ) {
1726
            $args[ $to ] = $args[ $from ];
1727
        }
1728
    }
1729
1730
    if ( get_query_var( 'paged' ) )
1731
        $args['page'] = get_query_var('paged');
1732
    else if ( get_query_var( 'page' ) )
1733
        $args['page'] = get_query_var( 'page' );
1734
    else if ( !empty( $args[ 'page' ] ) )
1735
        $args['page'] = $args[ 'page' ];
1736
    else
1737
        $args['page'] = 1;
1738
1739
    /**
1740
     * Generate WP_Query args. This logic will change if orders are moved to
1741
     * custom tables in the future.
1742
     */
1743
    $wp_query_args = array(
1744
        'post_type'      => 'wpi_invoice',
1745
        'post_status'    => $args['status'],
1746
        'posts_per_page' => $args['limit'],
1747
        'meta_query'     => array(),
1748
        'date_query'     => !empty( $args['date_query'] ) ? $args['date_query'] : array(),
1749
        'fields'         => 'ids',
1750
        'orderby'        => $args['orderby'],
1751
        'order'          => $args['order'],
1752
    );
1753
    
1754
    if ( !empty( $args['user'] ) ) {
1755
        $wp_query_args['author'] = absint( $args['user'] );
1756
    }
1757
1758
    if ( ! is_null( $args['parent'] ) ) {
1759
        $wp_query_args['post_parent'] = absint( $args['parent'] );
1760
    }
1761
1762
    if ( ! is_null( $args['offset'] ) ) {
1763
        $wp_query_args['offset'] = absint( $args['offset'] );
1764
    } else {
1765
        $wp_query_args['paged'] = absint( $args['page'] );
1766
    }
1767
1768
    if ( ! empty( $args['exclude'] ) ) {
1769
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
1770
    }
1771
1772
    if ( ! $args['paginate' ] ) {
1773
        $wp_query_args['no_found_rows'] = true;
1774
    }
1775
1776
    // Get results.
1777
    $invoices = new WP_Query( $wp_query_args );
1778
1779
    if ( 'objects' === $args['return'] ) {
1780
        $return = array_map( 'wpinv_get_invoice', $invoices->posts );
1781
    } elseif ( 'self' === $args['return'] ) {
1782
        return $invoices;
1783
    } else {
1784
        $return = $invoices->posts;
1785
    }
1786
1787
    if ( $args['paginate' ] ) {
1788
        return (object) array(
1789
            'invoices'      => $return,
1790
            'total'         => $invoices->found_posts,
1791
            'max_num_pages' => $invoices->max_num_pages,
1792
        );
1793
    } else {
1794
        return $return;
1795
    }
1796
}
1797
1798
function wpinv_get_user_invoices_columns() {
1799
    $columns = array(
1800
            'invoice-number'  => array( 'title' => __( 'ID', 'invoicing' ), 'class' => 'text-left' ),
1801
            'created-date'    => array( 'title' => __( 'Created Date', 'invoicing' ), 'class' => 'text-left' ),
1802
            'payment-date'    => array( 'title' => __( 'Payment Date', 'invoicing' ), 'class' => 'text-left' ),
1803
            'invoice-status'  => array( 'title' => __( 'Status', 'invoicing' ), 'class' => 'text-center' ),
1804
            'invoice-total'   => array( 'title' => __( 'Total', 'invoicing' ), 'class' => 'text-right' ),
1805
            'invoice-actions' => array( 'title' => '&nbsp;', 'class' => 'text-center' ),
1806
        );
1807
1808
    return apply_filters( 'wpinv_user_invoices_columns', $columns );
1809
}
1810
1811
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...
1812
    global $wpinv_receipt_args;
1813
1814
    $wpinv_receipt_args = shortcode_atts( array(
1815
        'error'           => __( 'Sorry, trouble retrieving payment receipt.', 'invoicing' ),
1816
        'price'           => true,
1817
        'discount'        => true,
1818
        'items'           => true,
1819
        'date'            => true,
1820
        'notes'           => true,
1821
        'invoice_key'     => false,
1822
        'payment_method'  => true,
1823
        'invoice_id'      => true
1824
    ), $atts, 'wpinv_receipt' );
1825
1826
    $session = wpinv_get_checkout_session();
1827
    if ( isset( $_GET['invoice_key'] ) ) {
1828
        $invoice_key = urldecode( $_GET['invoice_key'] );
1829
    } else if ( $session && isset( $session['invoice_key'] ) ) {
1830
        $invoice_key = $session['invoice_key'];
1831
    } elseif ( isset( $wpinv_receipt_args['invoice_key'] ) && $wpinv_receipt_args['invoice_key'] ) {
1832
        $invoice_key = $wpinv_receipt_args['invoice_key'];
1833
    } else if ( isset( $_GET['invoice-id'] ) ) {
1834
        $invoice_key = wpinv_get_payment_key( (int)$_GET['invoice-id'] );
1835
    }
1836
1837
    // No key found
1838
    if ( ! isset( $invoice_key ) ) {
1839
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1840
    }
1841
1842
    $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...
1843
    $user_can_view = wpinv_can_view_receipt( $invoice_key );
1844 View Code Duplication
    if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1845
        $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...
1846
        $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1847
    }
1848
1849
    // Key was provided, but user is logged out. Offer them the ability to login and view the receipt
1850
    if ( ! $user_can_view && ! empty( $invoice_key ) && ! is_user_logged_in() ) {
1851
        // login redirect
1852
        return '<p class="alert alert-error">' . __( 'You are not allowed to access this section', 'invoicing' ) . '</p>';
1853
    }
1854
1855
    if ( ! apply_filters( 'wpinv_user_can_view_receipt', $user_can_view, $wpinv_receipt_args ) ) {
1856
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1857
    }
1858
1859
    ob_start();
1860
1861
    wpinv_get_template_part( 'wpinv-invoice-receipt' );
1862
1863
    $display = ob_get_clean();
1864
1865
    return $display;
1866
}
1867
1868 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...
1869
	global $wpdb;
1870
1871
	$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 ) );
1872
1873
	if ( $invoice_id != NULL )
1874
		return $invoice_id;
1875
1876
	return 0;
1877
}
1878
1879
function wpinv_can_view_receipt( $invoice_key = '' ) {
1880
	$return = false;
1881
1882
	if ( empty( $invoice_key ) ) {
1883
		return $return;
1884
	}
1885
1886
	global $wpinv_receipt_args;
1887
1888
	$wpinv_receipt_args['id'] = wpinv_get_invoice_id_by_key( $invoice_key );
1889
	if ( isset( $_GET['invoice-id'] ) ) {
1890
		$wpinv_receipt_args['id'] = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? (int)$_GET['invoice-id'] : 0;
1891
	}
1892
1893
	if ( empty( $wpinv_receipt_args['id'] ) ) {
1894
		return $return;
1895
	}
1896
1897
	$invoice = wpinv_get_invoice( $wpinv_receipt_args['id'] );
1898
	if ( !( !empty( $invoice->ID ) && $invoice->get_key() === $invoice_key ) ) {
1899
		return $return;
1900
	}
1901
1902
	if ( is_user_logged_in() ) {
1903
		if ( (int)$invoice->get_user_id() === (int) get_current_user_id() ) {
1904
			$return = true;
1905
		}
1906
	}
1907
1908
	$session = wpinv_get_checkout_session();
1909
	if ( isset( $_GET['invoice_key'] ) || ( $session && isset( $session['invoice_key'] ) ) ) {
1910
		$check_key = isset( $_GET['invoice_key'] ) ? $_GET['invoice_key'] : $session['invoice_key'];
1911
1912
		if ( wpinv_require_login_to_checkout() ) {
1913
			$return = $return && $check_key === $invoice_key;
1914
		} else {
1915
			$return = $check_key === $invoice_key;
1916
		}
1917
	}
1918
1919
	return (bool) apply_filters( 'wpinv_can_view_receipt', $return, $invoice_key );
1920
}
1921
1922
function wpinv_pay_for_invoice() {
1923
    global $wpinv_euvat;
1924
    
1925
    if ( isset( $_GET['invoice_key'] ) ) {
1926
        $checkout_uri   = wpinv_get_checkout_uri();
1927
        $invoice_key    = sanitize_text_field( $_GET['invoice_key'] );
1928
        
1929
        if ( empty( $invoice_key ) ) {
1930
            wpinv_set_error( 'invalid_invoice', __( 'Invoice not found', 'invoicing' ) );
1931
            wp_redirect( $checkout_uri );
1932
            wpinv_die();
1933
        }
1934
        
1935
        do_action( 'wpinv_check_pay_for_invoice', $invoice_key );
1936
1937
        $invoice_id    = wpinv_get_invoice_id_by_key( $invoice_key );
1938
        $user_can_view = wpinv_can_view_receipt( $invoice_key );
1939 View Code Duplication
        if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1940
            $invoice_id     = (int)$_GET['invoice-id'];
1941
            $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1942
        }
1943
        
1944
        if ( $invoice_id && $user_can_view && ( $invoice = wpinv_get_invoice( $invoice_id ) ) ) {
1945
            if ( $invoice->needs_payment() ) {
1946
                $data                   = array();
1947
                $data['invoice_id']     = $invoice_id;
1948
                $data['cart_discounts'] = $invoice->get_discounts( true );
1949
                
1950
                wpinv_set_checkout_session( $data );
1951
                
1952
                if ( wpinv_get_option( 'vat_ip_country_default' ) ) {
1953
                    $_POST['country']   = $wpinv_euvat->get_country_by_ip();
1954
                    $_POST['state']     = $_POST['country'] == $invoice->country ? $invoice->state : '';
1955
                    
1956
                    wpinv_recalculate_tax( true );
1957
                }
1958
                
1959
            } else {
1960
                $checkout_uri = $invoice->get_view_url();
1961
            }
1962
        } else {
1963
            wpinv_set_error( 'invalid_invoice', __( 'You are not allowed to view this invoice', 'invoicing' ) );
1964
            
1965
            $checkout_uri = is_user_logged_in() ? wpinv_get_history_page_uri() : wp_login_url( get_permalink() );
1966
        }
1967
        
1968
        wp_redirect( $checkout_uri );
1969
        wpinv_die();
1970
    }
1971
}
1972
add_action( 'wpinv_pay_for_invoice', 'wpinv_pay_for_invoice' );
1973
1974
function wpinv_handle_pay_via_invoice_link( $invoice_key ) {
1975
    if ( !empty( $invoice_key ) && !empty( $_REQUEST['_wpipay'] ) && !is_user_logged_in() && $invoice_id = wpinv_get_invoice_id_by_key( $invoice_key ) ) {
1976
        if ( $invoice = wpinv_get_invoice( $invoice_id ) ) {
1977
            $user_id = $invoice->get_user_id();
1978
            $secret = sanitize_text_field( $_GET['_wpipay'] );
1979
            
1980
            if ( $secret === md5( $user_id . '::' . $invoice->get_email() . '::' . $invoice_key ) ) { // valid invoice link
1981
                $redirect_to = remove_query_arg( '_wpipay', get_permalink() );
1982
                
1983
                wpinv_guest_redirect( $redirect_to, $user_id );
1984
                wpinv_die();
1985
            }
1986
        }
1987
    }
1988
}
1989
add_action( 'wpinv_check_pay_for_invoice', 'wpinv_handle_pay_via_invoice_link' );
1990
1991
function wpinv_set_payment_transaction_id( $invoice_id = 0, $transaction_id = '' ) {
1992
    $invoice_id = is_object( $invoice_id ) && !empty( $invoice_id->ID ) ? $invoice_id : $invoice_id;
1993
    
1994
    if ( empty( $invoice_id ) && $invoice_id > 0 ) {
1995
        return false;
1996
    }
1997
    
1998
    if ( empty( $transaction_id ) ) {
1999
        $transaction_id = $invoice_id;
2000
    }
2001
2002
    $transaction_id = apply_filters( 'wpinv_set_payment_transaction_id', $transaction_id, $invoice_id );
2003
    
2004
    return wpinv_update_invoice_meta( $invoice_id, '_wpinv_transaction_id', $transaction_id );
2005
}
2006
2007
function wpinv_invoice_status_label( $status, $status_display = '' ) {
2008
    if ( empty( $status_display ) ) {
2009
        $status_display = wpinv_status_nicename( $status );
2010
    }
2011
    
2012
    switch ( $status ) {
2013
        case 'publish' :
2014
        case 'wpi-renewal' :
2015
            $class = 'label-success';
2016
        break;
2017
        case 'wpi-pending' :
2018
            $class = 'label-primary';
2019
        break;
2020
        case 'wpi-processing' :
2021
            $class = 'label-warning';
2022
        break;
2023
        case 'wpi-onhold' :
2024
            $class = 'label-info';
2025
        break;
2026
        case 'wpi-cancelled' :
2027
        case 'wpi-failed' :
2028
            $class = 'label-danger';
2029
        break;
2030
        default:
2031
            $class = 'label-default';
2032
        break;
2033
    }
2034
    
2035
    $label = '<span class="label label-inv-' . $status . ' ' . $class . '">' . $status_display . '</span>';
2036
    
2037
    return apply_filters( 'wpinv_invoice_status_label', $label, $status, $status_display );
2038
}
2039
2040
function wpinv_format_invoice_number( $number, $type = '' ) {
2041
    $check = apply_filters( 'wpinv_pre_format_invoice_number', null, $number, $type );
2042
    if ( null !== $check ) {
2043
        return $check;
2044
    }
2045
2046
    if ( !empty( $number ) && !is_numeric( $number ) ) {
2047
        return $number;
2048
    }
2049
2050
    $padd  = wpinv_get_option( 'invoice_number_padd' );
2051
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2052
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2053
    
2054
    $padd = absint( $padd );
2055
    $formatted_number = absint( $number );
2056
    
2057
    if ( $padd > 0 ) {
2058
        $formatted_number = zeroise( $formatted_number, $padd );
2059
    }    
2060
2061
    $formatted_number = $prefix . $formatted_number . $postfix;
2062
2063
    return apply_filters( 'wpinv_format_invoice_number', $formatted_number, $number, $prefix, $postfix, $padd );
2064
}
2065
2066
function wpinv_get_next_invoice_number( $type = '' ) {
2067
    $check = apply_filters( 'wpinv_get_pre_next_invoice_number', null, $type );
2068
    if ( null !== $check ) {
2069
        return $check;
2070
    }
2071
    
2072
    if ( !wpinv_sequential_number_active() ) {
2073
        return false;
2074
    }
2075
2076
    $number = $last_number = get_option( 'wpinv_last_invoice_number' );
2077
    $start  = wpinv_get_option( 'invoice_sequence_start' );
2078
    if ( !absint( $start ) > 0 ) {
2079
        $start = 1;
2080
    }
2081
    $increment_number = true;
2082
    $save_number = false;
2083
2084
    if ( !empty( $number ) && !is_numeric( $number ) && $number == wpinv_format_invoice_number( $number ) ) {
2085
        $number = wpinv_clean_invoice_number( $number );
2086
    }
2087
2088
    if ( empty( $number ) ) {
2089
        if ( !( $last_number === 0 || $last_number === '0' ) ) {
2090
            $last_invoice = wpinv_get_invoices( array( 'limit' => 1, 'order' => 'DESC', 'orderby' => 'ID', 'return' => 'posts', 'fields' => 'ids', 'status' => array_keys( wpinv_get_invoice_statuses( true ) ) ) );
2091
2092
            if ( !empty( $last_invoice[0] ) && $invoice_number = wpinv_get_invoice_number( $last_invoice[0] ) ) {
2093
                if ( is_numeric( $invoice_number ) ) {
2094
                    $number = $invoice_number;
2095
                } else {
2096
                    $number = wpinv_clean_invoice_number( $invoice_number );
2097
                }
2098
            }
2099
2100 View Code Duplication
            if ( empty( $number ) ) {
2101
                $increment_number = false;
2102
                $number = $start;
2103
                $save_number = ( $number - 1 );
2104
            } else {
2105
                $save_number = $number;
2106
            }
2107
        }
2108
    }
2109
2110 View Code Duplication
    if ( $start > $number ) {
2111
        $increment_number = false;
2112
        $number = $start;
2113
        $save_number = ( $number - 1 );
2114
    }
2115
2116
    if ( $save_number !== false ) {
2117
        update_option( 'wpinv_last_invoice_number', $save_number );
2118
    }
2119
    
2120
    $increment_number = apply_filters( 'wpinv_increment_payment_number', $increment_number, $number );
2121
2122
    if ( $increment_number ) {
2123
        $number++;
2124
    }
2125
2126
    return apply_filters( 'wpinv_get_next_invoice_number', $number );
2127
}
2128
2129
function wpinv_clean_invoice_number( $number, $type = '' ) {
2130
    $check = apply_filters( 'wpinv_pre_clean_invoice_number', null, $number, $type );
2131
    if ( null !== $check ) {
2132
        return $check;
2133
    }
2134
    
2135
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2136
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2137
2138
    $number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
2139
2140
    $length      = strlen( $number );
2141
    $postfix_pos = strrpos( $number, $postfix );
2142
    
2143
    if ( false !== $postfix_pos ) {
2144
        $number      = substr_replace( $number, '', $postfix_pos, $length );
2145
    }
2146
2147
    $number = intval( $number );
2148
2149
    return apply_filters( 'wpinv_clean_invoice_number', $number, $prefix, $postfix );
2150
}
2151
2152
function wpinv_save_number_post_saved( $post_ID, $post, $update ) {
2153
    global $wpdb;
2154
2155
    if ( !$update && !get_post_meta( $post_ID, '_wpinv_number', true ) ) {
2156
        wpinv_update_invoice_number( $post_ID, $post->post_status != 'auto-draft', $post->post_type );
2157
    }
2158
2159
    if ( !$update ) {
2160
        $wpdb->update( $wpdb->posts, array( 'post_name' => wpinv_generate_post_name( $post_ID ) ), array( 'ID' => $post_ID ) );
2161
        clean_post_cache( $post_ID );
2162
    }
2163
}
2164
add_action( 'save_post_wpi_invoice', 'wpinv_save_number_post_saved', 1, 3 );
2165
2166
function wpinv_save_number_post_updated( $post_ID, $post_after, $post_before ) {
2167
    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 ) {
2168
        wpinv_update_invoice_number( $post_ID, true, $post_after->post_type );
2169
    }
2170
}
2171
add_action( 'post_updated', 'wpinv_save_number_post_updated', 1, 3 );
2172
2173
function wpinv_update_invoice_number( $post_ID, $save_sequential = false, $type = '' ) {
2174
    global $wpdb;
2175
    
2176
    $check = apply_filters( 'wpinv_pre_update_invoice_number', null, $post_ID, $save_sequential, $type );
2177
    if ( null !== $check ) {
2178
        return $check;
2179
    }
2180
2181
    if ( wpinv_sequential_number_active() ) {
2182
        $number = wpinv_get_next_invoice_number();
2183
2184
        if ( $save_sequential ) {
2185
            update_option( 'wpinv_last_invoice_number', $number );
2186
        }
2187
    } else {
2188
        $number = $post_ID;
2189
    }
2190
2191
    $number = wpinv_format_invoice_number( $number );
2192
2193
    update_post_meta( $post_ID, '_wpinv_number', $number );
2194
2195
    $wpdb->update( $wpdb->posts, array( 'post_title' => $number ), array( 'ID' => $post_ID ) );
2196
2197
    clean_post_cache( $post_ID );
2198
2199
    return $number;
2200
}
2201
2202
function wpinv_post_name_prefix( $post_type = 'wpi_invoice' ) {
2203
    return apply_filters( 'wpinv_post_name_prefix', 'inv-', $post_type );
2204
}
2205
2206
function wpinv_generate_post_name( $post_ID ) {
2207
    $prefix = wpinv_post_name_prefix( get_post_type( $post_ID ) );
2208
    $post_name = sanitize_title( $prefix . $post_ID );
2209
2210
    return apply_filters( 'wpinv_generate_post_name', $post_name, $post_ID, $prefix );
2211
}
2212
2213
function wpinv_is_invoice_viewed( $invoice_id ) {
2214
    if ( empty( $invoice_id ) ) {
2215
        return false;
2216
    }
2217
2218
    $viewed_meta = get_post_meta( $invoice_id, '_wpinv_is_viewed', true );
2219
2220
    if ( isset($viewed_meta) && 1 == $viewed_meta ) {
2221
        $is_viewed = true;
2222
    } else {
2223
        $is_viewed = false;
2224
    }
2225
2226
    return apply_filters( 'wpinv_is_invoice_viewed', $is_viewed, $invoice_id );
2227
}
2228
2229
function wpinv_mark_invoice_viewed() {
2230
2231
    if ( isset( $_GET['invoice_key'] ) ) {
2232
        $invoice_key = urldecode($_GET['invoice_key']);
2233
2234
        $invoice_id = wpinv_get_invoice_id_by_key($invoice_key);
2235
        $invoice = new WPInv_Invoice($invoice_id);
2236
2237
        if(!$invoice_id){
2238
            return;
2239
        }
2240
2241
        if( is_user_logged_in()){
2242
            $current_user = wp_get_current_user();
2243
            if(!current_user_can('administrator') && $current_user->user_email == $invoice->get_email()){
2244
                update_post_meta($invoice_id,'_wpinv_is_viewed', 1);
2245
            }
2246
        } else {
2247
            update_post_meta($invoice_id,'_wpinv_is_viewed', 1);
2248
        }
2249
    }
2250
2251
}
2252
add_action( 'init', 'wpinv_mark_invoice_viewed' );
2253
2254
function wpinv_get_subscription( $invoice ) {
2255
    if ( empty( $invoice ) ) {
2256
        return false;
2257
    }
2258
    
2259
    if ( ! is_object( $invoice ) && is_scalar( $invoice ) ) {
2260
        $invoice = wpinv_get_invoice( $invoice );
2261
    }
2262
    
2263
    if ( !( is_object( $invoice ) && ! empty( $invoice->ID ) && $invoice->is_recurring() ) ) {
2264
        return false;
2265
    }
2266
    
2267
    $invoice_id = ! empty( $invoice->parent_invoice ) ? $invoice->parent_invoice : $invoice->ID;
2268
    
2269
    $subs_db    = new WPInv_Subscriptions_DB;
2270
    $subs       = $subs_db->get_subscriptions( array( 'parent_payment_id' => $invoice_id, 'number' => 1 ) );
2271
    
2272
    if ( ! empty( $subs ) ) {
2273
        return reset( $subs );
2274
    }
2275
    
2276
    return false;
2277
}