Passed
Pull Request — master (#284)
by Brian
07:10
created

WPInv_Ajax::create_payment_form_item()   B

Complexity

Conditions 10
Paths 33

Size

Total Lines 74
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 41
c 0
b 0
f 0
nc 33
nop 0
dl 0
loc 74
rs 7.6666

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
            'add_invoice_item' => false,
67
            'add_payment_form_item' => false,
68
            'remove_invoice_item' => false,
69
            'create_payment_form_item' => false,
70
            'create_invoice_item' => false,
71
            'get_billing_details' => false,
72
            'admin_recalculate_totals' => false,
73
            'admin_apply_discount' => false,
74
            'admin_remove_discount' => false,
75
            'check_email' => false,
76
            'run_tool' => false,
77
            'apply_discount' => true,
78
            'remove_discount' => true,
79
            'buy_items' => true,
80
        );
81
82
        foreach ( $ajax_events as $ajax_event => $nopriv ) {
83
            add_action( 'wp_ajax_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
84
            
85
            if ( !defined( 'WPI_AJAX_' . strtoupper( $nopriv ) ) ) {
86
                define( 'WPI_AJAX_' . strtoupper( $nopriv ), 1 );
87
            }
88
89
            if ( $nopriv ) {
90
                add_action( 'wp_ajax_nopriv_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
91
92
                add_action( 'wpinv_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
93
            }
94
        }
95
    }
96
    
97
    public static function add_note() {
98
        check_ajax_referer( 'add-invoice-note', '_nonce' );
99
100
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
101
            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...
102
        }
103
104
        $post_id   = absint( $_POST['post_id'] );
105
        $note      = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
106
        $note_type = sanitize_text_field( $_POST['note_type'] );
107
108
        $is_customer_note = $note_type == 'customer' ? 1 : 0;
109
110
        if ( $post_id > 0 ) {
111
            $note_id = wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
112
113
            if ( $note_id > 0 && !is_wp_error( $note_id ) ) {
114
                wpinv_get_invoice_note_line_item( $note_id );
115
            }
116
        }
117
118
        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...
119
    }
120
121
    public static function delete_note() {
122
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
123
124
        if ( !wpinv_current_user_can_manage_invoicing() ) {
125
            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...
126
        }
127
128
        $note_id = (int)$_POST['note_id'];
129
130
        if ( $note_id > 0 ) {
131
            wp_delete_comment( $note_id, true );
132
        }
133
134
        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...
135
    }
136
    
137
    public static function get_states_field() {
138
        echo wpinv_get_states_field();
139
        
140
        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...
141
    }
142
    
143
    public static function checkout() {
144
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
145
            define( 'WPINV_CHECKOUT', true );
146
        }
147
148
        wpinv_process_checkout();
149
        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...
150
    }
151
    
152
    public static function add_invoice_item() {
153
        global $wpi_userID, $wpinv_ip_address_country;
154
        check_ajax_referer( 'invoice-item', '_nonce' );
155
        if ( !wpinv_current_user_can_manage_invoicing() ) {
156
            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...
157
        }
158
        
159
        $item_id    = sanitize_text_field( $_POST['item_id'] );
160
        $invoice_id = absint( $_POST['invoice_id'] );
161
        
162
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
163
            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...
164
        }
165
        
166
        $invoice    = wpinv_get_invoice( $invoice_id );
167
        if ( empty( $invoice ) ) {
168
            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...
169
        }
170
        
171
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
172
            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...
173
        }
174
        
175
        if ( !empty( $_POST['user_id'] ) ) {
176
            $wpi_userID = absint( $_POST['user_id'] ); 
177
        }
178
179
        $item = new WPInv_Item( $item_id );
180
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
181
            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...
182
        }
183
        
184
        // Validate item before adding to invoice because recurring item must be paid individually.
185
        if ( !empty( $invoice->cart_details ) ) {
186
            $valid = true;
187
            
188
            if ( $recurring_item = $invoice->get_recurring() ) {
189
                if ( $recurring_item != $item_id ) {
190
                    $valid = false;
191
                }
192
            } else if ( wpinv_is_recurring_item( $item_id ) ) {
193
                $valid = false;
194
            }
195
            
196
            if ( !$valid ) {
197
                $response               = array();
198
                $response['success']    = false;
199
                $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
200
                wp_send_json( $response );
201
            }
202
        }
203
        
204
        $checkout_session = wpinv_get_checkout_session();
205
        
206
        $data                   = array();
207
        $data['invoice_id']     = $invoice_id;
208
        $data['cart_discounts'] = $invoice->get_discounts( true );
209
        
210
        wpinv_set_checkout_session( $data );
211
        
212
        $quantity = wpinv_item_quantities_enabled() && !empty($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : 1;
213
214
        $args = array(
215
            'id'            => $item_id,
216
            'quantity'      => $quantity,
217
            'item_price'    => $item->get_price(),
218
            'custom_price'  => '',
219
            'tax'           => 0.00,
220
            'discount'      => 0,
221
            'meta'          => array(),
222
            'fees'          => array()
223
        );
224
225
        $invoice->add_item( $item_id, $args );
226
        $invoice->save();
227
        
228
        if ( empty( $_POST['country'] ) ) {
229
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
230
        }
231
        if ( empty( $_POST['state'] ) ) {
232
            $_POST['state'] = $invoice->state;
233
        }
234
         
235
        $invoice->country   = sanitize_text_field( $_POST['country'] );
236
        $invoice->state     = sanitize_text_field( $_POST['state'] );
237
        
238
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
239
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
240
        
241
        $wpinv_ip_address_country = $invoice->country;
242
243
        $invoice->recalculate_totals(true);
244
        
245
        $response                       = array();
246
        $response['success']            = true;
247
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
248
        $response['data']['subtotal']   = $invoice->get_subtotal();
249
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
250
        $response['data']['tax']        = $invoice->get_tax();
251
        $response['data']['taxf']       = $invoice->get_tax(true);
252
        $response['data']['discount']   = $invoice->get_discount();
253
        $response['data']['discountf']  = $invoice->get_discount(true);
254
        $response['data']['total']      = $invoice->get_total();
255
        $response['data']['totalf']     = $invoice->get_total(true);
256
        
257
        wpinv_set_checkout_session($checkout_session);
258
        
259
        wp_send_json( $response );
260
    }
261
262
    /**
263
     * Handles the ajax requests to add a payment form item.
264
     */
265
    public static function add_payment_form_item() {
266
267
        // Check nonce...
268
        check_ajax_referer( 'invoice-item', '_nonce' );
269
270
        // ... and user capability.
271
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
272
            wp_send_json_error( __( 'You do not have permission to do that.', 'invoicing' ) );
273
            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...
274
        }
275
276
        // Prepare the item and the invoice.
277
        $item_id = absint( $_POST['item_id'] );
278
        $form_id = absint( $_POST['form_id'] );
279
        
280
        if ( empty( $item_id ) || empty( $form_id ) ) {
281
            wp_send_json_error( __( 'Invalid form or item.', 'invoicing' ) );
282
        }
283
284
        $new_item = new WPInv_Item( $item_id );
285
        if ( empty( $new_item ) || $new_item->post_type != 'wpi_item' ) {
286
            wp_send_json_error( __( 'Invalid item.', 'invoicing' ) );
287
        }
288
289
        // Fetch existing items.
290
        $items = get_post_meta( $form_id, 'wpinv_payment_form_items', true );
291
292
        if ( empty( $items ) || is_array( $items ) ) {
293
            $items = array();
294
        }
295
296
        // Only one recurring item per form please.
297
        $has_recurring = wpinv_is_recurring_item( $item_id );
298
        foreach ( $items as $index => $item_data ) {
299
300
            $id   = $item_data['id'];
301
            $item = new WPInv_Item( $id );
302
303
            if ( empty( $item ) || $item->post_type != 'wpi_item' ) {
304
                unset( $items[ $index ] );
305
                continue;
306
            }
307
308
            if ( $item_id == $id ) {
309
                unset( $items[ $index ] );
310
            }
311
312
            if ( $item->is_recurring() ) {
313
                $has_recurring = true;
314
            }
315
316
        }
317
318
        $items[] = array( 'id' => $new_item->ID );
319
320
        // One recurring item per form.
321
        if ( $has_recurring && 1 < count( $items ) ) {
322
            wp_send_json_error( __( 'You can not add item because recurring items must be paid individually!', 'invoicing' ) );
323
        }
324
325
        update_post_meta( $form_id, 'wpinv_payment_form_items', $items );
326
327
        ob_start();
328
        WPInv_Meta_Box_Form_Items::output( get_post( $form_id ) );
329
        $items = ob_get_clean();
330
        
331
        wp_send_json_success( $items );
332
    }
333
334
    /**
335
     * Handles the ajax requests to Create a new payment form item.
336
     */
337
    public static function create_payment_form_item() {
338
339
        // Check nonce...
340
        check_ajax_referer( 'invoice-item', '_nonce' );
341
342
        // ... and user capability.
343
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
344
            wp_send_json_error( __( 'You do not have permission to do that.', 'invoicing' ) );
345
            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...
346
        }
347
348
        // Item data.
349
        $form_id          = absint( $_POST['form_id'] );
350
        $item_price       = wpinv_sanitize_amount( $_POST['item_price'] );
351
        $item_name        = sanitize_text_field( $_POST['item_name'] );
352
        $item_description = wp_kses_post( $_POST['item_description'] );
353
        
354
        if ( empty( $item_name ) ) {
355
            wp_send_json_error( __( 'Specify a name for your item.', 'invoicing' ) );
356
        }
357
358
        // Fetch existing items.
359
        $items = get_post_meta( $form_id, 'wpinv_payment_form_items', true );
360
361
        if ( empty( $items ) || is_array( $items ) ) {
362
            $items = array();
363
        }
364
365
        // Only one recurring item per form please.
366
        foreach ( $items as $index => $item_data ) {
367
368
            $id   = $item_data['id'];
369
            $item = new WPInv_Item( $id );
370
371
            if ( empty( $item ) || $item->post_type != 'wpi_item' ) {
372
                unset( $items[ $index ] );
373
                continue;
374
            }
375
376
            if ( $item->is_recurring() ) {
377
                wp_send_json_error( __( 'You can not add item because recurring items must be paid individually!', 'invoicing' ) );
378
            }
379
380
        }
381
382
        $data = array(
383
            'post_title'   => $item_name,
384
            'post_excerpt' => $item_description,
385
            'post_status'  => 'publish',
386
            'meta'         => array(
387
                'type' => 'custom',
388
                'price' => $item_price,
389
                'vat_rule' => 'digital',
390
                'vat_class' => '_standard',
391
            )
392
        );
393
        
394
        $item  = new WPInv_Item();
395
        $item->create( $data );
396
397
        if ( empty( $item ) ) {
398
            wp_send_json_error( __( 'Error creating item', 'invoicing' ) );
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
        $items[] = array( 'id' => $item->ID );
403
404
        update_post_meta( $form_id, 'wpinv_payment_form_items', $items );
405
406
        ob_start();
407
        WPInv_Meta_Box_Form_Items::output( get_post( $form_id ) );
408
        $items = ob_get_clean();
409
        
410
        wp_send_json_success( $items );
411
    }
412
413
    public static function remove_invoice_item() {
414
        global $wpi_userID, $wpinv_ip_address_country;
415
        
416
        check_ajax_referer( 'invoice-item', '_nonce' );
417
        if ( !wpinv_current_user_can_manage_invoicing() ) {
418
            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...
419
        }
420
        
421
        $item_id    = sanitize_text_field( $_POST['item_id'] );
422
        $invoice_id = absint( $_POST['invoice_id'] );
423
        $cart_index = isset( $_POST['index'] ) && $_POST['index'] >= 0 ? $_POST['index'] : false;
424
        
425
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
426
            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...
427
        }
428
429
        $invoice    = wpinv_get_invoice( $invoice_id );
430
        if ( empty( $invoice ) ) {
431
            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...
432
        }
433
        
434
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
435
            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...
436
        }
437
        
438
        if ( !empty( $_POST['user_id'] ) ) {
439
            $wpi_userID = absint( $_POST['user_id'] ); 
440
        }
441
442
        $item       = new WPInv_Item( $item_id );
443
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
444
            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...
445
        }
446
        
447
        $checkout_session = wpinv_get_checkout_session();
448
        
449
        $data                   = array();
450
        $data['invoice_id']     = $invoice_id;
451
        $data['cart_discounts'] = $invoice->get_discounts( true );
452
        
453
        wpinv_set_checkout_session( $data );
454
455
        $args = array(
456
            'id'         => $item_id,
457
            'quantity'   => 1,
458
            'cart_index' => $cart_index
459
        );
460
461
        $invoice->remove_item( $item_id, $args );
462
        $invoice->save();
463
        
464
        if ( empty( $_POST['country'] ) ) {
465
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
466
        }
467
        if ( empty( $_POST['state'] ) ) {
468
            $_POST['state'] = $invoice->state;
469
        }
470
         
471
        $invoice->country   = sanitize_text_field( $_POST['country'] );
472
        $invoice->state     = sanitize_text_field( $_POST['state'] );
473
        
474
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
475
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
476
        
477
        $wpinv_ip_address_country = $invoice->country;
478
        
479
        $invoice->recalculate_totals(true);
480
        
481
        $response                       = array();
482
        $response['success']            = true;
483
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
484
        $response['data']['subtotal']   = $invoice->get_subtotal();
485
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
486
        $response['data']['tax']        = $invoice->get_tax();
487
        $response['data']['taxf']       = $invoice->get_tax(true);
488
        $response['data']['discount']   = $invoice->get_discount();
489
        $response['data']['discountf']  = $invoice->get_discount(true);
490
        $response['data']['total']      = $invoice->get_total();
491
        $response['data']['totalf']     = $invoice->get_total(true);
492
        
493
        wpinv_set_checkout_session($checkout_session);
494
        
495
        wp_send_json( $response );
496
    }
497
    
498
    public static function create_invoice_item() {
499
        check_ajax_referer( 'invoice-item', '_nonce' );
500
        if ( !wpinv_current_user_can_manage_invoicing() ) {
501
            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...
502
        }
503
        
504
        $invoice_id = absint( $_POST['invoice_id'] );
505
506
        // Find the item
507
        if ( !is_numeric( $invoice_id ) ) {
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
        $invoice     = wpinv_get_invoice( $invoice_id );
512
        if ( empty( $invoice ) ) {
513
            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...
514
        }
515
        
516
        // Validate item before adding to invoice because recurring item must be paid individually.
517
        if ( !empty( $invoice->cart_details ) && $invoice->get_recurring() ) {
518
            $response               = array();
519
            $response['success']    = false;
520
            $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
521
            wp_send_json( $response );
522
        }        
523
        
524
        $save_item = wp_unslash( $_POST['_wpinv_quick'] );
525
        
526
        $meta               = array();
527
        $meta['type']       = !empty($save_item['type']) ? sanitize_text_field($save_item['type']) : 'custom';
528
        $meta['price']      = !empty($save_item['price']) ? wpinv_sanitize_amount( $save_item['price'] ) : 0;
529
        $meta['vat_rule']   = !empty($save_item['vat_rule']) ? sanitize_text_field($save_item['vat_rule']) : 'digital';
530
        $meta['vat_class']  = !empty($save_item['vat_class']) ? sanitize_text_field($save_item['vat_class']) : '_standard';
531
        
532
        $data                   = array();
533
        $data['post_title']     = sanitize_text_field($save_item['name']);
534
        $data['post_status']    = 'publish';
535
        $data['post_excerpt']   = ! empty( $save_item['excerpt'] ) ? wp_kses_post( $save_item['excerpt'] ) : '';
536
        $data['meta']           = $meta;
537
        
538
        $item = new WPInv_Item();
539
        $item->create( $data );
540
        
541
        if ( !empty( $item ) ) {
542
            $_POST['item_id']   = $item->ID;
543
            $_POST['qty']       = !empty($save_item['qty']) && $save_item['qty'] > 0 ? (int)$save_item['qty'] : 1;
544
            
545
            self::add_invoice_item();
546
        }
547
        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...
548
    }
549
    
550
    public static function get_billing_details() {
551
        check_ajax_referer( 'get-billing-details', '_nonce' );
552
        
553
        if ( !wpinv_current_user_can_manage_invoicing() ) {
554
            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...
555
        }
556
557
        $user_id            = (int)$_POST['user_id'];
558
        $billing_details    = wpinv_get_user_address($user_id);
559
        $billing_details    = apply_filters( 'wpinv_fill_billing_details', $billing_details, $user_id );
560
        
561
        if (isset($billing_details['user_id'])) {
562
            unset($billing_details['user_id']);
563
        }
564
        
565
        if (isset($billing_details['email'])) {
566
            unset($billing_details['email']);
567
        }
568
569
        $response                               = array();
570
        $response['success']                    = true;
571
        $response['data']['billing_details']    = $billing_details;
572
        
573
        wp_send_json( $response );
574
    }
575
    
576
    public static function admin_recalculate_totals() {
577
        global $wpi_userID, $wpinv_ip_address_country;
578
        
579
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
580
        if ( !wpinv_current_user_can_manage_invoicing() ) {
581
            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...
582
        }
583
        
584
        $invoice_id = absint( $_POST['invoice_id'] );        
585
        $invoice    = wpinv_get_invoice( $invoice_id );
586
        if ( empty( $invoice ) ) {
587
            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...
588
        }
589
        
590
        $checkout_session = wpinv_get_checkout_session();
591
        
592
        $data                   = array();
593
        $data['invoice_id']     = $invoice_id;
594
        $data['cart_discounts'] = $invoice->get_discounts( true );
595
        
596
        wpinv_set_checkout_session( $data );
597
        
598
        if ( !empty( $_POST['user_id'] ) ) {
599
            $wpi_userID = absint( $_POST['user_id'] ); 
600
        }
601
        
602
        if ( empty( $_POST['country'] ) ) {
603
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
604
        }
605
            
606
        $invoice->country = sanitize_text_field( $_POST['country'] );
607
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
608
        if ( isset( $_POST['state'] ) ) {
609
            $invoice->state = sanitize_text_field( $_POST['state'] );
610
            $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
611
        }
612
        
613
        $wpinv_ip_address_country = $invoice->country;
614
        
615
        $invoice = $invoice->recalculate_totals(true);
616
        
617
        $response                       = array();
618
        $response['success']            = true;
619
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
620
        $response['data']['subtotal']   = $invoice->get_subtotal();
621
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
622
        $response['data']['tax']        = $invoice->get_tax();
623
        $response['data']['taxf']       = $invoice->get_tax(true);
624
        $response['data']['discount']   = $invoice->get_discount();
625
        $response['data']['discountf']  = $invoice->get_discount(true);
626
        $response['data']['total']      = $invoice->get_total();
627
        $response['data']['totalf']     = $invoice->get_total(true);
628
        
629
        wpinv_set_checkout_session($checkout_session);
630
        
631
        wp_send_json( $response );
632
    }
633
    
634
    public static function admin_apply_discount() {
635
        global $wpi_userID;
636
        
637
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
638
        if ( !wpinv_current_user_can_manage_invoicing() ) {
639
            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...
640
        }
641
        
642
        $invoice_id = absint( $_POST['invoice_id'] );
643
        $discount_code = sanitize_text_field( $_POST['code'] );
644
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
645
            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...
646
        }
647
        
648
        $invoice = wpinv_get_invoice( $invoice_id );
649
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
650
            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...
651
        }
652
        
653
        $checkout_session = wpinv_get_checkout_session();
654
        
655
        $data                   = array();
656
        $data['invoice_id']     = $invoice_id;
657
        $data['cart_discounts'] = $invoice->get_discounts( true );
658
        
659
        wpinv_set_checkout_session( $data );
660
        
661
        $response               = array();
662
        $response['success']    = false;
663
        $response['msg']        = __( 'This discount is invalid.', 'invoicing' );
664
        $response['data']['code'] = $discount_code;
665
        
666
        if ( wpinv_is_discount_valid( $discount_code, $invoice->get_user_id() ) ) {
667
            $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...
668
            
669
            $response['success'] = true;
670
            $response['msg'] = __( 'Discount has been applied successfully.', 'invoicing' );
671
        }  else {
672
            $errors = wpinv_get_errors();
673
            if ( !empty( $errors['wpinv-discount-error'] ) ) {
674
                $response['msg'] = $errors['wpinv-discount-error'];
675
            }
676
            wpinv_unset_error( 'wpinv-discount-error' );
677
        }
678
        
679
        wpinv_set_checkout_session($checkout_session);
680
        
681
        wp_send_json( $response );
682
    }
683
    
684
    public static function admin_remove_discount() {
685
        global $wpi_userID;
686
        
687
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
688
        if ( !wpinv_current_user_can_manage_invoicing() ) {
689
            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...
690
        }
691
        
692
        $invoice_id = absint( $_POST['invoice_id'] );
693
        $discount_code = sanitize_text_field( $_POST['code'] );
694
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
695
            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...
696
        }
697
        
698
        $invoice = wpinv_get_invoice( $invoice_id );
699
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
700
            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...
701
        }
702
        
703
        $checkout_session = wpinv_get_checkout_session();
704
        
705
        $data                   = array();
706
        $data['invoice_id']     = $invoice_id;
707
        $data['cart_discounts'] = $invoice->get_discounts( true );
708
        
709
        wpinv_set_checkout_session( $data );
710
        
711
        $response               = array();
712
        $response['success']    = false;
713
        $response['msg']        = NULL;
714
        
715
        $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...
716
        $response['success'] = true;
717
        $response['msg'] = __( 'Discount has been removed successfully.', 'invoicing' );
718
        
719
        wpinv_set_checkout_session($checkout_session);
720
        
721
        wp_send_json( $response );
722
    }
723
    
724
    public static function check_email() {
725
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
726
        if ( !wpinv_current_user_can_manage_invoicing() ) {
727
            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...
728
        }
729
        
730
        $email = sanitize_text_field( $_POST['email'] );
731
        
732
        $response = array();
733
        if ( is_email( $email ) && email_exists( $email ) && $user_data = get_user_by( 'email', $email ) ) {
734
            $user_id            = $user_data->ID;
735
            $user_login         = $user_data->user_login;
736
            $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...
737
            $billing_details    = wpinv_get_user_address($user_id);
738
            $billing_details    = apply_filters( 'wpinv_fill_billing_details', $billing_details, $user_id );
739
            
740
            if (isset($billing_details['user_id'])) {
741
                unset($billing_details['user_id']);
742
            }
743
            
744
            if (isset($billing_details['email'])) {
745
                unset($billing_details['email']);
746
            }
747
            
748
            $response['success']                    = true;
749
            $response['data']['id']                 = $user_data->ID;
750
            $response['data']['name']               = $user_data->user_email;
751
            $response['data']['billing_details']    = $billing_details;
752
        }
753
        
754
        wp_send_json( $response );
755
    }
756
    
757
    public static function run_tool() {
758
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
759
        if ( !wpinv_current_user_can_manage_invoicing() ) {
760
            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...
761
        }
762
        
763
        $tool = sanitize_text_field( $_POST['tool'] );
764
        
765
        do_action( 'wpinv_run_tool' );
766
        
767
        if ( !empty( $tool ) ) {
768
            do_action( 'wpinv_tool_' . $tool );
769
        }
770
    }
771
    
772
    public static function apply_discount() {
773
        global $wpi_userID;
774
        
775
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
776
        
777
        $response = array();
778
        
779
        if ( isset( $_POST['code'] ) ) {
780
            $discount_code = sanitize_text_field( $_POST['code'] );
781
782
            $response['success']        = false;
783
            $response['msg']            = '';
784
            $response['data']['code']   = $discount_code;
785
            
786
            $invoice = wpinv_get_invoice_cart();
787
            if ( empty( $invoice->ID ) ) {
788
                $response['msg'] = __( 'Invalid checkout request.', 'invoicing' );
789
                wp_send_json( $response );
790
            }
791
792
            $wpi_userID = $invoice->get_user_id();
793
794
            if ( wpinv_is_discount_valid( $discount_code, $wpi_userID ) ) {
795
                $discount       = wpinv_get_discount_by_code( $discount_code );
796
                $discounts      = wpinv_set_cart_discount( $discount_code );
797
                $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...
798
                $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...
799
                $cart_totals    = wpinv_recalculate_tax( true );
800
            
801
                if ( !empty( $cart_totals ) ) {
802
                    $response['success']        = true;
803
                    $response['data']           = $cart_totals;
804
                    $response['data']['code']   = $discount_code;
805
                } else {
806
                    $response['success']        = false;
807
                }
808
            } else {
809
                $errors = wpinv_get_errors();
810
                $response['msg']  = $errors['wpinv-discount-error'];
811
                wpinv_unset_error( 'wpinv-discount-error' );
812
            }
813
814
            // Allow for custom discount code handling
815
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
816
        }
817
        
818
        wp_send_json( $response );
819
    }
820
    
821
    public static function remove_discount() {
822
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
823
        
824
        $response = array();
825
        
826
        if ( isset( $_POST['code'] ) ) {
827
            $discount_code  = sanitize_text_field( $_POST['code'] );
828
            $discounts      = wpinv_unset_cart_discount( $discount_code );
829
            $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...
830
            $cart_totals    = wpinv_recalculate_tax( true );
831
            
832
            if ( !empty( $cart_totals ) ) {
833
                $response['success']        = true;
834
                $response['data']           = $cart_totals;
835
                $response['data']['code']   = $discount_code;
836
            } else {
837
                $response['success']        = false;
838
            }
839
            
840
            // Allow for custom discount code handling
841
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
842
        }
843
        
844
        wp_send_json( $response );
845
    }
846
847
848
    /**
849
     * Lets users buy items via ajax.
850
     *
851
     * @since 1.0.0
852
     */
853
    public static function buy_items() {
854
        $user_id = get_current_user_id();
855
856
        if ( empty( $user_id ) ) { // If not logged in then lets redirect to the login page
857
            wp_send_json( array(
858
                '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

858
                'success' => wp_login_url( /** @scrutinizer ignore-type */ wp_get_referer() )
Loading history...
859
            ) );
860
        } else {
861
            // Only check nonce if logged in as it could be cached when logged out.
862
            if ( ! isset( $_POST['wpinv_buy_nonce'] ) || ! wp_verify_nonce( $_POST['wpinv_buy_nonce'], 'wpinv_buy_items' ) ) {
863
                wp_send_json( array(
864
                    'error' => __( 'Security checks failed.', 'invoicing' )
865
                ) );
866
                wp_die();
867
            }
868
869
            // allow to set a custom price through post_id
870
            $items = $_POST['items'];
871
            $related_post_id = isset( $_POST['post_id'] ) ? (int)$_POST['post_id'] : 0;
872
            $custom_item_price = $related_post_id ? abs( get_post_meta( $related_post_id, '_wpi_custom_price', true ) ) : 0;
873
874
            $cart_items = array();
875
            if ( $items ) {
876
                $items = explode( ',', $items );
877
878
                foreach( $items as $item ) {
879
                    $item_id = $item;
880
                    $quantity = 1;
881
882
                    if ( strpos( $item, '|' ) !== false ) {
883
                        $item_parts = explode( '|', $item );
884
                        $item_id = $item_parts[0];
885
                        $quantity = $item_parts[1];
886
                    }
887
888
                    if ( $item_id && $quantity ) {
889
                        $cart_items_arr = array(
890
                            'id'            => (int)$item_id,
891
                            'quantity'      => (int)$quantity
892
                        );
893
894
                        // If there is a related post id then add it to meta
895
                        if ( $related_post_id ) {
896
                            $cart_items_arr['meta'] = array(
897
                                'post_id'   => $related_post_id
898
                            );
899
                        }
900
901
                        // If there is a custom price then set it.
902
                        if ( $custom_item_price ) {
903
                            $cart_items_arr['custom_price'] = $custom_item_price;
904
                        }
905
906
                        $cart_items[] = $cart_items_arr;
907
                    }
908
                }
909
            }
910
911
            /**
912
             * Filter the wpinv_buy shortcode cart items on the fly.
913
             *
914
             * @param array $cart_items The cart items array.
915
             * @param int $related_post_id The related post id if any.
916
             * @since 1.0.0
917
             */
918
            $cart_items = apply_filters( 'wpinv_buy_cart_items', $cart_items, $related_post_id );
919
920
            // Make sure its not in the cart already, if it is then redirect to checkout.
921
            $cart_invoice = wpinv_get_invoice_cart();
922
923
            if ( isset( $cart_invoice->items ) && !empty( $cart_invoice->items ) && !empty( $cart_items ) && serialize( $cart_invoice->items ) == serialize( $cart_items ) ) {
924
                wp_send_json( array(
925
                    'success' =>  $cart_invoice->get_checkout_payment_url()
926
                ) );
927
                wp_die();
928
            }
929
930
            // Check if user has invoice with same items waiting to be paid.
931
            $user_invoices = wpinv_get_users_invoices( $user_id , 10 , false , 'wpi-pending' );
932
            if ( !empty( $user_invoices ) ) {
933
                foreach( $user_invoices as $user_invoice ) {
934
                    $user_cart_details = array();
935
                    $invoice  = wpinv_get_invoice( $user_invoice->ID );
936
                    $cart_details = $invoice->get_cart_details();
937
938
                    if ( !empty( $cart_details ) ) {
939
                        foreach ( $cart_details as $invoice_item ) {
940
                            $ii_arr = array();
941
                            $ii_arr['id'] = (int)$invoice_item['id'];
942
                            $ii_arr['quantity'] = (int)$invoice_item['quantity'];
943
944
                            if (isset( $invoice_item['meta'] ) && !empty( $invoice_item['meta'] ) ) {
945
                                $ii_arr['meta'] = $invoice_item['meta'];
946
                            }
947
948
                            if ( isset( $invoice_item['custom_price'] ) && !empty( $invoice_item['custom_price'] ) ) {
949
                                $ii_arr['custom_price'] = $invoice_item['custom_price'];
950
                            }
951
952
                            $user_cart_details[] = $ii_arr;
953
                        }
954
                    }
955
956
                    if ( !empty( $user_cart_details ) && serialize( $cart_items ) == serialize( $user_cart_details ) ) {
957
                        wp_send_json( array(
958
                            'success' =>  $invoice->get_checkout_payment_url()
959
                        ) );
960
                        wp_die();
961
                    }
962
                }
963
            }
964
965
            // Create invoice and send user to checkout
966
            if ( !empty( $cart_items ) ) {
967
                $invoice_data = array(
968
                    'status'        =>  'wpi-pending',
969
                    'created_via'   =>  'wpi',
970
                    'user_id'       =>  $user_id,
971
                    'cart_details'  =>  $cart_items,
972
                );
973
974
                $invoice = wpinv_insert_invoice( $invoice_data, true );
975
976
                if ( !empty( $invoice ) && isset( $invoice->ID ) ) {
977
                    wp_send_json( array(
978
                        '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

978
                        '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...
979
                    ) );
980
                } else {
981
                    wp_send_json( array(
982
                        'error' => __( 'Invoice failed to create', 'invoicing' )
983
                    ) );
984
                }
985
            } else {
986
                wp_send_json( array(
987
                    'error' => __( 'Items not valid.', 'invoicing' )
988
                ) );
989
            }
990
        }
991
992
        wp_die();
993
    }
994
}
995
996
WPInv_Ajax::init();