Passed
Pull Request — master (#377)
by Brian
06:57
created

WPInv_Ajax::check_email()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 20
c 0
b 0
f 0
nc 10
nop 0
dl 0
loc 31
rs 8.4444
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
            'get_aui_states_field' => true,
66
            'checkout' => false,
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_new_user_email' => false,
78
            'run_tool' => false,
79
            'apply_discount' => true,
80
            'remove_discount' => true,
81
            'buy_items' => true,
82
            'payment_form_refresh_prices' => true,
83
        );
84
85
        foreach ( $ajax_events as $ajax_event => $nopriv ) {
86
            add_action( 'wp_ajax_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
87
            add_action( 'wp_ajax_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
88
            
89
            if ( !defined( 'WPI_AJAX_' . strtoupper( $nopriv ) ) ) {
90
                define( 'WPI_AJAX_' . strtoupper( $nopriv ), 1 );
91
            }
92
93
            if ( $nopriv ) {
94
                add_action( 'wp_ajax_nopriv_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
95
                add_action( 'wp_ajax_nopriv_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
96
97
                add_action( 'wpinv_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
98
            }
99
        }
100
    }
101
    
102
    public static function add_note() {
103
        check_ajax_referer( 'add-invoice-note', '_nonce' );
104
105
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
106
            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...
107
        }
108
109
        $post_id   = absint( $_POST['post_id'] );
110
        $note      = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
111
        $note_type = sanitize_text_field( $_POST['note_type'] );
112
113
        $is_customer_note = $note_type == 'customer' ? 1 : 0;
114
115
        if ( $post_id > 0 ) {
116
            $note_id = wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
117
118
            if ( $note_id > 0 && !is_wp_error( $note_id ) ) {
119
                wpinv_get_invoice_note_line_item( $note_id );
120
            }
121
        }
122
123
        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...
124
    }
125
126
    public static function delete_note() {
127
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
128
129
        if ( !wpinv_current_user_can_manage_invoicing() ) {
130
            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...
131
        }
132
133
        $note_id = (int)$_POST['note_id'];
134
135
        if ( $note_id > 0 ) {
136
            wp_delete_comment( $note_id, true );
137
        }
138
139
        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...
140
    }
141
    
142
    public static function get_states_field() {
143
        echo wpinv_get_states_field();
144
        
145
        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...
146
    }
147
    
148
    public static function checkout() {
149
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
150
            define( 'WPINV_CHECKOUT', true );
151
        }
152
153
        wpinv_process_checkout();
154
        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...
155
    }
156
    
157
    public static function add_invoice_item() {
158
        global $wpi_userID, $wpinv_ip_address_country;
159
        check_ajax_referer( 'invoice-item', '_nonce' );
160
        if ( !wpinv_current_user_can_manage_invoicing() ) {
161
            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...
162
        }
163
        
164
        $item_id    = sanitize_text_field( $_POST['item_id'] );
165
        $invoice_id = absint( $_POST['invoice_id'] );
166
        
167
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
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
        $invoice    = wpinv_get_invoice( $invoice_id );
172
        if ( empty( $invoice ) ) {
173
            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...
174
        }
175
        
176
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
177
            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...
178
        }
179
        
180
        if ( !empty( $_POST['user_id'] ) ) {
181
            $wpi_userID = absint( $_POST['user_id'] ); 
182
        }
183
184
        $item = new WPInv_Item( $item_id );
185
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
186
            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...
187
        }
188
        
189
        // Validate item before adding to invoice because recurring item must be paid individually.
190
        if ( !empty( $invoice->cart_details ) ) {
191
            $valid = true;
192
            
193
            if ( $recurring_item = $invoice->get_recurring() ) {
194
                if ( $recurring_item != $item_id ) {
195
                    $valid = false;
196
                }
197
            } else if ( wpinv_is_recurring_item( $item_id ) ) {
198
                $valid = false;
199
            }
200
            
201
            if ( !$valid ) {
202
                $response               = array();
203
                $response['success']    = false;
204
                $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
205
                wp_send_json( $response );
206
            }
207
        }
208
        
209
        $checkout_session = wpinv_get_checkout_session();
210
        
211
        $data                   = array();
212
        $data['invoice_id']     = $invoice_id;
213
        $data['cart_discounts'] = $invoice->get_discounts( true );
214
        
215
        wpinv_set_checkout_session( $data );
216
        
217
        $quantity = wpinv_item_quantities_enabled() && !empty($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : 1;
218
219
        $args = array(
220
            'id'            => $item_id,
221
            'quantity'      => $quantity,
222
            'item_price'    => $item->get_price(),
223
            'custom_price'  => '',
224
            'tax'           => 0.00,
225
            'discount'      => 0,
226
            'meta'          => array(),
227
            'fees'          => array()
228
        );
229
230
        $invoice->add_item( $item_id, $args );
231
        $invoice->save();
232
        
233
        if ( empty( $_POST['country'] ) ) {
234
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
235
        }
236
        if ( empty( $_POST['state'] ) ) {
237
            $_POST['state'] = $invoice->state;
238
        }
239
         
240
        $invoice->country   = sanitize_text_field( $_POST['country'] );
241
        $invoice->state     = sanitize_text_field( $_POST['state'] );
242
        
243
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
244
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
245
        
246
        $wpinv_ip_address_country = $invoice->country;
247
248
        $invoice->recalculate_totals(true);
249
        
250
        $response                       = array();
251
        $response['success']            = true;
252
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
253
        $response['data']['subtotal']   = $invoice->get_subtotal();
254
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
255
        $response['data']['tax']        = $invoice->get_tax();
256
        $response['data']['taxf']       = $invoice->get_tax(true);
257
        $response['data']['discount']   = $invoice->get_discount();
258
        $response['data']['discountf']  = $invoice->get_discount(true);
259
        $response['data']['total']      = $invoice->get_total();
260
        $response['data']['totalf']     = $invoice->get_total(true);
261
        
262
        wpinv_set_checkout_session($checkout_session);
263
        
264
        wp_send_json( $response );
265
    }
266
267
268
    public static function remove_invoice_item() {
269
        global $wpi_userID, $wpinv_ip_address_country;
270
        
271
        check_ajax_referer( 'invoice-item', '_nonce' );
272
        if ( !wpinv_current_user_can_manage_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
        $item_id    = sanitize_text_field( $_POST['item_id'] );
277
        $invoice_id = absint( $_POST['invoice_id'] );
278
        $cart_index = isset( $_POST['index'] ) && $_POST['index'] >= 0 ? $_POST['index'] : false;
279
        
280
        if ( !is_numeric( $invoice_id ) || !is_numeric( $item_id ) ) {
281
            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...
282
        }
283
284
        $invoice    = wpinv_get_invoice( $invoice_id );
285
        if ( empty( $invoice ) ) {
286
            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...
287
        }
288
        
289
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
290
            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...
291
        }
292
        
293
        if ( !empty( $_POST['user_id'] ) ) {
294
            $wpi_userID = absint( $_POST['user_id'] ); 
295
        }
296
297
        $item       = new WPInv_Item( $item_id );
298
        if ( !( !empty( $item ) && $item->post_type == 'wpi_item' ) ) {
299
            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...
300
        }
301
        
302
        $checkout_session = wpinv_get_checkout_session();
303
        
304
        $data                   = array();
305
        $data['invoice_id']     = $invoice_id;
306
        $data['cart_discounts'] = $invoice->get_discounts( true );
307
        
308
        wpinv_set_checkout_session( $data );
309
310
        $args = array(
311
            'id'         => $item_id,
312
            'quantity'   => 1,
313
            'cart_index' => $cart_index
314
        );
315
316
        $invoice->remove_item( $item_id, $args );
317
        $invoice->save();
318
        
319
        if ( empty( $_POST['country'] ) ) {
320
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
321
        }
322
        if ( empty( $_POST['state'] ) ) {
323
            $_POST['state'] = $invoice->state;
324
        }
325
         
326
        $invoice->country   = sanitize_text_field( $_POST['country'] );
327
        $invoice->state     = sanitize_text_field( $_POST['state'] );
328
        
329
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
330
        $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
331
        
332
        $wpinv_ip_address_country = $invoice->country;
333
        
334
        $invoice->recalculate_totals(true);
335
        
336
        $response                       = array();
337
        $response['success']            = true;
338
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
339
        $response['data']['subtotal']   = $invoice->get_subtotal();
340
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
341
        $response['data']['tax']        = $invoice->get_tax();
342
        $response['data']['taxf']       = $invoice->get_tax(true);
343
        $response['data']['discount']   = $invoice->get_discount();
344
        $response['data']['discountf']  = $invoice->get_discount(true);
345
        $response['data']['total']      = $invoice->get_total();
346
        $response['data']['totalf']     = $invoice->get_total(true);
347
        
348
        wpinv_set_checkout_session($checkout_session);
349
        
350
        wp_send_json( $response );
351
    }
352
    
353
    public static function create_invoice_item() {
354
        check_ajax_referer( 'invoice-item', '_nonce' );
355
        if ( !wpinv_current_user_can_manage_invoicing() ) {
356
            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...
357
        }
358
        
359
        $invoice_id = absint( $_POST['invoice_id'] );
360
361
        // Find the item
362
        if ( !is_numeric( $invoice_id ) ) {
363
            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...
364
        }        
365
        
366
        $invoice     = wpinv_get_invoice( $invoice_id );
367
        if ( empty( $invoice ) ) {
368
            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...
369
        }
370
        
371
        // Validate item before adding to invoice because recurring item must be paid individually.
372
        if ( !empty( $invoice->cart_details ) && $invoice->get_recurring() ) {
373
            $response               = array();
374
            $response['success']    = false;
375
            $response['msg']        = __( 'You can not add item because recurring item must be paid individually!', 'invoicing' );
376
            wp_send_json( $response );
377
        }        
378
        
379
        $save_item = wp_unslash( $_POST['_wpinv_quick'] );
380
        
381
        $meta               = array();
382
        $meta['type']       = !empty($save_item['type']) ? sanitize_text_field($save_item['type']) : 'custom';
383
        $meta['price']      = !empty($save_item['price']) ? wpinv_sanitize_amount( $save_item['price'] ) : 0;
384
        $meta['vat_rule']   = !empty($save_item['vat_rule']) ? sanitize_text_field($save_item['vat_rule']) : 'digital';
385
        $meta['vat_class']  = !empty($save_item['vat_class']) ? sanitize_text_field($save_item['vat_class']) : '_standard';
386
        
387
        $data                   = array();
388
        $data['post_title']     = sanitize_text_field($save_item['name']);
389
        $data['post_status']    = 'publish';
390
        $data['post_excerpt']   = ! empty( $save_item['excerpt'] ) ? wp_kses_post( $save_item['excerpt'] ) : '';
391
        $data['meta']           = $meta;
392
        
393
        $item = new WPInv_Item();
394
        $item->create( $data );
395
        
396
        if ( !empty( $item ) ) {
397
            $_POST['item_id']   = $item->ID;
398
            $_POST['qty']       = !empty($save_item['qty']) && $save_item['qty'] > 0 ? (int)$save_item['qty'] : 1;
399
            
400
            self::add_invoice_item();
401
        }
402
        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...
403
    }
404
405
    /**
406
     * Retrieves a given user's billing address.
407
     */
408
    public static function get_billing_details() {
409
410
        // Verify nonce.
411
        check_ajax_referer( 'wpinv-nonce' );
412
413
        // Can the user manage the plugin?
414
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
415
            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...
416
        }
417
418
        // Do we have a user id?
419
        $user_id = $_GET['user_id'];
420
421
        if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
422
            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...
423
        }
424
425
        // Fetch the billing details.
426
        $billing_details    = wpinv_get_user_address( $user_id );
427
        $billing_details    = apply_filters( 'wpinv_ajax_billing_details', $billing_details, $user_id );
428
429
        // unset the user id and email.
430
        $to_ignore = array( 'user_id', 'email' );
431
432
        foreach ( $to_ignore as $key ) {
433
            if ( isset( $billing_details[ $key ] ) ) {
434
                unset( $billing_details[ $key ] );
435
            }
436
        }
437
438
        wp_send_json_success( $billing_details );
439
440
    }
441
    
442
    public static function admin_recalculate_totals() {
443
        global $wpi_userID, $wpinv_ip_address_country;
444
        
445
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
446
        if ( !wpinv_current_user_can_manage_invoicing() ) {
447
            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...
448
        }
449
        
450
        $invoice_id = absint( $_POST['invoice_id'] );        
451
        $invoice    = wpinv_get_invoice( $invoice_id );
452
        if ( empty( $invoice ) ) {
453
            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...
454
        }
455
456
        $checkout_session = wpinv_get_checkout_session();
457
458
        $data                   = array();
459
        $data['invoice_id']     = $invoice_id;
460
        $data['cart_discounts'] = $invoice->get_discounts( true );
461
462
        wpinv_set_checkout_session( $data );
463
        
464
        if ( !empty( $_POST['user_id'] ) ) {
465
            $wpi_userID = absint( $_POST['user_id'] ); 
466
        }
467
        
468
        if ( empty( $_POST['country'] ) ) {
469
            $_POST['country'] = !empty($invoice->country) ? $invoice->country : wpinv_get_default_country();
470
        }
471
472
        $disable_taxes = 0;
473
        if ( ! empty( $_POST['disable_taxes'] ) ) {
474
            $disable_taxes = 1;
475
        }
476
        $invoice->set( 'disable_taxes', $disable_taxes );
477
478
        $invoice->country = sanitize_text_field( $_POST['country'] );
479
        $invoice->set( 'country', sanitize_text_field( $_POST['country'] ) );
480
        if ( isset( $_POST['state'] ) ) {
481
            $invoice->state = sanitize_text_field( $_POST['state'] );
482
            $invoice->set( 'state', sanitize_text_field( $_POST['state'] ) );
483
        }
484
        
485
        $wpinv_ip_address_country = $invoice->country;
486
        
487
        $invoice = $invoice->recalculate_totals(true);
488
        
489
        $response                       = array();
490
        $response['success']            = true;
491
        $response['data']['items']      = wpinv_admin_get_line_items( $invoice );
492
        $response['data']['subtotal']   = $invoice->get_subtotal();
493
        $response['data']['subtotalf']  = $invoice->get_subtotal(true);
494
        $response['data']['tax']        = $invoice->get_tax();
495
        $response['data']['taxf']       = $invoice->get_tax(true);
496
        $response['data']['discount']   = $invoice->get_discount();
497
        $response['data']['discountf']  = $invoice->get_discount(true);
498
        $response['data']['total']      = $invoice->get_total();
499
        $response['data']['totalf']     = $invoice->get_total(true);
500
        
501
        wpinv_set_checkout_session($checkout_session);
502
503
        wp_send_json( $response );
504
    }
505
    
506
    public static function admin_apply_discount() {
507
        global $wpi_userID;
508
        
509
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
510
        if ( !wpinv_current_user_can_manage_invoicing() ) {
511
            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...
512
        }
513
        
514
        $invoice_id = absint( $_POST['invoice_id'] );
515
        $discount_code = sanitize_text_field( $_POST['code'] );
516
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
517
            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...
518
        }
519
        
520
        $invoice = wpinv_get_invoice( $invoice_id );
521
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
522
            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...
523
        }
524
        
525
        $checkout_session = wpinv_get_checkout_session();
526
        
527
        $data                   = array();
528
        $data['invoice_id']     = $invoice_id;
529
        $data['cart_discounts'] = $invoice->get_discounts( true );
530
        
531
        wpinv_set_checkout_session( $data );
532
        
533
        $response               = array();
534
        $response['success']    = false;
535
        $response['msg']        = __( 'This discount is invalid.', 'invoicing' );
536
        $response['data']['code'] = $discount_code;
537
        
538
        if ( wpinv_is_discount_valid( $discount_code, $invoice->get_user_id() ) ) {
539
            $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...
540
            
541
            $response['success'] = true;
542
            $response['msg'] = __( 'Discount has been applied successfully.', 'invoicing' );
543
        }  else {
544
            $errors = wpinv_get_errors();
545
            if ( !empty( $errors['wpinv-discount-error'] ) ) {
546
                $response['msg'] = $errors['wpinv-discount-error'];
547
            }
548
            wpinv_unset_error( 'wpinv-discount-error' );
549
        }
550
        
551
        wpinv_set_checkout_session($checkout_session);
552
        
553
        wp_send_json( $response );
554
    }
555
    
556
    public static function admin_remove_discount() {
557
        global $wpi_userID;
558
        
559
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
560
        if ( !wpinv_current_user_can_manage_invoicing() ) {
561
            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...
562
        }
563
        
564
        $invoice_id = absint( $_POST['invoice_id'] );
565
        $discount_code = sanitize_text_field( $_POST['code'] );
566
        if ( empty( $invoice_id ) || empty( $discount_code ) ) {
567
            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...
568
        }
569
        
570
        $invoice = wpinv_get_invoice( $invoice_id );
571
        if ( empty( $invoice ) || ( !empty( $invoice ) && ( $invoice->is_paid() || $invoice->is_refunded() ) ) ) {
572
            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...
573
        }
574
        
575
        $checkout_session = wpinv_get_checkout_session();
576
        
577
        $data                   = array();
578
        $data['invoice_id']     = $invoice_id;
579
        $data['cart_discounts'] = $invoice->get_discounts( true );
580
        
581
        wpinv_set_checkout_session( $data );
582
        
583
        $response               = array();
584
        $response['success']    = false;
585
        $response['msg']        = NULL;
586
        
587
        $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...
588
        $response['success'] = true;
589
        $response['msg'] = __( 'Discount has been removed successfully.', 'invoicing' );
590
        
591
        wpinv_set_checkout_session($checkout_session);
592
        
593
        wp_send_json( $response );
594
    }
595
596
    /**
597
     * Checks if a new users email is valid.
598
     */
599
    public static function check_new_user_email() {
600
601
        // Verify nonce.
602
        check_ajax_referer( 'wpinv-nonce' );
603
604
        // Can the user manage the plugin?
605
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
606
            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...
607
        }
608
609
        // We need an email address.
610
        if ( empty( $_GET['email'] ) ) {
611
            _e( "Provide the new user's email address", 'invoicing' );
612
            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...
613
        }
614
615
        // Ensure the email is valid.
616
        $email = sanitize_text_field( $_GET['email'] );
617
        if ( ! is_email( $email ) ) {
618
            _e( 'Invalid email address', 'invoicing' );
619
            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...
620
        }
621
622
        // And it does not exist.
623
        if ( email_exists( $email ) ) {
624
            _e( 'A user with this email address already exists', 'invoicing' );
625
            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...
626
        }
627
628
        wp_send_json_success( true );
629
    }
630
    
631
    public static function run_tool() {
632
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
633
        if ( !wpinv_current_user_can_manage_invoicing() ) {
634
            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...
635
        }
636
        
637
        $tool = sanitize_text_field( $_POST['tool'] );
638
        
639
        do_action( 'wpinv_run_tool' );
640
        
641
        if ( !empty( $tool ) ) {
642
            do_action( 'wpinv_tool_' . $tool );
643
        }
644
    }
645
    
646
    public static function apply_discount() {
647
        global $wpi_userID;
648
        
649
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
650
        
651
        $response = array();
652
        
653
        if ( isset( $_POST['code'] ) ) {
654
            $discount_code = sanitize_text_field( $_POST['code'] );
655
656
            $response['success']        = false;
657
            $response['msg']            = '';
658
            $response['data']['code']   = $discount_code;
659
            
660
            $invoice = wpinv_get_invoice_cart();
661
            if ( empty( $invoice->ID ) ) {
662
                $response['msg'] = __( 'Invalid checkout request.', 'invoicing' );
663
                wp_send_json( $response );
664
            }
665
666
            $wpi_userID = $invoice->get_user_id();
667
668
            if ( wpinv_is_discount_valid( $discount_code, $wpi_userID ) ) {
669
                $discount       = wpinv_get_discount_by_code( $discount_code );
670
                $discounts      = wpinv_set_cart_discount( $discount_code );
671
                $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...
672
                $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...
673
                $cart_totals    = wpinv_recalculate_tax( true );
674
            
675
                if ( !empty( $cart_totals ) ) {
676
                    $response['success']        = true;
677
                    $response['data']           = $cart_totals;
678
                    $response['data']['code']   = $discount_code;
679
                } else {
680
                    $response['success']        = false;
681
                }
682
            } else {
683
                $errors = wpinv_get_errors();
684
                $response['msg']  = $errors['wpinv-discount-error'];
685
                wpinv_unset_error( 'wpinv-discount-error' );
686
            }
687
688
            // Allow for custom discount code handling
689
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
690
        }
691
        
692
        wp_send_json( $response );
693
    }
694
    
695
    public static function remove_discount() {
696
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
697
        
698
        $response = array();
699
        
700
        if ( isset( $_POST['code'] ) ) {
701
            $discount_code  = sanitize_text_field( $_POST['code'] );
702
            $discounts      = wpinv_unset_cart_discount( $discount_code );
703
            $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...
704
            $cart_totals    = wpinv_recalculate_tax( true );
705
            
706
            if ( !empty( $cart_totals ) ) {
707
                $response['success']        = true;
708
                $response['data']           = $cart_totals;
709
                $response['data']['code']   = $discount_code;
710
            } else {
711
                $response['success']        = false;
712
            }
713
            
714
            // Allow for custom discount code handling
715
            $response = apply_filters( 'wpinv_ajax_discount_response', $response );
716
        }
717
        
718
        wp_send_json( $response );
719
    }
720
721
    /**
722
     * Retrieves the markup for a payment form.
723
     */
724
    public static function get_payment_form() {
725
726
        // Check nonce.
727
        if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'], 'getpaid_ajax_form' ) ) {
728
            _e( 'Error: Reload the page and try again.', 'invoicing' );
729
            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...
730
        }
731
732
        // Is the request set up correctly?
733
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) ) {
734
			echo aui()->alert(
735
				array(
736
					'type'    => 'warning',
737
					'content' => __( 'No payment form or item provided', 'invoicing' ),
738
				)
739
            );
740
            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...
741
        }
742
743
        // Payment form or button?
744
		if ( ! empty( $_GET['form'] ) ) {
745
            echo getpaid_display_payment_form( $_GET['form'] );
746
		} else if( $_GET['invoice'] ) {
747
		    echo getpaid_display_invoice_payment_form( $_GET['invoice'] );
748
        } else {
749
			$items = getpaid_convert_items_to_array( $_GET['item'] );
750
		    echo getpaid_display_item_payment_form( $items );
751
        }
752
        
753
        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...
754
755
    }
756
757
    /**
758
     * Payment forms.
759
     *
760
     * @since 1.0.18
761
     */
762
    public static function payment_form() {
763
        global $invoicing, $wpi_checkout_id, $cart_total;
764
765
        // Check nonce.
766
        check_ajax_referer( 'getpaid_form_nonce' );
767
768
        // ... form fields...
769
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
770
            _e( 'Error: Reload the page and try again.', 'invoicing' );
771
            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...
772
        }
773
774
        // Load the submission.
775
        $submission = new GetPaid_Payment_Form_Submission();
776
777
        // Do we have an error?
778
        if ( ! empty( $submission->last_error ) ) {
779
            echo $submission->last_error;
780
            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...
781
        }
782
783
        // We need a billing email.
784
        if ( ! $submission->has_billing_email() || ! is_email( $submission->get_billing_email() ) ) {
785
            wp_send_json_error( __( 'Provide a valid billing email.', 'invoicing' ) );
786
        }
787
788
        // Prepare items.
789
        $items            = $submission->get_items();
790
        $prepared_items   = array();
791
792
        if ( ! empty( $items ) ) {
793
794
            foreach( $items as $item_id => $item ) {
795
796
                if ( $item->can_purchase() ) {
797
                    $prepared_items[] = array(
798
                        'id'           => $item_id,
799
                        'item_price'   => $item->get_price(),
800
                        'custom_price' => $item->get_price(),
801
                        'name'         => $item->get_name(),
802
                        'quantity'     => $item->get_quantity(),
803
                    );
804
                }
805
806
            }
807
808
        }
809
810
        if ( empty( $prepared_items ) ) {
811
            wp_send_json_error( __( 'You have not selected any items.', 'invoicing' ) );
812
        }
813
814
        if ( $submission->has_recurring && 1 != count( $prepared_items ) ) {
815
            wp_send_json_error( __( 'Recurring items should be bought individually.', 'invoicing' ) );
816
        }
817
818
        // Prepare the submission details.
819
        $prepared = array(
820
            'billing_email'                    => sanitize_email( $submission->get_billing_email() ),
821
            __( 'Billing Email', 'invoicing' ) => sanitize_email( $submission->get_billing_email() ),
822
            __( 'Form Id', 'invoicing' )       => absint( $submission->payment_form->get_id() ),
823
        );
824
825
        // Address fields.
826
        $address_fields = array();
827
828
        // Add discount code.
829
        if ( $submission->has_discount_code() ) {
830
            $address_fields['discount'] = array( $submission->get_discount_code() );
831
        }
832
833
        // Are all required fields provided?
834
        $data = $submission->get_data();
835
836
        foreach ( $submission->payment_form->get_elements() as $field ) {
837
838
            if ( ! empty( $field['premade'] ) ) {
839
                continue;
840
            }
841
842
            if ( ! $submission->is_required_field_set( $field ) ) {
843
                wp_send_json_error( __( 'Fill all required fields.', 'invoicing' ) );
844
            }
845
846
            if ( $field['type'] == 'address' ) {
847
848
                foreach ( $field['fields'] as $address_field ) {
849
850
                    if ( empty( $address_field['visible'] ) ) {
851
                        continue;
852
                    }
853
854
                    if ( ! empty( $address_field['required'] ) && empty( $data[ $address_field['name'] ] ) ) {
855
                        wp_send_json_error( __( 'Some required fields have not been filled.', 'invoicing' ) );
856
                    }
857
858
                    if ( isset( $data[ $address_field['name'] ] ) ) {
859
                        $label = str_replace( 'wpinv_', '', $address_field['name'] );
860
                        $address_fields[ $label ] = wpinv_clean( $data[ $address_field['name'] ] );
861
                    }
862
863
                }
864
865
            } else if ( isset( $data[ $field['id'] ] ) ) {
866
                $label = $field['id'];
867
868
                if ( isset( $field['label'] ) ) {
869
                    $label = $field['label'];
870
                }
871
872
                $prepared[ wpinv_clean( $label ) ] = wpinv_clean( $data[ $field['id'] ] );
873
            }
874
875
        }
876
877
        // (Maybe) create the user.
878
        $user = get_user_by( 'email', $prepared['billing_email'] );
879
880
        if ( empty( $user ) ) {
881
            $user = wpinv_create_user( $prepared['billing_email'] );
882
        }
883
884
        if ( is_wp_error( $user ) ) {
885
            wp_send_json_error( $user->get_error_message() );
886
        }
887
888
        if ( is_numeric( $user ) ) {
889
            $user = get_user_by( 'id', $user );
890
        }
891
892
        // Create the invoice.
893
        if ( ! $submission->has_invoice() ) {
894
895
            $invoice = wpinv_insert_invoice(
896
                array(
897
                    'status'        => 'wpi-pending',
898
                    'created_via'   => 'payment_form',
899
                    'user_id'       => $user->ID,
900
                    'cart_details'  => $prepared_items,
901
                    'user_info'     => $address_fields,
902
                ),
903
                true
904
            );
905
906
        } else {
907
908
            $invoice = $submission->get_invoice();
909
910
            if ( $invoice->is_paid() ) {
911
                wp_send_json_error( __( 'This invoice has already been paid for.', 'invoicing' ) );
912
            }
913
914
            $invoice = wpinv_update_invoice(
915
                array(
916
                    'ID'            => $submission->get_invoice()->ID,
917
                    'status'        => 'wpi-pending',
918
                    'cart_details'  => $prepared_items,
919
                    'user_info'     => $address_fields,
920
                ),
921
                true
922
            );
923
924
        }
925
926
        if ( is_wp_error( $invoice ) ) {
927
            wp_send_json_error( $invoice->get_error_message() );
928
        }
929
930
        if ( empty( $invoice ) ) {
931
            wp_send_json_error( __( 'Could not create your invoice.', 'invoicing' ) );
932
        }
933
934
        unset( $prepared['billing_email'] );
935
        update_post_meta( $invoice->ID, 'payment_form_data', $prepared );
936
937
        $wpi_checkout_id = $invoice->ID;
938
        $cart_total = wpinv_price(
939
            wpinv_format_amount(
940
                wpinv_get_cart_total( $invoice->get_cart_details(), NULL, $invoice ) ),
941
                $invoice->get_currency()
942
        );
943
944
        $data                   = array();
945
        $data['invoice_id']     = $invoice->ID;
946
        $data['cart_discounts'] = $invoice->get_discounts( true );
947
948
        wpinv_set_checkout_session( $data );
949
        add_filter( 'wp_redirect', array( $invoicing->form_elements, 'send_redirect_response' ) );
950
        add_action( 'wpinv_pre_send_back_to_checkout', array( $invoicing->form_elements, 'checkout_error' ) );
951
        
952
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
953
            define( 'WPINV_CHECKOUT', true );
954
        }
955
956
        wpinv_process_checkout();
957
958
        $invoicing->form_elements->checkout_error();
959
960
        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...
961
    }
962
963
    /**
964
     * Payment forms.
965
     *
966
     * @since 1.0.18
967
     */
968
    public static function get_payment_form_states_field() {
969
        global $invoicing;
970
971
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
972
            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...
973
        }
974
975
        $elements = $invoicing->form_elements->get_form_elements( $_GET['form'] );
976
977
        if ( empty( $elements ) ) {
978
            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...
979
        }
980
981
        $address_fields = array();
982
        foreach ( $elements as $element ) {
983
            if ( 'address' === $element['type'] ) {
984
                $address_fields = $element;
985
                break;
986
            }
987
        }
988
989
        if ( empty( $address_fields ) ) {
990
            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...
991
        }
992
993
        foreach( $address_fields['fields'] as $address_field ) {
994
995
            if ( 'wpinv_state' == $address_field['name'] ) {
996
997
                $label = $address_field['label'];
998
999
                if ( ! empty( $address_field['required'] ) ) {
1000
                    $label .= "<span class='text-danger'> *</span>";
1001
                }
1002
1003
                $states = wpinv_get_country_states( $_GET['country'] );
1004
1005
                if ( ! empty( $states ) ) {
1006
1007
                    $html = aui()->select(
1008
                            array(
1009
                                'options'          => $states,
1010
                                'name'             => esc_attr( $address_field['name'] ),
1011
                                'id'               => esc_attr( $address_field['name'] ),
1012
                                'placeholder'      => esc_attr( $address_field['placeholder'] ),
1013
                                'required'         => (bool) $address_field['required'],
1014
                                'no_wrap'          => true,
1015
                                'label'            => wp_kses_post( $label ),
1016
                                'select2'          => false,
1017
                            )
1018
                        );
1019
1020
                } else {
1021
1022
                    $html = aui()->input(
1023
                            array(
1024
                                'name'       => esc_attr( $address_field['name'] ),
1025
                                'id'         => esc_attr( $address_field['name'] ),
1026
                                'required'   => (bool) $address_field['required'],
1027
                                'label'      => wp_kses_post( $label ),
1028
                                'no_wrap'    => true,
1029
                                'type'       => 'text',
1030
                            )
1031
                        );
1032
1033
                }
1034
1035
                wp_send_json_success( str_replace( 'sr-only', '', $html ) );
1036
                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...
1037
1038
            }
1039
1040
        }
1041
    
1042
        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...
1043
    }
1044
1045
    /**
1046
     * Retrieves the states field for AUI forms.
1047
     */
1048
    public static function get_aui_states_field() {
1049
1050
        // Verify nonce.
1051
        check_ajax_referer( 'wpinv-nonce' );
1052
1053
        // We need a country.
1054
        if ( empty( $_GET['country'] ) ) {
1055
            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...
1056
        }
1057
1058
        $states = wpinv_get_country_states( trim( $_GET['country'] ) );
1059
        $state  = isset( $_GET['state'] ) ? trim( $_GET['state'] ) : wpinv_get_default_state();
1060
1061
        if ( empty( $states ) ) {
1062
1063
            $html = aui()->input(
1064
                array(
1065
                    'type'        => 'text',
1066
                    'id'          => 'wpinv_state',
1067
                    'name'        => 'wpinv_state',
1068
                    'label'       => __( 'State', 'invoicing' ),
1069
                    'label_type'  => 'vertical',
1070
                    'placeholder' => 'Liège',
1071
                    'class'       => 'form-control-sm',
1072
                    'value'       => $state,
1073
                )
1074
            );
1075
1076
        } else {
1077
1078
            $html = aui()->select(
1079
                array(
1080
                    'id'          => 'wpinv_state',
1081
                    'name'        => 'wpinv_state',
1082
                    'label'       => __( 'State', 'invoicing' ),
1083
                    'label_type'  => 'vertical',
1084
                    'placeholder' => __( 'Select a state', 'invoicing' ),
1085
                    'class'       => 'form-control-sm',
1086
                    'value'       => $state,
1087
                    'options'     => $states,
1088
                    'data-allow-clear' => 'false',
1089
                    'select2'          => true,
1090
                )
1091
            );
1092
1093
        }
1094
1095
        wp_send_json_success(
1096
            array(
1097
                'html'   => $html,
1098
                'select' => ! empty ( $states )
1099
            )
1100
        );
1101
1102
    }
1103
1104
    /**
1105
     * Refresh prices.
1106
     *
1107
     * @since 1.0.19
1108
     */
1109
    public static function payment_form_refresh_prices() {
1110
1111
        // Check nonce.
1112
        check_ajax_referer( 'getpaid_form_nonce' );
1113
1114
        // ... form fields...
1115
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
1116
            _e( 'Error: Reload the page and try again.', 'invoicing' );
1117
            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...
1118
        }
1119
1120
        // Load the submission.
1121
        $submission = new GetPaid_Payment_Form_Submission();
1122
1123
        // Do we have an error?
1124
        if ( ! empty( $submission->last_error ) ) {
1125
            echo $submission->last_error;
1126
            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...
1127
        }
1128
1129
        // Prepare the result.
1130
        $result = array(
1131
            'submission_id' => $submission->id,
1132
            'has_recurring' => $submission->has_recurring,
1133
            'is_free'       => $submission->get_payment_details(),
1134
            'totals'        => array(
1135
                'subtotal'  => wpinv_price( wpinv_format_amount( $submission->subtotal_amount ), $submission->get_currency() ),
1136
                'discount'  => wpinv_price( wpinv_format_amount( $submission->get_total_discount() ), $submission->get_currency() ),
1137
                'fees'      => wpinv_price( wpinv_format_amount( $submission->get_total_fees() ), $submission->get_currency() ),
1138
                'tax'       => wpinv_price( wpinv_format_amount( $submission->get_total_tax() ), $submission->get_currency() ),
1139
                'total'     => wpinv_price( wpinv_format_amount( $submission->get_total() ), $submission->get_currency() ),
1140
            ),
1141
        );
1142
1143
        // Add items.
1144
        $items = $submission->get_items();
1145
        if ( ! empty( $items ) ) {
1146
            $result['items'] = array();
1147
1148
            foreach( $items as $item_id => $item ) {
1149
                $result['items']["$item_id"] = wpinv_price( wpinv_format_amount( $item->get_price() * $item->get_qantity() ) );
1150
            }
1151
        }
1152
1153
        // Add invoice.
1154
        if ( $submission->has_invoice() ) {
1155
            $result['invoice'] = $submission->get_invoice()->ID;
1156
        }
1157
1158
        // Add discount code.
1159
        if ( $submission->has_discount_code() ) {
1160
            $result['discount_code'] = $submission->get_discount_code();
1161
        }
1162
1163
        // Filter the result.
1164
        $result = apply_filters( 'getpaid_payment_form_ajax_refresh_prices', $result, $submission );
1165
1166
        wp_send_json_success( $result );
1167
    }
1168
1169
    /**
1170
     * Lets users buy items via ajax.
1171
     *
1172
     * @since 1.0.0
1173
     */
1174
    public static function buy_items() {
1175
        $user_id = get_current_user_id();
1176
1177
        if ( empty( $user_id ) ) { // If not logged in then lets redirect to the login page
1178
            wp_send_json( array(
1179
                '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

1179
                'success' => wp_login_url( /** @scrutinizer ignore-type */ wp_get_referer() )
Loading history...
1180
            ) );
1181
        } else {
1182
            // Only check nonce if logged in as it could be cached when logged out.
1183
            if ( ! isset( $_POST['wpinv_buy_nonce'] ) || ! wp_verify_nonce( $_POST['wpinv_buy_nonce'], 'wpinv_buy_items' ) ) {
1184
                wp_send_json( array(
1185
                    'error' => __( 'Security checks failed.', 'invoicing' )
1186
                ) );
1187
                wp_die();
1188
            }
1189
1190
            // allow to set a custom price through post_id
1191
            $items = $_POST['items'];
1192
            $related_post_id = isset( $_POST['post_id'] ) ? (int)$_POST['post_id'] : 0;
1193
            $custom_item_price = $related_post_id ? abs( get_post_meta( $related_post_id, '_wpi_custom_price', true ) ) : 0;
1194
1195
            $cart_items = array();
1196
            if ( $items ) {
1197
                $items = explode( ',', $items );
1198
1199
                foreach( $items as $item ) {
1200
                    $item_id = $item;
1201
                    $quantity = 1;
1202
1203
                    if ( strpos( $item, '|' ) !== false ) {
1204
                        $item_parts = explode( '|', $item );
1205
                        $item_id = $item_parts[0];
1206
                        $quantity = $item_parts[1];
1207
                    }
1208
1209
                    if ( $item_id && $quantity ) {
1210
                        $cart_items_arr = array(
1211
                            'id'            => (int)$item_id,
1212
                            'quantity'      => (int)$quantity
1213
                        );
1214
1215
                        // If there is a related post id then add it to meta
1216
                        if ( $related_post_id ) {
1217
                            $cart_items_arr['meta'] = array(
1218
                                'post_id'   => $related_post_id
1219
                            );
1220
                        }
1221
1222
                        // If there is a custom price then set it.
1223
                        if ( $custom_item_price ) {
1224
                            $cart_items_arr['custom_price'] = $custom_item_price;
1225
                        }
1226
1227
                        $cart_items[] = $cart_items_arr;
1228
                    }
1229
                }
1230
            }
1231
1232
            /**
1233
             * Filter the wpinv_buy shortcode cart items on the fly.
1234
             *
1235
             * @param array $cart_items The cart items array.
1236
             * @param int $related_post_id The related post id if any.
1237
             * @since 1.0.0
1238
             */
1239
            $cart_items = apply_filters( 'wpinv_buy_cart_items', $cart_items, $related_post_id );
1240
1241
            // Make sure its not in the cart already, if it is then redirect to checkout.
1242
            $cart_invoice = wpinv_get_invoice_cart();
1243
1244
            if ( isset( $cart_invoice->items ) && !empty( $cart_invoice->items ) && !empty( $cart_items ) && serialize( $cart_invoice->items ) == serialize( $cart_items ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The property items does not exist on WPInv_Invoice. Since you implemented __get, consider adding a @property annotation.
Loading history...
1245
                wp_send_json( array(
1246
                    'success' =>  $cart_invoice->get_checkout_payment_url()
1247
                ) );
1248
                wp_die();
1249
            }
1250
1251
            // Check if user has invoice with same items waiting to be paid.
1252
            $user_invoices = wpinv_get_users_invoices( $user_id , 10 , false , 'wpi-pending' );
1253
            if ( !empty( $user_invoices ) ) {
1254
                foreach( $user_invoices as $user_invoice ) {
1255
                    $user_cart_details = array();
1256
                    $invoice  = wpinv_get_invoice( $user_invoice->ID );
1257
                    $cart_details = $invoice->get_cart_details();
1258
1259
                    if ( !empty( $cart_details ) ) {
1260
                        foreach ( $cart_details as $invoice_item ) {
1261
                            $ii_arr = array();
1262
                            $ii_arr['id'] = (int)$invoice_item['id'];
1263
                            $ii_arr['quantity'] = (int)$invoice_item['quantity'];
1264
1265
                            if (isset( $invoice_item['meta'] ) && !empty( $invoice_item['meta'] ) ) {
1266
                                $ii_arr['meta'] = $invoice_item['meta'];
1267
                            }
1268
1269
                            if ( isset( $invoice_item['custom_price'] ) && !empty( $invoice_item['custom_price'] ) ) {
1270
                                $ii_arr['custom_price'] = $invoice_item['custom_price'];
1271
                            }
1272
1273
                            $user_cart_details[] = $ii_arr;
1274
                        }
1275
                    }
1276
1277
                    if ( !empty( $user_cart_details ) && serialize( $cart_items ) == serialize( $user_cart_details ) ) {
1278
                        wp_send_json( array(
1279
                            'success' =>  $invoice->get_checkout_payment_url()
1280
                        ) );
1281
                        wp_die();
1282
                    }
1283
                }
1284
            }
1285
1286
            // Create invoice and send user to checkout
1287
            if ( !empty( $cart_items ) ) {
1288
                $invoice_data = array(
1289
                    'status'        =>  'wpi-pending',
1290
                    'created_via'   =>  'wpi',
1291
                    'user_id'       =>  $user_id,
1292
                    'cart_details'  =>  $cart_items,
1293
                );
1294
1295
                $invoice = wpinv_insert_invoice( $invoice_data, true );
1296
1297
                if ( !empty( $invoice ) && isset( $invoice->ID ) ) {
1298
                    wp_send_json( array(
1299
                        '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

1299
                        '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...
1300
                    ) );
1301
                } else {
1302
                    wp_send_json( array(
1303
                        'error' => __( 'Invoice failed to create', 'invoicing' )
1304
                    ) );
1305
                }
1306
            } else {
1307
                wp_send_json( array(
1308
                    'error' => __( 'Items not valid.', 'invoicing' )
1309
                ) );
1310
            }
1311
        }
1312
1313
        wp_die();
1314
    }
1315
}
1316
1317
WPInv_Ajax::init();