Passed
Push — master ( e6d0e0...44d5e5 )
by Brian
04:56
created

WPInv_Ajax::create_invoice_item()   B

Complexity

Conditions 10
Paths 9

Size

Total Lines 61
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 30
c 0
b 0
f 0
nc 9
nop 0
dl 0
loc 61
rs 7.6666

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Contains 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
            'edit_invoice_item'           => false,
97
            'create_invoice_item'         => false,
98
            'remove_invoice_item'         => false,
99
            'get_billing_details'         => false,
100
            'recalculate_invoice_totals'  => false,
101
            'check_new_user_email'        => false,
102
            'run_tool'                    => false,
103
            'payment_form_refresh_prices' => 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
    /**
165
     * Retrieves a given user's billing address.
166
     */
167
    public static function get_billing_details() {
168
169
        // Verify nonce.
170
        check_ajax_referer( 'wpinv-nonce' );
171
172
        // Can the user manage the plugin?
173
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
174
            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...
175
        }
176
177
        // Do we have a user id?
178
        $user_id = $_GET['user_id'];
179
180
        if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
181
            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...
182
        }
183
184
        // Fetch the billing details.
185
        $billing_details    = wpinv_get_user_address( $user_id );
186
        $billing_details    = apply_filters( 'wpinv_ajax_billing_details', $billing_details, $user_id );
187
188
        // unset the user id and email.
189
        $to_ignore = array( 'user_id', 'email' );
190
191
        foreach ( $to_ignore as $key ) {
192
            if ( isset( $billing_details[ $key ] ) ) {
193
                unset( $billing_details[ $key ] );
194
            }
195
        }
196
197
        wp_send_json_success( $billing_details );
198
199
    }
200
201
    /**
202
     * Checks if a new users email is valid.
203
     */
204
    public static function check_new_user_email() {
205
206
        // Verify nonce.
207
        check_ajax_referer( 'wpinv-nonce' );
208
209
        // Can the user manage the plugin?
210
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
211
            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...
212
        }
213
214
        // We need an email address.
215
        if ( empty( $_GET['email'] ) ) {
216
            _e( "Provide the new user's email address", 'invoicing' );
217
            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...
218
        }
219
220
        // Ensure the email is valid.
221
        $email = sanitize_text_field( $_GET['email'] );
222
        if ( ! is_email( $email ) ) {
223
            _e( 'Invalid email address', 'invoicing' );
224
            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...
225
        }
226
227
        // And it does not exist.
228
        $id = email_exists( $email );
229
        if ( $id ) {
230
            wp_send_json_success( compact( 'id' ) );
231
        }
232
233
        wp_send_json_success( true );
234
    }
235
    
236
    public static function run_tool() {
237
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
238
        if ( !wpinv_current_user_can_manage_invoicing() ) {
239
            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...
240
        }
241
        
242
        $tool = sanitize_text_field( $_POST['tool'] );
243
        
244
        do_action( 'wpinv_run_tool' );
245
        
246
        if ( !empty( $tool ) ) {
247
            do_action( 'wpinv_tool_' . $tool );
248
        }
249
    }
250
251
    /**
252
     * Retrieves the markup for a payment form.
253
     */
254
    public static function get_payment_form() {
255
256
        // Check nonce.
257
        check_ajax_referer( 'getpaid_form_nonce' );
258
259
        // Is the request set up correctly?
260
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) ) {
261
			echo aui()->alert(
262
				array(
263
					'type'    => 'warning',
264
					'content' => __( 'No payment form or item provided', 'invoicing' ),
265
				)
266
            );
267
            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...
268
        }
269
270
        // Payment form or button?
271
		if ( ! empty( $_GET['form'] ) ) {
272
            getpaid_display_payment_form( urldecode( $_GET['form'] ) );
273
		} else if( ! empty( $_GET['invoice'] ) ) {
274
		    getpaid_display_invoice_payment_form( urldecode( $_GET['invoice'] ) );
275
        } else {
276
			$items = getpaid_convert_items_to_array( urldecode( $_GET['item'] ) );
277
		    getpaid_display_item_payment_form( $items );
278
        }
279
280
        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...
281
282
    }
283
284
    /**
285
     * Payment forms.
286
     *
287
     * @since 1.0.18
288
     */
289
    public static function payment_form() {
290
291
        // Check nonce.
292
        check_ajax_referer( 'getpaid_form_nonce' );
293
294
        // ... form fields...
295
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
296
            _e( 'Error: Reload the page and try again.', 'invoicing' );
297
            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...
298
        }
299
300
        // Process the payment form.
301
        $checkout_class = apply_filters( 'getpaid_checkout_class', 'GetPaid_Checkout' );
302
        $checkout       = new $checkout_class( new GetPaid_Payment_Form_Submission() );
303
        $checkout->process_checkout();
304
305
        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...
306
    }
307
308
    /**
309
     * Payment forms.
310
     *
311
     * @since 1.0.18
312
     */
313
    public static function get_payment_form_states_field() {
314
315
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
316
            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...
317
        }
318
319
        $elements = getpaid_get_payment_form_elements( $_GET['form'] );
320
321
        if ( empty( $elements ) ) {
322
            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...
323
        }
324
325
        $address_fields = array();
326
        foreach ( $elements as $element ) {
327
            if ( 'address' === $element['type'] ) {
328
                $address_fields = $element;
329
                break;
330
            }
331
        }
332
333
        if ( empty( $address_fields ) ) {
334
            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...
335
        }
336
337
        foreach ( $address_fields['fields'] as $address_field ) {
338
339
            if ( 'wpinv_state' == $address_field['name'] ) {
340
341
                $wrap_class  = getpaid_get_form_element_grid_class( $address_field );
342
                $wrap_class  = esc_attr( "$wrap_class getpaid-address-field-wrapper" );
343
                $placeholder = empty( $address_field['placeholder'] ) ? '' : esc_attr( $address_field['placeholder'] );
344
                $description = empty( $address_field['description'] ) ? '' : wp_kses_post( $address_field['description'] );
345
                $value       = is_user_logged_in() ? get_user_meta( get_current_user_id(), '_wpinv_state', true ) : '';
346
                $label       = empty( $address_field['label'] ) ? '' : wp_kses_post( $address_field['label'] );
347
348
                if ( ! empty( $address_field['required'] ) ) {
349
                    $label .= "<span class='text-danger'> *</span>";
350
                }
351
352
                $html = getpaid_get_states_select_markup (
353
                    sanitize_text_field( $_GET['country'] ),
354
                    $value,
355
                    $placeholder,
356
                    $label,
357
                    $description,
358
                    ! empty( $address_field['required'] ),
359
                    $wrap_class,
360
                    wpinv_clean( $_GET['name'] )
361
                );
362
363
                wp_send_json_success( $html );
364
                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...
365
366
            }
367
368
        }
369
    
370
        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...
371
    }
372
373
    /**
374
     * Recalculates invoice totals.
375
     */
376
    public static function recalculate_invoice_totals() {
377
378
        // Verify nonce.
379
        check_ajax_referer( 'wpinv-nonce' );
380
381
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
382
            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...
383
        }
384
385
        // We need an invoice.
386
        if ( empty( $_POST['post_id'] ) ) {
387
            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...
388
        }
389
390
        // Fetch the invoice.
391
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
392
393
        // Ensure it exists.
394
        if ( ! $invoice->get_id() ) {
395
            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...
396
        }
397
398
        // Maybe set the country, state, currency.
399
        foreach ( array( 'country', 'state', 'currency', 'vat_number', 'discount_code' ) as $key ) {
400
            if ( isset( $_POST[ $key ] ) ) {
401
                $method = "set_$key";
402
                $invoice->$method( sanitize_text_field( $_POST[ $key ] ) );
403
            }
404
        }
405
406
        // Maybe disable taxes.
407
        $invoice->set_disable_taxes( ! empty( $_POST['taxes'] ) );
408
409
        // Discount code.
410
        if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) {
411
            $discount = new WPInv_Discount( $invoice->get_discount_code() );
412
            if ( $discount->exists() ) {
413
                $invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
414
            } else {
415
                $invoice->remove_discount( 'discount_code' );
416
            }
417
        }
418
419
        // Recalculate totals.
420
        $invoice->recalculate_total();
421
422
        $total        = wpinv_price( $invoice->get_total(), $invoice->get_currency() );
423
        $suscriptions = getpaid_get_invoice_subscriptions( $invoice );
424
        if ( is_a( $suscriptions, 'WPInv_Subscription' ) && $invoice->is_recurring() && $invoice->is_parent() && $invoice->get_total() != $invoice->get_recurring_total() ) {
425
            $recurring_total = wpinv_price( $invoice->get_recurring_total(), $invoice->get_currency() );
426
            $total          .= '<small class="form-text text-muted">' . sprintf( __( 'Recurring Price: %s', 'invoicing' ), $recurring_total ) . '</small>';
427
        }
428
429
        $totals = array(
430
            'subtotal' => wpinv_price( $invoice->get_subtotal(), $invoice->get_currency() ),
431
            'discount' => wpinv_price( $invoice->get_total_discount(), $invoice->get_currency() ),
432
            'tax'      => wpinv_price( $invoice->get_total_tax(), $invoice->get_currency() ),
433
            'total'    => $total,
434
        );
435
436
        $totals = apply_filters( 'getpaid_invoice_totals', $totals, $invoice );
437
438
        wp_send_json_success( compact( 'totals' ) );
439
    }
440
441
    /**
442
     * Get items belonging to a given invoice.
443
     */
444
    public static function get_invoice_items() {
445
446
        // Verify nonce.
447
        check_ajax_referer( 'wpinv-nonce' );
448
449
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
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
        // We need an invoice and items.
454
        if ( empty( $_POST['post_id'] ) ) {
455
            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...
456
        }
457
458
        // Fetch the invoice.
459
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
460
461
        // Ensure it exists.
462
        if ( ! $invoice->get_id() ) {
463
            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...
464
        }
465
466
        // Return an array of invoice items.
467
        $items = array();
468
469
        foreach ( $invoice->get_items() as $item ) {
470
            $items[] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency(), $invoice->is_renewal()  );
471
        }
472
473
        wp_send_json_success( compact( 'items' ) );
474
    }
475
476
    /**
477
     * Edits an invoice item.
478
     */
479
    public static function edit_invoice_item() {
480
481
        // Verify nonce.
482
        check_ajax_referer( 'wpinv-nonce' );
483
484
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
485
            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...
486
        }
487
488
        // We need an invoice and item details.
489
        if ( empty( $_POST['post_id'] ) || empty( $_POST['data'] ) ) {
490
            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...
491
        }
492
493
        // Fetch the invoice.
494
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
495
496
        // Ensure it exists and its not been paid for.
497
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
498
            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...
499
        }
500
501
        // Format the data.
502
        $data = wp_unslash( wp_list_pluck( $_POST['data'], 'value', 'field' ) );
503
504
        // Ensure that we have an item id.
505
        if ( empty( $data['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
        // Abort if the invoice does not have the specified item.
510
        $item = $invoice->get_item( (int) $data['id'] );
511
512
        if ( empty( $item ) ) {
513
            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...
514
        }
515
516
        // Update the item.
517
        $item->set_price( floatval( $data['price'] ) );
518
        $item->set_name( sanitize_text_field( $data['name'] ) );
519
        $item->set_description( wp_kses_post( $data['description'] ) );
520
        $item->set_quantity( floatval( $data['quantity'] ) );
521
522
        // Add it to the invoice.
523
        $error = $invoice->add_item( $item );
524
        $alert = false;
525
        if ( is_wp_error( $error ) ) {
526
            $alert = $error->get_error_message();
527
        }
528
529
        // Update totals.
530
        $invoice->recalculate_total();
531
532
        // Save the invoice.
533
        $invoice->save();
534
535
        // Return an array of invoice items.
536
        $items = array();
537
538
        foreach ( $invoice->get_items() as $item ) {
539
            $items[] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency()  );
540
        }
541
542
        wp_send_json_success( compact( 'items', 'alert' ) );
543
    }
544
545
    /**
546
     * Creates an invoice item.
547
     */
548
    public static function create_invoice_item() {
549
550
        // Verify nonce.
551
        check_ajax_referer( 'wpinv-nonce' );
552
553
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
554
            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...
555
        }
556
557
        // We need an invoice and item details.
558
        if ( empty( $_POST['post_id'] ) || empty( $_POST['data'] ) ) {
559
            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...
560
        }
561
562
        // Fetch the invoice.
563
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
564
565
        // Ensure it exists and its not been paid for.
566
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
567
            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...
568
        }
569
570
        // Format the data.
571
        $data = wp_unslash( wp_list_pluck( $_POST['data'], 'value', 'field' ) );
572
573
        $item = new WPInv_Item();
574
        $item->set_price( floatval( $data['price'] ) );
575
        $item->set_name( sanitize_text_field( $data['name'] ) );
576
        $item->set_description( wp_kses_post( $data['description'] ) );
577
        $item->set_status( 'publish' );
578
        $item->save();
579
580
        if ( ! $item->exists() ) {
581
            $alert = __( 'Could not create invoice item. Please try again.', 'invoicing' );
582
        } else {
583
            $item = new GetPaid_Form_Item( $item->get_id() );
584
            $item->set_quantity( floatval( $data['quantity'] ) );
585
586
            // Add it to the invoice.
587
            $error = $invoice->add_item( $item );
588
            $alert = false;
589
            if ( is_wp_error( $error ) ) {
590
                $alert = $error->get_error_message();
591
            }
592
593
            // Update totals.
594
            $invoice->recalculate_total();
595
596
            // Save the invoice.
597
            $invoice->save();
598
599
        }
600
601
        // Return an array of invoice items.
602
        $items = array();
603
604
        foreach ( $invoice->get_items() as $item ) {
605
            $items[] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency()  );
606
        }
607
608
        wp_send_json_success( compact( 'items', 'alert' ) );
609
    }
610
611
    /**
612
     * Deletes an invoice item.
613
     */
614
    public static function remove_invoice_item() {
615
616
        // Verify nonce.
617
        check_ajax_referer( 'wpinv-nonce' );
618
619
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
620
            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...
621
        }
622
623
        // We need an invoice and an item.
624
        if ( empty( $_POST['post_id'] ) || empty( $_POST['item_id'] ) ) {
625
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
626
        }
627
628
        // Fetch the invoice.
629
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
630
631
        // Ensure it exists and its not been paid for.
632
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
633
            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...
634
        }
635
636
        // Abort if the invoice does not have the specified item.
637
        $item = $invoice->get_item( (int) $_POST['item_id'] );
638
639
        if ( empty( $item ) ) {
640
            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...
641
        }
642
643
        $invoice->remove_item( (int) $_POST['item_id'] );
644
645
        // Update totals.
646
        $invoice->recalculate_total();
647
648
        // Save the invoice.
649
        $invoice->save();
650
651
        // Return an array of invoice items.
652
        $items = array();
653
654
        foreach ( $invoice->get_items() as $item ) {
655
            $items[] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency()  );
656
        }
657
658
        wp_send_json_success( compact( 'items' ) );
659
    }
660
661
    /**
662
     * Adds a items to an invoice.
663
     */
664
    public static function add_invoice_items() {
665
666
        // Verify nonce.
667
        check_ajax_referer( 'wpinv-nonce' );
668
669
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
670
            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...
671
        }
672
673
        // We need an invoice and items.
674
        if ( empty( $_POST['post_id'] ) || empty( $_POST['items'] ) ) {
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
        // Fetch the invoice.
679
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
680
        $alert   = false;
681
682
        // Ensure it exists and its not been paid for.
683
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
684
            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...
685
        }
686
687
        // Add the items.
688
        foreach ( $_POST['items'] as $data ) {
689
690
            $item = new GetPaid_Form_Item( $data[ 'id' ] );
691
692
            if ( is_numeric( $data[ 'qty' ] ) && (float) $data[ 'qty' ] > 0 ) {
693
                $item->set_quantity( $data[ 'qty' ] );
694
            }
695
696
            if ( $item->get_id() > 0 ) {
697
                $error = $invoice->add_item( $item );
698
699
                if ( is_wp_error( $error ) ) {
700
                    $alert = $error->get_error_message();
701
                }
702
703
            }
704
705
        }
706
707
        // Save the invoice.
708
        $invoice->recalculate_total();
709
        $invoice->save();
710
711
        // Return an array of invoice items.
712
        $items = array();
713
714
        foreach ( $invoice->get_items() as $item ) {
715
            $items[] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency() );
716
        }
717
718
        wp_send_json_success( compact( 'items', 'alert' ) );
719
    }
720
721
    /**
722
     * Retrieves items that should be added to an invoice.
723
     */
724
    public static function get_invoicing_items() {
725
726
        // Verify nonce.
727
        check_ajax_referer( 'wpinv-nonce' );
728
729
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
730
            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...
731
        }
732
733
        // We need a search term.
734
        if ( empty( $_GET['search'] ) ) {
735
            wp_send_json_success( array() );
736
        }
737
738
        // Retrieve items.
739
        $item_args = array(
740
            'post_type'      => 'wpi_item',
741
            'orderby'        => 'title',
742
            'order'          => 'ASC',
743
            'posts_per_page' => -1,
744
            'post_status'    => array( 'publish' ),
745
            's'              => trim( $_GET['search'] ),
746
            'meta_query'     => array(
747
                array(
748
                    'key'       => '_wpinv_type',
749
                    'compare'   => '!=',
750
                    'value'     => 'package'
751
                )
752
            )
753
        );
754
755
        $items = get_posts( apply_filters( 'getpaid_ajax_invoice_items_query_args', $item_args ) );
756
        $data  = array();
757
758
        $is_payment_form = ( ! empty( $_GET['post_id'] ) && 'wpi_payment_form' == get_post_type( $_GET['post_id'] ) );
759
760
        foreach ( $items as $item ) {
761
            $item      = new GetPaid_Form_Item( $item );
762
            $data[] = array(
763
                'id'        => (int) $item->get_id(),
764
                'text'      => strip_tags( $item->get_name() ),
765
                'form_data' => $is_payment_form ? $item->prepare_data_for_use( false ) : '',
766
            );
767
        }
768
769
        wp_send_json_success( $data );
770
771
    }
772
773
    /**
774
     * Retrieves items that should be added to an invoice.
775
     */
776
    public static function get_customers() {
777
778
        // Verify nonce.
779
        check_ajax_referer( 'wpinv-nonce' );
780
781
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
782
            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...
783
        }
784
785
        // We need a search term.
786
        if ( empty( $_GET['search'] ) ) {
787
            wp_send_json_success( array() );
788
        }
789
790
        // Retrieve customers.
791
    
792
        $customer_args = array(
793
            'fields'         => array( 'ID', 'user_email', 'display_name' ),
794
            'orderby'        => 'display_name',
795
            'search'         => '*' . sanitize_text_field( $_GET['search'] ) . '*',
796
            'search_columns' => array( 'user_login', 'user_email', 'display_name' ),
797
        );
798
799
        $customers = get_users( apply_filters( 'getpaid_ajax_invoice_customers_query_args', $customer_args ) );
800
        $data      = array();
801
802
        foreach ( $customers as $customer ) {
803
            $data[] = array(
804
                'id'        => (int) $customer->ID,
805
                'text'      => strip_tags( sprintf( _x( '%1$s (%2$s)', 'user dropdown', 'invoicing' ), $customer->display_name, $customer->user_email ) ),
806
            );
807
        }
808
809
        wp_send_json_success( $data );
810
811
    }
812
813
    /**
814
     * Retrieves the states field for AUI forms.
815
     */
816
    public static function get_aui_states_field() {
817
818
        // Verify nonce.
819
        check_ajax_referer( 'wpinv-nonce' );
820
821
        // We need a country.
822
        if ( empty( $_GET['country'] ) ) {
823
            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...
824
        }
825
826
        $states = wpinv_get_country_states( sanitize_text_field( $_GET['country'] ) );
827
        $state  = isset( $_GET['state'] ) ? sanitize_text_field( $_GET['state'] ) : wpinv_get_default_state();
828
        $name   = isset( $_GET['name'] ) ? sanitize_text_field( $_GET['name'] ) : 'wpinv_state';
829
        $class  = isset( $_GET['class'] ) ? sanitize_text_field( $_GET['class'] ) : 'form-control-sm';
830
831
        if ( empty( $states ) ) {
832
833
            $html = aui()->input(
834
                array(
835
                    'type'        => 'text',
836
                    'id'          => 'wpinv_state',
837
                    'name'        => $name,
838
                    'label'       => __( 'State', 'invoicing' ),
839
                    'label_type'  => 'vertical',
840
                    'placeholder' => __( 'State', 'invoicing' ),
841
                    'class'       => $class,
842
                    'value'       => $state,
843
                )
844
            );
845
846
        } else {
847
848
            $html = aui()->select(
849
                array(
850
                    'id'          => 'wpinv_state',
851
                    'name'        => $name,
852
                    'label'       => __( 'State', 'invoicing' ),
853
                    'label_type'  => 'vertical',
854
                    'placeholder' => __( 'Select a state', 'invoicing' ),
855
                    'class'       => $class,
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
     * Refresh prices.
876
     *
877
     * @since 1.0.19
878
     */
879
    public static function payment_form_refresh_prices() {
880
881
        // Check nonce.
882
        check_ajax_referer( 'getpaid_form_nonce' );
883
884
        // ... form fields...
885
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
886
            _e( 'Error: Reload the page and try again.', '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
        // Load the submission.
891
        $submission = new GetPaid_Payment_Form_Submission();
892
893
        // Do we have an error?
894
        if ( ! empty( $submission->last_error ) ) {
895
            wp_send_json_error(
896
                array(
897
                    'code'  => $submission->last_error_code,
898
                    'error' => $submission->last_error
899
                )
900
            );
901
        }
902
903
        // Prepare the response.
904
        $response = new GetPaid_Payment_Form_Submission_Refresh_Prices( $submission );
905
906
        // Filter the response.
907
        $response = apply_filters( 'getpaid_payment_form_ajax_refresh_prices', $response->response, $submission );
908
909
        wp_send_json_success( $response );
910
    }
911
912
}
913
914
WPInv_Ajax::init();