WPInv_Ajax   F
last analyzed

Complexity

Total Complexity 194

Size/Duplication

Total Lines 1164
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
eloc 552
dl 0
loc 1164
rs 2
c 4
b 1
f 1
wmc 194

27 Methods

Rating   Name   Duplication   Size   Complexity  
A wpinv_ajax_headers() 0 8 2
A init() 0 4 1
A define_ajax() 0 9 5
A do_wpinv_ajax() 0 14 3
A get_states_field() 0 4 1
A add_note() 0 22 6
A delete_note() 0 14 3
C get_payment_form_states_field() 0 57 14
B get_billing_details() 0 31 7
A run_tool() 0 13 3
B get_aui_states_field() 0 50 6
A payment_form() 0 14 2
C file_upload() 0 60 11
C recalculate_invoice_totals() 0 64 14
C add_invoice_items() 0 55 14
C edit_invoice_item() 0 70 12
A get_invoice_items() 0 31 6
C get_payment_form() 0 76 14
A payment_form_refresh_prices() 0 28 3
B check_new_user_email() 0 35 7
A get_customers() 0 36 5
B remove_invoice_item() 0 48 11
C recalculate_full_prices() 0 65 13
B create_invoice_item() 0 74 11
B get_invoicing_items() 0 54 7
B admin_add_invoice_item() 0 43 10
A add_ajax_events() 0 36 3

How to fix   Complexity   

Complex Class

Complex classes like WPInv_Ajax often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WPInv_Ajax, and based on these observations, apply Extract Interface, too.

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 array; 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
            'payment_form'                  => true,
90
            'get_payment_form'              => true,
91
            'get_payment_form_states_field' => true,
92
            'get_invoicing_items'           => false,
93
            'get_customers'                 => false,
94
            'get_invoice_items'             => false,
95
            'add_invoice_items'             => false,
96
            'admin_add_invoice_item'        => false,
97
            'recalculate_full_prices'       => false,
98
            'edit_invoice_item'             => false,
99
            'create_invoice_item'           => false,
100
            'remove_invoice_item'           => false,
101
            'get_billing_details'           => false,
102
            'recalculate_invoice_totals'    => false,
103
            'check_new_user_email'          => false,
104
            'run_tool'                      => false,
105
            'payment_form_refresh_prices'   => true,
106
            'file_upload'                   => true,
107
        );
108
109
        foreach ( $ajax_events as $ajax_event => $nopriv ) {
110
            add_action( 'wp_ajax_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
111
            add_action( 'wp_ajax_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
112
113
            if ( $nopriv ) {
114
                add_action( 'wp_ajax_nopriv_wpinv_' . $ajax_event, array( __CLASS__, $ajax_event ) );
115
                add_action( 'wp_ajax_nopriv_getpaid_' . $ajax_event, array( __CLASS__, $ajax_event ) );
116
                add_action( 'wpinv_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
117
            }
118
        }
119
    }
120
121
    public static function add_note() {
122
        check_ajax_referer( 'add-invoice-note', '_nonce' );
123
124
        $post_id   = absint( $_POST['post_id'] );
125
        $note      = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
126
        $note_type = sanitize_text_field( $_POST['note_type'] );
127
128
        if ( ! wpinv_current_user_can( 'invoice_add_note', array( 'invoice_id' => $post_id, 'note_type' => $note_type ) ) ) {
129
            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...
130
        }
131
132
        $is_customer_note = $note_type == 'customer' ? 1 : 0;
133
134
        if ( $post_id > 0 ) {
135
            $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

135
            $note_id = /** @scrutinizer ignore-deprecated */ wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
Loading history...
136
137
            if ( $note_id > 0 && ! is_wp_error( $note_id ) ) {
138
                wpinv_get_invoice_note_line_item( $note_id );
139
            }
140
        }
141
142
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
143
    }
144
145
    public static function delete_note() {
146
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
147
148
        $note_id = (int)$_POST['note_id'];
149
150
        if ( ! wpinv_current_user_can( 'invoice_delete_note', array( 'note_id' => $note_id ) ) ) {
151
            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...
152
        }
153
154
        if ( $note_id > 0 ) {
155
            wp_delete_comment( $note_id, true );
156
        }
157
158
        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...
159
    }
160
161
    public static function get_states_field() {
162
        wpinv_get_states_field();
163
164
        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...
165
    }
166
167
    /**
168
     * Retrieves a given user's billing address.
169
     */
170
    public static function get_billing_details() {
171
        // Verify nonce.
172
        check_ajax_referer( 'wpinv-nonce' );
173
174
        // Do we have a user id?
175
        $user_id = (int) $_GET['user_id'];
176
        $invoice_id = ! empty( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
177
178
        if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
179
            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...
180
        }
181
182
        // Can the user manage the plugin?
183
        if ( ! wpinv_current_user_can( 'invoice_get_billing_details', array( 'user_id' => $user_id, 'invoice_id' => $invoice_id ) ) ) {
184
            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...
185
        }
186
187
        // Fetch the billing details.
188
        $billing_details    = wpinv_get_user_address( $user_id );
189
        $billing_details    = apply_filters( 'wpinv_ajax_billing_details', $billing_details, $user_id );
190
191
        // unset the user id and email.
192
        $to_ignore = array( 'user_id', 'email' );
193
194
        foreach ( $to_ignore as $key ) {
195
            if ( isset( $billing_details[ $key ] ) ) {
196
                unset( $billing_details[ $key ] );
197
            }
198
        }
199
200
        wp_send_json_success( $billing_details );
201
202
    }
203
204
    /**
205
     * Checks if a new users email is valid.
206
     */
207
    public static function check_new_user_email() {
208
        // Verify nonce.
209
        check_ajax_referer( 'wpinv-nonce' );
210
211
        $invoice_id = ! empty( $_REQUEST['post_id'] ) ? absint( $_REQUEST['post_id'] ) : 0;
212
213
        if ( empty( $invoice_id ) ) {
214
            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...
215
        }
216
217
        // Can the user manage the plugin?
218
        if ( ! wpinv_current_user_can( 'invoice_check_new_user_email', array( 'invoice_id' => $invoice_id ) ) ) {
219
            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...
220
        }
221
222
        // We need an email address.
223
        if ( empty( $_GET['email'] ) ) {
224
            esc_html_e( "Provide the new user's email address", 'invoicing' );
225
            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...
226
        }
227
228
        // Ensure the email is valid.
229
        $email = sanitize_email( $_GET['email'] );
230
        if ( ! is_email( $email ) ) {
231
            esc_html_e( 'Invalid email address', 'invoicing' );
232
            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...
233
        }
234
235
        // And it does not exist.
236
        $id = email_exists( $email );
237
        if ( $id ) {
238
            wp_send_json_success( compact( 'id' ) );
239
        }
240
241
        wp_send_json_success( true );
242
    }
243
244
    public static function run_tool() {
245
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
246
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
        global $getpaid_force_checkbox;
265
266
        // Is the request set up correctly?
267
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) && empty( $_GET['invoice'] ) ) {
268
			aui()->alert(
269
				array(
270
					'type'    => 'warning',
271
					'content' => __( 'No payment form or item provided', 'invoicing' ),
272
                ),
273
                true
274
            );
275
            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...
276
        }
277
278
        // Payment form or button?
279
		if ( ! empty( $_GET['form'] ) ) {
280
            $form = sanitize_text_field( urldecode( $_GET['form'] ) );
281
282
            if ( false !== strpos( $form, '|' ) ) {
283
                $form_pos = strpos( $form, '|' );
284
                $_items   = getpaid_convert_items_to_array( substr( $form, $form_pos + 1 ) );
285
                $form     = substr( $form, 0, $form_pos );
286
287
                // Retrieve appropriate payment form.
288
                $payment_form = new GetPaid_Payment_Form( $form );
289
                $payment_form = $payment_form->exists() ? $payment_form : new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
290
291
                $items    = array();
292
                $item_ids = array();
293
294
                foreach ( $_items as $item_id => $qty ) {
295
                    if ( ! in_array( $item_id, $item_ids ) ) {
296
                        $item = new GetPaid_Form_Item( $item_id );
297
                        $item->set_quantity( $qty );
298
299
                        if ( 0 == $qty ) {
300
                            $item->set_allow_quantities( true );
301
                            $item->set_is_required( false );
302
                            $getpaid_force_checkbox = true;
303
                        }
304
305
                        $item_ids[] = $item->get_id();
306
                        $items[]    = $item;
307
                    }
308
                }
309
310
                if ( ! $payment_form->is_default() ) {
311
312
                    foreach ( $payment_form->get_items() as $item ) {
313
                        if ( ! in_array( $item->get_id(), $item_ids ) ) {
314
                            $item_ids[] = $item->get_id();
315
                            $items[]    = $item;
316
                        }
317
                    }
318
                }
319
320
                $payment_form->set_items( $items );
321
                $extra_items     = esc_attr( getpaid_convert_items_to_string( $_items ) );
322
                $extra_items_key = md5( NONCE_KEY . AUTH_KEY . $extra_items );
323
                $extra_items     = "<input type='hidden' name='getpaid-form-items' value='$extra_items' />";
324
                $extra_items    .= "<input type='hidden' name='getpaid-form-items-key' value='$extra_items_key' />";
325
                $payment_form->display( $extra_items );
326
                $getpaid_force_checkbox = false;
327
328
            } else {
329
                getpaid_display_payment_form( $form );
0 ignored issues
show
Bug introduced by
$form of type string is incompatible with the type GetPaid_Payment_Form expected by parameter $form of getpaid_display_payment_form(). ( Ignorable by Annotation )

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

329
                getpaid_display_payment_form( /** @scrutinizer ignore-type */ $form );
Loading history...
330
            }
331
} elseif ( ! empty( $_GET['invoice'] ) ) {
332
		    getpaid_display_invoice_payment_form( (int) urldecode( $_GET['invoice'] ) );
333
        } else {
334
			$items = getpaid_convert_items_to_array( sanitize_text_field( urldecode( $_GET['item'] ) ) );
335
		    getpaid_display_item_payment_form( $items );
336
        }
337
338
        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...
339
340
    }
341
342
    /**
343
     * Payment forms.
344
     *
345
     * @since 1.0.18
346
     */
347
    public static function payment_form() {
348
349
        // ... form fields...
350
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
351
            esc_html_e( 'Error: Reload the page and try again.', 'invoicing' );
352
            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...
353
        }
354
355
        // Process the payment form.
356
        $checkout_class = apply_filters( 'getpaid_checkout_class', 'GetPaid_Checkout' );
357
        $checkout       = new $checkout_class( new GetPaid_Payment_Form_Submission() );
358
        $checkout->process_checkout();
359
360
        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...
361
    }
362
363
    /**
364
     * Payment forms.
365
     *
366
     * @since 1.0.18
367
     */
368
    public static function get_payment_form_states_field() {
369
370
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
371
            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...
372
        }
373
374
        $elements = getpaid_get_payment_form_elements( (int) $_GET['form'] );
375
376
        if ( empty( $elements ) ) {
377
            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...
378
        }
379
380
        $address_fields = array();
381
        foreach ( $elements as $element ) {
382
            if ( 'address' === $element['type'] ) {
383
                $address_fields = $element;
384
                break;
385
            }
386
        }
387
388
        if ( empty( $address_fields ) ) {
389
            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...
390
        }
391
392
        foreach ( $address_fields['fields'] as $address_field ) {
393
394
            if ( 'wpinv_state' == $address_field['name'] ) {
395
396
                $wrap_class  = getpaid_get_form_element_grid_class( $address_field );
397
                $wrap_class  = esc_attr( "$wrap_class getpaid-address-field-wrapper" );
398
                $placeholder = empty( $address_field['placeholder'] ) ? '' : esc_attr( $address_field['placeholder'] );
399
                $description = empty( $address_field['description'] ) ? '' : wp_kses_post( $address_field['description'] );
400
                $value       = is_user_logged_in() ? get_user_meta( get_current_user_id(), '_wpinv_state', true ) : '';
401
                $label       = empty( $address_field['label'] ) ? '' : wp_kses_post( $address_field['label'] );
402
403
                if ( ! empty( $address_field['required'] ) ) {
404
                    $label .= "<span class='text-danger'> *</span>";
405
                }
406
407
                $html = getpaid_get_states_select_markup(
408
                    sanitize_text_field( $_GET['country'] ),
409
                    $value,
410
                    $placeholder,
411
                    $label,
412
                    $description,
413
                    ! empty( $address_field['required'] ),
414
                    $wrap_class,
415
                    sanitize_text_field( $_GET['name'] )
416
                );
417
418
                wp_send_json_success( $html );
419
                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...
420
421
            }
422
}
423
424
        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...
425
    }
426
427
    /**
428
     * Recalculates invoice totals.
429
     */
430
    public static function recalculate_invoice_totals() {
431
        // Verify nonce.
432
        check_ajax_referer( 'wpinv-nonce' );
433
434
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
435
436
        if ( empty( $invoice_id ) ) {
437
            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...
438
        }
439
440
        // Can the user manage the plugin?
441
        if ( ! wpinv_current_user_can( 'invoice_recalculate_totals', array( 'invoice_id' => $invoice_id ) ) ) {
442
            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...
443
        }
444
445
        // Fetch the invoice.
446
        $invoice = new WPInv_Invoice( $invoice_id );
447
448
        // Ensure it exists.
449
        if ( ! $invoice->get_id() ) {
450
            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...
451
        }
452
453
        // Maybe set the country, state, currency.
454
        foreach ( array( 'country', 'state', 'currency', 'vat_number', 'discount_code' ) as $key ) {
455
            if ( isset( $_POST[ $key ] ) ) {
456
                $method = "set_$key";
457
                $invoice->$method( sanitize_text_field( $_POST[ $key ] ) );
458
            }
459
        }
460
461
        // Maybe disable taxes.
462
        $invoice->set_disable_taxes( ! empty( $_POST['taxes'] ) );
463
464
        // Discount code.
465
        if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) {
466
            $discount = new WPInv_Discount( $invoice->get_discount_code() );
467
            if ( $discount->exists() ) {
468
                $invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
469
            } else {
470
                $invoice->remove_discount( 'discount_code' );
471
            }
472
        }
473
474
        // Recalculate totals.
475
        $invoice->recalculate_total();
476
477
        $total        = wpinv_price( $invoice->get_total(), $invoice->get_currency() );
478
        $suscriptions = getpaid_get_invoice_subscriptions( $invoice );
479
        if ( is_a( $suscriptions, 'WPInv_Subscription' ) && $invoice->is_recurring() && $invoice->is_parent() && $invoice->get_total() != $invoice->get_recurring_total() ) {
480
            $recurring_total = wpinv_price( $invoice->get_recurring_total(), $invoice->get_currency() );
481
            $total          .= '<small class="form-text text-muted">' . sprintf( __( 'Recurring Price: %s', 'invoicing' ), $recurring_total ) . '</small>';
482
        }
483
484
        $totals = array(
485
            'subtotal' => wpinv_price( $invoice->get_subtotal(), $invoice->get_currency() ),
486
            'discount' => wpinv_price( $invoice->get_total_discount(), $invoice->get_currency() ),
487
            'tax'      => wpinv_price( $invoice->get_total_tax(), $invoice->get_currency() ),
488
            'total'    => $total,
489
        );
490
491
        $totals = apply_filters( 'getpaid_invoice_totals', $totals, $invoice );
492
493
        wp_send_json_success( compact( 'totals' ) );
494
    }
495
496
    /**
497
     * Get items belonging to a given invoice.
498
     */
499
    public static function get_invoice_items() {
500
        // Verify nonce.
501
        check_ajax_referer( 'wpinv-nonce' );
502
503
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
504
505
        if ( empty( $invoice_id ) ) {
506
            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...
507
        }
508
509
        // Can the user manage the plugin?
510
        if ( ! wpinv_current_user_can( 'invoice_get_items', array( 'invoice_id' => $invoice_id ) ) ) {
511
            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...
512
        }
513
514
        // Fetch the invoice.
515
        $invoice = new WPInv_Invoice( $invoice_id );
516
517
        // Ensure it exists.
518
        if ( ! $invoice->get_id() ) {
519
            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...
520
        }
521
522
        // Return an array of invoice items.
523
        $items = array();
524
525
        foreach ( $invoice->get_items() as $item ) {
526
            $items[] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency(), $invoice->is_renewal() );
527
        }
528
529
        wp_send_json_success( compact( 'items' ) );
530
    }
531
532
    /**
533
     * Edits an invoice item.
534
     */
535
    public static function edit_invoice_item() {
536
        // Verify nonce.
537
        check_ajax_referer( 'wpinv-nonce' );
538
539
        // We need an invoice and item details.
540
        if ( empty( $_POST['post_id'] ) || empty( $_POST['data'] ) ) {
541
            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...
542
        }
543
544
        $invoice_id = absint( $_POST['post_id'] );
545
546
        if ( empty( $invoice_id ) ) {
547
            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...
548
        }
549
550
        // Can the user manage the plugin?
551
        if ( ! wpinv_current_user_can( 'invoice_edit_item', array( 'invoice_id' => $invoice_id ) ) ) {
552
            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...
553
        }
554
555
        // Fetch the invoice.
556
        $invoice = new WPInv_Invoice( $invoice_id );
557
558
        // Ensure it exists and its not been paid for.
559
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
560
            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...
561
        }
562
563
        // Format the data.
564
        $data = wp_kses_post_deep( wp_unslash( wp_list_pluck( $_POST['data'], 'value', 'field' ) ) );
565
566
        // Ensure that we have an item id.
567
        if ( empty( $data['id'] ) ) {
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
        // Abort if the invoice does not have the specified item.
572
        $item = $invoice->get_item( (int) $data['id'] );
573
574
        if ( empty( $item ) ) {
575
            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...
576
        }
577
578
        // Update the item.
579
        $item->set_price( getpaid_standardize_amount( $data['price'] ) );
580
        $item->set_name( sanitize_text_field( $data['name'] ) );
581
        $item->set_description( wp_kses_post( $data['description'] ) );
582
        $item->set_quantity( floatval( $data['quantity'] ) );
583
584
        // Add it to the invoice.
585
        $error = $invoice->add_item( $item );
586
        $alert = false;
587
        if ( is_wp_error( $error ) ) {
588
            $alert = $error->get_error_message();
589
        }
590
591
        // Update totals.
592
        $invoice->recalculate_total();
593
594
        // Save the invoice.
595
        $invoice->save();
596
597
        // Return an array of invoice items.
598
        $items = array();
599
600
        foreach ( $invoice->get_items() as $item ) {
601
            $items[] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency() );
602
        }
603
604
        wp_send_json_success( compact( 'items', 'alert' ) );
605
    }
606
607
    /**
608
     * Creates an invoice item.
609
     */
610
    public static function create_invoice_item() {
611
        // Verify nonce.
612
        check_ajax_referer( 'wpinv-nonce' );
613
614
        // We need an invoice and item details.
615
        if ( empty( $_POST['invoice_id'] ) || empty( $_POST['_wpinv_quick'] ) ) {
616
            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...
617
        }
618
619
        $invoice_id = absint( $_POST['invoice_id'] );
620
621
        if ( empty( $invoice_id ) ) {
622
            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...
623
        }
624
625
        if ( ! wpinv_current_user_can( 'invoice_create_item', array( 'invoice_id' => $invoice_id ) ) ) {
626
            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...
627
        }
628
629
        // Fetch the invoice.
630
        $invoice = new WPInv_Invoice( $invoice_id );
631
632
        // Ensure it exists and its not been paid for.
633
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
634
            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...
635
        }
636
637
        // Format the data.
638
        $data = wp_kses_post_deep( wp_unslash( $_POST['_wpinv_quick'] ) );
639
640
        $item = new WPInv_Item();
641
        $item->set_price( getpaid_standardize_amount( $data['price'] ) );
642
        $item->set_name( sanitize_text_field( $data['name'] ) );
643
        $item->set_description( wp_kses_post( $data['description'] ) );
644
        $item->set_type( sanitize_text_field( $data['type'] ) );
645
        $item->set_vat_rule( sanitize_text_field( $data['vat_rule'] ) );
646
        $item->set_vat_class( sanitize_text_field( $data['vat_class'] ) );
647
        $item->set_status( 'publish' );
648
        $item->save();
649
650
        if ( ! $item->exists() ) {
651
            $alert = __( 'Could not create invoice item. Please try again.', 'invoicing' );
652
            wp_send_json_success( compact( 'alert' ) );
653
        }
654
655
        if ( ! empty( $data['one-time'] ) ) {
656
            update_post_meta( $item->get_id(), '_wpinv_one_time', 'yes' );
657
        }
658
659
        $item = new GetPaid_Form_Item( $item->get_id() );
660
        $item->set_quantity( floatval( $data['qty'] ) );
661
662
        // Add it to the invoice.
663
        $error = $invoice->add_item( $item );
664
        $alert = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $alert is dead and can be removed.
Loading history...
665
666
        if ( is_wp_error( $error ) ) {
667
            $alert = $error->get_error_message();
668
            wp_send_json_success( compact( 'alert' ) );
669
         }
670
671
        // Update totals.
672
        $invoice->recalculate_total();
673
674
        // Save the invoice.
675
        $invoice->save();
676
677
        // Save the invoice.
678
        $invoice->recalculate_total();
679
        $invoice->save();
680
        ob_start();
681
        GetPaid_Meta_Box_Invoice_Items::output_row( GetPaid_Meta_Box_Invoice_Items::get_columns( $invoice ), $item, $invoice );
682
        $row = ob_get_clean();
683
        wp_send_json_success( compact( 'row' ) );
684
    }
685
686
    /**
687
     * Deletes an invoice item.
688
     */
689
    public static function remove_invoice_item() {
690
        // Verify nonce.
691
        check_ajax_referer( 'wpinv-nonce' );
692
693
        // We need an invoice and item.
694
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
695
        $item_id = ! empty( $_POST['item_id'] ) ? absint( $_POST['item_id'] ) : 0;
696
697
        if ( empty( $invoice_id ) || empty( $item_id ) ) {
698
            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...
699
        }
700
701
        // Can the user manage the plugin?
702
        if ( ! wpinv_current_user_can( 'invoice_remove_item', array( 'invoice_id' => $invoice_id, 'item_id' => $item_id ) ) ) {
703
            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...
704
        }
705
706
        // Fetch the invoice.
707
        $invoice = new WPInv_Invoice( $invoice_id );
708
709
        // Ensure it exists and its not been paid for.
710
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
711
            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...
712
        }
713
714
        // Abort if the invoice does not have the specified item.
715
        $item = $invoice->get_item( $item_id );
716
717
        if ( empty( $item ) ) {
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
        $invoice->remove_item( $item_id );
722
723
        // Update totals.
724
        $invoice->recalculate_total();
725
726
        // Save the invoice.
727
        $invoice->save();
728
729
        // Return an array of invoice items.
730
        $items = array();
731
732
        foreach ( $invoice->get_items() as $item ) {
733
            $items[] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency() );
734
        }
735
736
        wp_send_json_success( compact( 'items' ) );
737
    }
738
739
    /**
740
     * Adds an item to an invoice.
741
     */
742
    public static function recalculate_full_prices() {
743
        // Verify nonce.
744
        check_ajax_referer( 'wpinv-nonce' );
745
746
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
747
748
        if ( empty( $invoice_id ) ) {
749
            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...
750
        }
751
752
        if ( ! wpinv_current_user_can( 'invoice_recalculate_full_prices', array( 'invoice_id' => $invoice_id ) ) ) {
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
        // Fetch the invoice.
757
        $invoice = new WPInv_Invoice( $invoice_id );
758
        $alert   = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $alert is dead and can be removed.
Loading history...
759
760
        // Ensure it exists and its not been paid for.
761
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
762
            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...
763
        }
764
765
        $invoice->set_items( array() );
766
767
        if ( ! empty( $_POST['getpaid_items'] ) ) {
768
769
            foreach ( wp_kses_post_deep( wp_unslash( $_POST['getpaid_items'] ) ) as $item_id => $args ) {
770
                $item = new GetPaid_Form_Item( $item_id );
771
772
                if ( $item->exists() ) {
773
                    $item->set_price( getpaid_standardize_amount( $args['price'] ) );
774
                    $item->set_quantity( floatval( $args['quantity'] ) );
775
                    $item->set_name( sanitize_text_field( $args['name'] ) );
776
                    $item->set_description( wp_kses_post( $args['description'] ) );
777
                    $invoice->add_item( $item );
778
                }
779
            }
780
        }
781
782
        $invoice->set_disable_taxes( ! empty( $_POST['disable_taxes'] ) );
783
784
        // Maybe set the country, state, currency.
785
        foreach ( array( 'wpinv_country', 'wpinv_state', 'wpinv_currency', 'wpinv_vat_number', 'wpinv_discount_code' ) as $key ) {
786
            if ( isset( $_POST[ $key ] ) ) {
787
                $_key   = str_replace( 'wpinv_', '', $key );
788
                $method = "set_$_key";
789
                $invoice->$method( sanitize_text_field( $_POST[ $key ] ) );
790
            }
791
        }
792
793
        $discount = new WPInv_Discount( $invoice->get_discount_code() );
794
        if ( $discount->exists() ) {
795
            $invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
796
        } else {
797
            $invoice->remove_discount( 'discount_code' );
798
        }
799
800
        // Save the invoice.
801
        $invoice->recalculate_total();
802
        $invoice->save();
803
        ob_start();
804
        GetPaid_Meta_Box_Invoice_Items::output( get_post( $invoice->get_id() ), $invoice );
805
        $table = ob_get_clean();
806
        wp_send_json_success( compact( 'table' ) );
807
    }
808
809
    /**
810
     * Adds an item to an invoice.
811
     */
812
    public static function admin_add_invoice_item() {
813
        // Verify nonce.
814
        check_ajax_referer( 'wpinv-nonce' );
815
816
        // We need an invoice and item.
817
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
818
        $item_id = ! empty( $_POST['item_id'] ) ? absint( $_POST['item_id'] ) : 0;
819
820
        if ( empty( $invoice_id ) || empty( $item_id ) ) {
821
            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...
822
        }
823
824
        // Can the user manage the plugin?
825
        if ( ! wpinv_current_user_can( 'invoice_add_item', array( 'invoice_id' => $invoice_id, 'item_id' => $item_id ) ) ) {
826
            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...
827
        }
828
829
        // Fetch the invoice.
830
        $invoice = new WPInv_Invoice( $invoice_id );
831
        $alert   = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $alert is dead and can be removed.
Loading history...
832
833
        // Ensure it exists and its not been paid for.
834
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
835
            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...
836
        }
837
838
        // Add the item.
839
        $item  = new GetPaid_Form_Item( $item_id );
840
841
        $error = $invoice->add_item( $item );
842
843
        if ( is_wp_error( $error ) ) {
844
            $alert = $error->get_error_message();
845
            wp_send_json_success( compact( 'alert' ) );
846
        }
847
848
        // Save the invoice.
849
        $invoice->recalculate_total();
850
        $invoice->save();
851
        ob_start();
852
        GetPaid_Meta_Box_Invoice_Items::output_row( GetPaid_Meta_Box_Invoice_Items::get_columns( $invoice ), $item, $invoice );
853
        $row = ob_get_clean();
854
        wp_send_json_success( compact( 'row' ) );
855
    }
856
857
    /**
858
     * Adds a items to an invoice.
859
     */
860
    public static function add_invoice_items() {
861
        // Verify nonce.
862
        check_ajax_referer( 'wpinv-nonce' );
863
864
        $invoice_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
865
866
        // We need an invoice and items.
867
        if ( empty( $invoice_id ) || empty( $_POST['items'] ) ) {
868
            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...
869
        }
870
871
        // Can the user manage the plugin?
872
        if ( ! wpinv_current_user_can( 'invoice_add_items', array( 'invoice_id' => $invoice_id ) ) ) {
873
            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...
874
        }
875
876
        // Fetch the invoice.
877
        $invoice = new WPInv_Invoice( $invoice_id );
878
        $alert   = false;
879
880
        // Ensure it exists and its not been paid for.
881
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
882
            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...
883
        }
884
885
        // Add the items.
886
        foreach ( wp_kses_post_deep( wp_unslash( $_POST['items'] ) ) as $data ) {
887
888
            $item = new GetPaid_Form_Item( (int) $data['id'] );
889
890
            if ( is_numeric( $data['qty'] ) && (float) $data['qty'] > 0 ) {
891
                $item->set_quantity( floatval( $data['qty'] ) );
892
            }
893
894
            if ( $item->get_id() > 0 ) {
895
                $error = $invoice->add_item( $item );
896
897
                if ( is_wp_error( $error ) ) {
898
                    $alert = $error->get_error_message();
899
                }
900
}
901
}
902
903
        // Save the invoice.
904
        $invoice->recalculate_total();
905
        $invoice->save();
906
907
        // Return an array of invoice items.
908
        $items = array();
909
910
        foreach ( $invoice->get_items() as $item ) {
911
            $items[] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency() );
912
        }
913
914
        wp_send_json_success( compact( 'items', 'alert' ) );
915
    }
916
917
    /**
918
     * Retrieves items that should be added to an invoice.
919
     */
920
    public static function get_invoicing_items() {
921
        // Verify nonce.
922
        check_ajax_referer( 'wpinv-nonce' );
923
924
        // Can the user manage the plugin?
925
        if ( ! wpinv_current_user_can( 'get_invoicing_items' ) ) {
926
            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...
927
        }
928
929
        // We need a search term.
930
        if ( empty( $_GET['search'] ) ) {
931
            wp_send_json_success( array() );
932
        }
933
934
        // Retrieve items.
935
        $item_args = array(
936
            'post_type'      => 'wpi_item',
937
            'orderby'        => 'title',
938
            'order'          => 'ASC',
939
            'posts_per_page' => -1,
940
            'post_status'    => array( 'publish' ),
941
            's'              => sanitize_text_field( urldecode( $_GET['search'] ) ),
942
            'meta_query'     => array(
943
                array(
944
                    'key'     => '_wpinv_type',
945
                    'compare' => '!=',
946
                    'value'   => 'package',
947
                ),
948
                array(
949
                    'key'     => '_wpinv_one_time',
950
                    'compare' => 'NOT EXISTS',
951
                ),
952
            ),
953
        );
954
955
        if ( ! empty( $_GET['ignore'] ) ) {
956
            $item_args['exclude'] = wp_parse_id_list( sanitize_text_field( $_GET['ignore'] ) );
957
        }
958
959
        $items = get_posts( apply_filters( 'getpaid_ajax_invoice_items_query_args', $item_args ) );
960
        $data  = array();
961
962
        $is_payment_form = ( ! empty( $_GET['post_id'] ) && 'wpi_payment_form' == get_post_type( (int) $_GET['post_id'] ) );
963
964
        foreach ( $items as $item ) {
965
            $item      = new GetPaid_Form_Item( $item );
966
            $data[] = array(
967
                'id'        => (int) $item->get_id(),
968
                'text'      => strip_tags( $item->get_name() ),
969
                'form_data' => $is_payment_form ? $item->prepare_data_for_use( false ) : '',
970
            );
971
        }
972
973
        wp_send_json_success( $data );
974
975
    }
976
977
    /**
978
     * Retrieves items that should be added to an invoice.
979
     */
980
    public static function get_customers() {
981
        // Verify nonce.
982
        check_ajax_referer( 'wpinv-nonce' );
983
984
        $invoice_id = ! empty( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
985
986
        // Can the user manage the plugin?
987
        if ( ! wpinv_current_user_can( 'invoice_get_customers', array( 'invoice_id' => $invoice_id ) ) ) {
988
            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...
989
        }
990
991
        // We need a search term.
992
        if ( empty( $_GET['search'] ) ) {
993
            wp_send_json_success( array() );
994
        }
995
996
        // Retrieve customers.
997
998
        $customer_args = array(
999
            'fields'         => array( 'ID', 'user_email', 'display_name' ),
1000
            'orderby'        => 'display_name',
1001
            'search'         => '*' . sanitize_text_field( $_GET['search'] ) . '*',
1002
            'search_columns' => array( 'user_login', 'user_email', 'display_name' ),
1003
        );
1004
1005
        $customers = get_users( apply_filters( 'getpaid_ajax_invoice_customers_query_args', $customer_args ) );
1006
        $data      = array();
1007
1008
        foreach ( $customers as $customer ) {
1009
            $data[] = array(
1010
                'id'   => (int) $customer->ID,
1011
                'text' => strip_tags( sprintf( _x( '%1$s (%2$s)', 'user dropdown', 'invoicing' ), $customer->display_name, $customer->user_email ) ),
1012
            );
1013
        }
1014
1015
        wp_send_json_success( $data );
1016
1017
    }
1018
1019
    /**
1020
     * Retrieves the states field for AUI forms.
1021
     */
1022
    public static function get_aui_states_field() {
1023
1024
        // We need a country.
1025
        if ( empty( $_GET['country'] ) ) {
1026
            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...
1027
        }
1028
1029
        $states = wpinv_get_country_states( sanitize_text_field( $_GET['country'] ) );
1030
        $state  = isset( $_GET['state'] ) ? sanitize_text_field( $_GET['state'] ) : wpinv_get_default_state();
1031
        $name   = isset( $_GET['name'] ) ? sanitize_text_field( $_GET['name'] ) : 'wpinv_state';
1032
        $class  = isset( $_GET['class'] ) ? sanitize_text_field( $_GET['class'] ) : 'form-control-sm';
1033
1034
        if ( empty( $states ) ) {
1035
1036
            $html = aui()->input(
1037
                array(
1038
                    'type'        => 'text',
1039
                    'id'          => 'wpinv_state',
1040
                    'name'        => $name,
1041
                    'label'       => __( 'State', 'invoicing' ),
1042
                    'label_type'  => 'vertical',
1043
                    'placeholder' => __( 'State', 'invoicing' ),
1044
                    'class'       => $class,
1045
                    'value'       => $state,
1046
                )
1047
            );
1048
1049
        } else {
1050
1051
            $html = aui()->select(
1052
                array(
1053
                    'id'               => 'wpinv_state',
1054
                    'name'             => $name,
1055
                    'label'            => __( 'State', 'invoicing' ),
1056
                    'label_type'       => 'vertical',
1057
                    'placeholder'      => __( 'Select a state', 'invoicing' ),
1058
                    'class'            => $class,
1059
                    'value'            => $state,
1060
                    'options'          => $states,
1061
                    'data-allow-clear' => 'false',
1062
                    'select2'          => true,
1063
                )
1064
            );
1065
1066
        }
1067
1068
        wp_send_json_success(
1069
            array(
1070
                'html'   => $html,
1071
                'select' => ! empty( $states ),
1072
            )
1073
        );
1074
1075
    }
1076
1077
    /**
1078
     * Refresh prices.
1079
     *
1080
     * @since 1.0.19
1081
     */
1082
    public static function payment_form_refresh_prices() {
1083
1084
        // ... form fields...
1085
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
1086
            esc_html_e( 'Error: Reload the page and try again.', 'invoicing' );
1087
            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...
1088
        }
1089
1090
        // Load the submission.
1091
        $submission = new GetPaid_Payment_Form_Submission();
1092
1093
        // Do we have an error?
1094
        if ( ! empty( $submission->last_error ) ) {
1095
            wp_send_json_error(
1096
                array(
1097
                    'code'  => $submission->last_error_code,
1098
                    'error' => $submission->last_error,
1099
                )
1100
            );
1101
        }
1102
1103
        // Prepare the response.
1104
        $response = new GetPaid_Payment_Form_Submission_Refresh_Prices( $submission );
1105
1106
        // Filter the response.
1107
        $response = apply_filters( 'getpaid_payment_form_ajax_refresh_prices', $response->response, $submission );
1108
1109
        wp_send_json_success( $response );
1110
    }
1111
1112
    /**
1113
	 * Handles file uploads.
1114
	 *
1115
	 * @since       1.0.0
1116
	 * @return      void
1117
	 */
1118
	public static function file_upload() {
1119
1120
        // Check nonce.
1121
        check_ajax_referer( 'getpaid_form_nonce' );
1122
1123
        if ( empty( $_POST['form_id'] ) || empty( $_POST['field_name'] ) || empty( $_FILES['file'] ) ) {
1124
            wp_die( esc_html_e( 'Bad Request', 'invoicing' ), 400 );
1125
        }
1126
1127
        // Fetch form.
1128
        $form = new GetPaid_Payment_Form( intval( $_POST['form_id'] ) );
1129
1130
        if ( ! $form->is_active() ) {
1131
            wp_send_json_error( __( 'Payment form not active', 'invoicing' ) );
1132
        }
1133
1134
        // Fetch appropriate field.
1135
        $upload_field = current( wp_list_filter( $form->get_elements(), array( 'id' => sanitize_text_field( $_POST['field_name'] ) ) ) );
1136
        if ( empty( $upload_field ) ) {
1137
            wp_send_json_error( __( 'Invalid upload field.', 'invoicing' ) );
1138
        }
1139
1140
        // Prepare allowed file types.
1141
        $file_types = isset( $upload_field['file_types'] ) ? $upload_field['file_types'] : array( 'jpg|jpeg|jpe', 'gif', 'png' );
1142
        $all_types  = getpaid_get_allowed_mime_types();
1143
        $mime_types = array();
1144
1145
        foreach ( $file_types as $file_type ) {
1146
            if ( isset( $all_types[ $file_type ] ) ) {
1147
                $mime_types[] = $all_types[ $file_type ];
1148
            }
1149
        }
1150
1151
        if ( ! in_array( $_FILES['file']['type'], $mime_types ) ) {
1152
            wp_send_json_error( __( 'Unsupported file type.', 'invoicing' ) );
1153
        }
1154
1155
        // Upload file.
1156
        $file_name = explode( '.', strtolower( $_FILES['file']['name'] ) );
1157
        $file_name = uniqid( 'getpaid-' ) . '.' . array_pop( $file_name );
1158
1159
        $uploaded = wp_upload_bits(
1160
            $file_name,
1161
            null,
1162
            file_get_contents( $_FILES['file']['tmp_name'] )
1163
        );
1164
1165
        if ( ! empty( $uploaded['error'] ) ) {
1166
            wp_send_json_error( $uploaded['error'] );
1167
        }
1168
1169
        // Retrieve response.
1170
        $response = sprintf(
1171
            '<input type="hidden" name="%s[%s]" value="%s" />',
1172
            esc_attr( sanitize_text_field( $_POST['field_name'] ) ),
1173
            esc_url( $uploaded['url'] ),
1174
            esc_attr( sanitize_text_field( strtolower( $_FILES['file']['name'] ) ) )
1175
        );
1176
1177
        wp_send_json_success( $response );
1178
1179
	}
1180
1181
}
1182
1183
WPInv_Ajax::init();
1184