Passed
Pull Request — master (#78)
by Kiran
17:05 queued 04:03
created

wpinv-invoice-functions.php ➔ wpinv_update_invoice()   F

Complexity

Conditions 62
Paths > 20000

Size

Total Lines 223
Code Lines 123

Duplication

Lines 16
Ratio 7.17 %

Importance

Changes 0
Metric Value
cc 62
eloc 123
nc 6435092
nop 2
dl 16
loc 223
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Contains 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'] = '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'          => geodir_get_currency_type(),
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'] = geodir_get_currency_type();
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'] : '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
    if ( !empty( $invoice_data['invoice_key'] ) ) {
160
        $invoice->set( 'key', $invoice_data['invoice_key'] );
161
    }
162
    $invoice->set( 'mode', ( wpinv_is_test_mode() ? 'test' : 'live' ) );
163
    $invoice->set( 'parent_invoice', ( !empty( $invoice_data['parent'] ) ? absint( $invoice_data['parent'] ) : '' ) );
164
    
165
    if ( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) ) {
166
        foreach ( $invoice_data['cart_details'] as $key => $item ) {
167
            $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
168
            $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
169
            $name           = !empty( $item['name'] ) ? $item['name'] : '';
170
            $item_price     = isset( $item['item_price'] ) ? $item['item_price'] : '';
171
            
172
            $post_item  = new WPInv_Item( $item_id );
173
            if ( !empty( $post_item ) ) {
174
                $name       = !empty( $name ) ? $name : $post_item->get_name();
175
                $item_price = $item_price !== '' ? $item_price : $post_item->get_price();
176
            } else {
177
                continue;
178
            }
179
            
180
            $args = array(
181
                'name'          => $name,
182
                'quantity'      => $quantity,
183
                'item_price'    => $item_price,
184
                'custom_price'  => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
185
                'tax'           => !empty( $item['tax'] ) ? $item['tax'] : 0.00,
186
                'discount'      => isset( $item['discount'] ) ? $item['discount'] : 0,
187
                'meta'          => isset( $item['meta'] ) ? $item['meta'] : array(),
188
                'fees'          => isset( $item['fees'] ) ? $item['fees'] : array(),
189
            );
190
191
            $invoice->add_item( $item_id, $args );
192
        }
193
    }
194
195
    $invoice->increase_tax( wpinv_get_cart_fee_tax() );
196
197
    if ( isset( $invoice_data['post_date'] ) ) {
198
        $invoice->set( 'date', $invoice_data['post_date'] );
199
    }
200
    
201
    // Invoice due date
202
    if ( isset( $invoice_data['due_date'] ) ) {
203
        $invoice->set( 'due_date', $invoice_data['due_date'] );
204
    }
205
    
206
    $invoice->save();
207
    
208
    // Add notes
209
    if ( !empty( $invoice_data['private_note'] ) ) {
210
        $invoice->add_note( $invoice_data['private_note'] );
211
    }
212
    if ( !empty( $invoice_data['user_note'] ) ) {
213
        $invoice->add_note( $invoice_data['user_note'], true );
214
    }
215
    
216
    do_action( 'wpinv_insert_invoice', $invoice->ID, $invoice_data );
217
218
    if ( ! empty( $invoice->ID ) ) {
219
        global $wpi_userID, $wpinv_ip_address_country;
220
        
221
        $checkout_session = wpinv_get_checkout_session();
222
        
223
        $data_session                   = array();
224
        $data_session['invoice_id']     = $invoice->ID;
225
        $data_session['cart_discounts'] = $invoice->get_discounts( true );
226
        
227
        wpinv_set_checkout_session( $data_session );
228
        
229
        $wpi_userID         = (int)$invoice->get_user_id();
230
        
231
        $_POST['country']   = !empty( $invoice->country ) ? $invoice->country : wpinv_get_default_country();
232
        $_POST['state']     = $invoice->state;
233
234
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
235
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
236
        
237
        $wpinv_ip_address_country = $invoice->country;
238
        
239
        $invoice = $invoice->recalculate_totals( true );
240
        
241
        wpinv_set_checkout_session( $checkout_session );
242
                    
243
        return $invoice;
244
    }
245
    
246 View Code Duplication
    if ( $wp_error ) {
247
        if ( is_wp_error( $invoice ) ) {
248
            return $invoice;
249
        } else {
250
            return new WP_Error( 'wpinv_insert_invoice_error', __( 'Error in insert invoice.', 'invoicing' ) );
251
        }
252
    } else {
253
        return 0;
254
    }
255
}
256
257
function wpinv_update_invoice( $invoice_data = array(), $wp_error = false ) {
258
    $invoice_ID = !empty( $invoice_data['ID'] ) ? absint( $invoice_data['ID'] ) : NULL;
259
260
    if ( !$invoice_ID ) {
261
        if ( $wp_error ) {
262
            return new WP_Error( 'invalid_invoice_id', __( 'Invalid invoice ID.', 'invoicing' ) );
263
        }
264
        return 0;
265
    }
266
267
    $invoice = wpinv_get_invoice( $invoice_ID );
268
269
    $recurring_item = $invoice->is_recurring() ? $invoice->get_recurring( true ) : NULL;
270
271
    if ( empty( $invoice->ID ) ) {
272
        if ( $wp_error ) {
273
            return new WP_Error( 'invalid_invoice', __( 'Invalid invoice.', 'invoicing' ) );
274
        }
275
        return 0;
276
    }
277
278
    if ( !$invoice->has_status( array( 'pending' ) ) ) {
279
        if ( $wp_error ) {
280
            return new WP_Error( 'invalid_invoice_status', __( 'Only invoice with pending payment is allowed to update.', 'invoicing' ) );
281
        }
282
        return 0;
283
    }
284
285
    // Invoice status
286
    if ( !empty( $invoice_data['status'] ) ) {
287
        $invoice->set( 'status', $invoice_data['status'] );
288
    }
289
290
    // Invoice date
291
    if ( !empty( $invoice_data['post_date'] ) ) {
292
        $invoice->set( 'date', $invoice_data['post_date'] );
293
    }
294
295
    // Invoice due date
296
    if ( isset( $invoice_data['due_date'] ) ) {
297
        $invoice->set( 'due_date', $invoice_data['due_date'] );
298
    }
299
300
    // Invoice IP address
301
    if ( !empty( $invoice_data['ip'] ) ) {
302
        $invoice->set( 'ip', $invoice_data['ip'] );
303
    }
304
305
    // Invoice key
306
    if ( !empty( $invoice_data['invoice_key'] ) ) {
307
        $invoice->set( 'key', $invoice_data['invoice_key'] );
308
    }
309
    
310
    // User info
311
    if ( !empty( $invoice_data['user_info'] ) && is_array( $invoice_data['user_info'] ) ) {
312
        $user_info = wp_parse_args( $invoice_data['user_info'], $invoice->user_info );
313
314
        if ( $discounts = $invoice->get_discounts() ) {
315
            $set_discount = $discounts;
316
        } else {
317
            $set_discount = '';
318
        }
319
320
        // Manage discount
321
        if ( !empty( $invoice_data['user_info']['discount'] ) ) {
322
            // Remove discount
323
            if ( $invoice_data['user_info']['discount'] == 'none' ) {
324
                $set_discount = '';
325
            } else {
326
                $set_discount = $invoice_data['user_info']['discount'];
327
            }
328
329
            $invoice->set( 'discounts', $set_discount );
330
        }
331
332
        $user_info['discount'] = $set_discount;
333
334
        $invoice->set( 'user_info', $user_info );
335
    }
336
337
    if ( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) && $cart_details = $invoice_data['cart_details'] ) {
338
        $remove_items = !empty( $cart_details['remove_items'] ) && is_array( $cart_details['remove_items'] ) ? $cart_details['remove_items'] : array();
339
340
        if ( !empty( $remove_items[0]['id'] ) ) {
341
            foreach ( $remove_items as $item ) {
342
                $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
343
                $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
344
                if ( empty( $item_id ) ) {
345
                    continue;
346
                }
347
348
                foreach ( $invoice->cart_details as $cart_index => $cart_item ) {
349
                    if ( $item_id == $cart_item['id'] ) {
350
                        $args = array(
351
                            'id'         => $item_id,
352
                            'quantity'   => $quantity,
353
                            'cart_index' => $cart_index
354
                        );
355
356
                        $invoice->remove_item( $item_id, $args );
357
                        break;
358
                    }
359
                }
360
            }
361
        }
362
363
        $add_items = !empty( $cart_details['add_items'] ) && is_array( $cart_details['add_items'] ) ? $cart_details['add_items'] : array();
364
365
        if ( !empty( $add_items[0]['id'] ) ) {
366
            foreach ( $add_items as $item ) {
367
                $item_id        = !empty( $item['id'] ) ? $item['id'] : 0;
368
                $post_item      = new WPInv_Item( $item_id );
369
                if ( empty( $post_item ) ) {
370
                    continue;
371
                }
372
373
                $valid_item = true;
374 View Code Duplication
                if ( !empty( $recurring_item ) ) {
375
                    if ( $recurring_item->ID != $item_id ) {
376
                        $valid_item = false;
377
                    }
378
                } else if ( wpinv_is_recurring_item( $item_id ) ) {
379
                    $valid_item = false;
380
                }
381
                
382
                if ( !$valid_item ) {
383
                    if ( $wp_error ) {
384
                        return new WP_Error( 'invalid_invoice_item', __( 'You can not add item to invoice because recurring item must be paid individually!', 'invoicing' ) );
385
                    }
386
                    return 0;
387
                }
388
389
                $quantity       = !empty( $item['quantity'] ) ? $item['quantity'] : 1;
390
                $name           = !empty( $item['name'] ) ? $item['name'] : $post_item->get_name();
391
                $item_price     = isset( $item['item_price'] ) ? $item['item_price'] : $post_item->get_price();
392
393
                $args = array(
394
                    'name'          => $name,
395
                    'quantity'      => $quantity,
396
                    'item_price'    => $item_price,
397
                    'custom_price'  => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
398
                    'tax'           => !empty( $item['tax'] ) ? $item['tax'] : 0,
399
                    'discount'      => isset( $item['discount'] ) ? $item['discount'] : 0,
400
                    'meta'          => isset( $item['meta'] ) ? $item['meta'] : array(),
401
                    'fees'          => isset( $item['fees'] ) ? $item['fees'] : array(),
402
                );
403
404
                $invoice->add_item( $item_id, $args );
405
            }
406
        }
407
    }
408
    
409
    // Payment details
410
    if ( !empty( $invoice_data['payment_details'] ) && $payment_details = $invoice_data['payment_details'] ) {
411
        if ( !empty( $payment_details['gateway'] ) ) {
412
            $invoice->set( 'gateway', $payment_details['gateway'] );
413
        }
414
415
        if ( !empty( $payment_details['transaction_id'] ) ) {
416
            $invoice->set( 'transaction_id', $payment_details['transaction_id'] );
417
        }
418
    }
419
420
    do_action( 'wpinv_pre_update_invoice', $invoice->ID, $invoice_data );
421
422
    // Parent invoice
423
    if ( !empty( $invoice_data['parent'] ) ) {
424
        $invoice->set( 'parent_invoice', $invoice_data['parent'] );
425
    }
426
427
    // Save invoice data.
428
    $invoice->save();
429
    
430
    if ( empty( $invoice->ID ) || is_wp_error( $invoice ) ) {
431 View Code Duplication
        if ( $wp_error ) {
432
            if ( is_wp_error( $invoice ) ) {
433
                return $invoice;
434
            } else {
435
                return new WP_Error( 'wpinv_update_invoice_error', __( 'Error in update invoice.', 'invoicing' ) );
436
            }
437
        } else {
438
            return 0;
439
        }
440
    }
441
442
    // Add private note
443
    if ( !empty( $invoice_data['private_note'] ) ) {
444
        $invoice->add_note( $invoice_data['private_note'] );
445
    }
446
447
    // Add user note
448
    if ( !empty( $invoice_data['user_note'] ) ) {
449
        $invoice->add_note( $invoice_data['user_note'], true );
450
    }
451
452
    global $wpi_userID, $wpinv_ip_address_country;
453
454
    $checkout_session = wpinv_get_checkout_session();
455
456
    $data_session                   = array();
457
    $data_session['invoice_id']     = $invoice->ID;
458
    $data_session['cart_discounts'] = $invoice->get_discounts( true );
459
460
    wpinv_set_checkout_session( $data_session );
461
462
    $wpi_userID         = (int)$invoice->get_user_id();
463
464
    $_POST['country']   = !empty( $invoice->country ) ? $invoice->country : wpinv_get_default_country();
465
    $_POST['state']     = $invoice->state;
466
467
    $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
468
    $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
469
470
    $wpinv_ip_address_country = $invoice->country;
471
472
    $invoice = $invoice->recalculate_totals( true );
473
474
    do_action( 'wpinv_post_update_invoice', $invoice->ID, $invoice_data );
475
476
    wpinv_set_checkout_session( $checkout_session );
477
478
    return $invoice;
479
}
480
481
function wpinv_get_invoice( $invoice_id = 0, $cart = false ) {
482
    if ( $cart && empty( $invoice_id ) ) {
483
        $invoice_id = (int)wpinv_get_invoice_cart_id();
484
    }
485
486
    $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...
487
    return $invoice;
488
}
489
490
function wpinv_get_invoice_cart( $invoice_id = 0 ) {
491
    return wpinv_get_invoice( $invoice_id, true );
492
}
493
494
function wpinv_get_invoice_description( $invoice_id = 0 ) {
495
    $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...
496
    return $invoice->get_description();
497
}
498
499
function wpinv_get_invoice_currency_code( $invoice_id = 0 ) {
500
    $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...
501
    return $invoice->get_currency();
502
}
503
504
function wpinv_get_payment_user_email( $invoice_id ) {
505
    $invoice = new WPInv_Invoice( $invoice_id );
506
    return $invoice->get_email();
507
}
508
509
function wpinv_get_user_id( $invoice_id ) {
510
    $invoice = new WPInv_Invoice( $invoice_id );
511
    return $invoice->get_user_id();
512
}
513
514
function wpinv_get_invoice_status( $invoice_id, $return_label = false ) {
515
    $invoice = new WPInv_Invoice( $invoice_id );
516
    
517
    return $invoice->get_status( $return_label );
518
}
519
520
function wpinv_get_payment_gateway( $invoice_id, $return_label = false ) {
521
    $invoice = new WPInv_Invoice( $invoice_id );
522
    
523
    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...
524
}
525
526
function wpinv_get_payment_gateway_name( $invoice_id ) {
527
    $invoice = new WPInv_Invoice( $invoice_id );
528
    
529
    return $invoice->get_gateway_title();
530
}
531
532
function wpinv_get_payment_transaction_id( $invoice_id ) {
533
    $invoice = new WPInv_Invoice( $invoice_id );
534
    
535
    return $invoice->get_transaction_id();
536
}
537
538 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...
539
    global $wpdb;
540
541
    $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 ) );
542
543
    if ( $invoice_id != NULL )
544
        return $invoice_id;
545
546
    return 0;
547
}
548
549
function wpinv_get_invoice_meta( $invoice_id = 0, $meta_key = '_wpinv_payment_meta', $single = true ) {
550
    $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...
551
552
    return $invoice->get_meta( $meta_key, $single );
553
}
554
555
function wpinv_update_invoice_meta( $invoice_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
556
    $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...
557
    
558
    return $invoice->update_meta( $meta_key, $meta_value, $prev_value );
559
}
560
561
function wpinv_get_items( $invoice_id = 0 ) {
562
    $invoice            = wpinv_get_invoice( $invoice_id );
563
    
564
    $items              = $invoice->get_items();
565
    $invoice_currency   = $invoice->get_currency();
566
567 View Code Duplication
    if ( !empty( $items ) && is_array( $items ) ) {
568
        foreach ( $items as $key => $item ) {
569
            $items[$key]['currency'] = $invoice_currency;
570
571
            if ( !isset( $cart_item['subtotal'] ) ) {
572
                $items[$key]['subtotal'] = $items[$key]['amount'] * 1;
573
            }
574
        }
575
    }
576
577
    return apply_filters( 'wpinv_get_items', $items, $invoice_id );
578
}
579
580
function wpinv_get_fees( $invoice_id = 0 ) {
581
    $invoice           = wpinv_get_invoice( $invoice_id );
582
    $fees              = $invoice->get_fees();
583
584
    return apply_filters( 'wpinv_get_fees', $fees, $invoice_id );
585
}
586
587
function wpinv_get_invoice_ip( $invoice_id ) {
588
    $invoice = new WPInv_Invoice( $invoice_id );
589
    return $invoice->get_ip();
590
}
591
592
function wpinv_get_invoice_user_info( $invoice_id ) {
593
    $invoice = new WPInv_Invoice( $invoice_id );
594
    return $invoice->get_user_info();
595
}
596
597
function wpinv_subtotal( $invoice_id = 0, $currency = false ) {
598
    $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...
599
600
    return $invoice->get_subtotal( $currency );
601
}
602
603
function wpinv_tax( $invoice_id = 0, $currency = false ) {
604
    $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...
605
606
    return $invoice->get_tax( $currency );
607
}
608
609
function wpinv_discount( $invoice_id = 0, $currency = false, $dash = false ) {
610
    $invoice = wpinv_get_invoice( $invoice_id );
611
612
    return $invoice->get_discount( $currency, $dash );
613
}
614
615
function wpinv_discount_code( $invoice_id = 0 ) {
616
    $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...
617
618
    return $invoice->get_discount_code();
619
}
620
621
function wpinv_payment_total( $invoice_id = 0, $currency = false ) {
622
    $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...
623
624
    return $invoice->get_total( $currency );
625
}
626
627
function wpinv_get_date_created( $invoice_id = 0 ) {
628
    $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...
629
    
630
    $date_created   = $invoice->get_created_date();
631
    $date_created   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( get_option( 'date_format' ), strtotime( $date_created ) ) : '';
632
633
    return $date_created;
634
}
635
636
function wpinv_get_invoice_date( $invoice_id = 0, $format = '' ) {
637
    $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...
638
    
639
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
640
    $date_completed = $invoice->get_completed_date();
641
    $invoice_date   = $date_completed != '' && $date_completed != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_completed ) ) : '';
642
    if ( $invoice_date == '' ) {
643
        $date_created   = $invoice->get_created_date();
644
        $invoice_date   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_created ) ) : '';
645
    }
646
647
    return $invoice_date;
648
}
649
650
function wpinv_get_invoice_vat_number( $invoice_id = 0 ) {
651
    $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...
652
    
653
    return $invoice->vat_number;
654
}
655
656
function wpinv_insert_payment_note( $invoice_id = 0, $note = '', $user_type = false, $added_by_user = false ) {
657
    $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...
658
659
    return $invoice->add_note( $note, $user_type, $added_by_user );
660
}
661
662
function wpinv_get_invoice_notes( $invoice_id = 0, $type = '' ) {
663
    global $invoicing;
664
    
665
    if ( empty( $invoice_id ) ) {
666
        return NULL;
667
    }
668
    
669
    $notes = $invoicing->notes->get_invoice_notes( $invoice_id, $type );
670
    
671
    return apply_filters( 'wpinv_invoice_notes', $notes, $invoice_id, $type );
672
}
673
674
function wpinv_get_payment_key( $invoice_id = 0 ) {
675
	$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...
676
    return $invoice->get_key();
677
}
678
679
function wpinv_get_invoice_number( $invoice_id = 0 ) {
680
    $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...
681
    return $invoice->get_number();
682
}
683
684
function wpinv_get_cart_discountable_subtotal( $code_id ) {
685
    $cart_items = wpinv_get_cart_content_details();
686
    $items      = array();
687
688
    $excluded_items = wpinv_get_discount_excluded_items( $code_id );
689
690
    if( $cart_items ) {
691
692
        foreach( $cart_items as $item ) {
693
694
            if( ! in_array( $item['id'], $excluded_items ) ) {
695
                $items[] =  $item;
696
            }
697
        }
698
    }
699
700
    $subtotal = wpinv_get_cart_items_subtotal( $items );
701
702
    return apply_filters( 'wpinv_get_cart_discountable_subtotal', $subtotal );
703
}
704
705
function wpinv_get_cart_items_subtotal( $items ) {
706
    $subtotal = 0.00;
707
708
    if ( is_array( $items ) && ! empty( $items ) ) {
709
        $prices = wp_list_pluck( $items, 'subtotal' );
710
711
        if( is_array( $prices ) ) {
712
            $subtotal = array_sum( $prices );
713
        } else {
714
            $subtotal = 0.00;
715
        }
716
717
        if( $subtotal < 0 ) {
718
            $subtotal = 0.00;
719
        }
720
    }
721
722
    return apply_filters( 'wpinv_get_cart_items_subtotal', $subtotal );
723
}
724
725
function wpinv_get_cart_subtotal( $items = array() ) {
726
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
727
    $subtotal = wpinv_get_cart_items_subtotal( $items );
728
729
    return apply_filters( 'wpinv_get_cart_subtotal', $subtotal );
730
}
731
732
function wpinv_cart_subtotal( $items = array() ) {
733
    $price = wpinv_price( wpinv_format_amount( wpinv_get_cart_subtotal( $items ) ) );
734
735
    return $price;
736
}
737
738
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...
739
    $subtotal  = (float)wpinv_get_cart_subtotal( $items );
740
    $discounts = (float)wpinv_get_cart_discounted_amount( $items );
741
    $cart_tax  = (float)wpinv_get_cart_tax( $items );
742
    $fees      = (float)wpinv_get_cart_fee_total();
743
    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...
744
        $total = 0;
745
    } else {
746
        $total     = $subtotal - $discounts + $cart_tax + $fees;
747
    }
748
749
    if ( $total < 0 ) {
750
        $total = 0.00;
751
    }
752
    
753
    $total = (float)apply_filters( 'wpinv_get_cart_total', $total, $items );
754
755
    return wpinv_sanitize_amount( $total );
756
}
757
758
function wpinv_cart_total( $cart_items = array(), $echo = true, $invoice = array() ) {
759
    global $cart_total;
760
    $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...
761
    $total = apply_filters( 'wpinv_cart_total', $total, $cart_items, $invoice );
762
    
763
    $cart_total = $total;
764
765
    if ( !$echo ) {
766
        return $total;
767
    }
768
769
    echo $total;
770
}
771
772 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...
773
    $cart_tax = 0;
774
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
775
776
    if ( $items ) {
777
        $taxes = wp_list_pluck( $items, 'tax' );
778
779
        if( is_array( $taxes ) ) {
780
            $cart_tax = array_sum( $taxes );
781
        }
782
    }
783
784
    $cart_tax += wpinv_get_cart_fee_tax();
785
786
    return apply_filters( 'wpinv_get_cart_tax', wpinv_sanitize_amount( $cart_tax ) );
787
}
788
789 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...
790
    $cart_tax = wpinv_get_cart_tax( $items );
791
    $cart_tax = wpinv_price( wpinv_format_amount( $cart_tax ) );
792
793
    $tax = apply_filters( 'wpinv_cart_tax', $cart_tax, $items );
794
795
    if ( !$echo ) {
796
        return $tax;
797
    }
798
799
    echo $tax;
800
}
801
802
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...
803
    $invoice = wpinv_get_invoice_cart();
804
    $cart_discount_code = !empty( $invoice ) ? $invoice->get_discount_code() : '';
805
    
806
    return apply_filters( 'wpinv_get_cart_discount_code', $cart_discount_code );
807
}
808
809
function wpinv_cart_discount_code( $items = array(), $echo = false ) {
810
    $cart_discount_code = wpinv_get_cart_discount_code( $items );
811
812
    if ( $cart_discount_code != '' ) {
813
        $cart_discount_code = ' (' . $cart_discount_code . ')';
814
    }
815
    
816
    $discount_code = apply_filters( 'wpinv_cart_discount_code', $cart_discount_code, $items );
817
818
    if ( !$echo ) {
819
        return $discount_code;
820
    }
821
822
    echo $discount_code;
823
}
824
825
function wpinv_get_cart_discount( $items = array() ) {
826
    $invoice = wpinv_get_invoice_cart();
827
    $cart_discount = !empty( $invoice ) ? $invoice->get_discount() : 0;
828
    
829
    return apply_filters( 'wpinv_get_cart_discount', wpinv_sanitize_amount( $cart_discount ), $items );
830
}
831
832 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...
833
    $cart_discount = wpinv_get_cart_discount( $items );
834
    $cart_discount = wpinv_price( wpinv_format_amount( $cart_discount ) );
835
836
    $discount = apply_filters( 'wpinv_cart_discount', $cart_discount, $items );
837
838
    if ( !$echo ) {
839
        return $discount;
840
    }
841
842
    echo $discount;
843
}
844
845
function wpinv_get_cart_fees( $type = 'all', $item_id = 0 ) {
846
    $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...
847
    
848
    return $item->get_fees( $type, $item_id );
849
}
850
851
function wpinv_get_cart_fee_total() {
852
    $total  = 0;
853
    $fees = wpinv_get_cart_fees();
854
    
855
    if ( $fees ) {
856
        foreach ( $fees as $fee_id => $fee ) {
857
            $total += $fee['amount'];
858
        }
859
    }
860
861
    return apply_filters( 'wpinv_get_cart_fee_total', $total );
862
}
863
864
function wpinv_get_cart_fee_tax() {
865
    $tax  = 0;
866
    $fees = wpinv_get_cart_fees();
867
868
    if ( $fees ) {
869
        foreach ( $fees as $fee_id => $fee ) {
870
            if( ! empty( $fee['no_tax'] ) ) {
871
                continue;
872
            }
873
874
            $tax += wpinv_calculate_tax( $fee['amount'] );
875
        }
876
    }
877
878
    return apply_filters( 'wpinv_get_cart_fee_tax', $tax );
879
}
880
881
function wpinv_cart_has_recurring_item() {
882
    $cart_items = wpinv_get_cart_contents();
883
    
884
    if ( empty( $cart_items ) ) {
885
        return false;
886
    }
887
    
888
    $has_subscription = false;
889 View Code Duplication
    foreach( $cart_items as $cart_item ) {
890
        if ( !empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] )  ) {
891
            $has_subscription = true;
892
            break;
893
        }
894
    }
895
    
896
    return apply_filters( 'wpinv_cart_has_recurring_item', $has_subscription, $cart_items );
897
}
898
899
function wpinv_cart_has_free_trial() {
900
    $invoice = wpinv_get_invoice_cart();
901
    
902
    $free_trial = false;
903
    
904
    if ( !empty( $invoice ) && $invoice->is_free_trial() ) {
905
        $free_trial = true;
906
    }
907
    
908
    return apply_filters( 'wpinv_cart_has_free_trial', $free_trial, $invoice );
909
}
910
911
function wpinv_get_cart_contents() {
912
    $cart_details = wpinv_get_cart_details();
913
    
914
    return apply_filters( 'wpinv_get_cart_contents', $cart_details );
915
}
916
917
function wpinv_get_cart_content_details() {
918
    global $wpinv_euvat, $wpi_current_id, $wpi_item_id, $wpinv_is_last_cart_item, $wpinv_flat_discount_total;
919
    $cart_items = wpinv_get_cart_contents();
920
    
921
    if ( empty( $cart_items ) ) {
922
        return false;
923
    }
924
    $invoice = wpinv_get_invoice_cart();
925
926
    $details = array();
927
    $length  = count( $cart_items ) - 1;
0 ignored issues
show
Unused Code introduced by
$length is not used, you could remove the assignment.

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

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

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

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

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
961
        $tax_class          = $wpinv_euvat->get_item_class( $item_id );
962
        $tax                = wpinv_get_cart_item_tax( $item_id, $subtotal - $discount );
963
        
964
        if ( wpinv_prices_include_tax() ) {
965
            $subtotal -= wpinv_round_amount( $tax );
966
        }
967
        
968
        $total              = $subtotal - $discount + $tax;
969
        
970
        // Do not allow totals to go negatve
971
        if( $total < 0 ) {
972
            $total = 0;
973
        }
974
        
975
        $details[ $key ]  = array(
976
            'id'                => $item_id,
977
            'name'              => !empty($item['name']) ? $item['name'] : get_the_title( $item_id ),
978
            'item_price'        => wpinv_round_amount( $item_price ),
979
            'custom_price'      => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
980
            'quantity'          => $quantity,
981
            'discount'          => wpinv_round_amount( $discount ),
982
            'subtotal'          => wpinv_round_amount( $subtotal ),
983
            'tax'               => wpinv_round_amount( $tax ),
984
            'price'             => wpinv_round_amount( $total ),
985
            'vat_rates_class'   => $tax_class,
986
            'vat_rate'          => $tax_rate,
987
            'meta'              => isset( $item['meta'] ) ? $item['meta'] : array(),
988
            'fees'              => $fees,
989
        );
990
        
991
        if ( $wpinv_is_last_cart_item ) {
992
            $wpinv_is_last_cart_item   = false;
993
            $wpinv_flat_discount_total = 0.00;
994
        }
995
    }
996
    
997
    return $details;
998
}
999
1000
function wpinv_get_cart_details( $invoice_id = 0 ) {
1001
    global $ajax_cart_details;
1002
1003
    $invoice      = wpinv_get_invoice_cart( $invoice_id );
1004
    $cart_details = !empty( $ajax_cart_details ) ? $ajax_cart_details : $invoice->cart_details;
1005
1006
    $invoice_currency = $invoice->currency;
1007
1008 View Code Duplication
    if ( ! empty( $cart_details ) && is_array( $cart_details ) ) {
1009
        foreach ( $cart_details as $key => $cart_item ) {
1010
            $cart_details[ $key ]['currency'] = $invoice_currency;
1011
1012
            if ( ! isset( $cart_item['subtotal'] ) ) {
1013
                $cart_details[ $key ]['subtotal'] = $cart_item['price'];
1014
            }
1015
        }
1016
    }
1017
1018
    return apply_filters( 'wpinv_get_cart_details', $cart_details, $invoice_id );
1019
}
1020
1021
function wpinv_record_status_change( $invoice_id, $new_status, $old_status ) {
1022
    if ( 'wpi_invoice' != get_post_type( $invoice_id ) ) {
1023
        return;
1024
    }
1025
1026
    $invoice    = wpinv_get_invoice( $invoice_id );
1027
    
1028
    $old_status = wpinv_status_nicename( $old_status );
1029
    $new_status = wpinv_status_nicename( $new_status );
1030
1031
    $status_change = sprintf( __( 'Invoice status changed from %s to %s', 'invoicing' ), $old_status, $new_status );
1032
    
1033
    // Add note
1034
    return $invoice->add_note( $status_change, false, false, true );
1035
}
1036
add_action( 'wpinv_update_status', 'wpinv_record_status_change', 100, 3 );
1037
1038
function wpinv_complete_payment( $invoice_id, $new_status, $old_status ) {
1039
    global $wpi_has_free_trial;
1040
    
1041
    $wpi_has_free_trial = false;
1042
    
1043
    if ( $old_status == 'publish' ) {
1044
        return; // Make sure that payments are only paid once
1045
    }
1046
1047
    // Make sure the payment completion is only processed when new status is paid
1048
    if ( $new_status != 'publish' ) {
1049
        return;
1050
    }
1051
1052
    $invoice = new WPInv_Invoice( $invoice_id );
1053
    if ( empty( $invoice ) ) {
1054
        return;
1055
    }
1056
1057
    $wpi_has_free_trial = $invoice->is_free_trial();
1058
    $completed_date = $invoice->completed_date;
1059
    $cart_details   = $invoice->cart_details;
1060
1061
    do_action( 'wpinv_pre_complete_payment', $invoice_id );
1062
1063
    if ( is_array( $cart_details ) ) {
1064
        // Increase purchase count and earnings
1065
        foreach ( $cart_details as $cart_index => $item ) {
1066
            // Ensure these actions only run once, ever
1067
            if ( empty( $completed_date ) ) {
1068
                do_action( 'wpinv_complete_item_payment', $item['id'], $invoice_id, $item, $cart_index );
1069
            }
1070
        }
1071
    }
1072
    
1073
    // Check for discount codes and increment their use counts
1074
    if ( $discounts = $invoice->get_discounts( true ) ) {
1075
        if( ! empty( $discounts ) ) {
1076
            foreach( $discounts as $code ) {
1077
                wpinv_increase_discount_usage( $code );
1078
            }
1079
        }
1080
    }
1081
    
1082
    // Ensure this action only runs once ever
1083
    if( empty( $completed_date ) ) {
1084
        // Save the completed date
1085
        $invoice->set( 'completed_date', current_time( 'mysql', 0 ) );
1086
        $invoice->save();
1087
1088
        do_action( 'wpinv_complete_payment', $invoice_id );
1089
    }
1090
1091
    // Empty the shopping cart
1092
    wpinv_empty_cart();
1093
}
1094
add_action( 'wpinv_update_status', 'wpinv_complete_payment', 100, 3 );
1095
1096
function wpinv_update_payment_status( $invoice_id, $new_status = 'publish' ) {    
1097
    $invoice = !empty( $invoice_id ) && is_object( $invoice_id ) ? $invoice_id : wpinv_get_invoice( (int)$invoice_id );
1098
    
1099
    if ( empty( $invoice ) ) {
1100
        return false;
1101
    }
1102
    
1103
    return $invoice->update_status( $new_status );
1104
}
1105
1106
function wpinv_cart_has_fees( $type = 'all' ) {
1107
    return false;
1108
}
1109
1110
function wpinv_validate_checkout_fields() {    
1111
    // Check if there is $_POST
1112
    if ( empty( $_POST ) ) {
1113
        return false;
1114
    }
1115
    
1116
    // Start an array to collect valid data
1117
    $valid_data = array(
1118
        'gateway'          => wpinv_checkout_validate_gateway(), // Gateway fallback
1119
        'discount'         => wpinv_checkout_validate_discounts(), // Set default discount
1120
        'cc_info'          => wpinv_checkout_validate_cc() // Credit card info
1121
    );
1122
    
1123
    // Validate agree to terms
1124
    if ( wpinv_get_option( 'show_agree_to_terms', false ) ) {
1125
        wpinv_checkout_validate_agree_to_terms();
1126
    }
1127
    
1128
    $valid_data['logged_in_user']   = wpinv_checkout_validate_logged_in_user();
1129
    
1130
    // Return collected data
1131
    return $valid_data;
1132
}
1133
1134
function wpinv_checkout_validate_gateway() {
1135
    $gateway = wpinv_get_default_gateway();
1136
    
1137
    $invoice = wpinv_get_invoice_cart();
1138
    $has_subscription = $invoice->is_recurring();
1139
    if ( empty( $invoice ) ) {
1140
        wpinv_set_error( 'invalid_invoice', __( 'Your cart is empty.', 'invoicing' ) );
1141
        return $gateway;
1142
    }
1143
1144
    // Check if a gateway value is present
1145
    if ( !empty( $_REQUEST['wpi-gateway'] ) ) {
1146
        $gateway = sanitize_text_field( $_REQUEST['wpi-gateway'] );
1147
1148
        if ( $invoice->is_free() ) {
1149
            $gateway = 'manual';
1150
        } elseif ( !wpinv_is_gateway_active( $gateway ) ) {
1151
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled', 'invoicing' ) );
1152
        } elseif ( $has_subscription && !wpinv_gateway_support_subscription( $gateway ) ) {
1153
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway doesnot support subscription payment', 'invoicing' ) );
1154
        }
1155
    }
1156
1157
    if ( $has_subscription && count( wpinv_get_cart_contents() ) > 1 ) {
1158
        wpinv_set_error( 'subscription_invalid', __( 'Only one subscription may be purchased through payment per checkout.', 'invoicing' ) );
1159
    }
1160
1161
    return $gateway;
1162
}
1163
1164
function wpinv_checkout_validate_discounts() {
1165
    // Retrieve the discount stored in cookies
1166
    $discounts = wpinv_get_cart_discounts();
1167
    
1168
    $error = false;
1169
    // If we have discounts, loop through them
1170
    if ( ! empty( $discounts ) ) {
1171
        foreach ( $discounts as $discount ) {
1172
            // Check if valid
1173
            if (  !wpinv_is_discount_valid( $discount, get_current_user_id() ) ) {
1174
                // Discount is not valid
1175
                $error = true;
1176
            }
1177
        }
1178
    } else {
1179
        // No discounts
1180
        return NULL;
1181
    }
1182
1183
    if ( $error && !wpinv_get_errors() ) {
1184
        wpinv_set_error( 'invalid_discount', __( 'Discount code you entered is invalid', 'invoicing' ) );
1185
    }
1186
1187
    return implode( ',', $discounts );
1188
}
1189
1190
function wpinv_checkout_validate_cc() {
1191
    $card_data = wpinv_checkout_get_cc_info();
1192
1193
    // Validate the card zip
1194
    if ( !empty( $card_data['wpinv_zip'] ) ) {
1195
        if ( !wpinv_checkout_validate_cc_zip( $card_data['wpinv_zip'], $card_data['wpinv_country'] ) ) {
1196
            wpinv_set_error( 'invalid_cc_zip', __( 'The zip / postcode you entered for your billing address is invalid', 'invoicing' ) );
1197
        }
1198
    }
1199
1200
    // This should validate card numbers at some point too
1201
    return $card_data;
1202
}
1203
1204
function wpinv_checkout_get_cc_info() {
1205
	$cc_info = array();
1206
	$cc_info['card_name']      = isset( $_POST['card_name'] )       ? sanitize_text_field( $_POST['card_name'] )       : '';
1207
	$cc_info['card_number']    = isset( $_POST['card_number'] )     ? sanitize_text_field( $_POST['card_number'] )     : '';
1208
	$cc_info['card_cvc']       = isset( $_POST['card_cvc'] )        ? sanitize_text_field( $_POST['card_cvc'] )        : '';
1209
	$cc_info['card_exp_month'] = isset( $_POST['card_exp_month'] )  ? sanitize_text_field( $_POST['card_exp_month'] )  : '';
1210
	$cc_info['card_exp_year']  = isset( $_POST['card_exp_year'] )   ? sanitize_text_field( $_POST['card_exp_year'] )   : '';
1211
	$cc_info['card_address']   = isset( $_POST['wpinv_address'] )  ? sanitize_text_field( $_POST['wpinv_address'] ) : '';
1212
	$cc_info['card_city']      = isset( $_POST['wpinv_city'] )     ? sanitize_text_field( $_POST['wpinv_city'] )    : '';
1213
	$cc_info['card_state']     = isset( $_POST['wpinv_state'] )    ? sanitize_text_field( $_POST['wpinv_state'] )   : '';
1214
	$cc_info['card_country']   = isset( $_POST['wpinv_country'] )  ? sanitize_text_field( $_POST['wpinv_country'] ) : '';
1215
	$cc_info['card_zip']       = isset( $_POST['wpinv_zip'] )      ? sanitize_text_field( $_POST['wpinv_zip'] )     : '';
1216
1217
	// Return cc info
1218
	return $cc_info;
1219
}
1220
1221
function wpinv_checkout_validate_cc_zip( $zip = 0, $country_code = '' ) {
1222
    $ret = false;
1223
1224
    if ( empty( $zip ) || empty( $country_code ) )
1225
        return $ret;
1226
1227
    $country_code = strtoupper( $country_code );
1228
1229
    $zip_regex = array(
1230
        "AD" => "AD\d{3}",
1231
        "AM" => "(37)?\d{4}",
1232
        "AR" => "^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$",
1233
        "AS" => "96799",
1234
        "AT" => "\d{4}",
1235
        "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})$",
1236
        "AX" => "22\d{3}",
1237
        "AZ" => "\d{4}",
1238
        "BA" => "\d{5}",
1239
        "BB" => "(BB\d{5})?",
1240
        "BD" => "\d{4}",
1241
        "BE" => "^[1-9]{1}[0-9]{3}$",
1242
        "BG" => "\d{4}",
1243
        "BH" => "((1[0-2]|[2-9])\d{2})?",
1244
        "BM" => "[A-Z]{2}[ ]?[A-Z0-9]{2}",
1245
        "BN" => "[A-Z]{2}[ ]?\d{4}",
1246
        "BR" => "\d{5}[\-]?\d{3}",
1247
        "BY" => "\d{6}",
1248
        "CA" => "^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$",
1249
        "CC" => "6799",
1250
        "CH" => "^[1-9][0-9][0-9][0-9]$",
1251
        "CK" => "\d{4}",
1252
        "CL" => "\d{7}",
1253
        "CN" => "\d{6}",
1254
        "CR" => "\d{4,5}|\d{3}-\d{4}",
1255
        "CS" => "\d{5}",
1256
        "CV" => "\d{4}",
1257
        "CX" => "6798",
1258
        "CY" => "\d{4}",
1259
        "CZ" => "\d{3}[ ]?\d{2}",
1260
        "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",
1261
        "DK" => "^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$",
1262
        "DO" => "\d{5}",
1263
        "DZ" => "\d{5}",
1264
        "EC" => "([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?",
1265
        "EE" => "\d{5}",
1266
        "EG" => "\d{5}",
1267
        "ES" => "^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$",
1268
        "ET" => "\d{4}",
1269
        "FI" => "\d{5}",
1270
        "FK" => "FIQQ 1ZZ",
1271
        "FM" => "(9694[1-4])([ \-]\d{4})?",
1272
        "FO" => "\d{3}",
1273
        "FR" => "^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$",
1274
        "GE" => "\d{4}",
1275
        "GF" => "9[78]3\d{2}",
1276
        "GL" => "39\d{2}",
1277
        "GN" => "\d{3}",
1278
        "GP" => "9[78][01]\d{2}",
1279
        "GR" => "\d{3}[ ]?\d{2}",
1280
        "GS" => "SIQQ 1ZZ",
1281
        "GT" => "\d{5}",
1282
        "GU" => "969[123]\d([ \-]\d{4})?",
1283
        "GW" => "\d{4}",
1284
        "HM" => "\d{4}",
1285
        "HN" => "(?:\d{5})?",
1286
        "HR" => "\d{5}",
1287
        "HT" => "\d{4}",
1288
        "HU" => "\d{4}",
1289
        "ID" => "\d{5}",
1290
        "IE" => "((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?",
1291
        "IL" => "\d{5}",
1292
        "IN"=> "^[1-9][0-9][0-9][0-9][0-9][0-9]$", //india
1293
        "IO" => "BBND 1ZZ",
1294
        "IQ" => "\d{5}",
1295
        "IS" => "\d{3}",
1296
        "IT" => "^(V-|I-)?[0-9]{5}$",
1297
        "JO" => "\d{5}",
1298
        "JP" => "\d{3}-\d{4}",
1299
        "KE" => "\d{5}",
1300
        "KG" => "\d{6}",
1301
        "KH" => "\d{5}",
1302
        "KR" => "\d{3}[\-]\d{3}",
1303
        "KW" => "\d{5}",
1304
        "KZ" => "\d{6}",
1305
        "LA" => "\d{5}",
1306
        "LB" => "(\d{4}([ ]?\d{4})?)?",
1307
        "LI" => "(948[5-9])|(949[0-7])",
1308
        "LK" => "\d{5}",
1309
        "LR" => "\d{4}",
1310
        "LS" => "\d{3}",
1311
        "LT" => "\d{5}",
1312
        "LU" => "\d{4}",
1313
        "LV" => "\d{4}",
1314
        "MA" => "\d{5}",
1315
        "MC" => "980\d{2}",
1316
        "MD" => "\d{4}",
1317
        "ME" => "8\d{4}",
1318
        "MG" => "\d{3}",
1319
        "MH" => "969[67]\d([ \-]\d{4})?",
1320
        "MK" => "\d{4}",
1321
        "MN" => "\d{6}",
1322
        "MP" => "9695[012]([ \-]\d{4})?",
1323
        "MQ" => "9[78]2\d{2}",
1324
        "MT" => "[A-Z]{3}[ ]?\d{2,4}",
1325
        "MU" => "(\d{3}[A-Z]{2}\d{3})?",
1326
        "MV" => "\d{5}",
1327
        "MX" => "\d{5}",
1328
        "MY" => "\d{5}",
1329
        "NC" => "988\d{2}",
1330
        "NE" => "\d{4}",
1331
        "NF" => "2899",
1332
        "NG" => "(\d{6})?",
1333
        "NI" => "((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?",
1334
        "NL" => "^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$",
1335
        "NO" => "\d{4}",
1336
        "NP" => "\d{5}",
1337
        "NZ" => "\d{4}",
1338
        "OM" => "(PC )?\d{3}",
1339
        "PF" => "987\d{2}",
1340
        "PG" => "\d{3}",
1341
        "PH" => "\d{4}",
1342
        "PK" => "\d{5}",
1343
        "PL" => "\d{2}-\d{3}",
1344
        "PM" => "9[78]5\d{2}",
1345
        "PN" => "PCRN 1ZZ",
1346
        "PR" => "00[679]\d{2}([ \-]\d{4})?",
1347
        "PT" => "\d{4}([\-]\d{3})?",
1348
        "PW" => "96940",
1349
        "PY" => "\d{4}",
1350
        "RE" => "9[78]4\d{2}",
1351
        "RO" => "\d{6}",
1352
        "RS" => "\d{5}",
1353
        "RU" => "\d{6}",
1354
        "SA" => "\d{5}",
1355
        "SE" => "^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$",
1356
        "SG" => "\d{6}",
1357
        "SH" => "(ASCN|STHL) 1ZZ",
1358
        "SI" => "\d{4}",
1359
        "SJ" => "\d{4}",
1360
        "SK" => "\d{3}[ ]?\d{2}",
1361
        "SM" => "4789\d",
1362
        "SN" => "\d{5}",
1363
        "SO" => "\d{5}",
1364
        "SZ" => "[HLMS]\d{3}",
1365
        "TC" => "TKCA 1ZZ",
1366
        "TH" => "\d{5}",
1367
        "TJ" => "\d{6}",
1368
        "TM" => "\d{6}",
1369
        "TN" => "\d{4}",
1370
        "TR" => "\d{5}",
1371
        "TW" => "\d{3}(\d{2})?",
1372
        "UA" => "\d{5}",
1373
        "UK" => "^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$",
1374
        "US" => "^\d{5}([\-]?\d{4})?$",
1375
        "UY" => "\d{5}",
1376
        "UZ" => "\d{6}",
1377
        "VA" => "00120",
1378
        "VE" => "\d{4}",
1379
        "VI" => "008(([0-4]\d)|(5[01]))([ \-]\d{4})?",
1380
        "WF" => "986\d{2}",
1381
        "YT" => "976\d{2}",
1382
        "YU" => "\d{5}",
1383
        "ZA" => "\d{4}",
1384
        "ZM" => "\d{5}"
1385
    );
1386
1387
    if ( ! isset ( $zip_regex[ $country_code ] ) || preg_match( "/" . $zip_regex[ $country_code ] . "/i", $zip ) )
1388
        $ret = true;
1389
1390
    return apply_filters( 'wpinv_is_zip_valid', $ret, $zip, $country_code );
1391
}
1392
1393
function wpinv_checkout_validate_agree_to_terms() {
1394
    // Validate agree to terms
1395
    if ( ! isset( $_POST['wpi_agree_to_terms'] ) || $_POST['wpi_agree_to_terms'] != 1 ) {
1396
        // User did not agree
1397
        wpinv_set_error( 'agree_to_terms', apply_filters( 'wpinv_agree_to_terms_text', __( 'You must agree to the terms of use', 'invoicing' ) ) );
1398
    }
1399
}
1400
1401
function wpinv_checkout_validate_logged_in_user() {
1402
    $user_ID = get_current_user_id();
1403
    
1404
    $valid_user_data = array(
1405
        // Assume there will be errors
1406
        'user_id' => -1
1407
    );
1408
    
1409
    // Verify there is a user_ID
1410
    if ( $user_ID > 0 ) {
1411
        // Get the logged in user data
1412
        $user_data = get_userdata( $user_ID );
1413
        $required_fields  = wpinv_checkout_required_fields();
1414
1415
        // Loop through required fields and show error messages
1416
         if ( !empty( $required_fields ) ) {
1417
            foreach ( $required_fields as $field_name => $value ) {
1418
                if ( in_array( $value, $required_fields ) && empty( $_POST[ 'wpinv_' . $field_name ] ) ) {
1419
                    wpinv_set_error( $value['error_id'], $value['error_message'] );
1420
                }
1421
            }
1422
        }
1423
1424
        // Verify data
1425
        if ( $user_data ) {
1426
            // Collected logged in user data
1427
            $valid_user_data = array(
1428
                'user_id'     => $user_ID,
1429
                'email'       => isset( $_POST['wpinv_email'] ) ? sanitize_email( $_POST['wpinv_email'] ) : $user_data->user_email,
1430
                'first_name'  => isset( $_POST['wpinv_first_name'] ) && ! empty( $_POST['wpinv_first_name'] ) ? sanitize_text_field( $_POST['wpinv_first_name'] ) : $user_data->first_name,
1431
                'last_name'   => isset( $_POST['wpinv_last_name'] ) && ! empty( $_POST['wpinv_last_name']  ) ? sanitize_text_field( $_POST['wpinv_last_name']  ) : $user_data->last_name,
1432
            );
1433
1434
            if ( !empty( $_POST[ 'wpinv_email' ] ) && !is_email( $_POST[ 'wpinv_email' ] ) ) {
1435
                wpinv_set_error( 'invalid_email', __( 'Please enter a valid email address', 'invoicing' ) );
1436
            }
1437
        } else {
1438
            // Set invalid user error
1439
            wpinv_set_error( 'invalid_user', __( 'The user billing information is invalid', 'invoicing' ) );
1440
        }
1441
    }
1442
1443
    // Return user data
1444
    return $valid_user_data;
1445
}
1446
1447
function wpinv_checkout_form_get_user( $valid_data = array() ) {
1448
    // Initialize user
1449
    $user    = false;
1450
    $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...
1451
1452
    /*if ( $is_ajax ) {
1453
        // Do not create or login the user during the ajax submission (check for errors only)
1454
        return true;
1455
    } else */if ( is_user_logged_in() ) {
1456
        // Set the valid user as the logged in collected data
1457
        $user = $valid_data['logged_in_user'];
1458
    }
1459
1460
    // Verify we have an user
1461
    if ( false === $user || empty( $user ) ) {
1462
        // Return false
1463
        return false;
1464
    }
1465
    
1466
    $address_fields = array(
1467
        'first_name',
1468
        'last_name',
1469
        'company',
1470
        'vat_number',
1471
        ///'email',
1472
        'phone',
1473
        'address',
1474
        'city',
1475
        'state',
1476
        'country',
1477
        'zip',
1478
    );
1479
    
1480
    foreach ( $address_fields as $field ) {
1481
        $user[$field]  = !empty( $_POST['wpinv_' . $field] ) ? sanitize_text_field( $_POST['wpinv_' . $field] ) : false;
1482
        
1483
        if ( !empty( $user['user_id'] ) ) {
1484
            update_user_meta( $user['user_id'], '_wpinv_' . $field, $user[$field] );
1485
        }
1486
    }
1487
1488
    // Return valid user
1489
    return $user;
1490
}
1491
1492
function wpinv_set_checkout_session( $invoice_data = array() ) {
1493
    global $wpi_session;
1494
    
1495
    return $wpi_session->set( 'wpinv_checkout', $invoice_data );
1496
}
1497
1498
function wpinv_get_checkout_session() {
1499
	global $wpi_session;
1500
    
1501
    return $wpi_session->get( 'wpinv_checkout' );
1502
}
1503
1504
function wpinv_empty_cart() {
1505
    global $wpi_session;
1506
1507
    // Remove cart contents
1508
    $wpi_session->set( 'wpinv_checkout', NULL );
1509
1510
    // Remove all cart fees
1511
    $wpi_session->set( 'wpi_cart_fees', NULL );
1512
1513
    do_action( 'wpinv_empty_cart' );
1514
}
1515
1516
function wpinv_process_checkout() {
1517
    global $wpinv_euvat, $wpi_checkout_id;
1518
    
1519
    wpinv_clear_errors();
1520
    
1521
    $invoice = wpinv_get_invoice_cart();
1522
    
1523
    $wpi_checkout_id = $invoice->ID;
1524
    
1525
    do_action( 'wpinv_pre_process_checkout' );
1526
    
1527
    if ( !wpinv_get_cart_contents() ) { // Make sure the cart isn't empty
1528
        $valid_data = false;
1529
        wpinv_set_error( 'empty_cart', __( 'Your cart is empty', 'invoicing' ) );
1530
    } else {
1531
        // Validate the form $_POST data
1532
        $valid_data = wpinv_validate_checkout_fields();
1533
        
1534
        // Allow themes and plugins to hook to errors
1535
        do_action( 'wpinv_checkout_error_checks', $valid_data, $_POST );
1536
    }
1537
    
1538
    $is_ajax    = defined( 'DOING_AJAX' ) && DOING_AJAX;
1539
    
1540
    // Validate the user
1541
    $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...
1542
1543
    // Let extensions validate fields after user is logged in if user has used login/registration form
1544
    do_action( 'wpinv_checkout_user_error_checks', $user, $valid_data, $_POST );
1545
    
1546
    if ( false === $valid_data || wpinv_get_errors() || ! $user ) {
1547
        if ( $is_ajax ) {
1548
            do_action( 'wpinv_ajax_checkout_errors' );
1549
            die();
1550
        } else {
1551
            return false;
1552
        }
1553
    }
1554
1555
    if ( $is_ajax ) {
1556
        // Save address fields.
1557
        $address_fields = array( 'first_name', 'last_name', 'phone', 'address', 'city', 'country', 'state', 'zip', 'company' );
1558 View Code Duplication
        foreach ( $address_fields as $field ) {
1559
            if ( isset( $user[$field] ) ) {
1560
                $invoice->set( $field, $user[$field] );
1561
            }
1562
            
1563
            $invoice->save();
1564
        }
1565
1566
        $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...
1567
        $response['data']['subtotal']   = $invoice->get_subtotal();
1568
        $response['data']['subtotalf']  = $invoice->get_subtotal( true );
1569
        $response['data']['discount']   = $invoice->get_discount();
1570
        $response['data']['discountf']  = $invoice->get_discount( true );
1571
        $response['data']['tax']        = $invoice->get_tax();
1572
        $response['data']['taxf']       = $invoice->get_tax( true );
1573
        $response['data']['total']      = $invoice->get_total();
1574
        $response['data']['totalf']     = $invoice->get_total( true );
1575
        
1576
        wp_send_json( $response );
1577
    }
1578
    
1579
    $user_info = array(
1580
        'user_id'        => $user['user_id'],
1581
        'first_name'     => $user['first_name'],
1582
        'last_name'      => $user['last_name'],
1583
        'email'          => $user['email'],
1584
        'company'        => $user['company'],
1585
        'phone'          => $user['phone'],
1586
        'address'        => $user['address'],
1587
        'city'           => $user['city'],
1588
        'country'        => $user['country'],
1589
        'state'          => $user['state'],
1590
        'zip'            => $user['zip'],
1591
    );
1592
    
1593
    $cart_items = wpinv_get_cart_contents();
1594
    $discounts  = wpinv_get_cart_discounts();
1595
    
1596
    // Setup invoice information
1597
    $invoice_data = array(
1598
        'invoice_id'        => !empty( $invoice ) ? $invoice->ID : 0,
1599
        'items'             => $cart_items,
1600
        'cart_discounts'    => $discounts,
1601
        'fees'              => wpinv_get_cart_fees(),        // Any arbitrary fees that have been added to the cart
1602
        'subtotal'          => wpinv_get_cart_subtotal( $cart_items ),    // Amount before taxes and discounts
1603
        'discount'          => wpinv_get_cart_items_discount_amount( $cart_items, $discounts ), // Discounted amount
1604
        'tax'               => wpinv_get_cart_tax( $cart_items ),               // Taxed amount
1605
        'price'             => wpinv_get_cart_total( $cart_items, $discounts ),    // Amount after taxes
1606
        'invoice_key'       => $invoice->get_key() ? $invoice->get_key() : $invoice->generate_key(),
1607
        'user_email'        => $user['email'],
1608
        'date'              => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
1609
        'user_info'         => stripslashes_deep( $user_info ),
1610
        'post_data'         => $_POST,
1611
        'cart_details'      => $cart_items,
1612
        'gateway'           => $valid_data['gateway'],
1613
        'card_info'         => $valid_data['cc_info']
1614
    );
1615
    
1616
    $vat_info   = $wpinv_euvat->current_vat_data();
1617
    if ( is_array( $vat_info ) ) {
1618
        $invoice_data['user_info']['vat_number']        = $vat_info['number'];
1619
        $invoice_data['user_info']['vat_rate']          = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state']);
1620
        $invoice_data['user_info']['adddress_confirmed']    = isset($vat_info['adddress_confirmed']) ? $vat_info['adddress_confirmed'] : false;
1621
1622
        // Add the VAT rate to each item in the cart
1623
        foreach( $invoice_data['cart_details'] as $key => $item_data) {
1624
            $rate = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state'], $item_data['id']);
1625
            $invoice_data['cart_details'][$key]['vat_rate'] = wpinv_round_amount( $rate, 4 );
1626
        }
1627
    }
1628
    
1629
    // Save vat fields.
1630
    $address_fields = array( 'vat_number', 'vat_rate', 'adddress_confirmed' );
1631 View Code Duplication
    foreach ( $address_fields as $field ) {
1632
        if ( isset( $invoice_data['user_info'][$field] ) ) {
1633
            $invoice->set( $field, $invoice_data['user_info'][$field] );
1634
        }
1635
        
1636
        $invoice->save();
1637
    }
1638
1639
    // Add the user data for hooks
1640
    $valid_data['user'] = $user;
1641
    
1642
    // Allow themes and plugins to hook before the gateway
1643
    do_action( 'wpinv_checkout_before_gateway', $_POST, $user_info, $valid_data );
1644
    
1645
    // If the total amount in the cart is 0, send to the manual gateway. This emulates a free invoice
1646
    if ( !$invoice_data['price'] ) {
1647
        // Revert to manual
1648
        $invoice_data['gateway'] = 'manual';
1649
        $_POST['wpi-gateway'] = 'manual';
1650
    }
1651
    
1652
    // Allow the invoice data to be modified before it is sent to the gateway
1653
    $invoice_data = apply_filters( 'wpinv_data_before_gateway', $invoice_data, $valid_data );
1654
    
1655
    // Setup the data we're storing in the purchase session
1656
    $session_data = $invoice_data;
1657
    // Make sure credit card numbers are never stored in sessions
1658
    if ( !empty( $session_data['card_info']['card_number'] ) ) {
1659
        unset( $session_data['card_info']['card_number'] );
1660
    }
1661
    
1662
    // Used for showing item links to non logged-in users after purchase, and for other plugins needing purchase data.
1663
    wpinv_set_checkout_session( $invoice_data );
1664
    
1665
    // Set gateway
1666
    $invoice->update_meta( '_wpinv_gateway', $invoice_data['gateway'] );
1667
    $invoice->update_meta( '_wpinv_mode', ( wpinv_is_test_mode( $invoice_data['gateway'] ) ? 'test' : 'live' ) );
1668
    $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...
1669
    
1670
    do_action( 'wpinv_checkout_before_send_to_gateway', $invoice, $invoice_data );
1671
1672
    // Send info to the gateway for payment processing
1673
    wpinv_send_to_gateway( $invoice_data['gateway'], $invoice_data );
1674
    die();
1675
}
1676
add_action( 'wpinv_payment', 'wpinv_process_checkout' );
1677
1678
function wpinv_get_invoices( $args ) {
1679
    $args = wp_parse_args( $args, array(
1680
        'status'   => array_keys( wpinv_get_invoice_statuses() ),
1681
        'type'     => 'wpi_invoice',
1682
        'parent'   => null,
1683
        'user'     => null,
1684
        'email'    => '',
1685
        'limit'    => get_option( 'posts_per_page' ),
1686
        'offset'   => null,
1687
        'page'     => 1,
1688
        'exclude'  => array(),
1689
        'orderby'  => 'date',
1690
        'order'    => 'DESC',
1691
        'return'   => 'objects',
1692
        'paginate' => false,
1693
    ) );
1694
    
1695
    // Handle some BW compatibility arg names where wp_query args differ in naming.
1696
    $map_legacy = array(
1697
        'numberposts'    => 'limit',
1698
        'post_type'      => 'type',
1699
        'post_status'    => 'status',
1700
        'post_parent'    => 'parent',
1701
        'author'         => 'user',
1702
        'posts_per_page' => 'limit',
1703
        'paged'          => 'page',
1704
    );
1705
1706
    foreach ( $map_legacy as $from => $to ) {
1707
        if ( isset( $args[ $from ] ) ) {
1708
            $args[ $to ] = $args[ $from ];
1709
        }
1710
    }
1711
1712
    $wpinv_cpt = isset( $_REQUEST[ 'wpinv-cpt' ] ) ? $_REQUEST[ 'wpinv-cpt' ] : '';
1713
1714
    if ( get_query_var( 'paged' ) && 'wpi_invoice' == $wpinv_cpt )
1715
        $args['page'] = get_query_var('paged');
1716
    else if ( get_query_var( 'page' )  && 'wpi_invoice' == $wpinv_cpt )
1717
        $args['page'] = get_query_var( 'page' );
1718
    else if ( !empty( $args[ 'page' ] ) )
1719
        $args['page'] = $args[ 'page' ];
1720
    else
1721
        $args['page'] = 1;
1722
1723
    /**
1724
     * Generate WP_Query args. This logic will change if orders are moved to
1725
     * custom tables in the future.
1726
     */
1727
    $wp_query_args = array(
1728
        'post_type'      => 'wpi_invoice',
1729
        'post_status'    => $args['status'],
1730
        'posts_per_page' => $args['limit'],
1731
        'meta_query'     => array(),
1732
        'date_query'     => !empty( $args['date_query'] ) ? $args['date_query'] : array(),
1733
        'fields'         => 'ids',
1734
        'orderby'        => $args['orderby'],
1735
        'order'          => $args['order'],
1736
    );
1737
    
1738
    if ( !empty( $args['user'] ) ) {
1739
        $wp_query_args['author'] = absint( $args['user'] );
1740
    }
1741
1742
    if ( ! is_null( $args['parent'] ) ) {
1743
        $wp_query_args['post_parent'] = absint( $args['parent'] );
1744
    }
1745
1746
    if ( ! is_null( $args['offset'] ) ) {
1747
        $wp_query_args['offset'] = absint( $args['offset'] );
1748
    } else {
1749
        $wp_query_args['paged'] = absint( $args['page'] );
1750
    }
1751
1752
    if ( ! empty( $args['exclude'] ) ) {
1753
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
1754
    }
1755
1756
    if ( ! $args['paginate' ] ) {
1757
        $wp_query_args['no_found_rows'] = true;
1758
    }
1759
1760
    // Get results.
1761
    $invoices = new WP_Query( $wp_query_args );
1762
1763
    if ( 'objects' === $args['return'] ) {
1764
        $return = array_map( 'wpinv_get_invoice', $invoices->posts );
1765
    } elseif ( 'self' === $args['return'] ) {
1766
        return $invoices;
1767
    } else {
1768
        $return = $invoices->posts;
1769
    }
1770
1771
    if ( $args['paginate' ] ) {
1772
        return (object) array(
1773
            'invoices'      => $return,
1774
            'total'         => $invoices->found_posts,
1775
            'max_num_pages' => $invoices->max_num_pages,
1776
        );
1777
    } else {
1778
        return $return;
1779
    }
1780
}
1781
1782
function wpinv_get_user_invoices_columns() {
1783
    $columns = array(
1784
            'invoice-number'  => array( 'title' => __( 'ID', 'invoicing' ), 'class' => 'text-left' ),
1785
            'invoice-date'    => array( 'title' => __( 'Date', 'invoicing' ), 'class' => 'text-left' ),
1786
            'invoice-status'  => array( 'title' => __( 'Status', 'invoicing' ), 'class' => 'text-center' ),
1787
            'invoice-total'   => array( 'title' => __( 'Total', 'invoicing' ), 'class' => 'text-right' ),
1788
            'invoice-actions' => array( 'title' => '&nbsp;', 'class' => 'text-center' ),
1789
        );
1790
1791
    return apply_filters( 'wpinv_user_invoices_columns', $columns );
1792
}
1793
1794
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...
1795
    global $wpinv_receipt_args;
1796
1797
    $wpinv_receipt_args = shortcode_atts( array(
1798
        'error'           => __( 'Sorry, trouble retrieving payment receipt.', 'invoicing' ),
1799
        'price'           => true,
1800
        'discount'        => true,
1801
        'items'           => true,
1802
        'date'            => true,
1803
        'notes'           => true,
1804
        'invoice_key'     => false,
1805
        'payment_method'  => true,
1806
        'invoice_id'      => true
1807
    ), $atts, 'wpinv_receipt' );
1808
1809
    $session = wpinv_get_checkout_session();
1810
    if ( isset( $_GET['invoice_key'] ) ) {
1811
        $invoice_key = urldecode( $_GET['invoice_key'] );
1812
    } else if ( $session && isset( $session['invoice_key'] ) ) {
1813
        $invoice_key = $session['invoice_key'];
1814
    } elseif ( isset( $wpinv_receipt_args['invoice_key'] ) && $wpinv_receipt_args['invoice_key'] ) {
1815
        $invoice_key = $wpinv_receipt_args['invoice_key'];
1816
    } else if ( isset( $_GET['invoice-id'] ) ) {
1817
        $invoice_key = wpinv_get_payment_key( (int)$_GET['invoice-id'] );
1818
    }
1819
1820
    // No key found
1821
    if ( ! isset( $invoice_key ) ) {
1822
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1823
    }
1824
1825
    $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...
1826
    $user_can_view = wpinv_can_view_receipt( $invoice_key );
1827 View Code Duplication
    if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1828
        $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...
1829
        $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1830
    }
1831
1832
    // Key was provided, but user is logged out. Offer them the ability to login and view the receipt
1833
    if ( ! $user_can_view && ! empty( $invoice_key ) && ! is_user_logged_in() ) {
1834
        // login redirect
1835
        return '<p class="alert alert-error">' . __( 'You are not allowed to access this section', 'invoicing' ) . '</p>';
1836
    }
1837
1838
    if ( ! apply_filters( 'wpinv_user_can_view_receipt', $user_can_view, $wpinv_receipt_args ) ) {
1839
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1840
    }
1841
1842
    ob_start();
1843
1844
    wpinv_get_template_part( 'wpinv-invoice-receipt' );
1845
1846
    $display = ob_get_clean();
1847
1848
    return $display;
1849
}
1850
1851 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...
1852
	global $wpdb;
1853
1854
	$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 ) );
1855
1856
	if ( $invoice_id != NULL )
1857
		return $invoice_id;
1858
1859
	return 0;
1860
}
1861
1862
function wpinv_can_view_receipt( $invoice_key = '' ) {
1863
	$return = false;
1864
1865
	if ( empty( $invoice_key ) ) {
1866
		return $return;
1867
	}
1868
1869
	global $wpinv_receipt_args;
1870
1871
	$wpinv_receipt_args['id'] = wpinv_get_invoice_id_by_key( $invoice_key );
1872
	if ( isset( $_GET['invoice-id'] ) ) {
1873
		$wpinv_receipt_args['id'] = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? (int)$_GET['invoice-id'] : 0;
1874
	}
1875
1876
	$user_id = (int) wpinv_get_user_id( $wpinv_receipt_args['id'] );
1877
    $invoice_meta = wpinv_get_invoice_meta( $wpinv_receipt_args['id'] );
1878
1879
	if ( is_user_logged_in() ) {
1880
		if ( $user_id === (int) get_current_user_id() ) {
1881
			$return = true;
1882
		}
1883
	}
1884
1885
	$session = wpinv_get_checkout_session();
1886
	if ( ! empty( $session ) && ! is_user_logged_in() ) {
1887
		if ( $session['invoice_key'] === $invoice_meta['key'] ) {
1888
			$return = true;
1889
		}
1890
	}
1891
1892
	return (bool) apply_filters( 'wpinv_can_view_receipt', $return, $invoice_key );
1893
}
1894
1895
function wpinv_pay_for_invoice() {
1896
    global $wpinv_euvat;
1897
    
1898
    if ( isset( $_GET['invoice_key'] ) ) {
1899
        $checkout_uri   = wpinv_get_checkout_uri();
1900
        $invoice_key    = sanitize_text_field( $_GET['invoice_key'] );
1901
        
1902
        if ( empty( $invoice_key ) ) {
1903
            wpinv_set_error( 'invalid_invoice', __( 'Invoice not found', 'invoicing' ) );
1904
            wp_redirect( $checkout_uri );
1905
            wpinv_die();
1906
        }
1907
        
1908
        do_action( 'wpinv_check_pay_for_invoice', $invoice_key );
1909
1910
        $invoice_id    = wpinv_get_invoice_id_by_key( $invoice_key );
1911
        $user_can_view = wpinv_can_view_receipt( $invoice_key );
1912 View Code Duplication
        if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1913
            $invoice_id     = (int)$_GET['invoice-id'];
1914
            $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1915
        }
1916
        
1917
        if ( $invoice_id && $user_can_view && ( $invoice = wpinv_get_invoice( $invoice_id ) ) ) {
1918
            if ( $invoice->needs_payment() ) {
1919
                $data                   = array();
1920
                $data['invoice_id']     = $invoice_id;
1921
                $data['cart_discounts'] = $invoice->get_discounts( true );
1922
                
1923
                wpinv_set_checkout_session( $data );
1924
                
1925
                if ( wpinv_get_option( 'vat_ip_country_default' ) ) {
1926
                    $_POST['country']   = $wpinv_euvat->get_country_by_ip();
1927
                    $_POST['state']     = $_POST['country'] == $invoice->country ? $invoice->state : '';
1928
                    
1929
                    wpinv_recalculate_tax( true );
1930
                }
1931
                
1932
            } else {
1933
                $checkout_uri = $invoice->get_view_url();
1934
            }
1935
        } else {
1936
            wpinv_set_error( 'invalid_invoice', __( 'You are not allowed to view this invoice', 'invoicing' ) );
1937
            
1938
            $checkout_uri = is_user_logged_in() ? wpinv_get_history_page_uri() : wp_login_url( get_permalink() );
1939
        }
1940
        
1941
        wp_redirect( $checkout_uri );
1942
        wpinv_die();
1943
    }
1944
}
1945
add_action( 'wpinv_pay_for_invoice', 'wpinv_pay_for_invoice' );
1946
1947
function wpinv_handle_pay_via_invoice_link( $invoice_key ) {
1948
    if ( !empty( $invoice_key ) && !empty( $_REQUEST['_wpipay'] ) && !is_user_logged_in() && $invoice_id = wpinv_get_invoice_id_by_key( $invoice_key ) ) {
1949
        if ( $invoice = wpinv_get_invoice( $invoice_id ) ) {
1950
            $user_id = $invoice->get_user_id();
1951
            $secret = sanitize_text_field( $_GET['_wpipay'] );
1952
            
1953 View Code Duplication
            if ( $secret === md5( $user_id . '::' . $invoice->get_email() . '::' . $invoice_key ) ) { // valid invoice link
1954
                $redirect_to = remove_query_arg( '_wpipay', get_permalink() );
1955
                
1956
                wpinv_guest_redirect( $redirect_to, $user_id );
1957
                wpinv_die();
1958
            }
1959
        }
1960
    }
1961
}
1962
add_action( 'wpinv_check_pay_for_invoice', 'wpinv_handle_pay_via_invoice_link' );
1963
1964
function wpinv_set_payment_transaction_id( $invoice_id = 0, $transaction_id = '' ) {
1965
    $invoice_id = is_object( $invoice_id ) && !empty( $invoice_id->ID ) ? $invoice_id : $invoice_id;
1966
    
1967
    if ( empty( $invoice_id ) && $invoice_id > 0 ) {
1968
        return false;
1969
    }
1970
    
1971
    if ( empty( $transaction_id ) ) {
1972
        $transaction_id = $invoice_id;
1973
    }
1974
1975
    $transaction_id = apply_filters( 'wpinv_set_payment_transaction_id', $transaction_id, $invoice_id );
1976
    
1977
    return wpinv_update_invoice_meta( $invoice_id, '_wpinv_transaction_id', $transaction_id );
1978
}
1979
1980
function wpinv_invoice_status_label( $status, $status_display = '' ) {
1981
    if ( empty( $status_display ) ) {
1982
        $status_display = wpinv_status_nicename( $status );
1983
    }
1984
    
1985
    switch ( $status ) {
1986
        case 'publish' :
1987
        case 'wpi-renewal' :
1988
            $class = 'label-success';
1989
        break;
1990
        case 'pending' :
1991
            $class = 'label-primary';
1992
        break;
1993
        case 'wpi-processing' :
1994
            $class = 'label-warning';
1995
        break;
1996
        case 'wpi-onhold' :
1997
            $class = 'label-info';
1998
        break;
1999
        case 'wpi-cancelled' :
2000
        case 'wpi-failed' :
2001
            $class = 'label-danger';
2002
        break;
2003
        default:
2004
            $class = 'label-default';
2005
        break;
2006
    }
2007
    
2008
    $label = '<span class="label label-inv-' . $status . ' ' . $class . '">' . $status_display . '</span>';
2009
    
2010
    return apply_filters( 'wpinv_invoice_status_label', $label, $status, $status_display );
2011
}
2012
2013
function wpinv_format_invoice_number( $number ) {
2014
    $padd  = wpinv_get_option( 'invoice_number_padd' );
2015
    
2016
    // TODO maintain old invoice numbers if invoice number settings not saved. Should be removed before stable release.
2017
    if ( $padd === '' || $padd === false || $padd === NULL ) {
2018
        return wp_sprintf( __( 'WPINV-%d', 'invoicing' ), $number );
2019
    }
2020
    
2021
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2022
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2023
    
2024
    $padd = absint( $padd );
2025
    $formatted_number = absint( $number );
2026
    
2027
    if ( $padd > 0 ) {
2028
        $formatted_number = zeroise( $formatted_number, $padd );
2029
    }    
2030
2031
    $formatted_number = $prefix . $formatted_number . $postfix;
2032
2033
    return apply_filters( 'wpinv_format_invoice_number', $formatted_number, $number, $prefix, $postfix, $padd );
2034
}
2035
2036
function wpinv_get_next_invoice_number() {
2037
    if ( ! wpinv_get_option( 'sequential_invoice_number' ) ) {
2038
        return false;
2039
    }
2040
2041
    $number           = get_option( 'wpinv_last_invoice_number' );
2042
    $start            = wpinv_get_option( 'invoice_sequence_start', 1 );
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2043
    $increment_number = true;
2044
2045
    if ( false !== $number ) {
2046
        if ( empty( $number ) ) {
2047
            $number = $start;
2048
            $increment_number = false;
2049
        }
2050
    } else {
2051
        $last_invoice = wpinv_get_invoices( array( 'limit' => 1, 'order' => 'DESC', 'orderby' => 'ID', 'return' => 'posts', 'fields' => 'ids', 'status' => 'any' ) );
2052
2053
        if ( ! empty( $last_invoice[0] ) ) {
2054
            $number = wpinv_get_invoice_number( $last_invoice[0] );
2055
        }
2056
2057
        if ( ! empty( $number ) && ! empty( $last_invoice[0] ) && $number !== (int) $last_invoice[0] ) {
2058
            $number = wpinv_clean_invoice_number( $number );
2059
        } else {
2060
            $number = $start;
2061
            $increment_number = false;
2062
        }
2063
    }
2064
2065
    $increment_number = apply_filters( 'wpinv_increment_payment_number', $increment_number, $number );
2066
2067
    if ( $increment_number ) {
2068
        $number++;
2069
    }
2070
2071
    return apply_filters( 'wpinv_get_next_invoice_number', $number );
2072
}
2073
2074
function wpinv_clean_invoice_number( $number ) {
2075
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
2076
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
2077
2078
    $number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
2079
2080
    $length      = strlen( $number );
2081
    $postfix_pos = strrpos( $number, $postfix );
2082
    
2083
    if ( false !== $postfix_pos ) {
2084
        $number      = substr_replace( $number, '', $postfix_pos, $length );
2085
    }
2086
2087
    $number = intval( $number );
2088
2089
    return apply_filters( 'wpinv_clean_invoice_number', $number, $prefix, $postfix );
2090
}
2091
2092
function wpinv_save_number_post_saved( $post_ID, $post, $update ) {
2093
    global $wpdb;
2094
2095
    if ( !$update && !get_post_meta( $post_ID, '_wpinv_number', true ) ) {
2096
        wpinv_update_invoice_number( $post_ID, $post->post_status != 'auto-draft' );
2097
    }
2098
2099
    if ( !$update ) {
2100
        $wpdb->update( $wpdb->posts, array( 'post_name' => 'inv-' . $post_ID ), array( 'ID' => $post_ID ) );
2101
        clean_post_cache( $post_ID );
2102
    }
2103
}
2104
add_action( 'save_post_wpi_invoice', 'wpinv_save_number_post_saved', 1, 3 );
2105
2106
function wpinv_save_number_post_updated( $post_ID, $post_after, $post_before ) {
2107
    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 ) {
2108
        wpinv_update_invoice_number( $post_ID, true );
2109
    }
2110
}
2111
add_action( 'post_updated', 'wpinv_save_number_post_updated', 1, 3 );
2112
2113
function wpinv_update_invoice_number( $post_ID, $save_sequential = false ) {
2114
    global $wpdb;
2115
2116
    if ( wpinv_get_option( 'sequential_invoice_number' ) ) {
2117
        $number = wpinv_get_next_invoice_number();
2118
2119
        if ( $save_sequential ) {
2120
            update_option( 'wpinv_last_invoice_number', $number );
2121
        }
2122
    } else {
2123
        $number = $post_ID;
2124
    }
2125
2126
    $number = wpinv_format_invoice_number( $number );
2127
2128
    update_post_meta( $post_ID, '_wpinv_number', $number );
2129
2130
    $wpdb->update( $wpdb->posts, array( 'post_title' => $number ), array( 'ID' => $post_ID ) );
2131
2132
    clean_post_cache( $post_ID );
2133
2134
    return $number;
2135
}