Passed
Push — master ( 0587d7...bbe6ac )
by Brian
05:19
created

WPInv_Ajax::recalculate_invoice_totals()   C

Complexity

Conditions 12
Paths 21

Size

Total Lines 63
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 31
c 0
b 0
f 0
nc 21
nop 0
dl 0
loc 63
rs 6.9666

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 string[]; however, parameter $str of sanitize_text_field() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

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

130
            $note_id = /** @scrutinizer ignore-deprecated */ wpinv_insert_payment_note( $post_id, $note, $is_customer_note );
Loading history...
131
132
            if ( $note_id > 0 && !is_wp_error( $note_id ) ) {
133
                wpinv_get_invoice_note_line_item( $note_id );
134
            }
135
        }
136
137
        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...
138
    }
139
140
    public static function delete_note() {
141
        check_ajax_referer( 'delete-invoice-note', '_nonce' );
142
143
        if ( !wpinv_current_user_can_manage_invoicing() ) {
144
            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...
145
        }
146
147
        $note_id = (int)$_POST['note_id'];
148
149
        if ( $note_id > 0 ) {
150
            wp_delete_comment( $note_id, true );
151
        }
152
153
        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...
154
    }
155
    
156
    public static function get_states_field() {
157
        echo wpinv_get_states_field();
158
        
159
        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...
160
    }
161
162
    /**
163
     * Retrieves a given user's billing address.
164
     */
165
    public static function get_billing_details() {
166
167
        // Verify nonce.
168
        check_ajax_referer( 'wpinv-nonce' );
169
170
        // Can the user manage the plugin?
171
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
172
            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...
173
        }
174
175
        // Do we have a user id?
176
        $user_id = $_GET['user_id'];
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
        // Fetch the billing details.
183
        $billing_details    = wpinv_get_user_address( $user_id );
184
        $billing_details    = apply_filters( 'wpinv_ajax_billing_details', $billing_details, $user_id );
185
186
        // unset the user id and email.
187
        $to_ignore = array( 'user_id', 'email' );
188
189
        foreach ( $to_ignore as $key ) {
190
            if ( isset( $billing_details[ $key ] ) ) {
191
                unset( $billing_details[ $key ] );
192
            }
193
        }
194
195
        wp_send_json_success( $billing_details );
196
197
    }
198
199
    /**
200
     * Checks if a new users email is valid.
201
     */
202
    public static function check_new_user_email() {
203
204
        // Verify nonce.
205
        check_ajax_referer( 'wpinv-nonce' );
206
207
        // Can the user manage the plugin?
208
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
209
            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...
210
        }
211
212
        // We need an email address.
213
        if ( empty( $_GET['email'] ) ) {
214
            _e( "Provide the new user's email address", 'invoicing' );
215
            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...
216
        }
217
218
        // Ensure the email is valid.
219
        $email = sanitize_text_field( $_GET['email'] );
220
        if ( ! is_email( $email ) ) {
221
            _e( 'Invalid email address', 'invoicing' );
222
            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...
223
        }
224
225
        // And it does not exist.
226
        if ( email_exists( $email ) ) {
227
            _e( 'A user with this email address already exists', 'invoicing' );
228
            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...
229
        }
230
231
        wp_send_json_success( true );
232
    }
233
    
234
    public static function run_tool() {
235
        check_ajax_referer( 'wpinv-nonce', '_nonce' );
236
        if ( !wpinv_current_user_can_manage_invoicing() ) {
237
            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...
238
        }
239
        
240
        $tool = sanitize_text_field( $_POST['tool'] );
241
        
242
        do_action( 'wpinv_run_tool' );
243
        
244
        if ( !empty( $tool ) ) {
245
            do_action( 'wpinv_tool_' . $tool );
246
        }
247
    }
248
249
    /**
250
     * Retrieves the markup for a payment form.
251
     */
252
    public static function get_payment_form() {
253
254
        // Check nonce.
255
        check_ajax_referer( 'getpaid_form_nonce' );
256
257
        // Is the request set up correctly?
258
		if ( empty( $_GET['form'] ) && empty( $_GET['item'] ) ) {
259
			echo aui()->alert(
260
				array(
261
					'type'    => 'warning',
262
					'content' => __( 'No payment form or item provided', 'invoicing' ),
263
				)
264
            );
265
            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...
266
        }
267
268
        // Payment form or button?
269
		if ( ! empty( $_GET['form'] ) ) {
270
            getpaid_display_payment_form( urldecode( $_GET['form'] ) );
271
		} else if( ! empty( $_GET['invoice'] ) ) {
272
		    getpaid_display_invoice_payment_form( urldecode( $_GET['invoice'] ) );
273
        } else {
274
			$items = getpaid_convert_items_to_array( urldecode( $_GET['item'] ) );
275
		    getpaid_display_item_payment_form( $items );
276
        }
277
278
        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...
279
280
    }
281
282
    /**
283
     * Payment forms.
284
     *
285
     * @since 1.0.18
286
     */
287
    public static function payment_form() {
288
289
        // Check nonce.
290
        check_ajax_referer( 'getpaid_form_nonce' );
291
292
        // ... form fields...
293
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
294
            _e( 'Error: Reload the page and try again.', 'invoicing' );
295
            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...
296
        }
297
298
        // Process the payment form.
299
        $checkout_class = apply_filters( 'getpaid_checkout_class', 'GetPaid_Checkout' );
300
        $checkout       = new $checkout_class( new GetPaid_Payment_Form_Submission() );
301
        $checkout->process_checkout();
302
303
        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...
304
    }
305
306
    /**
307
     * Payment forms.
308
     *
309
     * @since 1.0.18
310
     */
311
    public static function get_payment_form_states_field() {
312
313
        if ( empty( $_GET['country'] ) || empty( $_GET['form'] ) ) {
314
            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...
315
        }
316
317
        $elements = getpaid_get_payment_form_elements( $_GET['form'] );
318
319
        if ( empty( $elements ) ) {
320
            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...
321
        }
322
323
        $address_fields = array();
324
        foreach ( $elements as $element ) {
325
            if ( 'address' === $element['type'] ) {
326
                $address_fields = $element;
327
                break;
328
            }
329
        }
330
331
        if ( empty( $address_fields ) ) {
332
            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...
333
        }
334
335
        foreach ( $address_fields['fields'] as $address_field ) {
336
337
            if ( 'wpinv_state' == $address_field['name'] ) {
338
339
                $wrap_class  = getpaid_get_form_element_grid_class( $address_field );
340
                $wrap_class  = esc_attr( "$wrap_class getpaid-address-field-wrapper" );
341
                $placeholder = empty( $address_field['placeholder'] ) ? '' : esc_attr( $address_field['placeholder'] );
342
                $description = empty( $address_field['description'] ) ? '' : wp_kses_post( $address_field['description'] );
343
                $value       = is_user_logged_in() ? get_user_meta( get_current_user_id(), '_wpinv_state', true ) : '';
344
                $label       = empty( $address_field['label'] ) ? '' : wp_kses_post( $address_field['label'] );
345
346
                if ( ! empty( $address_field['required'] ) ) {
347
                    $label .= "<span class='text-danger'> *</span>";
348
                }
349
350
                $html = getpaid_get_states_select_markup (
351
                    sanitize_text_field( $_GET['country'] ),
352
                    $value,
353
                    $placeholder,
354
                    $label,
355
                    $description,
356
                    ! empty( $address_field['required'] ),
357
                    $wrap_class,
358
                    wpinv_clean( $_GET['name'] )
359
                );
360
361
                wp_send_json_success( $html );
362
                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...
363
364
            }
365
366
        }
367
    
368
        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...
369
    }
370
371
    /**
372
     * Recalculates invoice totals.
373
     */
374
    public static function recalculate_invoice_totals() {
375
376
        // Verify nonce.
377
        check_ajax_referer( 'wpinv-nonce' );
378
379
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
380
            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...
381
        }
382
383
        // We need an invoice.
384
        if ( empty( $_POST['post_id'] ) ) {
385
            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...
386
        }
387
388
        // Fetch the invoice.
389
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
390
391
        // Ensure it exists.
392
        if ( ! $invoice->get_id() ) {
393
            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...
394
        }
395
396
        // Maybe set the country, state, currency.
397
        foreach ( array( 'country', 'state', 'currency', 'vat_number', 'discount_code' ) as $key ) {
398
            if ( isset( $_POST[ $key ] ) ) {
399
                $method = "set_$key";
400
                $invoice->$method( sanitize_text_field( $_POST[ $key ] ) );
401
            }
402
        }
403
404
        // Maybe disable taxes.
405
        $invoice->set_disable_taxes( ! empty( $_POST['taxes'] ) );
406
407
        // Discount code.
408
        if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) {
409
            $discount = new WPInv_Discount( $invoice->get_discount_code() );
410
            if ( $discount->exists() ) {
411
                $invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
412
            } else {
413
                $invoice->remove_discount( 'discount_code' );
414
            }
415
        }
416
417
        // Recalculate totals.
418
        $invoice->recalculate_total();
419
420
        $total = wpinv_price( $invoice->get_total(), $invoice->get_currency() );
421
422
        if ( $invoice->is_recurring() && $invoice->is_parent() && $invoice->get_total() != $invoice->get_recurring_total() ) {
423
            $recurring_total = wpinv_price( $invoice->get_recurring_total(), $invoice->get_currency() );
424
            $total          .= '<small class="form-text text-muted">' . sprintf( __( 'Recurring Price: %s', 'invoicing' ), $recurring_total ) . '</small>';
425
        }
426
427
        $totals = array(
428
            'subtotal' => wpinv_price( $invoice->get_subtotal(), $invoice->get_currency() ),
429
            'discount' => wpinv_price( $invoice->get_total_discount(), $invoice->get_currency() ),
430
            'tax'      => wpinv_price( $invoice->get_total_tax(), $invoice->get_currency() ),
431
            'total'    => $total,
432
        );
433
434
        $totals = apply_filters( 'getpaid_invoice_totals', $totals, $invoice );
435
436
        wp_send_json_success( compact( 'totals' ) );
437
    }
438
439
    /**
440
     * Get items belonging to a given invoice.
441
     */
442
    public static function get_invoice_items() {
443
444
        // Verify nonce.
445
        check_ajax_referer( 'wpinv-nonce' );
446
447
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
448
            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...
449
        }
450
451
        // We need an invoice and items.
452
        if ( empty( $_POST['post_id'] ) ) {
453
            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...
454
        }
455
456
        // Fetch the invoice.
457
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
458
459
        // Ensure it exists.
460
        if ( ! $invoice->get_id() ) {
461
            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...
462
        }
463
464
        // Return an array of invoice items.
465
        $items = array();
466
467
        foreach ( $invoice->get_items() as $item_id => $item ) {
468
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency(), $invoice->is_renewal()  );
469
        }
470
471
        wp_send_json_success( compact( 'items' ) );
472
    }
473
474
    /**
475
     * Edits an invoice item.
476
     */
477
    public static function edit_invoice_item() {
478
479
        // Verify nonce.
480
        check_ajax_referer( 'wpinv-nonce' );
481
482
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
483
            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...
484
        }
485
486
        // We need an invoice and item details.
487
        if ( empty( $_POST['post_id'] ) || empty( $_POST['data'] ) ) {
488
            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...
489
        }
490
491
        // Fetch the invoice.
492
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
493
494
        // Ensure it exists and its not been paid for.
495
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
496
            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...
497
        }
498
499
        // Format the data.
500
        $data = wp_list_pluck( $_POST['data'], 'value', 'field' );
501
502
        // Ensure that we have an item id.
503
        if ( empty( $data['id'] ) ) {
504
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
505
        }
506
507
        // Abort if the invoice does not have the specified item.
508
        $item = $invoice->get_item( (int) $data['id'] );
509
510
        if ( empty( $item ) ) {
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
        // Update the item.
515
        $item->set_price( $data['price'] );
516
        $item->set_name( $data['name'] );
517
        $item->set_description( $data['description'] );
518
        $item->set_quantity( $data['quantity'] );
519
520
        // Add it to the invoice.
521
        $error = $invoice->add_item( $item );
522
        $alert = false;
523
        if ( is_wp_error( $error ) ) {
524
            $alert = $error->get_error_message();
525
        }
526
527
        // Update totals.
528
        $invoice->recalculate_total();
529
530
        // Save the invoice.
531
        $invoice->save();
532
533
        // Return an array of invoice items.
534
        $items = array();
535
536
        foreach ( $invoice->get_items() as $item_id => $item ) {
537
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency()  );
538
        }
539
540
        wp_send_json_success( compact( 'items', 'alert' ) );
541
    }
542
543
    /**
544
     * Deletes an invoice item.
545
     */
546
    public static function remove_invoice_item() {
547
548
        // Verify nonce.
549
        check_ajax_referer( 'wpinv-nonce' );
550
551
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
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
        // We need an invoice and an item.
556
        if ( empty( $_POST['post_id'] ) || empty( $_POST['item_id'] ) ) {
557
            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...
558
        }
559
560
        // Fetch the invoice.
561
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
562
563
        // Ensure it exists and its not been paid for.
564
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
565
            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...
566
        }
567
568
        // Abort if the invoice does not have the specified item.
569
        $item = $invoice->get_item( (int) $_POST['item_id'] );
570
571
        if ( empty( $item ) ) {
572
            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...
573
        }
574
575
        $invoice->remove_item( (int) $_POST['item_id'] );
576
577
        // Update totals.
578
        $invoice->recalculate_total();
579
580
        // Save the invoice.
581
        $invoice->save();
582
583
        // Return an array of invoice items.
584
        $items = array();
585
586
        foreach ( $invoice->get_items() as $item_id => $item ) {
587
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax(  $invoice->get_currency()  );
588
        }
589
590
        wp_send_json_success( compact( 'items' ) );
591
    }
592
593
    /**
594
     * Adds a items to an invoice.
595
     */
596
    public static function add_invoice_items() {
597
598
        // Verify nonce.
599
        check_ajax_referer( 'wpinv-nonce' );
600
601
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
602
            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...
603
        }
604
605
        // We need an invoice and items.
606
        if ( empty( $_POST['post_id'] ) || empty( $_POST['items'] ) ) {
607
            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...
608
        }
609
610
        // Fetch the invoice.
611
        $invoice = new WPInv_Invoice( trim( $_POST['post_id'] ) );
612
        $alert   = false;
613
614
        // Ensure it exists and its not been paid for.
615
        if ( ! $invoice->get_id() || $invoice->is_paid() || $invoice->is_refunded() ) {
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
        // Add the items.
620
        foreach ( $_POST['items'] as $data ) {
621
622
            $item = new GetPaid_Form_Item( $data[ 'id' ] );
623
624
            if ( is_numeric( $data[ 'qty' ] ) && (float) $data[ 'qty' ] > 0 ) {
625
                $item->set_quantity( $data[ 'qty' ] );
626
            }
627
628
            if ( $item->get_id() > 0 ) {
629
                $error = $invoice->add_item( $item );
630
631
                if ( is_wp_error( $error ) ) {
632
                    $alert = $error->get_error_message();
633
                }
634
635
            }
636
637
        }
638
639
        // Save the invoice.
640
        $invoice->recalculate_total();
641
        $invoice->save();
642
643
        // Return an array of invoice items.
644
        $items = array();
645
646
        foreach ( $invoice->get_items() as $item_id => $item ) {
647
            $items[ $item_id ] = $item->prepare_data_for_invoice_edit_ajax( $invoice->get_currency() );
648
        }
649
650
        wp_send_json_success( compact( 'items', 'alert' ) );
651
    }
652
653
    /**
654
     * Retrieves items that should be added to an invoice.
655
     */
656
    public static function get_invoicing_items() {
657
658
        // Verify nonce.
659
        check_ajax_referer( 'wpinv-nonce' );
660
661
        if ( ! wpinv_current_user_can_manage_invoicing() ) {
662
            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...
663
        }
664
665
        // We need a search term.
666
        if ( empty( $_GET['search'] ) ) {
667
            wp_send_json_success( array() );
668
        }
669
670
        // Retrieve items.
671
        $item_args = array(
672
            'post_type'      => 'wpi_item',
673
            'orderby'        => 'title',
674
            'order'          => 'ASC',
675
            'posts_per_page' => -1,
676
            'post_status'    => array( 'publish' ),
677
            's'              => trim( $_GET['search'] ),
678
            'meta_query'     => array(
679
                array(
680
                    'key'       => '_wpinv_type',
681
                    'compare'   => '!=',
682
                    'value'     => 'package'
683
                )
684
            )
685
        );
686
687
        $items = get_posts( apply_filters( 'getpaid_ajax_invoice_items_query_args', $item_args ) );
688
        $data  = array();
689
690
691
        $is_payment_form = ( ! empty( $_GET['post_id'] ) && 'wpi_payment_form' == get_post_type( $_GET['post_id'] ) );
692
693
        foreach ( $items as $item ) {
694
            $item      = new GetPaid_Form_Item( $item );
695
            $data[] = array(
696
                'id'        => (int) $item->get_id(),
697
                'text'      => strip_tags( $item->get_name() ),
698
                'form_data' => $is_payment_form ? $item->prepare_data_for_use( false ) : '',
699
            );
700
        }
701
702
        wp_send_json_success( $data );
703
704
    }
705
706
    /**
707
     * Retrieves the states field for AUI forms.
708
     */
709
    public static function get_aui_states_field() {
710
711
        // Verify nonce.
712
        check_ajax_referer( 'wpinv-nonce' );
713
714
        // We need a country.
715
        if ( empty( $_GET['country'] ) ) {
716
            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...
717
        }
718
719
        $states = wpinv_get_country_states( sanitize_text_field( $_GET['country'] ) );
720
        $state  = isset( $_GET['state'] ) ? sanitize_text_field( $_GET['state'] ) : wpinv_get_default_state();
721
        $name   = isset( $_GET['name'] ) ? sanitize_text_field( $_GET['name'] ) : 'wpinv_state';
722
        $class  = isset( $_GET['class'] ) ? sanitize_text_field( $_GET['class'] ) : 'form-control-sm';
723
724
        if ( empty( $states ) ) {
725
726
            $html = aui()->input(
727
                array(
728
                    'type'        => 'text',
729
                    'id'          => 'wpinv_state',
730
                    'name'        => $name,
731
                    'label'       => __( 'State', 'invoicing' ),
732
                    'label_type'  => 'vertical',
733
                    'placeholder' => __( 'State', 'invoicing' ),
734
                    'class'       => $class,
735
                    'value'       => $state,
736
                )
737
            );
738
739
        } else {
740
741
            $html = aui()->select(
742
                array(
743
                    'id'          => 'wpinv_state',
744
                    'name'        => $name,
745
                    'label'       => __( 'State', 'invoicing' ),
746
                    'label_type'  => 'vertical',
747
                    'placeholder' => __( 'Select a state', 'invoicing' ),
748
                    'class'       => $class,
749
                    'value'       => $state,
750
                    'options'     => $states,
751
                    'data-allow-clear' => 'false',
752
                    'select2'          => true,
753
                )
754
            );
755
756
        }
757
758
        wp_send_json_success(
759
            array(
760
                'html'   => $html,
761
                'select' => ! empty ( $states )
762
            )
763
        );
764
765
    }
766
767
    /**
768
     * Refresh prices.
769
     *
770
     * @since 1.0.19
771
     */
772
    public static function payment_form_refresh_prices() {
773
774
        // Check nonce.
775
        check_ajax_referer( 'getpaid_form_nonce' );
776
777
        // ... form fields...
778
        if ( empty( $_POST['getpaid_payment_form_submission'] ) ) {
779
            _e( 'Error: Reload the page and try again.', 'invoicing' );
780
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
781
        }
782
783
        // Load the submission.
784
        $submission = new GetPaid_Payment_Form_Submission();
785
786
        // Do we have an error?
787
        if ( ! empty( $submission->last_error ) ) {
788
            echo $submission->last_error;
789
            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...
790
        }
791
792
        // Prepare the response.
793
        $response = new GetPaid_Payment_Form_Submission_Refresh_Prices( $submission );
794
        
795
        // Filter the response.
796
        $response = apply_filters( 'getpaid_payment_form_ajax_refresh_prices', $response->response, $submission );
797
798
        wp_send_json_success( $response );
799
    }
800
801
}
802
803
WPInv_Ajax::init();