Passed
Pull Request — master (#57)
by Kiran
04:35
created

wpinv-invoice-functions.php ➔ wpinv_save_number_post_updated()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 3
nc 2
nop 3
dl 0
loc 5
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
function wpinv_get_invoice_cart_id() {
15
    $wpinv_checkout = wpinv_get_checkout_session();
16
    
17
    if ( !empty( $wpinv_checkout['invoice_id'] ) ) {
18
        return $wpinv_checkout['invoice_id'];
19
    }
20
    
21
    return NULL;
22
}
23
24
function wpinv_insert_invoice( $invoice_data = array(), $wp_error = false ) {
25
    if ( empty( $invoice_data ) ) {
26
        return false;
27
    }
28
    
29
    if ( !( !empty( $invoice_data['cart_details'] ) && is_array( $invoice_data['cart_details'] ) ) ) {
30
        return $wp_error ? new WP_Error( 'wpinv_invalid_items', __( 'Invoice must have atleast on item.', 'invoicing' ) ) : 0;
31
    }
32
    
33
    if ( empty( $invoice_data['user_id'] ) ) {
34
        $invoice_data['user_id'] = get_current_user_id();
35
    }
36
    
37
    $invoice_data['invoice_id'] = !empty( $invoice_data['invoice_id'] ) ? (int)$invoice_data['invoice_id'] : 0;
38
    
39
    if ( empty( $invoice_data['status'] ) ) {
40
        $invoice_data['status'] = '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
    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_get_invoice( $invoice_id = 0, $cart = false ) {
258
    if ( $cart && empty( $invoice_id ) ) {
259
        $invoice_id = (int)wpinv_get_invoice_cart_id();
260
    }
261
262
    $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...
263
    return $invoice;
264
}
265
266
function wpinv_get_invoice_cart( $invoice_id = 0 ) {
267
    return wpinv_get_invoice( $invoice_id, true );
268
}
269
270
function wpinv_get_invoice_description( $invoice_id = 0 ) {
271
    $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...
272
    return $invoice->get_description();
273
}
274
275
function wpinv_get_invoice_currency_code( $invoice_id = 0 ) {
276
    $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...
277
    return $invoice->get_currency();
278
}
279
280
function wpinv_get_payment_user_email( $invoice_id ) {
281
    $invoice = new WPInv_Invoice( $invoice_id );
282
    return $invoice->get_email();
283
}
284
285
function wpinv_get_user_id( $invoice_id ) {
286
    $invoice = new WPInv_Invoice( $invoice_id );
287
    return $invoice->get_user_id();
288
}
289
290
function wpinv_get_invoice_status( $invoice_id, $return_label = false ) {
291
    $invoice = new WPInv_Invoice( $invoice_id );
292
    
293
    return $invoice->get_status( $return_label );
294
}
295
296
function wpinv_get_payment_gateway( $invoice_id, $return_label = false ) {
297
    $invoice = new WPInv_Invoice( $invoice_id );
298
    
299
    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...
300
}
301
302
function wpinv_get_payment_gateway_name( $invoice_id ) {
303
    $invoice = new WPInv_Invoice( $invoice_id );
304
    
305
    return $invoice->get_gateway_title();
306
}
307
308
function wpinv_get_payment_transaction_id( $invoice_id ) {
309
    $invoice = new WPInv_Invoice( $invoice_id );
310
    
311
    return $invoice->get_transaction_id();
312
}
313
314 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...
315
    global $wpdb;
316
317
    $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 ) );
318
319
    if ( $invoice_id != NULL )
320
        return $invoice_id;
321
322
    return 0;
323
}
324
325
function wpinv_get_invoice_meta( $invoice_id = 0, $meta_key = '_wpinv_payment_meta', $single = true ) {
326
    $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...
327
328
    return $invoice->get_meta( $meta_key, $single );
329
}
330
331
function wpinv_update_invoice_meta( $invoice_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
332
    $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...
333
    
334
    return $invoice->update_meta( $meta_key, $meta_value, $prev_value );
335
}
336
337
function wpinv_get_items( $invoice_id = 0 ) {
338
    $invoice            = wpinv_get_invoice( $invoice_id );
339
    
340
    $items              = $invoice->get_items();
341
    $invoice_currency   = $invoice->get_currency();
342
343 View Code Duplication
    if ( !empty( $items ) && is_array( $items ) ) {
344
        foreach ( $items as $key => $item ) {
345
            $items[$key]['currency'] = $invoice_currency;
346
347
            if ( !isset( $cart_item['subtotal'] ) ) {
348
                $items[$key]['subtotal'] = $items[$key]['amount'] * 1;
349
            }
350
        }
351
    }
352
353
    return apply_filters( 'wpinv_get_items', $items, $invoice_id );
354
}
355
356
function wpinv_get_fees( $invoice_id = 0 ) {
357
    $invoice           = wpinv_get_invoice( $invoice_id );
358
    $fees              = $invoice->get_fees();
359
360
    return apply_filters( 'wpinv_get_fees', $fees, $invoice_id );
361
}
362
363
function wpinv_get_invoice_ip( $invoice_id ) {
364
    $invoice = new WPInv_Invoice( $invoice_id );
365
    return $invoice->get_ip();
366
}
367
368
function wpinv_get_invoice_user_info( $invoice_id ) {
369
    $invoice = new WPInv_Invoice( $invoice_id );
370
    return $invoice->get_user_info();
371
}
372
373
function wpinv_subtotal( $invoice_id = 0, $currency = false ) {
374
    $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...
375
376
    return $invoice->get_subtotal( $currency );
377
}
378
379
function wpinv_tax( $invoice_id = 0, $currency = false ) {
380
    $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...
381
382
    return $invoice->get_tax( $currency );
383
}
384
385
function wpinv_discount( $invoice_id = 0, $currency = false, $dash = false ) {
386
    $invoice = wpinv_get_invoice( $invoice_id );
387
388
    return $invoice->get_discount( $currency, $dash );
389
}
390
391
function wpinv_discount_code( $invoice_id = 0 ) {
392
    $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...
393
394
    return $invoice->get_discount_code();
395
}
396
397
function wpinv_payment_total( $invoice_id = 0, $currency = false ) {
398
    $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...
399
400
    return $invoice->get_total( $currency );
401
}
402
403
function wpinv_get_date_created( $invoice_id = 0 ) {
404
    $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...
405
    
406
    $date_created   = $invoice->get_created_date();
407
    $date_created   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( get_option( 'date_format' ), strtotime( $date_created ) ) : '';
408
409
    return $date_created;
410
}
411
412
function wpinv_get_invoice_date( $invoice_id = 0, $format = '' ) {
413
    $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...
414
    
415
    $format         = !empty( $format ) ? $format : get_option( 'date_format' );
416
    $date_completed = $invoice->get_completed_date();
417
    $invoice_date   = $date_completed != '' && $date_completed != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_completed ) ) : '';
418
    if ( $invoice_date == '' ) {
419
        $date_created   = $invoice->get_created_date();
420
        $invoice_date   = $date_created != '' && $date_created != '0000-00-00 00:00:00' ? date_i18n( $format, strtotime( $date_created ) ) : '';
421
    }
422
423
    return $invoice_date;
424
}
425
426
function wpinv_get_invoice_vat_number( $invoice_id = 0 ) {
427
    $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...
428
    
429
    return $invoice->vat_number;
430
}
431
432
function wpinv_insert_payment_note( $invoice_id = 0, $note = '', $user_type = false, $added_by_user = false ) {
433
    $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...
434
435
    return $invoice->add_note( $note, $user_type, $added_by_user );
436
}
437
438
function wpinv_get_invoice_notes( $invoice_id = 0, $type = '' ) {
439
    global $invoicing;
440
    
441
    if ( empty( $invoice_id ) ) {
442
        return NULL;
443
    }
444
    
445
    $notes = $invoicing->notes->get_invoice_notes( $invoice_id, $type );
446
    
447
    return apply_filters( 'wpinv_invoice_notes', $notes, $invoice_id, $type );
448
}
449
450
function wpinv_get_payment_key( $invoice_id = 0 ) {
451
	$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...
452
    return $invoice->get_key();
453
}
454
455
function wpinv_get_invoice_number( $invoice_id = 0 ) {
456
    $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...
457
    return $invoice->get_number();
458
}
459
460
function wpinv_get_cart_discountable_subtotal( $code_id ) {
461
    $cart_items = wpinv_get_cart_content_details();
462
    $items      = array();
463
464
    $excluded_items = wpinv_get_discount_excluded_items( $code_id );
465
466
    if( $cart_items ) {
467
468
        foreach( $cart_items as $item ) {
469
470
            if( ! in_array( $item['id'], $excluded_items ) ) {
471
                $items[] =  $item;
472
            }
473
        }
474
    }
475
476
    $subtotal = wpinv_get_cart_items_subtotal( $items );
477
478
    return apply_filters( 'wpinv_get_cart_discountable_subtotal', $subtotal );
479
}
480
481
function wpinv_get_cart_items_subtotal( $items ) {
482
    $subtotal = 0.00;
483
484
    if ( is_array( $items ) && ! empty( $items ) ) {
485
        $prices = wp_list_pluck( $items, 'subtotal' );
486
487
        if( is_array( $prices ) ) {
488
            $subtotal = array_sum( $prices );
489
        } else {
490
            $subtotal = 0.00;
491
        }
492
493
        if( $subtotal < 0 ) {
494
            $subtotal = 0.00;
495
        }
496
    }
497
498
    return apply_filters( 'wpinv_get_cart_items_subtotal', $subtotal );
499
}
500
501
function wpinv_get_cart_subtotal( $items = array() ) {
502
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
503
    $subtotal = wpinv_get_cart_items_subtotal( $items );
504
505
    return apply_filters( 'wpinv_get_cart_subtotal', $subtotal );
506
}
507
508
function wpinv_cart_subtotal( $items = array() ) {
509
    $price = wpinv_price( wpinv_format_amount( wpinv_get_cart_subtotal( $items ) ) );
510
511
    return $price;
512
}
513
514
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...
515
    $subtotal  = (float)wpinv_get_cart_subtotal( $items );
516
    $discounts = (float)wpinv_get_cart_discounted_amount( $items );
517
    $cart_tax  = (float)wpinv_get_cart_tax( $items );
518
    $fees      = (float)wpinv_get_cart_fee_total();
519
    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...
520
        $total = 0;
521
    } else {
522
        $total     = $subtotal - $discounts + $cart_tax + $fees;
523
    }
524
525
    if ( $total < 0 ) {
526
        $total = 0.00;
527
    }
528
    
529
    $total = (float)apply_filters( 'wpinv_get_cart_total', $total, $items );
530
531
    return wpinv_sanitize_amount( $total );
532
}
533
534
function wpinv_cart_total( $cart_items = array(), $echo = true, $invoice = array() ) {
535
    global $cart_total;
536
    $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...
537
    $total = apply_filters( 'wpinv_cart_total', $total, $cart_items, $invoice );
538
    
539
    $cart_total = $total;
540
541
    if ( !$echo ) {
542
        return $total;
543
    }
544
545
    echo $total;
546
}
547
548 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...
549
    $cart_tax = 0;
550
    $items    = !empty( $items ) ? $items : wpinv_get_cart_content_details();
551
552
    if ( $items ) {
553
        $taxes = wp_list_pluck( $items, 'tax' );
554
555
        if( is_array( $taxes ) ) {
556
            $cart_tax = array_sum( $taxes );
557
        }
558
    }
559
560
    $cart_tax += wpinv_get_cart_fee_tax();
561
562
    return apply_filters( 'wpinv_get_cart_tax', wpinv_sanitize_amount( $cart_tax ) );
563
}
564
565 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...
566
    $cart_tax = wpinv_get_cart_tax( $items );
567
    $cart_tax = wpinv_price( wpinv_format_amount( $cart_tax ) );
568
569
    $tax = apply_filters( 'wpinv_cart_tax', $cart_tax, $items );
570
571
    if ( !$echo ) {
572
        return $tax;
573
    }
574
575
    echo $tax;
576
}
577
578
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...
579
    $invoice = wpinv_get_invoice_cart();
580
    $cart_discount_code = !empty( $invoice ) ? $invoice->get_discount_code() : '';
581
    
582
    return apply_filters( 'wpinv_get_cart_discount_code', $cart_discount_code );
583
}
584
585
function wpinv_cart_discount_code( $items = array(), $echo = false ) {
586
    $cart_discount_code = wpinv_get_cart_discount_code( $items );
587
588
    if ( $cart_discount_code != '' ) {
589
        $cart_discount_code = ' (' . $cart_discount_code . ')';
590
    }
591
    
592
    $discount_code = apply_filters( 'wpinv_cart_discount_code', $cart_discount_code, $items );
593
594
    if ( !$echo ) {
595
        return $discount_code;
596
    }
597
598
    echo $discount_code;
599
}
600
601
function wpinv_get_cart_discount( $items = array() ) {
602
    $invoice = wpinv_get_invoice_cart();
603
    $cart_discount = !empty( $invoice ) ? $invoice->get_discount() : 0;
604
    
605
    return apply_filters( 'wpinv_get_cart_discount', wpinv_sanitize_amount( $cart_discount ), $items );
606
}
607
608 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...
609
    $cart_discount = wpinv_get_cart_discount( $items );
610
    $cart_discount = wpinv_price( wpinv_format_amount( $cart_discount ) );
611
612
    $discount = apply_filters( 'wpinv_cart_discount', $cart_discount, $items );
613
614
    if ( !$echo ) {
615
        return $discount;
616
    }
617
618
    echo $discount;
619
}
620
621
function wpinv_get_cart_fees( $type = 'all', $item_id = 0 ) {
622
    $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...
623
    
624
    return $item->get_fees( $type, $item_id );
625
}
626
627
function wpinv_get_cart_fee_total() {
628
    $total  = 0;
629
    $fees = wpinv_get_cart_fees();
630
    
631
    if ( $fees ) {
632
        foreach ( $fees as $fee_id => $fee ) {
633
            $total += $fee['amount'];
634
        }
635
    }
636
637
    return apply_filters( 'wpinv_get_cart_fee_total', $total );
638
}
639
640
function wpinv_get_cart_fee_tax() {
641
    $tax  = 0;
642
    $fees = wpinv_get_cart_fees();
643
644
    if ( $fees ) {
645
        foreach ( $fees as $fee_id => $fee ) {
646
            if( ! empty( $fee['no_tax'] ) ) {
647
                continue;
648
            }
649
650
            $tax += wpinv_calculate_tax( $fee['amount'] );
651
        }
652
    }
653
654
    return apply_filters( 'wpinv_get_cart_fee_tax', $tax );
655
}
656
657
function wpinv_cart_has_recurring_item() {
658
    $cart_items = wpinv_get_cart_contents();
659
    
660
    if ( empty( $cart_items ) ) {
661
        return false;
662
    }
663
    
664
    $has_subscription = false;
665 View Code Duplication
    foreach( $cart_items as $cart_item ) {
666
        if ( !empty( $cart_item['id'] ) && wpinv_is_recurring_item( $cart_item['id'] )  ) {
667
            $has_subscription = true;
668
            break;
669
        }
670
    }
671
    
672
    return apply_filters( 'wpinv_cart_has_recurring_item', $has_subscription, $cart_items );
673
}
674
675
function wpinv_cart_has_free_trial() {
676
    $invoice = wpinv_get_invoice_cart();
677
    
678
    $free_trial = false;
679
    
680
    if ( !empty( $invoice ) && $invoice->is_free_trial() ) {
681
        $free_trial = true;
682
    }
683
    
684
    return apply_filters( 'wpinv_cart_has_free_trial', $free_trial, $invoice );
685
}
686
687
function wpinv_get_cart_contents() {
688
    $cart_details = wpinv_get_cart_details();
689
    
690
    return apply_filters( 'wpinv_get_cart_contents', $cart_details );
691
}
692
693
function wpinv_get_cart_content_details() {
694
    global $wpinv_euvat, $wpi_current_id, $wpi_item_id, $wpinv_is_last_cart_item, $wpinv_flat_discount_total;
695
    $cart_items = wpinv_get_cart_contents();
696
    
697
    if ( empty( $cart_items ) ) {
698
        return false;
699
    }
700
    $invoice = wpinv_get_invoice_cart();
701
702
    $details = array();
703
    $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...
704
    
705
    if ( empty( $_POST['country'] ) ) {
706
        $_POST['country'] = $invoice->country;
707
    }
708
    if ( !isset( $_POST['state'] ) ) {
709
        $_POST['state'] = $invoice->state;
710
    }
711
712
    foreach( $cart_items as $key => $item ) {
713
        $item_id            = isset( $item['id'] ) ? sanitize_text_field( $item['id'] ) : '';
714
        if ( empty( $item_id ) ) {
715
            continue;
716
        }
717
        
718
        $wpi_current_id         = $invoice->ID;
719
        $wpi_item_id            = $item_id;
720
        
721
        if ( isset( $item['custom_price'] ) && $item['custom_price'] !== '' ) {
722
            $item_price = $item['custom_price'];
723
        } else {
724
            if ( isset( $item['item_price'] ) && $item['item_price'] !== '' && $item['item_price'] !== false ) {
725
                $item_price = $item['item_price'];
726
            } else {
727
                $item_price = wpinv_get_item_price( $item_id );
728
            }
729
        }
730
        $discount           = wpinv_get_cart_item_discount_amount( $item );
731
        $discount           = apply_filters( 'wpinv_get_cart_content_details_item_discount_amount', $discount, $item );
732
        $quantity           = wpinv_get_cart_item_quantity( $item );
733
        $fees               = wpinv_get_cart_fees( 'fee', $item_id );
734
        
735
        $subtotal           = $item_price * $quantity;
736
        $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...
737
        $tax_class          = $wpinv_euvat->get_item_class( $item_id );
738
        $tax                = wpinv_get_cart_item_tax( $item_id, $subtotal - $discount );
739
        
740
        if ( wpinv_prices_include_tax() ) {
741
            $subtotal -= wpinv_round_amount( $tax );
742
        }
743
        
744
        $total              = $subtotal - $discount + $tax;
745
        
746
        // Do not allow totals to go negatve
747
        if( $total < 0 ) {
748
            $total = 0;
749
        }
750
        
751
        $details[ $key ]  = array(
752
            'id'                => $item_id,
753
            'name'              => !empty($item['name']) ? $item['name'] : get_the_title( $item_id ),
754
            'item_price'        => wpinv_round_amount( $item_price ),
755
            'custom_price'      => isset( $item['custom_price'] ) ? $item['custom_price'] : '',
756
            'quantity'          => $quantity,
757
            'discount'          => wpinv_round_amount( $discount ),
758
            'subtotal'          => wpinv_round_amount( $subtotal ),
759
            'tax'               => wpinv_round_amount( $tax ),
760
            'price'             => wpinv_round_amount( $total ),
761
            'vat_rates_class'   => $tax_class,
762
            'vat_rate'          => $tax_rate,
763
            'meta'              => isset( $item['meta'] ) ? $item['meta'] : array(),
764
            'fees'              => $fees,
765
        );
766
        
767
        if ( $wpinv_is_last_cart_item ) {
768
            $wpinv_is_last_cart_item   = false;
769
            $wpinv_flat_discount_total = 0.00;
770
        }
771
    }
772
    
773
    return $details;
774
}
775
776
function wpinv_get_cart_details( $invoice_id = 0 ) {
777
    global $ajax_cart_details;
778
779
    $invoice      = wpinv_get_invoice_cart( $invoice_id );
780
    $cart_details = !empty( $ajax_cart_details ) ? $ajax_cart_details : $invoice->cart_details;
781
782
    $invoice_currency = $invoice->currency;
783
784 View Code Duplication
    if ( ! empty( $cart_details ) && is_array( $cart_details ) ) {
785
        foreach ( $cart_details as $key => $cart_item ) {
786
            $cart_details[ $key ]['currency'] = $invoice_currency;
787
788
            if ( ! isset( $cart_item['subtotal'] ) ) {
789
                $cart_details[ $key ]['subtotal'] = $cart_item['price'];
790
            }
791
        }
792
    }
793
794
    return apply_filters( 'wpinv_get_cart_details', $cart_details, $invoice_id );
795
}
796
797
function wpinv_record_status_change( $invoice_id, $new_status, $old_status ) {
798
    if ( 'wpi_invoice' != get_post_type( $invoice_id ) ) {
799
        return;
800
    }
801
802
    $invoice    = wpinv_get_invoice( $invoice_id );
803
    
804
    $old_status = wpinv_status_nicename( $old_status );
805
    $new_status = wpinv_status_nicename( $new_status );
806
807
    $status_change = sprintf( __( 'Invoice status changed from %s to %s', 'invoicing' ), $old_status, $new_status );
808
    
809
    // Add note
810
    return $invoice->add_note( $status_change, false, false, true );
811
}
812
add_action( 'wpinv_update_status', 'wpinv_record_status_change', 100, 3 );
813
814
function wpinv_complete_payment( $invoice_id, $new_status, $old_status ) {
815
    global $wpi_has_free_trial;
816
    
817
    $wpi_has_free_trial = false;
818
    
819
    if ( $old_status == 'publish' ) {
820
        return; // Make sure that payments are only paid once
821
    }
822
823
    // Make sure the payment completion is only processed when new status is paid
824
    if ( $new_status != 'publish' ) {
825
        return;
826
    }
827
828
    $invoice = new WPInv_Invoice( $invoice_id );
829
    if ( empty( $invoice ) ) {
830
        return;
831
    }
832
833
    $wpi_has_free_trial = $invoice->is_free_trial();
834
    $completed_date = $invoice->completed_date;
835
    $cart_details   = $invoice->cart_details;
836
837
    do_action( 'wpinv_pre_complete_payment', $invoice_id );
838
839
    if ( is_array( $cart_details ) ) {
840
        // Increase purchase count and earnings
841
        foreach ( $cart_details as $cart_index => $item ) {
842
            // Ensure these actions only run once, ever
843
            if ( empty( $completed_date ) ) {
844
                do_action( 'wpinv_complete_item_payment', $item['id'], $invoice_id, $item, $cart_index );
845
            }
846
        }
847
    }
848
    
849
    // Check for discount codes and increment their use counts
850
    if ( $discounts = $invoice->get_discounts( true ) ) {
851
        if( ! empty( $discounts ) ) {
852
            foreach( $discounts as $code ) {
853
                wpinv_increase_discount_usage( $code );
854
            }
855
        }
856
    }
857
    
858
    // Ensure this action only runs once ever
859
    if( empty( $completed_date ) ) {
860
        // Save the completed date
861
        $invoice->set( 'completed_date', current_time( 'mysql', 0 ) );
862
        $invoice->save();
863
864
        do_action( 'wpinv_complete_payment', $invoice_id );
865
    }
866
867
    // Empty the shopping cart
868
    wpinv_empty_cart();
869
}
870
add_action( 'wpinv_update_status', 'wpinv_complete_payment', 100, 3 );
871
872
function wpinv_update_payment_status( $invoice_id, $new_status = 'publish' ) {    
873
    $invoice = !empty( $invoice_id ) && is_object( $invoice_id ) ? $invoice_id : wpinv_get_invoice( (int)$invoice_id );
874
    
875
    if ( empty( $invoice ) ) {
876
        return false;
877
    }
878
    
879
    return $invoice->update_status( $new_status );
880
}
881
882
function wpinv_cart_has_fees( $type = 'all' ) {
883
    return false;
884
}
885
886
function wpinv_validate_checkout_fields() {    
887
    // Check if there is $_POST
888
    if ( empty( $_POST ) ) {
889
        return false;
890
    }
891
    
892
    // Start an array to collect valid data
893
    $valid_data = array(
894
        'gateway'          => wpinv_checkout_validate_gateway(), // Gateway fallback
895
        'discount'         => wpinv_checkout_validate_discounts(), // Set default discount
896
        'cc_info'          => wpinv_checkout_validate_cc() // Credit card info
897
    );
898
    
899
    // Validate agree to terms
900
    if ( wpinv_get_option( 'show_agree_to_terms', false ) ) {
901
        wpinv_checkout_validate_agree_to_terms();
902
    }
903
    
904
    $valid_data['logged_in_user']   = wpinv_checkout_validate_logged_in_user();
905
    
906
    // Return collected data
907
    return $valid_data;
908
}
909
910
function wpinv_checkout_validate_gateway() {
911
    $gateway = wpinv_get_default_gateway();
912
    
913
    $invoice = wpinv_get_invoice_cart();
914
    $has_subscription = $invoice->is_recurring();
915
    if ( empty( $invoice ) ) {
916
        wpinv_set_error( 'invalid_invoice', __( 'Your cart is empty.', 'invoicing' ) );
917
        return $gateway;
918
    }
919
920
    // Check if a gateway value is present
921
    if ( !empty( $_REQUEST['wpi-gateway'] ) ) {
922
        $gateway = sanitize_text_field( $_REQUEST['wpi-gateway'] );
923
924
        if ( $invoice->is_free() ) {
925
            $gateway = 'manual';
926
        } elseif ( !wpinv_is_gateway_active( $gateway ) ) {
927
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled', 'invoicing' ) );
928
        } elseif ( $has_subscription && !wpinv_gateway_support_subscription( $gateway ) ) {
929
            wpinv_set_error( 'invalid_gateway', __( 'The selected payment gateway doesnot support subscription payment', 'invoicing' ) );
930
        }
931
    }
932
933
    if ( $has_subscription && count( wpinv_get_cart_contents() ) > 1 ) {
934
        wpinv_set_error( 'subscription_invalid', __( 'Only one subscription may be purchased through payment per checkout.', 'invoicing' ) );
935
    }
936
937
    return $gateway;
938
}
939
940
function wpinv_checkout_validate_discounts() {
941
    // Retrieve the discount stored in cookies
942
    $discounts = wpinv_get_cart_discounts();
943
    
944
    $error = false;
945
    // If we have discounts, loop through them
946
    if ( ! empty( $discounts ) ) {
947
        foreach ( $discounts as $discount ) {
948
            // Check if valid
949
            if (  !wpinv_is_discount_valid( $discount, get_current_user_id() ) ) {
950
                // Discount is not valid
951
                $error = true;
952
            }
953
        }
954
    } else {
955
        // No discounts
956
        return NULL;
957
    }
958
959
    if ( $error && !wpinv_get_errors() ) {
960
        wpinv_set_error( 'invalid_discount', __( 'Discount code you entered is invalid', 'invoicing' ) );
961
    }
962
963
    return implode( ',', $discounts );
964
}
965
966
function wpinv_checkout_validate_cc() {
967
    $card_data = wpinv_checkout_get_cc_info();
968
969
    // Validate the card zip
970
    if ( !empty( $card_data['wpinv_zip'] ) ) {
971
        if ( !wpinv_checkout_validate_cc_zip( $card_data['wpinv_zip'], $card_data['wpinv_country'] ) ) {
972
            wpinv_set_error( 'invalid_cc_zip', __( 'The zip / postcode you entered for your billing address is invalid', 'invoicing' ) );
973
        }
974
    }
975
976
    // This should validate card numbers at some point too
977
    return $card_data;
978
}
979
980
function wpinv_checkout_get_cc_info() {
981
	$cc_info = array();
982
	$cc_info['card_name']      = isset( $_POST['card_name'] )       ? sanitize_text_field( $_POST['card_name'] )       : '';
983
	$cc_info['card_number']    = isset( $_POST['card_number'] )     ? sanitize_text_field( $_POST['card_number'] )     : '';
984
	$cc_info['card_cvc']       = isset( $_POST['card_cvc'] )        ? sanitize_text_field( $_POST['card_cvc'] )        : '';
985
	$cc_info['card_exp_month'] = isset( $_POST['card_exp_month'] )  ? sanitize_text_field( $_POST['card_exp_month'] )  : '';
986
	$cc_info['card_exp_year']  = isset( $_POST['card_exp_year'] )   ? sanitize_text_field( $_POST['card_exp_year'] )   : '';
987
	$cc_info['card_address']   = isset( $_POST['wpinv_address'] )  ? sanitize_text_field( $_POST['wpinv_address'] ) : '';
988
	$cc_info['card_city']      = isset( $_POST['wpinv_city'] )     ? sanitize_text_field( $_POST['wpinv_city'] )    : '';
989
	$cc_info['card_state']     = isset( $_POST['wpinv_state'] )    ? sanitize_text_field( $_POST['wpinv_state'] )   : '';
990
	$cc_info['card_country']   = isset( $_POST['wpinv_country'] )  ? sanitize_text_field( $_POST['wpinv_country'] ) : '';
991
	$cc_info['card_zip']       = isset( $_POST['wpinv_zip'] )      ? sanitize_text_field( $_POST['wpinv_zip'] )     : '';
992
993
	// Return cc info
994
	return $cc_info;
995
}
996
997
function wpinv_checkout_validate_cc_zip( $zip = 0, $country_code = '' ) {
998
    $ret = false;
999
1000
    if ( empty( $zip ) || empty( $country_code ) )
1001
        return $ret;
1002
1003
    $country_code = strtoupper( $country_code );
1004
1005
    $zip_regex = array(
1006
        "AD" => "AD\d{3}",
1007
        "AM" => "(37)?\d{4}",
1008
        "AR" => "^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$",
1009
        "AS" => "96799",
1010
        "AT" => "\d{4}",
1011
        "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})$",
1012
        "AX" => "22\d{3}",
1013
        "AZ" => "\d{4}",
1014
        "BA" => "\d{5}",
1015
        "BB" => "(BB\d{5})?",
1016
        "BD" => "\d{4}",
1017
        "BE" => "^[1-9]{1}[0-9]{3}$",
1018
        "BG" => "\d{4}",
1019
        "BH" => "((1[0-2]|[2-9])\d{2})?",
1020
        "BM" => "[A-Z]{2}[ ]?[A-Z0-9]{2}",
1021
        "BN" => "[A-Z]{2}[ ]?\d{4}",
1022
        "BR" => "\d{5}[\-]?\d{3}",
1023
        "BY" => "\d{6}",
1024
        "CA" => "^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$",
1025
        "CC" => "6799",
1026
        "CH" => "^[1-9][0-9][0-9][0-9]$",
1027
        "CK" => "\d{4}",
1028
        "CL" => "\d{7}",
1029
        "CN" => "\d{6}",
1030
        "CR" => "\d{4,5}|\d{3}-\d{4}",
1031
        "CS" => "\d{5}",
1032
        "CV" => "\d{4}",
1033
        "CX" => "6798",
1034
        "CY" => "\d{4}",
1035
        "CZ" => "\d{3}[ ]?\d{2}",
1036
        "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",
1037
        "DK" => "^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$",
1038
        "DO" => "\d{5}",
1039
        "DZ" => "\d{5}",
1040
        "EC" => "([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?",
1041
        "EE" => "\d{5}",
1042
        "EG" => "\d{5}",
1043
        "ES" => "^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$",
1044
        "ET" => "\d{4}",
1045
        "FI" => "\d{5}",
1046
        "FK" => "FIQQ 1ZZ",
1047
        "FM" => "(9694[1-4])([ \-]\d{4})?",
1048
        "FO" => "\d{3}",
1049
        "FR" => "^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$",
1050
        "GE" => "\d{4}",
1051
        "GF" => "9[78]3\d{2}",
1052
        "GL" => "39\d{2}",
1053
        "GN" => "\d{3}",
1054
        "GP" => "9[78][01]\d{2}",
1055
        "GR" => "\d{3}[ ]?\d{2}",
1056
        "GS" => "SIQQ 1ZZ",
1057
        "GT" => "\d{5}",
1058
        "GU" => "969[123]\d([ \-]\d{4})?",
1059
        "GW" => "\d{4}",
1060
        "HM" => "\d{4}",
1061
        "HN" => "(?:\d{5})?",
1062
        "HR" => "\d{5}",
1063
        "HT" => "\d{4}",
1064
        "HU" => "\d{4}",
1065
        "ID" => "\d{5}",
1066
        "IE" => "((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?",
1067
        "IL" => "\d{5}",
1068
        "IN"=> "^[1-9][0-9][0-9][0-9][0-9][0-9]$", //india
1069
        "IO" => "BBND 1ZZ",
1070
        "IQ" => "\d{5}",
1071
        "IS" => "\d{3}",
1072
        "IT" => "^(V-|I-)?[0-9]{5}$",
1073
        "JO" => "\d{5}",
1074
        "JP" => "\d{3}-\d{4}",
1075
        "KE" => "\d{5}",
1076
        "KG" => "\d{6}",
1077
        "KH" => "\d{5}",
1078
        "KR" => "\d{3}[\-]\d{3}",
1079
        "KW" => "\d{5}",
1080
        "KZ" => "\d{6}",
1081
        "LA" => "\d{5}",
1082
        "LB" => "(\d{4}([ ]?\d{4})?)?",
1083
        "LI" => "(948[5-9])|(949[0-7])",
1084
        "LK" => "\d{5}",
1085
        "LR" => "\d{4}",
1086
        "LS" => "\d{3}",
1087
        "LT" => "\d{5}",
1088
        "LU" => "\d{4}",
1089
        "LV" => "\d{4}",
1090
        "MA" => "\d{5}",
1091
        "MC" => "980\d{2}",
1092
        "MD" => "\d{4}",
1093
        "ME" => "8\d{4}",
1094
        "MG" => "\d{3}",
1095
        "MH" => "969[67]\d([ \-]\d{4})?",
1096
        "MK" => "\d{4}",
1097
        "MN" => "\d{6}",
1098
        "MP" => "9695[012]([ \-]\d{4})?",
1099
        "MQ" => "9[78]2\d{2}",
1100
        "MT" => "[A-Z]{3}[ ]?\d{2,4}",
1101
        "MU" => "(\d{3}[A-Z]{2}\d{3})?",
1102
        "MV" => "\d{5}",
1103
        "MX" => "\d{5}",
1104
        "MY" => "\d{5}",
1105
        "NC" => "988\d{2}",
1106
        "NE" => "\d{4}",
1107
        "NF" => "2899",
1108
        "NG" => "(\d{6})?",
1109
        "NI" => "((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?",
1110
        "NL" => "^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$",
1111
        "NO" => "\d{4}",
1112
        "NP" => "\d{5}",
1113
        "NZ" => "\d{4}",
1114
        "OM" => "(PC )?\d{3}",
1115
        "PF" => "987\d{2}",
1116
        "PG" => "\d{3}",
1117
        "PH" => "\d{4}",
1118
        "PK" => "\d{5}",
1119
        "PL" => "\d{2}-\d{3}",
1120
        "PM" => "9[78]5\d{2}",
1121
        "PN" => "PCRN 1ZZ",
1122
        "PR" => "00[679]\d{2}([ \-]\d{4})?",
1123
        "PT" => "\d{4}([\-]\d{3})?",
1124
        "PW" => "96940",
1125
        "PY" => "\d{4}",
1126
        "RE" => "9[78]4\d{2}",
1127
        "RO" => "\d{6}",
1128
        "RS" => "\d{5}",
1129
        "RU" => "\d{6}",
1130
        "SA" => "\d{5}",
1131
        "SE" => "^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$",
1132
        "SG" => "\d{6}",
1133
        "SH" => "(ASCN|STHL) 1ZZ",
1134
        "SI" => "\d{4}",
1135
        "SJ" => "\d{4}",
1136
        "SK" => "\d{3}[ ]?\d{2}",
1137
        "SM" => "4789\d",
1138
        "SN" => "\d{5}",
1139
        "SO" => "\d{5}",
1140
        "SZ" => "[HLMS]\d{3}",
1141
        "TC" => "TKCA 1ZZ",
1142
        "TH" => "\d{5}",
1143
        "TJ" => "\d{6}",
1144
        "TM" => "\d{6}",
1145
        "TN" => "\d{4}",
1146
        "TR" => "\d{5}",
1147
        "TW" => "\d{3}(\d{2})?",
1148
        "UA" => "\d{5}",
1149
        "UK" => "^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$",
1150
        "US" => "^\d{5}([\-]?\d{4})?$",
1151
        "UY" => "\d{5}",
1152
        "UZ" => "\d{6}",
1153
        "VA" => "00120",
1154
        "VE" => "\d{4}",
1155
        "VI" => "008(([0-4]\d)|(5[01]))([ \-]\d{4})?",
1156
        "WF" => "986\d{2}",
1157
        "YT" => "976\d{2}",
1158
        "YU" => "\d{5}",
1159
        "ZA" => "\d{4}",
1160
        "ZM" => "\d{5}"
1161
    );
1162
1163
    if ( ! isset ( $zip_regex[ $country_code ] ) || preg_match( "/" . $zip_regex[ $country_code ] . "/i", $zip ) )
1164
        $ret = true;
1165
1166
    return apply_filters( 'wpinv_is_zip_valid', $ret, $zip, $country_code );
1167
}
1168
1169
function wpinv_checkout_validate_agree_to_terms() {
1170
    // Validate agree to terms
1171
    if ( ! isset( $_POST['wpi_agree_to_terms'] ) || $_POST['wpi_agree_to_terms'] != 1 ) {
1172
        // User did not agree
1173
        wpinv_set_error( 'agree_to_terms', apply_filters( 'wpinv_agree_to_terms_text', __( 'You must agree to the terms of use', 'invoicing' ) ) );
1174
    }
1175
}
1176
1177
function wpinv_checkout_validate_logged_in_user() {
1178
    $user_ID = get_current_user_id();
1179
    
1180
    $valid_user_data = array(
1181
        // Assume there will be errors
1182
        'user_id' => -1
1183
    );
1184
    
1185
    // Verify there is a user_ID
1186
    if ( $user_ID > 0 ) {
1187
        // Get the logged in user data
1188
        $user_data = get_userdata( $user_ID );
1189
        $required_fields  = wpinv_checkout_required_fields();
1190
1191
        // Loop through required fields and show error messages
1192
         if ( !empty( $required_fields ) ) {
1193
            foreach ( $required_fields as $field_name => $value ) {
1194
                if ( in_array( $value, $required_fields ) && empty( $_POST[ 'wpinv_' . $field_name ] ) ) {
1195
                    wpinv_set_error( $value['error_id'], $value['error_message'] );
1196
                }
1197
            }
1198
        }
1199
1200
        // Verify data
1201
        if ( $user_data ) {
1202
            // Collected logged in user data
1203
            $valid_user_data = array(
1204
                'user_id'     => $user_ID,
1205
                'email'       => isset( $_POST['wpinv_email'] ) ? sanitize_email( $_POST['wpinv_email'] ) : $user_data->user_email,
1206
                'first_name'  => isset( $_POST['wpinv_first_name'] ) && ! empty( $_POST['wpinv_first_name'] ) ? sanitize_text_field( $_POST['wpinv_first_name'] ) : $user_data->first_name,
1207
                'last_name'   => isset( $_POST['wpinv_last_name'] ) && ! empty( $_POST['wpinv_last_name']  ) ? sanitize_text_field( $_POST['wpinv_last_name']  ) : $user_data->last_name,
1208
            );
1209
1210
            if ( !empty( $_POST[ 'wpinv_email' ] ) && !is_email( $_POST[ 'wpinv_email' ] ) ) {
1211
                wpinv_set_error( 'invalid_email', __( 'Please enter a valid email address', 'invoicing' ) );
1212
            }
1213
        } else {
1214
            // Set invalid user error
1215
            wpinv_set_error( 'invalid_user', __( 'The user billing information is invalid', 'invoicing' ) );
1216
        }
1217
    }
1218
1219
    // Return user data
1220
    return $valid_user_data;
1221
}
1222
1223
function wpinv_checkout_form_get_user( $valid_data = array() ) {
1224
    // Initialize user
1225
    $user    = false;
1226
    $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...
1227
1228
    /*if ( $is_ajax ) {
1229
        // Do not create or login the user during the ajax submission (check for errors only)
1230
        return true;
1231
    } else */if ( is_user_logged_in() ) {
1232
        // Set the valid user as the logged in collected data
1233
        $user = $valid_data['logged_in_user'];
1234
    }
1235
1236
    // Verify we have an user
1237
    if ( false === $user || empty( $user ) ) {
1238
        // Return false
1239
        return false;
1240
    }
1241
    
1242
    $address_fields = array(
1243
        'first_name',
1244
        'last_name',
1245
        'company',
1246
        'vat_number',
1247
        ///'email',
1248
        'phone',
1249
        'address',
1250
        'city',
1251
        'state',
1252
        'country',
1253
        'zip',
1254
    );
1255
    
1256
    foreach ( $address_fields as $field ) {
1257
        $user[$field]  = !empty( $_POST['wpinv_' . $field] ) ? sanitize_text_field( $_POST['wpinv_' . $field] ) : false;
1258
        
1259
        if ( !empty( $user['user_id'] ) ) {
1260
            update_user_meta( $user['user_id'], '_wpinv_' . $field, $user[$field] );
1261
        }
1262
    }
1263
1264
    // Return valid user
1265
    return $user;
1266
}
1267
1268
function wpinv_set_checkout_session( $invoice_data = array() ) {
1269
    global $wpi_session;
1270
    
1271
    return $wpi_session->set( 'wpinv_checkout', $invoice_data );
1272
}
1273
1274
function wpinv_get_checkout_session() {
1275
	global $wpi_session;
1276
    
1277
    return $wpi_session->get( 'wpinv_checkout' );
1278
}
1279
1280
function wpinv_empty_cart() {
1281
    global $wpi_session;
1282
1283
    // Remove cart contents
1284
    $wpi_session->set( 'wpinv_checkout', NULL );
1285
1286
    // Remove all cart fees
1287
    $wpi_session->set( 'wpi_cart_fees', NULL );
1288
1289
    do_action( 'wpinv_empty_cart' );
1290
}
1291
1292
function wpinv_process_checkout() {
1293
    global $wpinv_euvat, $wpi_checkout_id;
1294
    
1295
    wpinv_clear_errors();
1296
    
1297
    $invoice = wpinv_get_invoice_cart();
1298
    
1299
    $wpi_checkout_id = $invoice->ID;
1300
    
1301
    do_action( 'wpinv_pre_process_checkout' );
1302
    
1303
    if ( !wpinv_get_cart_contents() ) { // Make sure the cart isn't empty
1304
        $valid_data = false;
1305
        wpinv_set_error( 'empty_cart', __( 'Your cart is empty', 'invoicing' ) );
1306
    } else {
1307
        // Validate the form $_POST data
1308
        $valid_data = wpinv_validate_checkout_fields();
1309
        
1310
        // Allow themes and plugins to hook to errors
1311
        do_action( 'wpinv_checkout_error_checks', $valid_data, $_POST );
1312
    }
1313
    
1314
    $is_ajax    = defined( 'DOING_AJAX' ) && DOING_AJAX;
1315
    
1316
    // Validate the user
1317
    $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...
1318
1319
    // Let extensions validate fields after user is logged in if user has used login/registration form
1320
    do_action( 'wpinv_checkout_user_error_checks', $user, $valid_data, $_POST );
1321
    
1322
    if ( false === $valid_data || wpinv_get_errors() || ! $user ) {
1323
        if ( $is_ajax ) {
1324
            do_action( 'wpinv_ajax_checkout_errors' );
1325
            die();
1326
        } else {
1327
            return false;
1328
        }
1329
    }
1330
1331
    if ( $is_ajax ) {
1332
        // Save address fields.
1333
        $address_fields = array( 'first_name', 'last_name', 'phone', 'address', 'city', 'country', 'state', 'zip', 'company' );
1334 View Code Duplication
        foreach ( $address_fields as $field ) {
1335
            if ( isset( $user[$field] ) ) {
1336
                $invoice->set( $field, $user[$field] );
1337
            }
1338
            
1339
            $invoice->save();
1340
        }
1341
1342
        $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...
1343
        $response['data']['subtotal']   = $invoice->get_subtotal();
1344
        $response['data']['subtotalf']  = $invoice->get_subtotal( true );
1345
        $response['data']['discount']   = $invoice->get_discount();
1346
        $response['data']['discountf']  = $invoice->get_discount( true );
1347
        $response['data']['tax']        = $invoice->get_tax();
1348
        $response['data']['taxf']       = $invoice->get_tax( true );
1349
        $response['data']['total']      = $invoice->get_total();
1350
        $response['data']['totalf']     = $invoice->get_total( true );
1351
        
1352
        wp_send_json( $response );
1353
    }
1354
    
1355
    $user_info = array(
1356
        'user_id'        => $user['user_id'],
1357
        'first_name'     => $user['first_name'],
1358
        'last_name'      => $user['last_name'],
1359
        'email'          => $user['email'],
1360
        'company'        => $user['company'],
1361
        'phone'          => $user['phone'],
1362
        'address'        => $user['address'],
1363
        'city'           => $user['city'],
1364
        'country'        => $user['country'],
1365
        'state'          => $user['state'],
1366
        'zip'            => $user['zip'],
1367
    );
1368
    
1369
    $cart_items = wpinv_get_cart_contents();
1370
    $discounts  = wpinv_get_cart_discounts();
1371
    
1372
    // Setup invoice information
1373
    $invoice_data = array(
1374
        'invoice_id'        => !empty( $invoice ) ? $invoice->ID : 0,
1375
        'items'             => $cart_items,
1376
        'cart_discounts'    => $discounts,
1377
        'fees'              => wpinv_get_cart_fees(),        // Any arbitrary fees that have been added to the cart
1378
        'subtotal'          => wpinv_get_cart_subtotal( $cart_items ),    // Amount before taxes and discounts
1379
        'discount'          => wpinv_get_cart_items_discount_amount( $cart_items, $discounts ), // Discounted amount
1380
        'tax'               => wpinv_get_cart_tax( $cart_items ),               // Taxed amount
1381
        'price'             => wpinv_get_cart_total( $cart_items, $discounts ),    // Amount after taxes
1382
        'invoice_key'       => $invoice->get_key() ? $invoice->get_key() : $invoice->generate_key(),
1383
        'user_email'        => $user['email'],
1384
        'date'              => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
1385
        'user_info'         => stripslashes_deep( $user_info ),
1386
        'post_data'         => $_POST,
1387
        'cart_details'      => $cart_items,
1388
        'gateway'           => $valid_data['gateway'],
1389
        'card_info'         => $valid_data['cc_info']
1390
    );
1391
    
1392
    $vat_info   = $wpinv_euvat->current_vat_data();
1393
    if ( is_array( $vat_info ) ) {
1394
        $invoice_data['user_info']['vat_number']        = $vat_info['number'];
1395
        $invoice_data['user_info']['vat_rate']          = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state']);
1396
        $invoice_data['user_info']['adddress_confirmed']    = isset($vat_info['adddress_confirmed']) ? $vat_info['adddress_confirmed'] : false;
1397
1398
        // Add the VAT rate to each item in the cart
1399
        foreach( $invoice_data['cart_details'] as $key => $item_data) {
1400
            $rate = wpinv_get_tax_rate($invoice_data['user_info']['country'], $invoice_data['user_info']['state'], $item_data['id']);
1401
            $invoice_data['cart_details'][$key]['vat_rate'] = wpinv_round_amount( $rate, 4 );
1402
        }
1403
    }
1404
    
1405
    // Save vat fields.
1406
    $address_fields = array( 'vat_number', 'vat_rate', 'adddress_confirmed' );
1407 View Code Duplication
    foreach ( $address_fields as $field ) {
1408
        if ( isset( $invoice_data['user_info'][$field] ) ) {
1409
            $invoice->set( $field, $invoice_data['user_info'][$field] );
1410
        }
1411
        
1412
        $invoice->save();
1413
    }
1414
1415
    // Add the user data for hooks
1416
    $valid_data['user'] = $user;
1417
    
1418
    // Allow themes and plugins to hook before the gateway
1419
    do_action( 'wpinv_checkout_before_gateway', $_POST, $user_info, $valid_data );
1420
    
1421
    // If the total amount in the cart is 0, send to the manual gateway. This emulates a free invoice
1422
    if ( !$invoice_data['price'] ) {
1423
        // Revert to manual
1424
        $invoice_data['gateway'] = 'manual';
1425
        $_POST['wpi-gateway'] = 'manual';
1426
    }
1427
    
1428
    // Allow the invoice data to be modified before it is sent to the gateway
1429
    $invoice_data = apply_filters( 'wpinv_data_before_gateway', $invoice_data, $valid_data );
1430
    
1431
    // Setup the data we're storing in the purchase session
1432
    $session_data = $invoice_data;
1433
    // Make sure credit card numbers are never stored in sessions
1434
    if ( !empty( $session_data['card_info']['card_number'] ) ) {
1435
        unset( $session_data['card_info']['card_number'] );
1436
    }
1437
    
1438
    // Used for showing item links to non logged-in users after purchase, and for other plugins needing purchase data.
1439
    wpinv_set_checkout_session( $invoice_data );
1440
    
1441
    // Set gateway
1442
    $invoice->update_meta( '_wpinv_gateway', $invoice_data['gateway'] );
1443
    $invoice->update_meta( '_wpinv_mode', ( wpinv_is_test_mode( $invoice_data['gateway'] ) ? 'test' : 'live' ) );
1444
    $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...
1445
    
1446
    do_action( 'wpinv_checkout_before_send_to_gateway', $invoice, $invoice_data );
1447
1448
    // Send info to the gateway for payment processing
1449
    wpinv_send_to_gateway( $invoice_data['gateway'], $invoice_data );
1450
    die();
1451
}
1452
add_action( 'wpinv_payment', 'wpinv_process_checkout' );
1453
1454
function wpinv_get_invoices( $args ) {
1455
    $args = wp_parse_args( $args, array(
1456
        'status'   => array_keys( wpinv_get_invoice_statuses() ),
1457
        'type'     => 'wpi_invoice',
1458
        'parent'   => null,
1459
        'user'     => null,
1460
        'email'    => '',
1461
        'limit'    => get_option( 'posts_per_page' ),
1462
        'offset'   => null,
1463
        'page'     => 1,
1464
        'exclude'  => array(),
1465
        'orderby'  => 'date',
1466
        'order'    => 'DESC',
1467
        'return'   => 'objects',
1468
        'paginate' => false,
1469
    ) );
1470
    
1471
    // Handle some BW compatibility arg names where wp_query args differ in naming.
1472
    $map_legacy = array(
1473
        'numberposts'    => 'limit',
1474
        'post_type'      => 'type',
1475
        'post_status'    => 'status',
1476
        'post_parent'    => 'parent',
1477
        'author'         => 'user',
1478
        'posts_per_page' => 'limit',
1479
        'paged'          => 'page',
1480
    );
1481
1482
    foreach ( $map_legacy as $from => $to ) {
1483
        if ( isset( $args[ $from ] ) ) {
1484
            $args[ $to ] = $args[ $from ];
1485
        }
1486
    }
1487
1488
    $wpinv_cpt = isset( $_REQUEST[ 'wpinv-cpt' ] ) ? $_REQUEST[ 'wpinv-cpt' ] : '';
1489
1490
    if ( get_query_var( 'paged' ) && 'wpi_invoice' == $wpinv_cpt )
1491
        $args['page'] = get_query_var('paged');
1492
    else if ( get_query_var( 'page' )  && 'wpi_invoice' == $wpinv_cpt )
1493
        $args['page'] = get_query_var( 'page' );
1494
    else if ( !empty( $args[ 'page' ] ) )
1495
        $args['page'] = $args[ 'page' ];
1496
    else
1497
        $args['page'] = 1;
1498
1499
    /**
1500
     * Generate WP_Query args. This logic will change if orders are moved to
1501
     * custom tables in the future.
1502
     */
1503
    $wp_query_args = array(
1504
        'post_type'      => 'wpi_invoice',
1505
        'post_status'    => $args['status'],
1506
        'posts_per_page' => $args['limit'],
1507
        'meta_query'     => array(),
1508
        'date_query'     => !empty( $args['date_query'] ) ? $args['date_query'] : array(),
1509
        'fields'         => 'ids',
1510
        'orderby'        => $args['orderby'],
1511
        'order'          => $args['order'],
1512
    );
1513
    
1514
    if ( !empty( $args['user'] ) ) {
1515
        $wp_query_args['author'] = absint( $args['user'] );
1516
    }
1517
1518
    if ( ! is_null( $args['parent'] ) ) {
1519
        $wp_query_args['post_parent'] = absint( $args['parent'] );
1520
    }
1521
1522
    if ( ! is_null( $args['offset'] ) ) {
1523
        $wp_query_args['offset'] = absint( $args['offset'] );
1524
    } else {
1525
        $wp_query_args['paged'] = absint( $args['page'] );
1526
    }
1527
1528
    if ( ! empty( $args['exclude'] ) ) {
1529
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
1530
    }
1531
1532
    if ( ! $args['paginate' ] ) {
1533
        $wp_query_args['no_found_rows'] = true;
1534
    }
1535
1536
    // Get results.
1537
    $invoices = new WP_Query( $wp_query_args );
1538
1539
    if ( 'objects' === $args['return'] ) {
1540
        $return = array_map( 'wpinv_get_invoice', $invoices->posts );
1541
    } elseif ( 'self' === $args['return'] ) {
1542
        return $invoices;
1543
    } else {
1544
        $return = $invoices->posts;
1545
    }
1546
1547
    if ( $args['paginate' ] ) {
1548
        return (object) array(
1549
            'invoices'      => $return,
1550
            'total'         => $invoices->found_posts,
1551
            'max_num_pages' => $invoices->max_num_pages,
1552
        );
1553
    } else {
1554
        return $return;
1555
    }
1556
}
1557
1558
function wpinv_get_user_invoices_columns() {
1559
    $columns = array(
1560
            'invoice-number'  => array( 'title' => __( 'ID', 'invoicing' ), 'class' => 'text-left' ),
1561
            'invoice-date'    => array( 'title' => __( 'Date', 'invoicing' ), 'class' => 'text-left' ),
1562
            'invoice-status'  => array( 'title' => __( 'Status', 'invoicing' ), 'class' => 'text-center' ),
1563
            'invoice-total'   => array( 'title' => __( 'Total', 'invoicing' ), 'class' => 'text-right' ),
1564
            'invoice-actions' => array( 'title' => '&nbsp;', 'class' => 'text-center' ),
1565
        );
1566
1567
    return apply_filters( 'wpinv_user_invoices_columns', $columns );
1568
}
1569
1570
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...
1571
    global $wpinv_receipt_args;
1572
1573
    $wpinv_receipt_args = shortcode_atts( array(
1574
        'error'           => __( 'Sorry, trouble retrieving payment receipt.', 'invoicing' ),
1575
        'price'           => true,
1576
        'discount'        => true,
1577
        'items'           => true,
1578
        'date'            => true,
1579
        'notes'           => true,
1580
        'invoice_key'     => false,
1581
        'payment_method'  => true,
1582
        'invoice_id'      => true
1583
    ), $atts, 'wpinv_receipt' );
1584
1585
    $session = wpinv_get_checkout_session();
1586
    if ( isset( $_GET['invoice_key'] ) ) {
1587
        $invoice_key = urldecode( $_GET['invoice_key'] );
1588
    } else if ( $session && isset( $session['invoice_key'] ) ) {
1589
        $invoice_key = $session['invoice_key'];
1590
    } elseif ( isset( $wpinv_receipt_args['invoice_key'] ) && $wpinv_receipt_args['invoice_key'] ) {
1591
        $invoice_key = $wpinv_receipt_args['invoice_key'];
1592
    } else if ( isset( $_GET['invoice-id'] ) ) {
1593
        $invoice_key = wpinv_get_payment_key( (int)$_GET['invoice-id'] );
1594
    }
1595
1596
    // No key found
1597
    if ( ! isset( $invoice_key ) ) {
1598
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1599
    }
1600
1601
    $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...
1602
    $user_can_view = wpinv_can_view_receipt( $invoice_key );
1603 View Code Duplication
    if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1604
        $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...
1605
        $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1606
    }
1607
1608
    // Key was provided, but user is logged out. Offer them the ability to login and view the receipt
1609
    if ( ! $user_can_view && ! empty( $invoice_key ) && ! is_user_logged_in() ) {
1610
        // login redirect
1611
        return '<p class="alert alert-error">' . __( 'You are not allowed to access this section', 'invoicing' ) . '</p>';
1612
    }
1613
1614
    if ( ! apply_filters( 'wpinv_user_can_view_receipt', $user_can_view, $wpinv_receipt_args ) ) {
1615
        return '<p class="alert alert-error">' . $wpinv_receipt_args['error'] . '</p>';
1616
    }
1617
1618
    ob_start();
1619
1620
    wpinv_get_template_part( 'wpinv-invoice-receipt' );
1621
1622
    $display = ob_get_clean();
1623
1624
    return $display;
1625
}
1626
1627 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...
1628
	global $wpdb;
1629
1630
	$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 ) );
1631
1632
	if ( $invoice_id != NULL )
1633
		return $invoice_id;
1634
1635
	return 0;
1636
}
1637
1638
function wpinv_can_view_receipt( $invoice_key = '' ) {
1639
	$return = false;
1640
1641
	if ( empty( $invoice_key ) ) {
1642
		return $return;
1643
	}
1644
1645
	global $wpinv_receipt_args;
1646
1647
	$wpinv_receipt_args['id'] = wpinv_get_invoice_id_by_key( $invoice_key );
1648
	if ( isset( $_GET['invoice-id'] ) ) {
1649
		$wpinv_receipt_args['id'] = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? (int)$_GET['invoice-id'] : 0;
1650
	}
1651
1652
	$user_id = (int) wpinv_get_user_id( $wpinv_receipt_args['id'] );
1653
    $invoice_meta = wpinv_get_invoice_meta( $wpinv_receipt_args['id'] );
1654
1655
	if ( is_user_logged_in() ) {
1656
		if ( $user_id === (int) get_current_user_id() ) {
1657
			$return = true;
1658
		}
1659
	}
1660
1661
	$session = wpinv_get_checkout_session();
1662
	if ( ! empty( $session ) && ! is_user_logged_in() ) {
1663
		if ( $session['invoice_key'] === $invoice_meta['key'] ) {
1664
			$return = true;
1665
		}
1666
	}
1667
1668
	return (bool) apply_filters( 'wpinv_can_view_receipt', $return, $invoice_key );
1669
}
1670
1671
function wpinv_pay_for_invoice() {
1672
    global $wpinv_euvat;
1673
    
1674
    if ( isset( $_GET['invoice_key'] ) ) {
1675
        $checkout_uri   = wpinv_get_checkout_uri();
1676
        $invoice_key    = sanitize_text_field( $_GET['invoice_key'] );
1677
        
1678
        if ( empty( $invoice_key ) ) {
1679
            wpinv_set_error( 'invalid_invoice', __( 'Invoice not found', 'invoicing' ) );
1680
            wp_redirect( $checkout_uri );
1681
            wpinv_die();
1682
        }
1683
        
1684
        do_action( 'wpinv_check_pay_for_invoice', $invoice_key );
1685
1686
        $invoice_id    = wpinv_get_invoice_id_by_key( $invoice_key );
1687
        $user_can_view = wpinv_can_view_receipt( $invoice_key );
1688 View Code Duplication
        if ( $user_can_view && isset( $_GET['invoice-id'] ) ) {
1689
            $invoice_id     = (int)$_GET['invoice-id'];
1690
            $user_can_view  = $invoice_key == wpinv_get_payment_key( (int)$_GET['invoice-id'] ) ? true : false;
1691
        }
1692
        
1693
        if ( $invoice_id && $user_can_view && ( $invoice = wpinv_get_invoice( $invoice_id ) ) ) {
1694
            if ( $invoice->needs_payment() ) {
1695
                $data                   = array();
1696
                $data['invoice_id']     = $invoice_id;
1697
                $data['cart_discounts'] = $invoice->get_discounts( true );
1698
                
1699
                wpinv_set_checkout_session( $data );
1700
                
1701
                if ( wpinv_get_option( 'vat_ip_country_default' ) ) {
1702
                    $_POST['country']   = $wpinv_euvat->get_country_by_ip();
1703
                    $_POST['state']     = $_POST['country'] == $invoice->country ? $invoice->state : '';
1704
                    
1705
                    wpinv_recalculate_tax( true );
1706
                }
1707
                
1708
            } else {
1709
                $checkout_uri = $invoice->get_view_url();
1710
            }
1711
        } else {
1712
            wpinv_set_error( 'invalid_invoice', __( 'You are not allowed to view this invoice', 'invoicing' ) );
1713
            
1714
            $checkout_uri = is_user_logged_in() ? wpinv_get_history_page_uri() : wp_login_url( get_permalink() );
1715
        }
1716
        
1717
        wp_redirect( $checkout_uri );
1718
        wpinv_die();
1719
    }
1720
}
1721
add_action( 'wpinv_pay_for_invoice', 'wpinv_pay_for_invoice' );
1722
1723
function wpinv_handle_pay_via_invoice_link( $invoice_key ) {
1724
    if ( !empty( $invoice_key ) && !empty( $_REQUEST['_wpipay'] ) && !is_user_logged_in() && $invoice_id = wpinv_get_invoice_id_by_key( $invoice_key ) ) {
1725
        if ( $invoice = wpinv_get_invoice( $invoice_id ) ) {
1726
            $user_id = $invoice->get_user_id();
1727
            $secret = sanitize_text_field( $_GET['_wpipay'] );
1728
            
1729 View Code Duplication
            if ( $secret === md5( $user_id . '::' . $invoice->get_email() . '::' . $invoice_key ) ) { // valid invoice link
1730
                $redirect_to = remove_query_arg( '_wpipay', get_permalink() );
1731
                
1732
                wpinv_guest_redirect( $redirect_to, $user_id );
1733
                wpinv_die();
1734
            }
1735
        }
1736
    }
1737
}
1738
add_action( 'wpinv_check_pay_for_invoice', 'wpinv_handle_pay_via_invoice_link' );
1739
1740
function wpinv_set_payment_transaction_id( $invoice_id = 0, $transaction_id = '' ) {
1741
    $invoice_id = is_object( $invoice_id ) && !empty( $invoice_id->ID ) ? $invoice_id : $invoice_id;
1742
    
1743
    if ( empty( $invoice_id ) && $invoice_id > 0 ) {
1744
        return false;
1745
    }
1746
    
1747
    if ( empty( $transaction_id ) ) {
1748
        $transaction_id = $invoice_id;
1749
    }
1750
1751
    $transaction_id = apply_filters( 'wpinv_set_payment_transaction_id', $transaction_id, $invoice_id );
1752
    
1753
    return wpinv_update_invoice_meta( $invoice_id, '_wpinv_transaction_id', $transaction_id );
1754
}
1755
1756
function wpinv_invoice_status_label( $status, $status_display = '' ) {
1757
    if ( empty( $status_display ) ) {
1758
        $status_display = wpinv_status_nicename( $status );
1759
    }
1760
    
1761
    switch ( $status ) {
1762
        case 'publish' :
1763
        case 'wpi-renewal' :
1764
            $class = 'label-success';
1765
        break;
1766
        case 'pending' :
1767
            $class = 'label-primary';
1768
        break;
1769
        case 'wpi-processing' :
1770
            $class = 'label-warning';
1771
        break;
1772
        case 'wpi-onhold' :
1773
            $class = 'label-info';
1774
        break;
1775
        case 'wpi-cancelled' :
1776
        case 'wpi-failed' :
1777
            $class = 'label-danger';
1778
        break;
1779
        default:
1780
            $class = 'label-default';
1781
        break;
1782
    }
1783
    
1784
    $label = '<span class="label label-inv-' . $status . ' ' . $class . '">' . $status_display . '</span>';
1785
    
1786
    return apply_filters( 'wpinv_invoice_status_label', $label, $status, $status_display );
1787
}
1788
1789
function wpinv_format_invoice_number( $number ) {
1790
    $padd  = wpinv_get_option( 'invoice_number_padd' );
1791
    
1792
    // TODO maintain old invoice numbers if invoice number settings not saved. Should be removed before stable release.
1793
    if ( $padd === '' || $padd === false || $padd === NULL ) {
1794
        return wp_sprintf( __( 'WPINV-%d', 'invoicing' ), $number );
1795
    }
1796
    
1797
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
1798
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
1799
    
1800
    $padd = absint( $padd );
1801
    $formatted_number = absint( $number );
1802
    
1803
    if ( $padd > 0 ) {
1804
        $formatted_number = zeroise( $formatted_number, $padd );
1805
    }    
1806
1807
    $formatted_number = $prefix . $formatted_number . $postfix;
1808
1809
    return apply_filters( 'wpinv_format_invoice_number', $formatted_number, $number, $prefix, $postfix, $padd );
1810
}
1811
1812
function wpinv_get_next_invoice_number() {
1813
    if ( ! wpinv_get_option( 'sequential_invoice_number' ) ) {
1814
        return false;
1815
    }
1816
1817
    $number           = get_option( 'wpinv_last_invoice_number' );
1818
    $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...
1819
    $increment_number = true;
1820
1821
    if ( false !== $number ) {
1822
        if ( empty( $number ) ) {
1823
            $number = $start;
1824
            $increment_number = false;
1825
        }
1826
    } else {
1827
        $last_invoice = wpinv_get_invoices( array( 'limit' => 1, 'order' => 'DESC', 'orderby' => 'ID', 'return' => 'posts', 'fields' => 'ids', 'status' => 'any' ) );
1828
1829
        if ( ! empty( $last_invoice[0] ) ) {
1830
            $number = wpinv_get_invoice_number( $last_invoice[0] );
1831
        }
1832
1833
        if ( ! empty( $number ) && ! empty( $last_invoice[0] ) && $number !== (int) $last_invoice[0] ) {
1834
            $number = wpinv_clean_invoice_number( $number );
1835
        } else {
1836
            $number = $start;
1837
            $increment_number = false;
1838
        }
1839
    }
1840
1841
    $increment_number = apply_filters( 'wpinv_increment_payment_number', $increment_number, $number );
1842
1843
    if ( $increment_number ) {
1844
        $number++;
1845
    }
1846
1847
    return apply_filters( 'wpinv_get_next_invoice_number', $number );
1848
}
1849
1850
function wpinv_clean_invoice_number( $number ) {
1851
    $prefix  = wpinv_get_option( 'invoice_number_prefix' );
1852
    $postfix = wpinv_get_option( 'invoice_number_postfix' );
1853
1854
    $number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1855
1856
    $length      = strlen( $number );
1857
    $postfix_pos = strrpos( $number, $postfix );
1858
    
1859
    if ( false !== $postfix_pos ) {
1860
        $number      = substr_replace( $number, '', $postfix_pos, $length );
1861
    }
1862
1863
    $number = intval( $number );
1864
1865
    return apply_filters( 'wpinv_clean_invoice_number', $number, $prefix, $postfix );
1866
}
1867
1868
function wpinv_save_number_post_saved( $post_ID, $post, $update ) {
1869
    global $wpdb;
1870
1871
    if ( !$update && !get_post_meta( $post_ID, '_wpinv_number', true ) ) {
1872
        wpinv_update_invoice_number( $post_ID, $post->post_status != 'auto-draft' );
1873
    }
1874
1875
    if ( !$update ) {
1876
        $wpdb->update( $wpdb->posts, array( 'post_name' => 'inv-' . $post_ID ), array( 'ID' => $post_ID ) );
1877
        clean_post_cache( $post_ID );
1878
    }
1879
}
1880
add_action( 'save_post_wpi_invoice', 'wpinv_save_number_post_saved', 1, 3 );
1881
1882
function wpinv_save_number_post_updated( $post_ID, $post_after, $post_before ) {
1883
    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 ) {
1884
        wpinv_update_invoice_number( $post_ID, true );
1885
    }
1886
}
1887
add_action( 'post_updated', 'wpinv_save_number_post_updated', 1, 3 );
1888
1889
function wpinv_update_invoice_number( $post_ID, $save_sequential = false ) {
1890
    global $wpdb;
1891
1892
    if ( wpinv_get_option( 'sequential_invoice_number' ) ) {
1893
        $number = wpinv_get_next_invoice_number();
1894
1895
        if ( $save_sequential ) {
1896
            update_option( 'wpinv_last_invoice_number', $number );
1897
        }
1898
    } else {
1899
        $number = $post_ID;
1900
    }
1901
1902
    $number = wpinv_format_invoice_number( $number );
1903
1904
    update_post_meta( $post_ID, '_wpinv_number', $number );
1905
1906
    $wpdb->update( $wpdb->posts, array( 'post_title' => $number ), array( 'ID' => $post_ID ) );
1907
1908
    clean_post_cache( $post_ID );
1909
1910
    return $number;
1911
}