Passed
Push — master ( 6929e7...c24352 )
by Brian
10:18 queued 05:36
created

WPInv_Ajax::ip_geolocation()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 45
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
c 0
b 0
f 0
dl 0
loc 45
rs 8.9617
cc 6
nc 6
nop 0
1
<?php
2
/**
3
 * Contains the ajax handlers.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * WPInv_Ajax class.
13
 */
14
class WPInv_Ajax {
15
16
    /**
17
	 * Hook in ajax handlers.
18
	 */
19
	public static function init() {
20
		add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 );
21
		add_action( 'template_redirect', array( __CLASS__, 'do_wpinv_ajax' ), 0 );
22
		self::add_ajax_events();
23
    }
24
25
    /**
26
	 * Set GetPaid AJAX constant and headers.
27
	 */
28
	public static function define_ajax() {
29
30
		if ( ! empty( $_GET['wpinv-ajax'] ) ) {
31
			getpaid_maybe_define_constant( 'DOING_AJAX', true );
32
			getpaid_maybe_define_constant( 'WPInv_DOING_AJAX', true );
33
			if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) {
34
				/** @scrutinizer ignore-unhandled */ @ini_set( 'display_errors', 0 );
35
			}
36
			$GLOBALS['wpdb']->hide_errors();
37
		}
38
39
    }
40
    
41
    /**
42
	 * Send headers for GetPaid Ajax Requests.
43
	 *
44
	 * @since 1.0.18
45
	 */
46
	private static function wpinv_ajax_headers() {
47
		if ( ! headers_sent() ) {
48
			send_origin_headers();
49
			send_nosniff_header();
50
			nocache_headers();
51
			header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
52
			header( 'X-Robots-Tag: noindex' );
53
			status_header( 200 );
54
		}
55
    }
56
    
57
    /**
58
	 * Check for GetPaid Ajax request and fire action.
59
	 */
60
	public static function do_wpinv_ajax() {
61
		global $wp_query;
62
63
		if ( ! empty( $_GET['wpinv-ajax'] ) ) {
64
			$wp_query->set( 'wpinv-ajax', sanitize_text_field( wp_unslash( $_GET['wpinv-ajax'] ) ) );
0 ignored issues
show
Bug introduced by
It seems like wp_unslash($_GET['wpinv-ajax']) can also be of type string[]; however, parameter $str of sanitize_text_field() 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

64
			$wp_query->set( 'wpinv-ajax', sanitize_text_field( /** @scrutinizer ignore-type */ wp_unslash( $_GET['wpinv-ajax'] ) ) );
Loading history...
65
		}
66
67
		$action = $wp_query->get( 'wpinv-ajax' );
68
69
		if ( $action ) {
70
			self::wpinv_ajax_headers();
71
			$action = sanitize_text_field( $action );
72
			do_action( 'wpinv_ajax_' . $action );
73
			wp_die();
74
		}
75
76
    }
77
78
    /**
79
	 * Hook in ajax methods.
80
	 */
81
    public static function add_ajax_events() {
82
83
        // array( 'event' => is_frontend )
84
        $ajax_events = array(
85
            'add_note'                    => false,
86
            'delete_note'                 => false,
87
            'get_states_field'            => true,
88
            'get_aui_states_field'        => true,
89
            'checkout'                    => false,
90
            'payment_form'                => true,
91
            'get_payment_form'            => true,
92
            'get_payment_form_states_field' => true,
93
            'get_invoicing_items'         => false,
94
            'get_invoice_items'           => false,
95
            'add_invoice_items'           => false,
96
            'edit_invoice_item'           => false,
97
            'get_billing_details'         => false,
98
            'recalculate_invoice_totals'  => false,
99
            'check_new_user_email'        => false,
100
            'run_tool'                    => false,
101
            'buy_items'                   => true,
102
            'payment_form_refresh_prices' => true,
103
            'ip_geolocation'              => true,
104
        );
105
106
        foreach ( $ajax_events as $ajax_event => $nopriv ) {
107
            add_action( 'wp_ajax_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
108
            add_action( 'wp_ajax_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
109
110
            if ( $nopriv ) {
111
                add_action( 'wp_ajax_nopriv_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
112
                add_action( 'wp_ajax_nopriv_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
113
                add_action( 'wpinv_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
114
            }
115
        }
116
    }
117
    
118
    public static function add_note() {
119
        check_ajax_referer( 'add-invoice-note', '_nonce' );
120
121
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
122
            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...
123
        }
124
125
        $post_id   = absint( $_POST['post_id'] );
126
        $note      = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
127
        $note_type = sanitize_text_field( $_POST['note_type'] );
128
129
        $is_customer_note = $note_type == 'customer' ? 1 : 0;
130
131
        if ( $post_id > 0 ) {
132
            $note_id = wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_insert_payment_note() has been deprecated. ( Ignorable by Annotation )

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

132
            $note_id = /** @scrutinizer ignore-deprecated */ wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
Loading history...
133
134
            if ( $note_id > 0 && !is_wp_error( $note_id ) ) {
135
                wpinv_get_invoice_note_line_item( $note_id );
136
            }
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 delete_note() {
143
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
144
145
        if ( !wpinv_current_user_can_manage_invoicing() ) {
146
            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...
147
        }
148
149
        $note_id = (int)$_POST['note_id'];
150
151
        if ( $note_id > 0 ) {
152
            wp_delete_comment( $note_id, true );
153
        }
154
155
        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...
156
    }
157
    
158
    public static function get_states_field() {
159
        echo wpinv_get_states_field();
160
        
161
        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...
162
    }
163
    
164
    public static function checkout() {
165
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
166
            define( 'WPINV_CHECKOUT', true );
167
        }
168
169
        wpinv_process_checkout();
170
        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...
171
    }
172
173
    /**
174
     * Retrieves a given user's billing address.
175
     */
176
    public static function get_billing_details() {
177
178
        // Verify nonce.
179
        check_ajax_referer( 'wpinv-nonce' );
180
181
        // Can the user manage the plugin?
182
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
183
            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...
184
        }
185
186
        // Do we have a user id?
187
        $user_id = $_GET['user_id'];
188
189
        if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
190
            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...
191
        }
192
193
        // Fetch the billing details.
194
        $billing_details    = wpinv_get_user_address( $user_id );
195
        $billing_details    = apply_filters( 'wpinv_ajax_billing_details', $billing_details, $user_id );
196
197
        // unset the user id and email.
198
        $to_ignore = array( 'user_id', 'email' );
199
200
        foreach ( $to_ignore as $key ) {
201
            if ( isset( $billing_details[ $key ] ) ) {
202
                unset( $billing_details[ $key ] );
203
            }
204
        }
205
206
        wp_send_json_success( $billing_details );
207
208
    }
209
210
    /**
211
     * Checks if a new users email is valid.
212
     */
213
    public static function check_new_user_email() {
214
215
        // Verify nonce.
216
        check_ajax_referer( 'wpinv-nonce' );
217
218
        // Can the user manage the plugin?
219
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
220
            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...
221
        }
222
223
        // We need an email address.
224
        if ( empty( $_GET['email'] ) ) {
225
            _e( "Provide the new user's email address", 'invoicing' );
226
            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...
227
        }
228
229
        // Ensure the email is valid.
230
        $email = sanitize_text_field( $_GET['email'] );
231
        if ( ! is_email( $email ) ) {
232
            _e( 'Invalid email address', 'invoicing' );
233
            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...
234
        }
235
236
        // And it does not exist.
237
        if ( email_exists( $email ) ) {
238
            _e( 'A user with this email address already exists', 'invoicing' );
239
            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...
240
        }
241
242
        wp_send_json_success( true );
243
    }
244
    
245
    public static function run_tool() {
246
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
247
        if ( !wpinv_current_user_can_manage_invoicing() ) {
248
            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...
249
        }
250
        
251
        $tool = sanitize_text_field( $_POST['tool'] );
252
        
253
        do_action( 'wpinv_run_tool' );
254
        
255
        if ( !empty( $tool ) ) {
256
            do_action( 'wpinv_tool_' . $tool );
257
        }
258
    }
259
260
    /**
261
     * Retrieves the markup for a payment form.
262
     */
263
    public static function get_payment_form() {
264
265
        // Check nonce.
266
        if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'], 'getpaid_ajax_form' ) ) {
267
            _e( 'Error: Reload the page and try again.', 'invoicing' );
268
            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...
269
        }
270
271
        // Is the request set up correctly?
272
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) ) {
273
			echo aui()->alert(
274
				array(
275
					'type'    => 'warning',
276
					'content' => __( 'No payment form or item provided', 'invoicing' ),
277
				)
278
            );
279
            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...
280
        }
281
282
        // Payment form or button?
283
		if ( ! empty( $_GET['form'] ) ) {
284
            echo getpaid_display_payment_form( $_GET['form'] );
0 ignored issues
show
Bug introduced by
Are you sure the usage of getpaid_display_payment_form($_GET['form']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
285
		} else if( $_GET['invoice'] ) {
286
		    echo getpaid_display_invoice_payment_form( $_GET['invoice'] );
287
        } else {
288
			$items = getpaid_convert_items_to_array( $_GET['item'] );
289
		    echo getpaid_display_item_payment_form( $items );
290
        }
291
        
292
        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...
293
294
    }
295
296
    /**
297
     * Payment forms.
298
     *
299
     * @since 1.0.18
300
     */
301
    public static function payment_form() {
302
        global $invoicing, $wpi_checkout_id, $cart_total;
303
304
        // Check nonce.
305
        check_ajax_referer( 'getpaid_form_nonce' );
306
307
        // ... form fields...
308
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
309
            _e( 'Error: Reload the page and try again.', 'invoicing' );
310
            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...
311
        }
312
313
        // Load the submission.
314
        $submission = new GetPaid_Payment_Form_Submission();
315
316
        // Do we have an error?
317
        if ( ! empty( $submission->last_error ) ) {
318
            echo $submission->last_error;
319
            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...
320
        }
321
322
        // We need a billing email.
323
        if ( ! $submission->has_billing_email() || ! is_email( $submission->get_billing_email() ) ) {
324
            wp_send_json_error( __( 'Provide a valid billing email.', 'invoicing' ) );
325
        }
326
327
        // Prepare items.
328
        $items = $submission->get_items();
329
330
        // Ensure that we have items.
331
        if ( empty( $items ) ) {
332
            wp_send_json_error( __( 'You have not selected any items.', 'invoicing' ) );
333
        }
334
335
        // Prepare the invoice.
336
        if ( ! $submission->has_invoice() ) {
337
            $invoice = new WPInv_Invoice();
338
        } else {
339
            $invoice = $submission->get_invoice();
340
        }
341
342
        // Make sure that it is neither paid or refunded.
343
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
344
            wp_send_json_error( __( 'This invoice has already been paid for.', 'invoicing' ) );
345
        }
346
347
        // Set the billing email.
348
        $invoice->set_email( sanitize_email( $submission->get_billing_email() ) );
349
350
        // Payment form.
351
        $invoice->set_payment_form( absint( $submission->get_payment_form()->get_id() ) );
352
353
        // Discount code.
354
        if ( $submission->has_discount_code() ) {
355
            $invoice->set_discount_code( $submission->get_discount_code() );
356
        }
357
358
        // Items, Fees, taxes and discounts.
359
        $invoice->set_items( $items );
360
        $invoice->set_fees( $submission->get_fees() );
361
        $invoice->set_taxes( $submission->get_taxes() );
362
        $invoice->set_discounts( $submission->get_discounts() );
363
364
        // Prepared submission details.
365
        $prepared = array();
366
367
        // Raw submission details.
368
        $data = $submission->get_data();
369
370
        // Loop throught the submitted details.
371
        foreach ( $submission->payment_form->get_elements() as $field ) {
372
373
            if ( ! empty( $field['premade'] ) ) {
374
                continue;
375
            }
376
377
            // If it is required and not set, abort.
378
            if ( ! $submission->is_required_field_set( $field ) ) {
379
                wp_send_json_error( __( 'Some required fields are not set.', 'invoicing' ) );
380
            }
381
382
            // Handle address fields.
383
            if ( $field['type'] == 'address' ) {
384
385
                foreach ( $field['fields'] as $address_field ) {
386
387
                    // skip if it is not visible.
388
                    if ( empty( $address_field['visible'] ) ) {
389
                        continue;
390
                    }
391
392
                    // If it is required and not set, abort
393
                    if ( ! empty( $address_field['required'] ) && empty( $data[ $address_field['name'] ] ) ) {
394
                        wp_send_json_error( __( 'Some required fields are not set.', 'invoicing' ) );
395
                    }
396
397
                    if ( isset( $data[ $address_field['name'] ] ) ) {
398
                        $name   = str_replace( 'wpinv_', '', $address_field['name'] );
399
                        $method = "set_$name";
400
                        $invoice->$method( wpinv_clean( $data[ $address_field['name'] ] ) );
401
                    }
402
403
                }
404
405
            } else if ( isset( $data[ $field['id'] ] ) ) {
406
                $label = $field['id'];
407
408
                if ( isset( $field['label'] ) ) {
409
                    $label = $field['label'];
410
                }
411
412
                $prepared[ wpinv_clean( $label ) ] = wpinv_clean( $data[ $field['id'] ] );
413
            }
414
415
        }
416
417
        // (Maybe) create the user.
418
        $user = get_current_user_id();
419
420
        if ( empty( $user ) ) {
421
            $user = get_user_by( 'email', $submission->get_billing_email() );
422
        }
423
424
        if ( empty( $user ) ) {
425
            $user = wpinv_create_user( $submission->get_billing_email() );
426
        }
427
428
        if ( is_wp_error( $user ) ) {
429
            wp_send_json_error( $user->get_error_message() );
430
        }
431
432
        if ( is_numeric( $user ) ) {
433
            $user = get_user_by( 'id', $user );
434
        }
435
436
        $invoice->set_user_id( $user->ID );
437
438
        $invoice->recalculate_total();
439
440
        // Save the invoice.
441
        $invoice->save();
442
443
        // Was it saved successfully:
444
        if ($invoice->get_id() == 0 ) {
445
            wp_send_json_error( __( 'An error occured while saving your invoice.', 'invoicing' ) );
446
        }
447
448
        // Save payment form data.
449
        update_post_meta( $invoice->get_id(), 'payment_form_data', $prepared );
450
451
        // Backwards compatibility.
452
        $wpi_checkout_id = $invoice->get_id();
453
        $cart_total      = wpinv_price(
454
            wpinv_format_amount( $invoice->get_total() ),
455
            $invoice->get_currency()
456
        );
457
458
        $data                   = array();
459
        $data['invoice_id']     = $invoice->get_id();
460
        $data['cart_discounts'] = array ( $invoice->get_discount_code() );
461
462
        wpinv_set_checkout_session( $data );
0 ignored issues
show
Unused Code introduced by
The call to wpinv_set_checkout_session() has too many arguments starting with $data. ( Ignorable by Annotation )

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

462
        /** @scrutinizer ignore-call */ 
463
        wpinv_set_checkout_session( $data );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Deprecated Code introduced by
The function wpinv_set_checkout_session() has been deprecated. ( Ignorable by Annotation )

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

462
        /** @scrutinizer ignore-deprecated */ wpinv_set_checkout_session( $data );
Loading history...
463
        add_filter( 'wp_redirect', array( $invoicing->form_elements, 'send_redirect_response' ) );
464
        add_action( 'wpinv_pre_send_back_to_checkout', array( $invoicing->form_elements, 'checkout_error' ) );
465
466
        if ( ! defined( 'WPINV_CHECKOUT' ) ) {
467
            define( 'WPINV_CHECKOUT', true );
468
        }
469
470
        wpinv_process_checkout( $invoice, $submission->get_data() );
0 ignored issues
show
Unused Code introduced by
The call to wpinv_process_checkout() has too many arguments starting with $invoice. ( Ignorable by Annotation )

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

470
        /** @scrutinizer ignore-call */ 
471
        wpinv_process_checkout( $invoice, $submission->get_data() );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
471
472
        $invoicing->form_elements->checkout_error();
473
474
        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...
475
    }
476
477
    /**
478
     * Payment forms.
479
     *
480
     * @since 1.0.18
481
     */
482
    public static function get_payment_form_states_field() {
483
        global $invoicing;
484
485
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
486
            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...
487
        }
488
489
        $elements = $invoicing->form_elements->get_form_elements( $_GET['form'] );
490
491
        if ( empty( $elements ) ) {
492
            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...
493
        }
494
495
        $address_fields = array();
496
        foreach ( $elements as $element ) {
497
            if ( 'address' === $element['type'] ) {
498
                $address_fields = $element;
499
                break;
500
            }
501
        }
502
503
        if ( empty( $address_fields ) ) {
504
            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...
505
        }
506
507
        foreach( $address_fields['fields'] as $address_field ) {
508
509
            if ( 'wpinv_state' == $address_field['name'] ) {
510
511
                $label = $address_field['label'];
512
513
                if ( ! empty( $address_field['required'] ) ) {
514
                    $label .= "<span class='text-danger'> *</span>";
515
                }
516
517
                $states = wpinv_get_country_states( $_GET['country'] );
518
519
                if ( ! empty( $states ) ) {
520
521
                    $html = aui()->select(
522
                            array(
523
                                'options'          => $states,
524
                                'name'             => esc_attr( $address_field['name'] ),
525
                                'id'               => esc_attr( $address_field['name'] ),
526
                                'placeholder'      => esc_attr( $address_field['placeholder'] ),
527
                                'required'         => (bool) $address_field['required'],
528
                                'no_wrap'          => true,
529
                                'label'            => wp_kses_post( $label ),
530
                                'select2'          => false,
531
                            )
532
                        );
533
534
                } else {
535
536
                    $html = aui()->input(
537
                            array(
538
                                'name'       => esc_attr( $address_field['name'] ),
539
                                'id'         => esc_attr( $address_field['name'] ),
540
                                'required'   => (bool) $address_field['required'],
541
                                'label'      => wp_kses_post( $label ),
542
                                'no_wrap'    => true,
543
                                'type'       => 'text',
544
                            )
545
                        );
546
547
                }
548
549
                wp_send_json_success( str_replace( 'sr-only', '', $html ) );
550
                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...
551
552
            }
553
554
        }
555
    
556
        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...
557
    }
558
559
    /**
560
     * Recalculates invoice totals.
561
     */
562
    public static function recalculate_invoice_totals() {
563
564
        // Verify nonce.
565
        check_ajax_referer( 'wpinv-nonce' );
566
567
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
568
            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...
569
        }
570
571
        // We need an invoice.
572
        if ( empty( $_POST['post_id'] ) ) {
573
            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...
574
        }
575
576
        // Fetch the invoice.
577
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
578
579
        // Ensure it exists.
580
        if ( ! $invoice->get_id() ) {
581
            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...
582
        }
583
584
        // Maybe set the country, state, currency.
585
        foreach ( array( 'country', 'state', 'currency' ) as $key ) {
586
            if ( isset( $_POST[ $key ] ) ) {
587
                $method = "set_$key";
588
                $invoice->$method( $_POST[ $key ] );
589
            }
590
        }
591
592
        // Maybe disable taxes.
593
        $invoice->set_disable_taxes( ! empty( $_POST['taxes'] ) );
594
595
        // Recalculate totals.
596
        $invoice->recalculate_total();
597
598
        $totals = array(
599
            'subtotal' => wpinv_price( wpinv_format_amount( $invoice->get_subtotal() ) ),
600
            'discount' => wpinv_price( wpinv_format_amount( $invoice->get_total_discount() ) ),
601
            'tax'      => wpinv_price( wpinv_format_amount( $invoice->get_total_tax() ) ),
602
            'total'    => wpinv_price( wpinv_format_amount( $invoice->get_total() ) ),
603
        );
604
605
        $totals = apply_filters( 'getpaid_invoice_totals', $totals, $invoice );
606
607
        wp_send_json_success( compact( 'totals' ) );
608
    }
609
610
    /**
611
     * Get items belonging to a given invoice.
612
     */
613
    public static function get_invoice_items() {
614
615
        // Verify nonce.
616
        check_ajax_referer( 'wpinv-nonce' );
617
618
        if ( ! wpinv_current_user_can_manage_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
        // We need an invoice and items.
623
        if ( empty( $_POST['post_id'] ) ) {
624
            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...
625
        }
626
627
        // Fetch the invoice.
628
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
629
630
        // Ensure it exists.
631
        if ( ! $invoice->get_id() ) {
632
            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...
633
        }
634
635
        // Return an array of invoice items.
636
        $items = array();
637
638
        foreach ( $invoice->get_items() as $item_id => $item ) {
639
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax();
640
        }
641
642
        wp_send_json_success( compact( 'items' ) );
643
    }
644
645
    /**
646
     * Edits an invoice item.
647
     */
648
    public static function edit_invoice_item() {
649
650
        // Verify nonce.
651
        check_ajax_referer( 'wpinv-nonce' );
652
653
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
654
            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...
655
        }
656
657
        // We need an invoice and item details.
658
        if ( empty( $_POST['post_id'] ) || empty( $_POST['data'] ) ) {
659
            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...
660
        }
661
662
        // Fetch the invoice.
663
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
664
665
        // Ensure it exists and its not been paid for.
666
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
667
            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...
668
        }
669
670
        // Format the data.
671
        $data = wp_list_pluck( $_POST['data'], 'value', 'field' );
672
673
        // Ensure that we have an item id.
674
        if ( empty( $data['id'] ) ) {
675
            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...
676
        }
677
678
        // Abort if the invoice does not have the specified item.
679
        $item = $invoice->get_item( (int) $data['id'] );
680
681
        if ( empty( $item ) ) {
682
            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...
683
        }
684
685
        // Update the item.
686
        $item->set_price( $data['price'] );
687
        $item->set_name( $data['name'] );
688
        $item->set_description( $data['description'] );
689
        $item->set_quantity( $data['quantity'] );
690
691
        // Add it to the invoice.
692
        $invoice->add_item( $item );
693
694
        // Update totals.
695
        $invoice->recalculate_total();
696
697
        // Save the invoice.
698
        $invoice->save();
699
700
        // Return an array of invoice items.
701
        $items = array();
702
703
        foreach ( $invoice->get_items() as $item_id => $item ) {
704
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax();
705
        }
706
707
        wp_send_json_success( compact( 'items' ) );
708
    }
709
    /**
710
     * Adds a items to an invoice.
711
     */
712
    public static function add_invoice_items() {
713
714
        // Verify nonce.
715
        check_ajax_referer( 'wpinv-nonce' );
716
717
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
718
            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...
719
        }
720
721
        // We need an invoice and items.
722
        if ( empty( $_POST['post_id'] ) || empty( $_POST['items'] ) ) {
723
            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...
724
        }
725
726
        // Fetch the invoice.
727
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
728
        $alert   = false;
729
730
        // Ensure it exists and its not been paid for.
731
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
732
            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...
733
        }
734
735
        // Add the items.
736
        foreach ( $_POST['items'] as $data ) {
737
738
            $item = new GetPaid_Form_Item( $data[ 'id' ] );
739
740
            if ( is_numeric( $data[ 'qty' ] ) && (int) $data[ 'qty' ] > 0 ) {
741
                $item->set_quantity( $data[ 'qty' ] );
742
            }
743
744
            if ( $item->get_id() > 0 ) {
745
                if ( ! $invoice->add_item( $item ) ) {
746
                    $alert = __( 'An invoice can only contain one recurring item', 'invoicing' );
747
                }
748
            }
749
750
        }
751
752
        // Save the invoice.
753
        $invoice->recalculate_total();
754
        $invoice->save();
755
756
        // Return an array of invoice items.
757
        $items = array();
758
759
        foreach ( $invoice->get_items() as $item_id => $item ) {
760
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax();
761
        }
762
763
        wp_send_json_success( compact( 'items', 'alert' ) );
764
    }
765
766
    /**
767
     * Retrieves items that should be added to an invoice.
768
     */
769
    public static function get_invoicing_items() {
770
771
        // Verify nonce.
772
        check_ajax_referer( 'wpinv-nonce' );
773
774
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
775
            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...
776
        }
777
778
        // We need a search term.
779
        if ( empty( $_GET['search'] ) ) {
780
            wp_send_json_success( array() );
781
        }
782
783
        // Retrieve items.
784
        $item_args = array(
785
            'post_type'      => 'wpi_item',
786
            'orderby'        => 'title',
787
            'order'          => 'ASC',
788
            'posts_per_page' => -1,
789
            'post_status'    => array( 'publish' ),
790
            's'              => trim( $_GET['search'] ),
791
            'meta_query'     => array(
792
                array(
793
                    'key'       => '_wpinv_type',
794
                    'compare'   => '!=',
795
                    'value'     => 'package'
796
                )
797
            )
798
        );
799
800
        $items = get_posts( apply_filters( 'getpaid_ajax_invoice_items_query_args', $item_args ) );
801
        $data  = array();
802
803
        foreach ( $items as $item ) {
804
            $item      = new GetPaid_Form_Item( $item );
805
            $data[] = array(
806
                'id'   => $item->get_id(),
807
                'text' => $item->get_name()
808
            );
809
        }
810
811
        wp_send_json_success( $data );
812
813
    }
814
815
    /**
816
     * Retrieves the states field for AUI forms.
817
     */
818
    public static function get_aui_states_field() {
819
820
        // Verify nonce.
821
        check_ajax_referer( 'wpinv-nonce' );
822
823
        // We need a country.
824
        if ( empty( $_GET['country'] ) ) {
825
            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...
826
        }
827
828
        $states = wpinv_get_country_states( trim( $_GET['country'] ) );
829
        $state  = isset( $_GET['state'] ) ? trim( $_GET['state'] ) : wpinv_get_default_state();
830
831
        if ( empty( $states ) ) {
832
833
            $html = aui()->input(
834
                array(
835
                    'type'        => 'text',
836
                    'id'          => 'wpinv_state',
837
                    'name'        => 'wpinv_state',
838
                    'label'       => __( 'State', 'invoicing' ),
839
                    'label_type'  => 'vertical',
840
                    'placeholder' => 'Liège',
841
                    'class'       => 'form-control-sm',
842
                    'value'       => $state,
843
                )
844
            );
845
846
        } else {
847
848
            $html = aui()->select(
849
                array(
850
                    'id'          => 'wpinv_state',
851
                    'name'        => 'wpinv_state',
852
                    'label'       => __( 'State', 'invoicing' ),
853
                    'label_type'  => 'vertical',
854
                    'placeholder' => __( 'Select a state', 'invoicing' ),
855
                    'class'       => 'form-control-sm',
856
                    'value'       => $state,
857
                    'options'     => $states,
858
                    'data-allow-clear' => 'false',
859
                    'select2'          => true,
860
                )
861
            );
862
863
        }
864
865
        wp_send_json_success(
866
            array(
867
                'html'   => $html,
868
                'select' => ! empty ( $states )
869
            )
870
        );
871
872
    }
873
874
    /**
875
     * IP geolocation.
876
     *
877
     * @since 1.0.19
878
     */
879
    public static function ip_geolocation() {
880
881
        // Check nonce.
882
        check_ajax_referer( 'getpaid-ip-location' );
883
884
        // IP address.
885
        if ( empty( $_GET['ip'] ) || ! rest_is_ip_address( $_GET['ip'] ) ) {
886
            _e( 'Invalid IP Address.', 'invoicing' );
887
            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...
888
        }
889
890
        // Retrieve location info.
891
        $location = getpaid_geolocate_ip_address( $_GET['ip'] );
892
893
        if ( empty( $location ) ) {
894
            _e( 'Unable to find geolocation for the IP Address.', 'invoicing' );
895
            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...
896
        }
897
898
        // Sorry.
899
        extract( $location );
900
901
        // Prepare the address.
902
        $content = '';
903
904
        if ( ! empty( $location['city'] ) ) {
905
            $content .=  $location['city']  . ', ';
906
        }
907
        
908
        if ( ! empty( $location['region'] ) ) {
909
            $content .=  $location['region']  . ', ';
910
        }
911
        
912
        $content .=  $location['country'] . ' (' . $location['iso'] . ')';
913
914
        $location['address'] = $content;
915
916
        $content  = '<p>'. sprintf( __( '<b>Address:</b> %s', 'invoicing' ), $content ) . '</p>';
917
        $content .= '<p>'. $location['credit'] . '</p>';
918
919
        $location['content'] = $content;
920
921
        wpinv_get_template( 'geolocation.php', $location );
922
923
        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...
924
    }
925
926
    /**
927
     * Refresh prices.
928
     *
929
     * @since 1.0.19
930
     */
931
    public static function payment_form_refresh_prices() {
932
933
        // Check nonce.
934
        check_ajax_referer( 'getpaid_form_nonce' );
935
936
        // ... form fields...
937
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
938
            _e( 'Error: Reload the page and try again.', 'invoicing' );
939
            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...
940
        }
941
942
        // Load the submission.
943
        $submission = new GetPaid_Payment_Form_Submission();
944
945
        // Do we have an error?
946
        if ( ! empty( $submission->last_error ) ) {
947
            echo $submission->last_error;
948
            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...
949
        }
950
951
        // Prepare the result.
952
        $result = array(
953
954
            'submission_id' => $submission->id,
955
            'has_recurring' => $submission->has_recurring,
956
            'is_free'       => $submission->get_payment_details(),
957
958
            'totals'        => array(
959
                'subtotal'  => wpinv_price( wpinv_format_amount( $submission->subtotal_amount ), $submission->get_currency() ),
960
                'discount'  => wpinv_price( wpinv_format_amount( $submission->get_total_discount() ), $submission->get_currency() ),
961
                'fees'      => wpinv_price( wpinv_format_amount( $submission->get_total_fees() ), $submission->get_currency() ),
962
                'tax'       => wpinv_price( wpinv_format_amount( $submission->get_total_tax() ), $submission->get_currency() ),
963
                'total'     => wpinv_price( wpinv_format_amount( $submission->get_total() ), $submission->get_currency() ),
964
            ),
965
966
            'texts'         => array(
967
                '.getpaid-checkout-total-payable' => wpinv_price( wpinv_format_amount( $submission->get_total() ), $submission->get_currency() ),
968
            )
969
970
        );
971
972
        // Add items.
973
        $items = $submission->get_items();
974
        if ( ! empty( $items ) ) {
975
            $result['items'] = array();
976
977
            foreach( $items as $item_id => $item ) {
978
                $result['items']["$item_id"] = wpinv_price( wpinv_format_amount( $item->get_price() * $item->get_quantity() ) );
979
            }
980
        }
981
982
        // Add invoice.
983
        if ( $submission->has_invoice() ) {
984
            $result['invoice'] = $submission->get_invoice()->ID;
985
        }
986
987
        // Add discount code.
988
        if ( $submission->has_discount_code() ) {
989
            $result['discount_code'] = $submission->get_discount_code();
990
        }
991
992
        // Filter the result.
993
        $result = apply_filters( 'getpaid_payment_form_ajax_refresh_prices', $result, $submission );
994
995
        wp_send_json_success( $result );
996
    }
997
998
    /**
999
     * Lets users buy items via ajax.
1000
     *
1001
     * @since 1.0.0
1002
     */
1003
    public static function buy_items() {
1004
        $user_id = get_current_user_id();
1005
1006
        if ( empty( $user_id ) ) { // If not logged in then lets redirect to the login page
1007
            wp_send_json( array(
1008
                '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

1008
                'success' => wp_login_url( /** @scrutinizer ignore-type */ wp_get_referer() )
Loading history...
1009
            ) );
1010
        } else {
1011
            // Only check nonce if logged in as it could be cached when logged out.
1012
            if ( ! isset( $_POST['wpinv_buy_nonce'] ) || ! wp_verify_nonce( $_POST['wpinv_buy_nonce'], 'wpinv_buy_items' ) ) {
1013
                wp_send_json( array(
1014
                    'error' => __( 'Security checks failed.', 'invoicing' )
1015
                ) );
1016
                wp_die();
1017
            }
1018
1019
            // allow to set a custom price through post_id
1020
            $items = $_POST['items'];
1021
            $related_post_id = isset( $_POST['post_id'] ) ? (int)$_POST['post_id'] : 0;
1022
            $custom_item_price = $related_post_id ? abs( get_post_meta( $related_post_id, '_wpi_custom_price', true ) ) : 0;
1023
1024
            $cart_items = array();
1025
            if ( $items ) {
1026
                $items = explode( ',', $items );
1027
1028
                foreach( $items as $item ) {
1029
                    $item_id = $item;
1030
                    $quantity = 1;
1031
1032
                    if ( strpos( $item, '|' ) !== false ) {
1033
                        $item_parts = explode( '|', $item );
1034
                        $item_id = $item_parts[0];
1035
                        $quantity = $item_parts[1];
1036
                    }
1037
1038
                    if ( $item_id && $quantity ) {
1039
                        $cart_items_arr = array(
1040
                            'id'            => (int)$item_id,
1041
                            'quantity'      => (int)$quantity
1042
                        );
1043
1044
                        // If there is a related post id then add it to meta
1045
                        if ( $related_post_id ) {
1046
                            $cart_items_arr['meta'] = array(
1047
                                'post_id'   => $related_post_id
1048
                            );
1049
                        }
1050
1051
                        // If there is a custom price then set it.
1052
                        if ( $custom_item_price ) {
1053
                            $cart_items_arr['custom_price'] = $custom_item_price;
1054
                        }
1055
1056
                        $cart_items[] = $cart_items_arr;
1057
                    }
1058
                }
1059
            }
1060
1061
            /**
1062
             * Filter the wpinv_buy shortcode cart items on the fly.
1063
             *
1064
             * @param array $cart_items The cart items array.
1065
             * @param int $related_post_id The related post id if any.
1066
             * @since 1.0.0
1067
             */
1068
            $cart_items = apply_filters( 'wpinv_buy_cart_items', $cart_items, $related_post_id );
1069
1070
            // Make sure its not in the cart already, if it is then redirect to checkout.
1071
            $cart_invoice = wpinv_get_invoice_cart();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_invoice_cart() has been deprecated. ( Ignorable by Annotation )

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

1071
            $cart_invoice = /** @scrutinizer ignore-deprecated */ wpinv_get_invoice_cart();
Loading history...
1072
1073
            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...
1074
                wp_send_json( array(
1075
                    'success' =>  $cart_invoice->get_checkout_payment_url()
1076
                ) );
1077
                wp_die();
1078
            }
1079
1080
            // Check if user has invoice with same items waiting to be paid.
1081
            $user_invoices = wpinv_get_users_invoices( $user_id , 10 , false , 'wpi-pending' );
1082
            if ( !empty( $user_invoices ) ) {
1083
                foreach( $user_invoices as $user_invoice ) {
1084
                    $user_cart_details = array();
1085
                    $invoice  = wpinv_get_invoice( $user_invoice->ID );
1086
                    $cart_details = $invoice->get_cart_details();
1087
1088
                    if ( !empty( $cart_details ) ) {
1089
                        foreach ( $cart_details as $invoice_item ) {
1090
                            $ii_arr = array();
1091
                            $ii_arr['id'] = (int)$invoice_item['id'];
1092
                            $ii_arr['quantity'] = (int)$invoice_item['quantity'];
1093
1094
                            if (isset( $invoice_item['meta'] ) && !empty( $invoice_item['meta'] ) ) {
1095
                                $ii_arr['meta'] = $invoice_item['meta'];
1096
                            }
1097
1098
                            if ( isset( $invoice_item['custom_price'] ) && !empty( $invoice_item['custom_price'] ) ) {
1099
                                $ii_arr['custom_price'] = $invoice_item['custom_price'];
1100
                            }
1101
1102
                            $user_cart_details[] = $ii_arr;
1103
                        }
1104
                    }
1105
1106
                    if ( !empty( $user_cart_details ) && serialize( $cart_items ) == serialize( $user_cart_details ) ) {
1107
                        wp_send_json( array(
1108
                            'success' =>  $invoice->get_checkout_payment_url()
1109
                        ) );
1110
                        wp_die();
1111
                    }
1112
                }
1113
            }
1114
1115
            // Create invoice and send user to checkout
1116
            if ( !empty( $cart_items ) ) {
1117
                $invoice_data = array(
1118
                    'status'        =>  'wpi-pending',
1119
                    'created_via'   =>  'wpi',
1120
                    'user_id'       =>  $user_id,
1121
                    'cart_details'  =>  $cart_items,
1122
                );
1123
1124
                $invoice = wpinv_insert_invoice( $invoice_data, true );
1125
1126
                if ( !empty( $invoice ) && isset( $invoice->ID ) ) {
1127
                    wp_send_json( array(
1128
                        '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

1128
                        '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...
1129
                    ) );
1130
                } else {
1131
                    wp_send_json( array(
1132
                        'error' => __( 'Invoice failed to create', 'invoicing' )
1133
                    ) );
1134
                }
1135
            } else {
1136
                wp_send_json( array(
1137
                    'error' => __( 'Items not valid.', 'invoicing' )
1138
                ) );
1139
            }
1140
        }
1141
1142
        wp_die();
1143
    }
1144
}
1145
1146
WPInv_Ajax::init();