Passed
Push — master ( 555ee7...c90a51 )
by Brian
09:54 queued 04:19
created

WPInv_Ajax::payment_form()   F

Complexity

Conditions 41
Paths > 20000

Size

Total Lines 242
Code Lines 127

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 41
eloc 127
nc 122880
nop 0
dl 0
loc 242
rs 0
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
class WPInv_Ajax {
15
    public static function init() {
16
        add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 );
17
        add_action( 'template_redirect', array( __CLASS__, 'do_wpinv_ajax' ), 0 );
18
        self::add_ajax_events();
19
    }
20
21
    public static function define_ajax() {
22
        if ( !empty( $_GET['wpinv-ajax'] ) ) {
23
            if ( ! defined( 'DOING_AJAX' ) ) {
24
                define( 'DOING_AJAX', true );
25
            }
26
            if ( ! defined( 'WC_DOING_AJAX' ) ) {
27
                define( 'WC_DOING_AJAX', true );
28
            }
29
            // Turn off display_errors during AJAX events to prevent malformed JSON
30
            if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) {
31
                /** @scrutinizer ignore-unhandled */ @ini_set( 'display_errors', 0 );
32
            }
33
            $GLOBALS['wpdb']->hide_errors();
34
        }
35
    }
36
    
37
    public static function do_wpinv_ajax() {
38
        global $wp_query;
39
40
        if ( !empty( $_GET['wpinv-ajax'] ) ) {
41
            $wp_query->set( 'wpinv-ajax', sanitize_text_field( $_GET['wpinv-ajax'] ) );
42
        }
43
44
        if ( $action = $wp_query->get( 'wpinv-ajax' ) ) {
45
            self::wpinv_ajax_headers();
46
            do_action( 'wpinv_ajax_' . sanitize_text_field( $action ) );
47
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
48
        }
49
    }
50
    
51
    private static function wpinv_ajax_headers() {
52
        send_origin_headers();
53
        /** @scrutinizer ignore-unhandled */ @header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
54
        /** @scrutinizer ignore-unhandled */ @header( 'X-Robots-Tag: noindex' );
55
        send_nosniff_header();
56
        nocache_headers();
57
        status_header( 200 );
58
    }
59
    
60
    public static function add_ajax_events() {
61
        $ajax_events = array(
62
            'add_note' => false,
63
            'delete_note' => false,
64
            'get_states_field' => true,
65
            'checkout' => false,
66
            'payment_form_get_taxes' => true,
67
            'payment_form'     => true,
68
            'get_payment_form' => true,
69
            'get_payment_form_states_field' => true,
70
            'add_invoice_item' => false,
71
            'remove_invoice_item' => false,
72
            'create_invoice_item' => false,
73
            'get_billing_details' => false,
74
            'admin_recalculate_totals' => false,
75
            'admin_apply_discount' => false,
76
            'admin_remove_discount' => false,
77
            'check_email' => false,
78
            'run_tool' => false,
79
            'apply_discount' => true,
80
            'remove_discount' => true,
81
            'buy_items' => true,
82
        );
83
84
        foreach ( $ajax_events as $ajax_event => $nopriv ) {
85
            add_action( 'wp_ajax_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
86
            
87
            if ( !defined( 'WPI_AJAX_' . strtoupper( $nopriv ) ) ) {
88
                define( 'WPI_AJAX_' . strtoupper( $nopriv ), 1 );
89
            }
90
91
            if ( $nopriv ) {
92
                add_action( 'wp_ajax_nopriv_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
93
94
                add_action( 'wpinv_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
95
            }
96
        }
97
    }
98
    
99
    public static function add_note() {
100
        check_ajax_referer( 'add-invoice-note', '_nonce' );
101
102
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
103
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
104
        }
105
106
        $post_id   = absint( $_POST['post_id'] );
107
        $note      = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
108
        $note_type = sanitize_text_field( $_POST['note_type'] );
109
110
        $is_customer_note = $note_type == 'customer' ? 1 : 0;
111
112
        if ( $post_id > 0 ) {
113
            $note_id = wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
114
115
            if ( $note_id > 0 && !is_wp_error( $note_id ) ) {
116
                wpinv_get_invoice_note_line_item( $note_id );
117
            }
118
        }
119
120
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
121
    }
122
123
    public static function delete_note() {
124
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
125
126
        if ( !wpinv_current_user_can_manage_invoicing() ) {
127
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
128
        }
129
130
        $note_id = (int)$_POST['note_id'];
131
132
        if ( $note_id > 0 ) {
133
            wp_delete_comment( $note_id, true );
134
        }
135
136
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
137
    }
138
    
139
    public static function get_states_field() {
140
        echo wpinv_get_states_field();
141
        
142
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
143
    }
144
    
145
    public static function checkout() {
146
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
147
            define( 'WPINV_CHECKOUT', true );
148
        }
149
150
        wpinv_process_checkout();
151
        die(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
152
    }
153
    
154
    public static function add_invoice_item() {
155
        global $wpi_userID, $wpinv_ip_address_country;
156
        check_ajax_referer( 'invoice-item', '_nonce' );
157
        if ( !wpinv_current_user_can_manage_invoicing() ) {
158
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
159
        }
160
        
161
        $item_id    = sanitize_text_field( $_POST['item_id'] );
162
        $invoice_id = absint( $_POST['invoice_id'] );
163
        
164
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
165
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
166
        }
167
        
168
        $invoice    = wpinv_get_invoice( $invoice_id );
169
        if ( empty( $invoice ) ) {
170
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
171
        }
172
        
173
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
174
            die(); // Don't allow modify items for paid invoice.
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
175
        }
176
        
177
        if ( !empty( $_POST['user_id'] ) ) {
178
            $wpi_userID = absint( $_POST['user_id'] ); 
179
        }
180
181
        $item = new WPInv_Item( $item_id );
182
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
183
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
184
        }
185
        
186
        // Validate item before adding to invoice because recurring item must be paid individually.
187
        if ( !empty( $invoice->cart_details ) ) {
188
            $valid = true;
189
            
190
            if ( $recurring_item = $invoice->get_recurring() ) {
191
                if ( $recurring_item != $item_id ) {
192
                    $valid = false;
193
                }
194
            } else if ( wpinv_is_recurring_item( $item_id ) ) {
195
                $valid = false;
196
            }
197
            
198
            if ( !$valid ) {
199
                $response               = array();
200
                $response['success']    = false;
201
                $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
202
                wp_send_json( $response );
203
            }
204
        }
205
        
206
        $checkout_session = wpinv_get_checkout_session();
207
        
208
        $data                   = array();
209
        $data['invoice_id']     = $invoice_id;
210
        $data['cart_discounts'] = $invoice->get_discounts( true );
211
        
212
        wpinv_set_checkout_session( $data );
213
        
214
        $quantity = wpinv_item_quantities_enabled() && !empty($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : 1;
215
216
        $args = array(
217
            'id'            => $item_id,
218
            'quantity'      => $quantity,
219
            'item_price'    => $item->get_price(),
220
            'custom_price'  => '',
221
            'tax'           => 0.00,
222
            'discount'      => 0,
223
            'meta'          => array(),
224
            'fees'          => array()
225
        );
226
227
        $invoice->add_item( $item_id, $args );
228
        $invoice->save();
229
        
230
        if ( empty( $_POST['country'] ) ) {
231
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
232
        }
233
        if ( empty( $_POST['state'] ) ) {
234
            $_POST['state'] = $invoice->state;
235
        }
236
         
237
        $invoice->country   = sanitize_text_field( $_POST['country'] );
238
        $invoice->state     = sanitize_text_field( $_POST['state'] );
239
        
240
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
241
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
242
        
243
        $wpinv_ip_address_country = $invoice->country;
244
245
        $invoice->recalculate_totals(true);
246
        
247
        $response                       = array();
248
        $response['success']            = true;
249
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
250
        $response['data']['subtotal']   = $invoice->get_subtotal();
251
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
252
        $response['data']['tax']        = $invoice->get_tax();
253
        $response['data']['taxf']       = $invoice->get_tax(true);
254
        $response['data']['discount']   = $invoice->get_discount();
255
        $response['data']['discountf']  = $invoice->get_discount(true);
256
        $response['data']['total']      = $invoice->get_total();
257
        $response['data']['totalf']     = $invoice->get_total(true);
258
        
259
        wpinv_set_checkout_session($checkout_session);
260
        
261
        wp_send_json( $response );
262
    }
263
264
265
    public static function remove_invoice_item() {
266
        global $wpi_userID, $wpinv_ip_address_country;
267
        
268
        check_ajax_referer( 'invoice-item', '_nonce' );
269
        if ( !wpinv_current_user_can_manage_invoicing() ) {
270
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
271
        }
272
        
273
        $item_id    = sanitize_text_field( $_POST['item_id'] );
274
        $invoice_id = absint( $_POST['invoice_id'] );
275
        $cart_index = isset( $_POST['index'] ) && $_POST['index'] >= 0 ? $_POST['index'] : false;
276
        
277
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
278
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
279
        }
280
281
        $invoice    = wpinv_get_invoice( $invoice_id );
282
        if ( empty( $invoice ) ) {
283
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
284
        }
285
        
286
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
287
            die(); // Don't allow modify items for paid invoice.
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
288
        }
289
        
290
        if ( !empty( $_POST['user_id'] ) ) {
291
            $wpi_userID = absint( $_POST['user_id'] ); 
292
        }
293
294
        $item       = new WPInv_Item( $item_id );
295
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
296
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
297
        }
298
        
299
        $checkout_session = wpinv_get_checkout_session();
300
        
301
        $data                   = array();
302
        $data['invoice_id']     = $invoice_id;
303
        $data['cart_discounts'] = $invoice->get_discounts( true );
304
        
305
        wpinv_set_checkout_session( $data );
306
307
        $args = array(
308
            'id'         => $item_id,
309
            'quantity'   => 1,
310
            'cart_index' => $cart_index
311
        );
312
313
        $invoice->remove_item( $item_id, $args );
314
        $invoice->save();
315
        
316
        if ( empty( $_POST['country'] ) ) {
317
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
318
        }
319
        if ( empty( $_POST['state'] ) ) {
320
            $_POST['state'] = $invoice->state;
321
        }
322
         
323
        $invoice->country   = sanitize_text_field( $_POST['country'] );
324
        $invoice->state     = sanitize_text_field( $_POST['state'] );
325
        
326
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
327
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
328
        
329
        $wpinv_ip_address_country = $invoice->country;
330
        
331
        $invoice->recalculate_totals(true);
332
        
333
        $response                       = array();
334
        $response['success']            = true;
335
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
336
        $response['data']['subtotal']   = $invoice->get_subtotal();
337
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
338
        $response['data']['tax']        = $invoice->get_tax();
339
        $response['data']['taxf']       = $invoice->get_tax(true);
340
        $response['data']['discount']   = $invoice->get_discount();
341
        $response['data']['discountf']  = $invoice->get_discount(true);
342
        $response['data']['total']      = $invoice->get_total();
343
        $response['data']['totalf']     = $invoice->get_total(true);
344
        
345
        wpinv_set_checkout_session($checkout_session);
346
        
347
        wp_send_json( $response );
348
    }
349
    
350
    public static function create_invoice_item() {
351
        check_ajax_referer( 'invoice-item', '_nonce' );
352
        if ( !wpinv_current_user_can_manage_invoicing() ) {
353
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
354
        }
355
        
356
        $invoice_id = absint( $_POST['invoice_id'] );
357
358
        // Find the item
359
        if ( !is_numeric( $invoice_id ) ) {
360
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
361
        }        
362
        
363
        $invoice     = wpinv_get_invoice( $invoice_id );
364
        if ( empty( $invoice ) ) {
365
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
366
        }
367
        
368
        // Validate item before adding to invoice because recurring item must be paid individually.
369
        if ( !empty( $invoice->cart_details ) && $invoice->get_recurring() ) {
370
            $response               = array();
371
            $response['success']    = false;
372
            $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
373
            wp_send_json( $response );
374
        }        
375
        
376
        $save_item = wp_unslash( $_POST['_wpinv_quick'] );
377
        
378
        $meta               = array();
379
        $meta['type']       = !empty($save_item['type']) ? sanitize_text_field($save_item['type']) : 'custom';
380
        $meta['price']      = !empty($save_item['price']) ? wpinv_sanitize_amount( $save_item['price'] ) : 0;
381
        $meta['vat_rule']   = !empty($save_item['vat_rule']) ? sanitize_text_field($save_item['vat_rule']) : 'digital';
382
        $meta['vat_class']  = !empty($save_item['vat_class']) ? sanitize_text_field($save_item['vat_class']) : '_standard';
383
        
384
        $data                   = array();
385
        $data['post_title']     = sanitize_text_field($save_item['name']);
386
        $data['post_status']    = 'publish';
387
        $data['post_excerpt']   = ! empty( $save_item['excerpt'] ) ? wp_kses_post( $save_item['excerpt'] ) : '';
388
        $data['meta']           = $meta;
389
        
390
        $item = new WPInv_Item();
391
        $item->create( $data );
392
        
393
        if ( !empty( $item ) ) {
394
            $_POST['item_id']   = $item->ID;
395
            $_POST['qty']       = !empty($save_item['qty']) && $save_item['qty'] > 0 ? (int)$save_item['qty'] : 1;
396
            
397
            self::add_invoice_item();
398
        }
399
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
400
    }
401
    
402
    public static function get_billing_details() {
403
        check_ajax_referer( 'get-billing-details', '_nonce' );
404
        
405
        if ( !wpinv_current_user_can_manage_invoicing() ) {
406
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
407
        }
408
409
        $user_id            = (int)$_POST['user_id'];
410
        $billing_details    = wpinv_get_user_address($user_id);
411
        $billing_details    = apply_filters( 'wpinv_fill_billing_details', $billing_details, $user_id );
412
        
413
        if (isset($billing_details['user_id'])) {
414
            unset($billing_details['user_id']);
415
        }
416
        
417
        if (isset($billing_details['email'])) {
418
            unset($billing_details['email']);
419
        }
420
421
        $response                               = array();
422
        $response['success']                    = true;
423
        $response['data']['billing_details']    = $billing_details;
424
        
425
        wp_send_json( $response );
426
    }
427
    
428
    public static function admin_recalculate_totals() {
429
        global $wpi_userID, $wpinv_ip_address_country;
430
        
431
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
432
        if ( !wpinv_current_user_can_manage_invoicing() ) {
433
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
434
        }
435
        
436
        $invoice_id = absint( $_POST['invoice_id'] );        
437
        $invoice    = wpinv_get_invoice( $invoice_id );
438
        if ( empty( $invoice ) ) {
439
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
440
        }
441
442
        $checkout_session = wpinv_get_checkout_session();
443
444
        $data                   = array();
445
        $data['invoice_id']     = $invoice_id;
446
        $data['cart_discounts'] = $invoice->get_discounts( true );
447
448
        wpinv_set_checkout_session( $data );
449
        
450
        if ( !empty( $_POST['user_id'] ) ) {
451
            $wpi_userID = absint( $_POST['user_id'] ); 
452
        }
453
        
454
        if ( empty( $_POST['country'] ) ) {
455
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
456
        }
457
458
        $disable_taxes = 0;
459
        if ( ! empty( $_POST['disable_taxes'] ) ) {
460
            $disable_taxes = 1;
461
        }
462
        $invoice->set( 'disable_taxes', $disable_taxes );
463
464
        $invoice->country = sanitize_text_field( $_POST['country'] );
465
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
466
        if ( isset( $_POST['state'] ) ) {
467
            $invoice->state = sanitize_text_field( $_POST['state'] );
468
            $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
469
        }
470
        
471
        $wpinv_ip_address_country = $invoice->country;
472
        
473
        $invoice = $invoice->recalculate_totals(true);
474
        
475
        $response                       = array();
476
        $response['success']            = true;
477
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
478
        $response['data']['subtotal']   = $invoice->get_subtotal();
479
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
480
        $response['data']['tax']        = $invoice->get_tax();
481
        $response['data']['taxf']       = $invoice->get_tax(true);
482
        $response['data']['discount']   = $invoice->get_discount();
483
        $response['data']['discountf']  = $invoice->get_discount(true);
484
        $response['data']['total']      = $invoice->get_total();
485
        $response['data']['totalf']     = $invoice->get_total(true);
486
        
487
        wpinv_set_checkout_session($checkout_session);
488
489
        wp_send_json( $response );
490
    }
491
    
492
    public static function admin_apply_discount() {
493
        global $wpi_userID;
494
        
495
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
496
        if ( !wpinv_current_user_can_manage_invoicing() ) {
497
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
498
        }
499
        
500
        $invoice_id = absint( $_POST['invoice_id'] );
501
        $discount_code = sanitize_text_field( $_POST['code'] );
502
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
503
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
504
        }
505
        
506
        $invoice = wpinv_get_invoice( $invoice_id );
507
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
508
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
509
        }
510
        
511
        $checkout_session = wpinv_get_checkout_session();
512
        
513
        $data                   = array();
514
        $data['invoice_id']     = $invoice_id;
515
        $data['cart_discounts'] = $invoice->get_discounts( true );
516
        
517
        wpinv_set_checkout_session( $data );
518
        
519
        $response               = array();
520
        $response['success']    = false;
521
        $response['msg']        = __( 'This discount is invalid.', 'invoicing' );
522
        $response['data']['code'] = $discount_code;
523
        
524
        if ( wpinv_is_discount_valid( $discount_code, $invoice->get_user_id() ) ) {
525
            $discounts = wpinv_set_cart_discount( $discount_code );
0 ignored issues
show
Unused Code introduced by
The assignment to $discounts is dead and can be removed.
Loading history...
526
            
527
            $response['success'] = true;
528
            $response['msg'] = __( 'Discount has been applied successfully.', 'invoicing' );
529
        }  else {
530
            $errors = wpinv_get_errors();
531
            if ( !empty( $errors['wpinv-discount-error'] ) ) {
532
                $response['msg'] = $errors['wpinv-discount-error'];
533
            }
534
            wpinv_unset_error( 'wpinv-discount-error' );
535
        }
536
        
537
        wpinv_set_checkout_session($checkout_session);
538
        
539
        wp_send_json( $response );
540
    }
541
    
542
    public static function admin_remove_discount() {
543
        global $wpi_userID;
544
        
545
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
546
        if ( !wpinv_current_user_can_manage_invoicing() ) {
547
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
548
        }
549
        
550
        $invoice_id = absint( $_POST['invoice_id'] );
551
        $discount_code = sanitize_text_field( $_POST['code'] );
552
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
553
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
554
        }
555
        
556
        $invoice = wpinv_get_invoice( $invoice_id );
557
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
558
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
559
        }
560
        
561
        $checkout_session = wpinv_get_checkout_session();
562
        
563
        $data                   = array();
564
        $data['invoice_id']     = $invoice_id;
565
        $data['cart_discounts'] = $invoice->get_discounts( true );
566
        
567
        wpinv_set_checkout_session( $data );
568
        
569
        $response               = array();
570
        $response['success']    = false;
571
        $response['msg']        = NULL;
572
        
573
        $discounts  = wpinv_unset_cart_discount( $discount_code );
0 ignored issues
show
Unused Code introduced by
The assignment to $discounts is dead and can be removed.
Loading history...
574
        $response['success'] = true;
575
        $response['msg'] = __( 'Discount has been removed successfully.', 'invoicing' );
576
        
577
        wpinv_set_checkout_session($checkout_session);
578
        
579
        wp_send_json( $response );
580
    }
581
    
582
    public static function check_email() {
583
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
584
        if ( !wpinv_current_user_can_manage_invoicing() ) {
585
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
586
        }
587
        
588
        $email = sanitize_text_field( $_POST['email'] );
589
        
590
        $response = array();
591
        if ( is_email( $email ) && email_exists( $email ) && $user_data = get_user_by( 'email', $email ) ) {
592
            $user_id            = $user_data->ID;
593
            $user_login         = $user_data->user_login;
594
            $display_name       = $user_data->display_name ? $user_data->display_name : $user_login;
0 ignored issues
show
Unused Code introduced by
The assignment to $display_name is dead and can be removed.
Loading history...
595
            $billing_details    = wpinv_get_user_address($user_id);
596
            $billing_details    = apply_filters( 'wpinv_fill_billing_details', $billing_details, $user_id );
597
            
598
            if (isset($billing_details['user_id'])) {
599
                unset($billing_details['user_id']);
600
            }
601
            
602
            if (isset($billing_details['email'])) {
603
                unset($billing_details['email']);
604
            }
605
            
606
            $response['success']                    = true;
607
            $response['data']['id']                 = $user_data->ID;
608
            $response['data']['name']               = $user_data->user_email;
609
            $response['data']['billing_details']    = $billing_details;
610
        }
611
        
612
        wp_send_json( $response );
613
    }
614
    
615
    public static function run_tool() {
616
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
617
        if ( !wpinv_current_user_can_manage_invoicing() ) {
618
            die(-1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
619
        }
620
        
621
        $tool = sanitize_text_field( $_POST['tool'] );
622
        
623
        do_action( 'wpinv_run_tool' );
624
        
625
        if ( !empty( $tool ) ) {
626
            do_action( 'wpinv_tool_' . $tool );
627
        }
628
    }
629
    
630
    public static function apply_discount() {
631
        global $wpi_userID;
632
        
633
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
634
        
635
        $response = array();
636
        
637
        if ( isset( $_POST['code'] ) ) {
638
            $discount_code = sanitize_text_field( $_POST['code'] );
639
640
            $response['success']        = false;
641
            $response['msg']            = '';
642
            $response['data']['code']   = $discount_code;
643
            
644
            $invoice = wpinv_get_invoice_cart();
645
            if ( empty( $invoice->ID ) ) {
646
                $response['msg'] = __( 'Invalid checkout request.', 'invoicing' );
647
                wp_send_json( $response );
648
            }
649
650
            $wpi_userID = $invoice->get_user_id();
651
652
            if ( wpinv_is_discount_valid( $discount_code, $wpi_userID ) ) {
653
                $discount       = wpinv_get_discount_by_code( $discount_code );
654
                $discounts      = wpinv_set_cart_discount( $discount_code );
655
                $amount         = wpinv_format_discount_rate( wpinv_get_discount_type( $discount->ID ), wpinv_get_discount_amount( $discount->ID ) );
0 ignored issues
show
Unused Code introduced by
The assignment to $amount is dead and can be removed.
Loading history...
656
                $total          = wpinv_get_cart_total( null, $discounts );
0 ignored issues
show
Unused Code introduced by
The assignment to $total is dead and can be removed.
Loading history...
657
                $cart_totals    = wpinv_recalculate_tax( true );
658
            
659
                if ( !empty( $cart_totals ) ) {
660
                    $response['success']        = true;
661
                    $response['data']           = $cart_totals;
662
                    $response['data']['code']   = $discount_code;
663
                } else {
664
                    $response['success']        = false;
665
                }
666
            } else {
667
                $errors = wpinv_get_errors();
668
                $response['msg']  = $errors['wpinv-discount-error'];
669
                wpinv_unset_error( 'wpinv-discount-error' );
670
            }
671
672
            // Allow for custom discount code handling
673
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
674
        }
675
        
676
        wp_send_json( $response );
677
    }
678
    
679
    public static function remove_discount() {
680
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
681
        
682
        $response = array();
683
        
684
        if ( isset( $_POST['code'] ) ) {
685
            $discount_code  = sanitize_text_field( $_POST['code'] );
686
            $discounts      = wpinv_unset_cart_discount( $discount_code );
687
            $total          = wpinv_get_cart_total( null, $discounts );
0 ignored issues
show
Unused Code introduced by
The assignment to $total is dead and can be removed.
Loading history...
688
            $cart_totals    = wpinv_recalculate_tax( true );
689
            
690
            if ( !empty( $cart_totals ) ) {
691
                $response['success']        = true;
692
                $response['data']           = $cart_totals;
693
                $response['data']['code']   = $discount_code;
694
            } else {
695
                $response['success']        = false;
696
            }
697
            
698
            // Allow for custom discount code handling
699
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
700
        }
701
        
702
        wp_send_json( $response );
703
    }
704
705
    /**
706
     * Retrieves the markup for a payment form.
707
     */
708
    public static function get_payment_form() {
709
710
        // Check nonce.
711
        if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'], 'getpaid_ajax_form' ) ) {
712
            _e( 'Error: Reload the page and try again.', 'invoicing' );
713
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
714
        }
715
716
        // Is the request set up correctly?
717
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) ) {
718
			echo aui()->alert(
0 ignored issues
show
Bug introduced by
The function aui was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

718
			echo /** @scrutinizer ignore-call */ aui()->alert(
Loading history...
719
				array(
720
					'type'    => 'warning',
721
					'content' => __( 'No payment form or item provided', 'invoicing' ),
722
				)
723
            );
724
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
725
        }
726
727
        // Payment form or button?
728
		if ( ! empty( $_GET['form'] ) ) {
729
            echo getpaid_display_payment_form( $_GET['form'] );
730
		} else if( $_GET['invoice'] ) {
731
		    echo getpaid_display_invoice_payment_form( $_GET['invoice'] );
732
        } else {
733
			$items = getpaid_convert_items_to_array( $_GET['item'] );
734
		    echo getpaid_display_item_payment_form( $items );
735
        }
736
        
737
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
738
739
    }
740
741
    /**
742
     * Payment forms.
743
     *
744
     * @since 1.0.18
745
     */
746
    public static function payment_form() {
747
        global $invoicing, $wpi_checkout_id, $cart_total;
748
749
        // Check nonce.
750
        if ( ! isset( $_POST['wpinv_payment_form'] ) || ! wp_verify_nonce( $_POST['wpinv_payment_form'], 'wpinv_payment_form' ) ) {
751
            wp_send_json_error( __( 'Security checks failed.', 'invoicing' ) );
752
        }
753
754
        // Prepare submitted data...
755
        $data = wp_unslash( $_POST );
756
757
        // ... form fields...
758
        if ( empty( $data['form_id'] ) || 'publish' != get_post_status( $data['form_id'] ) ) {
759
            wp_send_json_error( __( 'This payment form is no longer active.', 'invoicing' ) );
760
        }
761
762
        if ( empty( $data['billing_email'] ) || ! is_email( $data['billing_email'] ) ) {
763
            wp_send_json_error( __( 'Provide a valid billing email.', 'invoicing' ) );
764
        }
765
766
        $prepared = array(
767
            'billing_email'                    => sanitize_email( $data['billing_email'] ),
768
            __( 'Billing Email', 'invoicing' ) => sanitize_email( $data['billing_email'] ),
769
            __( 'Form Id', 'invoicing' )       => absint( $data['form_id'] ),
770
        );
771
772
        $prepared['billing_email'] = sanitize_email( $data['billing_email'] );
773
774
        $fields = $invoicing->form_elements->get_form_elements( $data['form_id'] );
775
776
        // ... and form items.
777
        if ( ! empty( $data['invoice_id'] ) ) {
778
            $invoice = wpinv_get_invoice( $data['invoice_id'] );
779
780
            if ( empty( $invoice ) ) {
781
                wp_send_json_error( __( 'Invalid invoice.', 'invoicing' ) );
782
            }
783
784
            if ( $invoice->is_paid() ) {
785
                wp_send_json_error( __( 'This invoice has already been paid.', 'invoicing' ) );
786
            }
787
788
            $items   = $invoicing->form_elements->convert_checkout_items( $invoice->cart_details, $invoice );
789
790
        } else {
791
792
            if ( isset( $data['form_items'] ) ) {
793
                $items = getpaid_convert_items_to_array( $data['form_items'] );
794
                $items = $invoicing->form_elements->convert_normal_items( $items );
795
            } else {
796
                $items = $invoicing->form_elements->get_form_items( $data['form_id'] );
797
            }
798
799
            $invoice = 0;
800
        }
801
802
        $prepared_items = array();
803
        $address_fields = array();
804
805
        if ( ! empty( $data['wpinv-items'] ) ) {
806
807
            $selected_items = wpinv_clean( $data['wpinv-items'] );
808
809
            foreach ( $items as $item ) {
810
811
                if ( ! empty( $item['required'] ) && ! isset( $selected_items[ $item['id'] ] ) ) {
812
                    wp_send_json_error( __( 'A required item is missing.', 'invoicing' ) );
813
                }
814
815
                if ( ! isset( $selected_items[ $item['id'] ] ) ) {
816
                    continue;
817
                }
818
819
                $quantity = empty( $item['quantity'] ) ? 1 : absint( $item['quantity'] );
820
821
                if ( ! empty( $item['allow_quantities'] ) && ! empty( $data["wpinv-item-{$item['id']}-quantity"] ) ) {
822
823
                    $_quantity = intval( $data["wpinv-item-{$item['id']}-quantity"] );
824
825
                    if ( ! empty( $_quantity ) ) {
826
                        $quantity = $_quantity;
827
                    }
828
                }
829
830
                // Custom pricing.
831
                if ( ! empty( $item['custom_price'] ) ) {
832
833
                    $minimum_price = wpinv_sanitize_amount( $item['minimum_price'] );
834
                    $set_price     = wpinv_sanitize_amount( $selected_items[ $item['id'] ] );
835
836
                    if ( $set_price < $minimum_price ) {
837
                        wp_send_json_error( __( 'The provided amount is less than the minimum allowed value.', 'invoicing' ) );
838
                    }
839
840
                    $prepared_items[] = array(
841
                        'id'           =>$item['id'],
842
                        'item_price'   => wpinv_sanitize_amount( $item['price'] ),
843
                        'custom_price' => $set_price,
844
                        'name'         => $item['title'],
845
                        'quantity'     => $quantity,
846
                    );
847
848
                } else {
849
850
                    $prepared_items[] = array(
851
                        'id'           => $item['id'],
852
                        'item_price'   => wpinv_sanitize_amount( $item['price'] ),
853
                        'custom_price' => wpinv_sanitize_amount( $item['price'] ),
854
                        'name'         => $item['title'],
855
                        'quantity'     => $quantity,
856
                    );
857
858
                }
859
860
            }
861
862
        } else {
863
864
            wp_send_json_error( __( 'You have not selected any items.', 'invoicing' ) );
865
866
        }
867
868
        // Are all required fields provided?
869
        foreach ( $fields as $field ) {
870
871
            if ( ! empty( $field['premade'] ) ) {
872
                continue;
873
            }
874
875
            if ( ! empty( $field['required'] ) && empty( $data[ $field['id'] ] ) ) {
876
                wp_send_json_error( __( 'Some required fields have not been filled.', 'invoicing' ) );
877
            }
878
879
            if ( $field['type'] == 'address' ) {
880
881
                foreach ( $field['fields'] as $address_field ) {
882
883
                    if ( empty( $address_field['visible'] ) ) {
884
                        continue;
885
                    }
886
887
                    if ( ! empty( $address_field['required'] ) && empty( $data[ $address_field['name'] ] ) ) {
888
                        wp_send_json_error( __( 'Some required fields have not been filled.', 'invoicing' ) );
889
                    }
890
891
                    if ( isset( $data[ $address_field['name'] ] ) ) {
892
                        $label = str_replace( 'wpinv_', '', $address_field['name'] );
893
                        $address_fields[ $label ] = wpinv_clean( $data[ $address_field['name'] ] );
894
                    }
895
896
                }
897
898
            } else if ( isset( $data[ $field['id'] ] ) ) {
899
                $label = $field['id'];
900
901
                if ( isset( $field['label'] ) ) {
902
                    $label = $field['label'];
903
                }
904
905
                $prepared[ wpinv_clean( $label ) ] = wpinv_clean( $data[ $field['id'] ] );
906
            }
907
908
        }
909
910
        $user = get_user_by( 'email', $prepared['billing_email'] );
911
912
        if ( empty( $user ) ) {
913
            $user = wpinv_create_user( $prepared['billing_email'] );
914
        }
915
916
        if ( is_wp_error( $user ) ) {
917
            wp_send_json_error( $user->get_error_message() );
918
        }
919
920
        if ( is_numeric( $user ) ) {
921
            $user = get_user_by( 'id', $user );
922
        }
923
924
        // Create the invoice.
925
        if ( empty( $invoice ) ) {
926
927
            $invoice = wpinv_insert_invoice(
928
                array(
929
                    'status'        => 'wpi-pending',
930
                    'created_via'   => 'payment_form',
931
                    'user_id'       => $user->ID,
0 ignored issues
show
Bug introduced by
The property ID does not seem to exist on WP_Error.
Loading history...
932
                    'cart_details'  => $prepared_items,
933
                    'user_info'     => $address_fields,
934
                ),
935
                true
936
            );
937
938
        } else {
939
940
            $invoice = wpinv_update_invoice(
941
                array(
942
                    'ID'            => $invoice->ID,
943
                    'status'        => 'wpi-pending',
944
                    'cart_details'  => $prepared_items,
945
                    'user_info'     => $address_fields,
946
                ),
947
                true
948
            );
949
950
        }
951
        
952
953
        if ( is_wp_error( $invoice ) ) {
954
            wp_send_json_error( $invoice->get_error_message() );
0 ignored issues
show
Bug introduced by
The method get_error_message() does not exist on WPInv_Invoice. ( Ignorable by Annotation )

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

954
            wp_send_json_error( $invoice->/** @scrutinizer ignore-call */ get_error_message() );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
955
        }
956
957
        if ( empty( $invoice ) ) {
958
            wp_send_json_error( __( 'Could not create your invoice.', 'invoicing' ) );
959
        }
960
961
        unset( $prepared['billing_email'] );
962
        update_post_meta( $invoice->ID, 'payment_form_data', $prepared );
963
964
        $wpi_checkout_id = $invoice->ID;
965
        $cart_total = wpinv_price(
966
            wpinv_format_amount(
967
                wpinv_get_cart_total( $invoice->get_cart_details(), NULL, $invoice ) ),
0 ignored issues
show
Bug introduced by
The method get_cart_details() does not exist on WP_Error. ( Ignorable by Annotation )

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

967
                wpinv_get_cart_total( $invoice->/** @scrutinizer ignore-call */ get_cart_details(), NULL, $invoice ) ),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
968
                $invoice->get_currency()
0 ignored issues
show
Bug introduced by
The method get_currency() does not exist on WP_Error. ( Ignorable by Annotation )

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

968
                $invoice->/** @scrutinizer ignore-call */ 
969
                          get_currency()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
969
        );
970
971
        $data                   = array();
972
        $data['invoice_id']     = $invoice->ID;
973
        $data['cart_discounts'] = $invoice->get_discounts( true );
0 ignored issues
show
Bug introduced by
The method get_discounts() does not exist on WP_Error. ( Ignorable by Annotation )

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

973
        /** @scrutinizer ignore-call */ 
974
        $data['cart_discounts'] = $invoice->get_discounts( true );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
974
975
        wpinv_set_checkout_session( $data );
976
        add_filter( 'wp_redirect', array( $invoicing->form_elements, 'send_redirect_response' ) );
977
        add_action( 'wpinv_pre_send_back_to_checkout', array( $invoicing->form_elements, 'checkout_error' ) );
978
        
979
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
980
            define( 'WPINV_CHECKOUT', true );
981
        }
982
983
        wpinv_process_checkout();
984
985
        $invoicing->form_elements->checkout_error();
986
987
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
988
    }
989
990
    /**
991
     * Payment forms.
992
     *
993
     * @since 1.0.18
994
     */
995
    public static function get_payment_form_states_field() {
996
        global $invoicing;
997
998
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
999
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1000
        }
1001
1002
        $elements = $invoicing->form_elements->get_form_elements( $_GET['form'] );
1003
1004
        if ( empty( $elements ) ) {
1005
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1006
        }
1007
1008
        $address_fields = array();
1009
        foreach ( $elements as $element ) {
1010
            if ( 'address' === $element['type'] ) {
1011
                $address_fields = $element;
1012
                break;
1013
            }
1014
        }
1015
1016
        if ( empty( $address_fields ) ) {
1017
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1018
        }
1019
1020
        foreach( $address_fields['fields'] as $address_field ) {
1021
1022
            if ( 'wpinv_state' == $address_field['name'] ) {
1023
1024
                $label = $address_field['label'];
1025
1026
                if ( ! empty( $address_field['required'] ) ) {
1027
                    $label .= "<span class='text-danger'> *</span>";
1028
                }
1029
1030
                $states = wpinv_get_country_states( $_GET['country'] );
1031
1032
                if ( ! empty( $states ) ) {
1033
1034
                    $html = aui()->select(
0 ignored issues
show
Bug introduced by
The function aui was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1034
                    $html = /** @scrutinizer ignore-call */ aui()->select(
Loading history...
1035
                            array(
1036
                                'options'          => $states,
1037
                                'name'             => esc_attr( $address_field['name'] ),
1038
                                'id'               => esc_attr( $address_field['name'] ),
1039
                                'placeholder'      => esc_attr( $address_field['placeholder'] ),
1040
                                'required'         => (bool) $address_field['required'],
1041
                                'no_wrap'          => true,
1042
                                'label'            => wp_kses_post( $label ),
1043
                                'select2'          => false,
1044
                            )
1045
                        );
1046
1047
                } else {
1048
1049
                    $html = aui()->input(
1050
                            array(
1051
                                'name'       => esc_attr( $address_field['name'] ),
1052
                                'id'         => esc_attr( $address_field['name'] ),
1053
                                'required'   => (bool) $address_field['required'],
1054
                                'label'      => wp_kses_post( $label ),
1055
                                'no_wrap'    => true,
1056
                                'type'       => 'text',
1057
                            )
1058
                        );
1059
1060
                }
1061
1062
                wp_send_json_success( str_replace( 'sr-only', '', $html ) );
1063
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1064
1065
            }
1066
1067
        }
1068
    
1069
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1070
    }
1071
1072
    /**
1073
     * Payment forms.
1074
     *
1075
     * @since 1.0.18
1076
     */
1077
    public static function payment_form_get_taxes() {
1078
        global $invoicing;
1079
1080
        // Check nonce.
1081
        check_ajax_referer( 'wpinv_payment_form', 'wpinv_payment_form' );
1082
1083
        // Prepare submitted data...
1084
        $data = wp_unslash( $_POST );
1085
1086
        // ... form fields...
1087
        if ( empty( $data['form_id'] ) || 'publish' != get_post_status( $data['form_id'] ) ) {
1088
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1089
        }
1090
1091
        // For existing invoices.
1092
        if ( ! empty( $data['invoice_id'] ) ) {
1093
            $invoice = wpinv_get_invoice( $data['invoice_id'] );
1094
1095
            if ( empty( $invoice ) ) {
1096
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1097
            }
1098
1099
            $items   = $invoicing->form_elements->convert_checkout_items( $invoice->cart_details, $invoice );
1100
            $country = $invoice->country;
1101
            $state   = $invoice->state;
1102
1103
        } else {
1104
1105
            if ( isset( $data['form_items'] ) ) {
1106
                $items = getpaid_convert_items_to_array( $data['form_items'] );
1107
                $items = $invoicing->form_elements->convert_normal_items( $items );
1108
            } else {
1109
                $items = $invoicing->form_elements->get_form_items( $data['form_id'] );
1110
            }
1111
1112
            $country   = wpinv_default_billing_country();
1113
            $state     = false;
1114
        }
1115
1116
        // What we will calculate.
1117
        $total     = 0;
1118
        $tax       = 0;
1119
        $sub_total = 0;
1120
1121
        if ( ! empty( $data['wpinv_country'] ) ) {
1122
            $country = $data['wpinv_country'];
1123
        }
1124
1125
        if ( ! empty( $data['wpinv_state'] ) ) {
1126
            $state = $data['wpinv_state'];
1127
        }
1128
1129
        if ( ! empty( $data['wpinv-items'] ) ) {
1130
1131
            $selected_items = wpinv_clean( $data['wpinv-items'] );
1132
1133
            foreach ( $items as $item ) {
1134
1135
                if ( ! isset( $selected_items[ $item['id'] ] ) ) {
1136
                    continue;
1137
                }
1138
1139
                $quantity = empty( $item['quantity'] ) ? 1 : absint( $item['quantity'] );
1140
1141
                if ( ! empty( $item['allow_quantities'] ) && ! empty( $data["wpinv-item-{$item['id']}-quantity"] ) ) {
1142
1143
                    $quantity = intval( $data["wpinv-item-{$item['id']}-quantity"] );
1144
1145
                    if ( 1 > $quantity ) {
1146
                        $quantity = 1;
1147
                    }
1148
1149
                }
1150
1151
                // Custom pricing.
1152
                $price = wpinv_sanitize_amount( $item['price'] );
1153
                if ( ! empty( $item['custom_price'] ) ) {
1154
1155
                    $minimum_price = wpinv_sanitize_amount( $item['minimum_price'] );
1156
                    $set_price     = wpinv_sanitize_amount( $selected_items[ $item['id'] ] );
1157
1158
                    if ( $set_price < $minimum_price ) {
1159
                        $set_price = $minimum_price;
1160
                    }
1161
1162
                    $price = wpinv_sanitize_amount( $set_price );
1163
1164
                }
1165
1166
                $price  = $quantity * floatval( $price );
1167
1168
                if ( wpinv_use_taxes() ) {
1169
1170
                    $rate = wpinv_get_tax_rate( $country, $state, (int) $item['id'] );
1171
1172
                    if ( wpinv_prices_include_tax() ) {
1173
                        $pre_tax  = ( $price - $price * $rate * 0.01 );
1174
                        $item_tax = $price - $pre_tax;
1175
                    } else {
1176
                        $pre_tax  = $price;
1177
                        $item_tax = $price * $rate * 0.01;
1178
                    }
1179
1180
                    $tax       = $tax + $item_tax;
1181
                    $sub_total = $sub_total + $pre_tax;
1182
                    $total     = $sub_total + $tax;
1183
1184
                } else {
1185
                    $total  = $total + $price;
1186
                }
1187
1188
            }
1189
1190
        }
1191
1192
        wp_send_json_success( array(
1193
            'total'     => wpinv_price( wpinv_format_amount( $total ) ),
1194
            'tax'       => wpinv_price( wpinv_format_amount( $tax ) ),
1195
            'sub_total' => wpinv_price( wpinv_format_amount( $sub_total ) ),
1196
        ));
1197
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1198
    }
1199
1200
    /**
1201
     * Lets users buy items via ajax.
1202
     *
1203
     * @since 1.0.0
1204
     */
1205
    public static function buy_items() {
1206
        $user_id = get_current_user_id();
1207
1208
        if ( empty( $user_id ) ) { // If not logged in then lets redirect to the login page
1209
            wp_send_json( array(
1210
                'success' => wp_login_url( wp_get_referer() )
0 ignored issues
show
Bug introduced by
It seems like wp_get_referer() can also be of type false; however, parameter $redirect of wp_login_url() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1210
                'success' => wp_login_url( /** @scrutinizer ignore-type */ wp_get_referer() )
Loading history...
1211
            ) );
1212
        } else {
1213
            // Only check nonce if logged in as it could be cached when logged out.
1214
            if ( ! isset( $_POST['wpinv_buy_nonce'] ) || ! wp_verify_nonce( $_POST['wpinv_buy_nonce'], 'wpinv_buy_items' ) ) {
1215
                wp_send_json( array(
1216
                    'error' => __( 'Security checks failed.', 'invoicing' )
1217
                ) );
1218
                wp_die();
1219
            }
1220
1221
            // allow to set a custom price through post_id
1222
            $items = $_POST['items'];
1223
            $related_post_id = isset( $_POST['post_id'] ) ? (int)$_POST['post_id'] : 0;
1224
            $custom_item_price = $related_post_id ? abs( get_post_meta( $related_post_id, '_wpi_custom_price', true ) ) : 0;
1225
1226
            $cart_items = array();
1227
            if ( $items ) {
1228
                $items = explode( ',', $items );
1229
1230
                foreach( $items as $item ) {
1231
                    $item_id = $item;
1232
                    $quantity = 1;
1233
1234
                    if ( strpos( $item, '|' ) !== false ) {
1235
                        $item_parts = explode( '|', $item );
1236
                        $item_id = $item_parts[0];
1237
                        $quantity = $item_parts[1];
1238
                    }
1239
1240
                    if ( $item_id && $quantity ) {
1241
                        $cart_items_arr = array(
1242
                            'id'            => (int)$item_id,
1243
                            'quantity'      => (int)$quantity
1244
                        );
1245
1246
                        // If there is a related post id then add it to meta
1247
                        if ( $related_post_id ) {
1248
                            $cart_items_arr['meta'] = array(
1249
                                'post_id'   => $related_post_id
1250
                            );
1251
                        }
1252
1253
                        // If there is a custom price then set it.
1254
                        if ( $custom_item_price ) {
1255
                            $cart_items_arr['custom_price'] = $custom_item_price;
1256
                        }
1257
1258
                        $cart_items[] = $cart_items_arr;
1259
                    }
1260
                }
1261
            }
1262
1263
            /**
1264
             * Filter the wpinv_buy shortcode cart items on the fly.
1265
             *
1266
             * @param array $cart_items The cart items array.
1267
             * @param int $related_post_id The related post id if any.
1268
             * @since 1.0.0
1269
             */
1270
            $cart_items = apply_filters( 'wpinv_buy_cart_items', $cart_items, $related_post_id );
1271
1272
            // Make sure its not in the cart already, if it is then redirect to checkout.
1273
            $cart_invoice = wpinv_get_invoice_cart();
1274
1275
            if ( isset( $cart_invoice->items ) && !empty( $cart_invoice->items ) && !empty( $cart_items ) && serialize( $cart_invoice->items ) == serialize( $cart_items ) ) {
1276
                wp_send_json( array(
1277
                    'success' =>  $cart_invoice->get_checkout_payment_url()
1278
                ) );
1279
                wp_die();
1280
            }
1281
1282
            // Check if user has invoice with same items waiting to be paid.
1283
            $user_invoices = wpinv_get_users_invoices( $user_id , 10 , false , 'wpi-pending' );
1284
            if ( !empty( $user_invoices ) ) {
1285
                foreach( $user_invoices as $user_invoice ) {
1286
                    $user_cart_details = array();
1287
                    $invoice  = wpinv_get_invoice( $user_invoice->ID );
1288
                    $cart_details = $invoice->get_cart_details();
1289
1290
                    if ( !empty( $cart_details ) ) {
1291
                        foreach ( $cart_details as $invoice_item ) {
1292
                            $ii_arr = array();
1293
                            $ii_arr['id'] = (int)$invoice_item['id'];
1294
                            $ii_arr['quantity'] = (int)$invoice_item['quantity'];
1295
1296
                            if (isset( $invoice_item['meta'] ) && !empty( $invoice_item['meta'] ) ) {
1297
                                $ii_arr['meta'] = $invoice_item['meta'];
1298
                            }
1299
1300
                            if ( isset( $invoice_item['custom_price'] ) && !empty( $invoice_item['custom_price'] ) ) {
1301
                                $ii_arr['custom_price'] = $invoice_item['custom_price'];
1302
                            }
1303
1304
                            $user_cart_details[] = $ii_arr;
1305
                        }
1306
                    }
1307
1308
                    if ( !empty( $user_cart_details ) && serialize( $cart_items ) == serialize( $user_cart_details ) ) {
1309
                        wp_send_json( array(
1310
                            'success' =>  $invoice->get_checkout_payment_url()
1311
                        ) );
1312
                        wp_die();
1313
                    }
1314
                }
1315
            }
1316
1317
            // Create invoice and send user to checkout
1318
            if ( !empty( $cart_items ) ) {
1319
                $invoice_data = array(
1320
                    'status'        =>  'wpi-pending',
1321
                    'created_via'   =>  'wpi',
1322
                    'user_id'       =>  $user_id,
1323
                    'cart_details'  =>  $cart_items,
1324
                );
1325
1326
                $invoice = wpinv_insert_invoice( $invoice_data, true );
1327
1328
                if ( !empty( $invoice ) && isset( $invoice->ID ) ) {
1329
                    wp_send_json( array(
1330
                        'success' =>  $invoice->get_checkout_payment_url()
0 ignored issues
show
Bug introduced by
The method get_checkout_payment_url() does not exist on WP_Error. ( Ignorable by Annotation )

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

1330
                        'success' =>  $invoice->/** @scrutinizer ignore-call */ get_checkout_payment_url()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1331
                    ) );
1332
                } else {
1333
                    wp_send_json( array(
1334
                        'error' => __( 'Invoice failed to create', 'invoicing' )
1335
                    ) );
1336
                }
1337
            } else {
1338
                wp_send_json( array(
1339
                    'error' => __( 'Items not valid.', 'invoicing' )
1340
                ) );
1341
            }
1342
        }
1343
1344
        wp_die();
1345
    }
1346
}
1347
1348
WPInv_Ajax::init();