Issues (850)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class-getpaid-meta-box-invoice-items.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * Invoice Items
5
 *
6
 * Display the invoice items meta box.
7
 *
8
 */
9
10
if ( ! defined( 'ABSPATH' ) ) {
11
	exit; // Exit if accessed directly
12
}
13
14
/**
15
 * GetPaid_Meta_Box_Invoice_Items Class.
16
 */
17
class GetPaid_Meta_Box_Invoice_Items {
18
19
    public static function get_columns( $invoice ) {
20
        $use_taxes = $invoice->is_taxable() && wpinv_use_taxes();
21
        $columns   = array(
22
            'id'     => __( 'ID', 'invoicing' ),
23
            'title'  => __( 'Item', 'invoicing' ),
24
            'price'  => sprintf(
25
                '<span class="getpaid-hide-if-hours getpaid-hide-if-quantity">%s</span>
26
                <span class="getpaid-hide-if-hours hide-if-amount">%s</span>
27
                <span class="getpaid-hide-if-quantity hide-if-amount">%s</span>',
28
                __( 'Amount', 'invoicing' ),
29
                __( 'Price', 'invoicing' ),
30
                __( 'Rate', 'invoicing' )
31
            ),
32
            'qty'    => sprintf(
33
                '<span class="getpaid-hide-if-hours">%s</span><span class="getpaid-hide-if-quantity">%s</span>',
34
                __( 'Quantity', 'invoicing' ),
35
                __( 'Hours', 'invoicing' )
36
            ),
37
            'total'  => __( 'Total', 'invoicing' ),
38
            'tax'    => $invoice->get_item_tax_name(),
39
            'action' => '',
40
        );
41
42
        if ( ! $use_taxes ) {
43
            unset( $columns['tax'] );
44
        }
45
46
        return $columns;
47
    }
48
49
    public static function output( $post, $invoice = false ) {
50
51
        if ( apply_filters( 'getpaid_use_new_invoice_items_metabox', false ) ) {
52
            return self::output2( $post );
0 ignored issues
show
Are you sure the usage of self::output2($post) targeting GetPaid_Meta_Box_Invoice_Items::output2() seems to always return null.

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

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

}

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

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

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

Loading history...
53
        }
54
55
        $post_id    = ! empty( $post->ID ) ? $post->ID : 0;
56
        $invoice    = $invoice instanceof WPInv_Invoice ? $invoice : new WPInv_Invoice( $post_id );
57
        $use_taxes  = $invoice->is_taxable() && wpinv_use_taxes();
58
        $item_types = apply_filters( 'wpinv_item_types_for_quick_add_item', wpinv_get_item_types(), $post );
59
        $columns    = self::get_columns( $invoice );
60
        $cols       = count( $columns );
61
        $class      = '';
62
63
        unset( $item_types['adv'] );
64
        unset( $item_types['package'] );
65
66
        if ( $invoice->is_paid() ) {
67
            $class .= ' wpinv-paid';
68
        }
69
70
        if ( $invoice->is_refunded() ) {
71
            $class .= ' wpinv-refunded';
72
        }
73
74
        if ( $invoice->is_recurring() ) {
75
            $class .= ' wpi-recurring';
76
        }
77
78
		$refund_url = wp_nonce_url(
79
			add_query_arg(
80
				array(
81
					'getpaid-admin-action' => 'refund_invoice',
82
					'invoice_id'           => $invoice->get_id(),
83
				)
84
			),
85
			'getpaid-nonce',
86
			'getpaid-nonce'
87
		);
88
    ?>
89
90
        <div class="wpinv-items-wrap<?php echo esc_attr( $class ); ?>" id="wpinv_items_wrap" data-status="<?php echo esc_attr( $invoice->get_status() ); ?>">
91
            <table id="wpinv_items" class="wpinv-items" cellspacing="0" cellpadding="0">
92
93
                <thead>
94
                    <tr>
95
                        <?php foreach ( $columns as $key => $label ) : ?>
96
                            <th class="
97
                            <?php
98
                            echo esc_attr( $key );
99
							echo 'total' == $key || 'qty' == $key ? ' hide-if-amount' : '';
100
							?>
101
							"><?php echo wp_kses_post( $label ); ?></th>
102
                        <?php endforeach; ?>
103
                    </tr>
104
                </thead>
105
106
                <tbody class="wpinv-line-items">
107
                    <?php
108
                        foreach ( $invoice->get_items() as $int => $item ) {
109
						self::output_row( $columns, $item, $invoice, $int % 2 == 0 ? 'even' : 'odd' );
110
                        }
111
                    ?>
112
                </tbody>
113
114
                <tfoot class="wpinv-totals">
115
                    <tr>
116
                        <td colspan="<?php echo (int) $cols; ?>" style="padding:0;border:0">
117
                            <div id="wpinv-quick-add">
118
                                <table cellspacing="0" cellpadding="0">
119
                                    <tr>
120
                                        <td class="id">&nbsp;</td>
121
                                        <td class="title">
122
123
                                            <div class="wp-clearfix">
124
                                                <label class="wpi-item-name">
125
                                                    <span class="input-text-wrap">
126
                                                        <input type="text" style="width: 100%" placeholder="<?php esc_attr_e( 'Item Name', 'invoicing' ); ?>" class="wpinv-quick-item-name" name="_wpinv_quick[name]">
127
                                                    </span>
128
                                                </label>
129
                                            </div>
130
131
                                            <div class="wp-clearfix">
132
                                                <label class="wpi-item-price">
133
                                                    <span class="input-text-wrap">
134
                                                    <input type="text" style="width: 200px" placeholder="<?php esc_attr_e( 'Item Price', 'invoicing' ); ?>" class="wpinv-quick-item-price" name="_wpinv_quick[price]">
135
                                                        &times; <input type="text" style="width: 140px" placeholder="<?php esc_attr_e( 'Item Quantity', 'invoicing' ); ?>" class="wpinv-quick-item-qty" name="_wpinv_quick[qty]">
136
                                                    </span>
137
                                                </label>
138
                                            </div>
139
140
                                            <div class="wp-clearfix">
141
                                                <label class="wpi-item-name">
142
                                                    <span class="input-text-wrap">
143
                                                        <textarea rows="4" style="width: 100%" placeholder="<?php esc_attr_e( 'Item Description', 'invoicing' ); ?>" class="wpinv-quick-item-description" name="_wpinv_quick[description]"></textarea>
144
                                                    </span>
145
                                                </label>
146
                                            </div>
147
148
                                            <div class="wp-clearfix">
149
                                                <label class="wpi-item-type">
150
                                                    <span class="input-text-wrap">
151
                                                        <?php
152
                                                        wpinv_html_select(
153
                                                            array(
154
																'options'          => $item_types,
155
																'name'             => '_wpinv_quick[type]',
156
																'id'               => '_wpinv_quick_type',
157
																'selected'         => 'custom',
158
																'show_option_all'  => false,
159
																'show_option_none' => false,
160
																'class'            => 'gdmbx2-text-medium wpinv-quick-type',
161
                                                            )
162
                                                        );
163
                                                            ?>
164
                                                    </span>
165
                                                </label>
166
                                            </div>
167
168
                                            <?php if ( $use_taxes ) : ?>
169
                                                <div class="wp-clearfix">
170
                                                    <label class="wpi-vat-rule">
171
                                                        <span class="input-text-wrap">
172
                                                            <?php
173
                                                                wpinv_html_select(
174
                                                                    array(
175
																		'options'          => array_merge(
176
																			array( '' => __( 'Select VAT Rule', 'invoicing' ) ),
177
																			getpaid_get_tax_rules()
178
																		),
179
																		'name'             => '_wpinv_quick[vat_rule]',
180
																		'id'               => '_wpinv_quick_vat_rule',
181
																		'show_option_all'  => false,
182
																		'show_option_none' => false,
183
																		'class'            => 'gdmbx2-text-medium wpinv-quick-vat-rule',
184
																		'selected'         => 'digital',
185
                                                                    )
186
                                                                );
187
                                                            ?>
188
                                                        </span>
189
                                                    </label>
190
                                                </div>
191
                                                <div class="wp-clearfix">
192
                                                    <label class="wpi-vat-class">
193
                                                        <span class="input-text-wrap">
194
                                                            <?php
195
                                                                wpinv_html_select(
196
                                                                    array(
197
																		'options'          => array_merge(
198
																			array( '' => __( 'Select VAT Class', 'invoicing' ) ),
199
																			getpaid_get_tax_classes()
200
																		),
201
																		'name'             => '_wpinv_quick[vat_class]',
202
																		'id'               => '_wpinv_quick_vat_class',
203
																		'show_option_all'  => false,
204
																		'show_option_none' => false,
205
																		'class'            => 'gdmbx2-text-medium wpinv-quick-vat-class',
206
																		'selected'         => '_standard',
207
                                                                    )
208
                                                                );
209
                                                            ?>
210
                                                        </span>
211
                                                    </label>
212
                                                </div>
213
                                            <?php endif; ?>
214
215
                                            <div class="wp-clearfix bsui">
216
                                                <?php
217
                                                    aui()->input(
218
                                                        array(
219
                                                            'type'    => 'checkbox',
220
                                                            'name'    => '_wpinv_quick[one-time]',
221
                                                            'id'      => '_wpinv_quick-one-time',
222
                                                            'label'   => __( "One time item (won't be saved to regular items list)", 'invoicing' ),
223
                                                            'value'   => 1,
224
                                                            'no_wrap' => true,
225
                                                            'checked' => false,
226
                                                        ),
227
                                                        true
228
                                                    );
229
                                                ?>
230
                                            </div>
231
232
                                            <div class="wp-clearfix">
233
                                                <label class="wpi-item-actions">
234
                                                    <span class="input-text-wrap">
235
                                                        <input type="button" value="Save" class="button button-primary" id="wpinv-save-item"><input type="button" value="Cancel" class="button button-secondary" id="wpinv-cancel-item">
236
                                                    </span>
237
                                                </label>
238
                                            </div>
239
                                        </td>
240
                                    </tr>
241
                                </table>
242
                            </div>
243
                        </td>
244
                    </tr>
245
                    <tr class="totals">
246
                        <td colspan="<?php echo ( (int) $cols - 4 ); ?>"></td>
247
                        <td colspan="4">
248
                            <table cellspacing="0" cellpadding="0">
249
                                <tr class="subtotal">
250
                                    <td class="name"><?php esc_html_e( 'Sub Total:', 'invoicing' ); ?></td>
251
                                    <td class="total"><?php wpinv_the_price( $invoice->get_subtotal(), $invoice->get_currency() ); ?></td>
252
                                    <td class="action"></td>
253
                                </tr>
254
                                <tr class="discount">
255
                                    <td class="name"><?php esc_html_e( 'Discount:', 'invoicing' ); ?></td>
256
                                    <td class="total"><?php wpinv_the_price( $invoice->get_total_discount(), $invoice->get_currency() ); ?></td>
257
                                    <td class="action"></td>
258
                                </tr>
259
                                <?php if ( $use_taxes ) : ?>
260
                                <?php if ( is_array( $taxes = $invoice->get_taxes() ) && wpinv_display_individual_tax_rates() ) { ?>
261
                                <?php foreach ( $taxes as $tax_key => $tax_item ) { ?>
262
                                <tr class="tax">
263
                                    <td class="name"><?php echo esc_html( $invoice->get_tax_item_name( $tax_key, $tax_item, ':' ) ); ?></td>
264
                                    <td class="total"><?php wpinv_the_price( $invoice->get_tax_item_amount( $tax_key, $tax_item ), $invoice->get_currency() ); ?></td>
265
                                    <td class="action"></td>
266
                                </tr>
267
                                <?php } ?>
268
                                <?php } else { ?>
269
                                <tr class="tax">
270
                                    <td class="name"><?php esc_html_e( 'Tax:', 'invoicing' ); ?></td>
271
                                    <td class="total"><?php wpinv_the_price( $invoice->get_total_tax(), $invoice->get_currency() ); ?></td>
272
                                    <td class="action"></td>
273
                                </tr>
274
                                <?php } ?>
275
                                <?php endif; ?>
276
                                <tr class="total">
277
                                    <td class="name"><?php esc_html_e( 'Total:', 'invoicing' ); ?></td>
278
                                    <td class="total"><?php wpinv_the_price( $invoice->get_total(), $invoice->get_currency() ); ?></td>
279
                                    <td class="action"></td>
280
                                </tr>
281
                            </table>
282
                        </td>
283
                    </tr>
284
                </tfoot>
285
286
            </table>
287
288
            <!-- Add items to an invoice -->
289
            <div class="bsui">
290
                <div class="modal fade" id="getpaid-refund-invoice-modal" tabindex="-1" role="dialog" aria-labelledby="getpaid-refund-invoice-modal-label" aria-hidden="true">
291
                     <div class="modal-dialog modal-dialog-centered" role="document">
292
                        <div class="modal-content">
293
                            <div class="modal-header">
294
                                <h5 class="modal-title" id="getpaid-refund-invoice-modal-label"><?php esc_html_e( 'Refund Payment', 'invoicing' ); ?></h5>
295
                                <button type="button" class="close btn-close" data-bs-dismiss="modal" data-dismiss="modal" aria-label="<?php esc_html_e( 'Close', 'invoicing' ); ?>">
296
                                    <?php if ( empty( $GLOBALS['aui_bs5'] ) ) : ?>
297
                                        <span aria-hidden="true">×</span>
298
                                    <?php endif; ?>
299
                                </button>
300
                            </div>
301
                            <div class="modal-body">
302
								<p>
303
									<?php esc_html_e( 'Are you sure you want to refund this payment?', 'invoicing' ); ?>
304
								</p>
305
								<?php if ( getpaid_payment_gateway_supports( $invoice->get_gateway(), 'refunds' ) ) : ?>
306
									<?php
307
										aui()->input(
308
											array(
309
												'type'  => 'checkbox',
310
												'name'  => 'getpaid_refund_remote',
311
												'id'    => 'getpaid_refund_remote',
312
												'label' => sprintf(
313
													'Refund payment in %s',
314
													wpinv_get_gateway_admin_label( $invoice->get_gateway() )
315
												),
316
												'value' => 1,
317
												'class' => 'getpaid-refund-field',
318
											),
319
											true
320
										);
321
									?>
322
								<?php endif; ?>
323
324
								<?php if ( getpaid_get_invoice_subscriptions( $invoice ) ) : ?>
325
									<?php
326
										aui()->input(
327
											array(
328
												'type'  => 'checkbox',
329
												'name'  => 'getpaid_cancel_subscription',
330
												'id'    => 'getpaid_cancel_subscription',
331
												'label' => __( 'Cancel subscription', 'invoicing' ),
332
												'value' => 1,
333
												'class' => 'getpaid-refund-field',
334
											),
335
											true
336
										);
337
									?>
338
								<?php endif; ?>
339
                            </div>
340
                            <div class="modal-footer">
341
                                <button type="button" class="btn btn-secondary getpaid-cancel" data-bs-dismiss="modal" data-dismiss="modal"><?php esc_html_e( 'Cancel', 'invoicing' ); ?></button>
342
                                <a
343
									href="<?php echo esc_url_raw( $refund_url ); ?>"
344
									data-href="<?php echo esc_url_raw( $refund_url ); ?>"
345
									class="btn btn-primary getpaid-refund-payment-button"
346
								><?php esc_html_e( 'Refund', 'invoicing' ); ?></a>
347
								<script>
348
									// Update the refund URL when the user changes the refund options.
349
									jQuery( function( $ ) {
350
										$( '.getpaid-refund-field' ).on( 'change', function() {
351
											var $this = $( this ),
352
												$modal = $this.closest( '.modal' ),
353
												$button = $modal.find( '.getpaid-refund-payment-button' ),
354
												href = $button.data( 'href' );
355
356
                                            $( '.getpaid-refund-field:checked' ).each( function() {
357
                                                href = href.replace( 'getpaid-admin-action=refund_invoice', 'getpaid-admin-action=refund_invoice&' + $( this ).attr( 'name' ) + '=1' );
358
                                            } );
359
360
											$button.attr( 'href', href );
361
										} );
362
									} );
363
								</script>
364
                            </div>
365
                        </div>
366
                    </div>
367
                </div>
368
            </div>
369
370
            <div class="wpinv-actions">
371
                <?php
372
                    if ( $invoice->is_paid() ) {
373
374
						printf(
375
							'<span class="bsui"><button type="button" class="button button-primary" data-toggle="modal" data-bs-toggle="modal" data-bs-target="#getpaid-refund-invoice-modal" data-target="#getpaid-refund-invoice-modal">%s</button></span>',
376
							esc_html__( 'Refund', 'invoicing' )
377
						);
378
                    } elseif ( ! $invoice->is_refunded() ) {
379
						wpinv_item_dropdown(
380
							array(
381
								'name'           => 'wpinv_invoice_item',
382
								'id'             => 'wpinv_invoice_item',
383
								'show_recurring' => true,
384
								'class'          => 'wpi_select2',
385
							)
386
						);
387
388
						echo '&nbsp;' . '<button type="button" class="button button-primary" id="wpinv-add-item">' . sprintf( esc_html__( 'Add item to %s', 'invoicing' ), esc_html( $invoice->get_label() ) ) . '</button>';
389
						echo '&nbsp;' . '<button type="button" class="button button-primary" id="wpinv-new-item">' . esc_html__( 'Create new item', 'invoicing' ) . '</button>';
390
						echo '&nbsp;' . '<button type="button" class="button button-primary wpinv-flr" id="wpinv-recalc-totals">' . esc_html__( 'Recalculate Totals', 'invoicing' ) . '</button>';
391
392
                    }
393
                ?>
394
                <?php do_action( 'wpinv_invoice_items_actions', $invoice ); ?>
395
            </div>
396
        </div>
397
        <?php
398
    }
399
400
    public static function output_row( $columns, $item, $invoice, $class = 'even' ) {
401
402
    ?>
403
        <tr class="item item-<?php echo esc_attr( $class ); ?>" data-item-id="<?php echo esc_attr( $item->get_id() ); ?>">
404
            <?php foreach ( array_keys( $columns ) as $column ) : ?>
405
                <td class="
406
					<?php
407
						echo esc_attr( $column );
408
						echo 'total' == $column || 'qty' == $column ? ' hide-if-amount' : '';
409
					?>
410
				">
411
                    <?php
412
                        switch ( $column ) {
413
						case 'id':
414
							echo (int) $item->get_id();
415
							break;
416
						case 'title':
417
							printf(
418
								'<a href="%s" target="_blank">%s</a>',
419
								esc_url( get_edit_post_link( $item->get_id() ) ),
420
								esc_html( $item->get_raw_name() )
421
							);
422
423
							$summary = apply_filters( 'getpaid_admin_invoice_line_item_summary', $item->get_description(), $item, $invoice );
424
							if ( $summary !== '' ) {
425
								printf(
426
									'<span class="meta">%s</span>',
427
									wp_kses_post( wpautop( $summary ) )
428
								);
429
							}
430
431
							printf(
432
								'<input type="hidden" value="%s" name="getpaid_items[%s][name]" class="getpaid-recalculate-prices-on-change" />',
433
								esc_attr( $item->get_raw_name() ),
434
								(int) $item->get_id()
435
							);
436
437
							printf(
438
								'<textarea style="display: none;" name="getpaid_items[%s][description]" class="getpaid-recalculate-prices-on-change">%s</textarea>',
439
								(int) $item->get_id(),
440
								esc_attr( $item->get_description() )
441
							);
442
443
							break;
444
						case 'price':
445
							printf(
446
								'<input type="text" value="%s" name="getpaid_items[%s][price]" style="width: 100px;" class="getpaid-admin-invoice-item-price getpaid-recalculate-prices-on-change" />',
447
								esc_attr( getpaid_unstandardize_amount( $item->get_price() ) ),
448
								(int) $item->get_id()
449
							);
450
451
							break;
452
						case 'qty':
453
							printf(
454
								'<input type="text" style="width: 100px;" value="%s" name="getpaid_items[%s][quantity]" class="getpaid-admin-invoice-item-quantity getpaid-recalculate-prices-on-change" />',
455
								floatval( $item->get_quantity() ),
456
								(int) $item->get_id()
457
							);
458
459
							break;
460
						case 'total':
461
							wpinv_the_price( $item->get_sub_total(), $invoice->get_currency() );
462
463
							break;
464
						case 'tax':
465
							echo floatval( wpinv_round_amount( getpaid_get_invoice_tax_rate( $invoice, $item ), 2 ) ) . '%';
466
467
							break;
468
						case 'action':
469
							if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) {
470
								echo '<i class="fa fa-trash wpinv-item-remove"></i>';
471
                                }
472
							break;
473
                        }
474
                        do_action( 'getpaid_admin_edit_invoice_item_' . $column, $item, $invoice );
475
                    ?>
476
                </td>
477
            <?php endforeach; ?>
478
        </tr>
479
        <?php
480
    }
481
482
    /**
483
	 * Output the metabox.
484
	 *
485
	 * @param WP_Post $post
486
	 */
487
    public static function output2( $post ) {
488
489
        // Prepare the invoice.
490
        $invoice = new WPInv_Invoice( $post );
491
492
        // Invoice items.
493
        $items = $invoice->get_items();
494
495
        $totals = array(
496
497
            'subtotal' => array(
498
                'label' => __( 'Items Subtotal', 'invoicing' ),
499
                'value' => wpinv_price( $invoice->get_subtotal(), $invoice->get_currency() ),
500
            ),
501
502
            'discount' => array(
503
                'label' => __( 'Total Discount', 'invoicing' ),
504
                'value' => wpinv_price( $invoice->get_total_discount(), $invoice->get_currency() ),
505
            ),
506
507
            'tax'      => array(
508
                'label' => __( 'Total Tax', 'invoicing' ),
509
                'value' => wpinv_price( $invoice->get_total_tax(), $invoice->get_currency() ),
510
            ),
511
512
            'total'    => array(
513
                'label' => __( 'Invoice Total', 'invoicing' ),
514
                'value' => wpinv_price( $invoice->get_total(), $invoice->get_currency() ),
515
            ),
516
        );
517
518
        if ( ! wpinv_use_taxes() ) {
519
            unset( $totals['tax'] );
520
        }
521
522
        $item_args = array(
523
            'post_type'      => 'wpi_item',
524
            'orderby'        => 'title',
525
            'order'          => 'ASC',
526
            'posts_per_page' => -1,
527
            'post_status'    => array( 'publish' ),
528
            'meta_query'     => array(
529
                array(
530
                    'key'     => '_wpinv_type',
531
                    'compare' => '!=',
532
                    'value'   => 'package',
533
                ),
534
                array(
535
                    'key'     => '_wpinv_one_time',
536
                    'compare' => 'NOT EXISTS',
537
                ),
538
            ),
539
        );
540
541
        ?>
542
543
        <style>
544
            #poststuff .input-group-text,
545
            #poststuff .form-control {
546
                border-color: #7e8993;
547
            }
548
549
            #wpinv-details label {
550
                margin-bottom: 3px;
551
                font-weight: 600;
552
            }
553
        </style>
554
555
                <div class="bsui getpaid-invoice-items-inner <?php echo empty( $items ) ? 'no-items' : 'has-items'; ?> <?php echo $invoice->is_paid() || $invoice->is_refunded() ? 'not-editable' : 'editable'; ?>" style="margin-top: 1.5rem; padding: 0 12px 12px;">
556
557
                    <?php if ( ! $invoice->is_paid() && ! $invoice->is_refunded() ) : ?>
558
                        <?php do_action( 'wpinv_meta_box_before_invoice_template_row', $invoice->get_id() ); ?>
559
560
                        <div class="row">
561
                            <div class="col-12 col-sm-6">
562
                                <?php
563
                                    aui()->select(
564
                                        array(
565
                                            'id'          => 'wpinv_template',
566
                                            'name'        => 'wpinv_template',
567
                                            'label'       => __( 'Template', 'invoicing' ),
568
                                            'label_type'  => 'vertical',
569
                                            'placeholder' => __( 'Choose a template', 'invoicing' ),
570
                                            'class'       => 'form-control-sm',
571
                                            'value'       => $invoice->get_template( 'edit' ),
572
                                            'options'     => array(
573
                                                'quantity' => __( 'Quantity', 'invoicing' ),
574
                                                'hours'    => __( 'Hours', 'invoicing' ),
575
                                                'amount'   => __( 'Amount Only', 'invoicing' ),
576
                                            ),
577
                                            'data-allow-clear' => 'false',
578
                                            'select2'     => true,
579
                                        ),
580
                                        true
581
                                    );
582
                                ?>
583
                            </div>
584
                            <div class="col-12 col-sm-6">
585
                                <?php
586
587
                                    // Set currency.
588
                                    aui()->select(
589
                                        array(
590
                                            'id'          => 'wpinv_currency',
591
                                            'name'        => 'wpinv_currency',
592
                                            'label'       => __( 'Currency', 'invoicing' ),
593
                                            'label_type'  => 'vertical',
594
                                            'placeholder' => __( 'Select Invoice Currency', 'invoicing' ),
595
                                            'class'       => 'form-control-sm',
596
                                            'value'       => $invoice->get_currency( 'edit' ),
597
                                            'required'    => false,
598
                                            'data-allow-clear' => 'false',
599
                                            'select2'     => true,
600
                                            'options'     => wpinv_get_currencies(),
601
                                        ),
602
                                        true
603
                                    );
604
605
                                ?>
606
                            </div>
607
                        </div>
608
609
                        <?php do_action( 'wpinv_meta_box_invoice_template_row', $invoice->get_id() ); ?>
610
                    <?php endif; ?>
611
612
                    <table cellpadding="0" cellspacing="0" class="getpaid_invoice_items">
613
                        <thead>
614
                            <tr>
615
                                <th class="getpaid-item" colspan="2"><?php esc_html_e( 'Item', 'invoicing' ); ?></th>
616
                                <th class="getpaid-quantity hide-if-amount text-right">
617
                                    <span class="getpaid-hide-if-hours"><?php esc_html_e( 'Quantity', 'invoicing' ); ?></span>
618
                                    <span class="getpaid-hide-if-quantity"><?php esc_html_e( 'Hours', 'invoicing' ); ?></span>
619
                                </th>
620
                                <th class="getpaid-price hide-if-amount text-right">
621
                                    <span class="getpaid-hide-if-hours"><?php esc_html_e( 'Price', 'invoicing' ); ?></span>
622
                                    <span class="getpaid-hide-if-quantity"><?php esc_html_e( 'Rate', 'invoicing' ); ?></span>
623
                                </th>
624
                                <th class="getpaid-item-subtotal text-right">
625
                                    <span class="getpaid-hide-if-hours getpaid-hide-if-quantity"><?php esc_html_e( 'Amount', 'invoicing' ); ?></span>
626
                                    <span class="hide-if-amount"><?php esc_html_e( 'Total', 'invoicing' ); ?></span>
627
                                </th>
628
                                <th class="getpaid-item-actions hide-if-not-editable" width="70px">&nbsp;</th>
629
                            </tr>
630
                        </thead>
631
		                <tbody class="getpaid_invoice_line_items">
632
                            <tr class="hide-if-has-items hide-if-not-editable">
633
                                <td colspan="2" class="pt-4 pb-4">
634
                                    <button type="button" class="button button-primary add-invoice-item" data-toggle="modal" data-target="#getpaid-add-items-to-invoice"><?php esc_html_e( 'Add Existing Items', 'invoicing' ); ?></button>
635
                                    <button type="button" class="button button-secondary create-invoice-item" data-toggle="modal" data-target="#getpaid-create-invoice-item"><?php esc_html_e( 'Create New Item', 'invoicing' ); ?></button>
636
                                </td>
637
                                <td class="hide-if-amount">&nbsp;</th>
638
                                <td class="hide-if-amount">&nbsp;</th>
639
                                <td>&nbsp;</th>
640
                                <td width="1%">&nbsp;</th>
641
                            </tr>
642
                            <tr class="getpaid-invoice-item-template d-none">
643
                                <td class="getpaid-item" colspan="2">
644
                                    <span class='item-name'></span>
645
                                    <small class="form-text text-muted item-description"></small>
646
                                </td>
647
                                <td class="getpaid-quantity hide-if-amount text-right item-quantity"></td>
648
                                <td class="getpaid-price hide-if-amount text-right item-price"></td>
649
                                <td class="getpaid-item-subtotal text-right">
650
                                    <span class="getpaid-hide-if-hours getpaid-hide-if-quantity item-price"></span>
651
                                    <span class="hide-if-amount item-total"></span>
652
                                </td>
653
                                <td class="getpaid-item-actions hide-if-not-editable" width="70px">
654
                                    <span class="dashicons dashicons-edit"></span>
655
                                    <span class="dashicons dashicons-trash"></span>
656
                                </td>
657
                            </tr>
658
659
                        </tbody>
660
                    </table>
661
662
                    <div class="getpaid-invoice-totals-row">
663
                        <div class="row">
664
                            <div class="col-12 col-sm-6 offset-sm-6">
665
                                <table class="getpaid-invoice-totals text-right w-100">
666
                                    <tbody>
667
                                        <?php foreach ( apply_filters( 'getpaid_invoice_subtotal_rows', $totals, $invoice ) as $key => $data ) : ?>
668
                                            <tr class="getpaid-totals-<?php echo esc_attr( $key ); ?>">
669
                                                <td class="label"><?php echo esc_html( $data['label'] ); ?>:</td>
670
                                                <td width="1%"></td>
671
                                                <td class="value"><?php echo wp_kses_post( $data['value'] ); ?></td>
672
                                            </tr>
673
                                        <?php endforeach; ?>
674
                                    </tbody>
675
                                </table>
676
                            </div>
677
                        </div>
678
                    </div>
679
680
                    <!-- Actions -->
681
                    <div class="getpaid-invoice-item-actions hide-if-no-items hide-if-not-editable">
682
                        <div class="row">
683
                            <div class="text-left col-12 col-sm-8">
684
                                <button type="button" class="button button-primary add-invoice-item" data-toggle="modal" data-target="#getpaid-add-items-to-invoice"><?php esc_html_e( 'Add Existing Item', 'invoicing' ); ?></button>
685
                                <button type="button" class="button button-secondary create-invoice-item" data-toggle="modal" data-target="#getpaid-create-invoice-item"><?php esc_html_e( 'Create New Item', 'invoicing' ); ?></button>
686
                                <?php do_action( 'getpaid-invoice-items-actions', $invoice ); ?>
687
                            </div>
688
                            <div class="text-right col-12 col-sm-4">
689
                                <button type="button" class="button button-primary recalculate-totals-button"><?php esc_html_e( 'Recalculate Totals', 'invoicing' ); ?></button>
690
                            </div>
691
                        </div>
692
                    </div>
693
694
                    <div class="getpaid-invoice-item-actions hide-if-editable">
695
                        <p class="description m-2 text-right text-muted"><?php esc_html_e( 'This invoice is no longer editable', 'invoicing' ); ?></p>
696
                    </div>
697
698
                    <!-- Add items to an invoice -->
699
                    <div class="modal fade" id="getpaid-add-items-to-invoice" tabindex="-1" role="dialog" aria-labelledby="getpaid-add-item-to-invoice-label" aria-hidden="true">
700
                        <div class="modal-dialog modal-dialog-centered" role="document">
701
                            <div class="modal-content">
702
                                <div class="modal-header">
703
                                    <h5 class="modal-title" id="getpaid-add-item-to-invoice-label"><?php esc_html_e( 'Add Item(s)', 'invoicing' ); ?></h5>
704
                                    <button type="button" class="close btn-close" data-dismiss="modal" aria-label="<?php esc_html_e( 'Close', 'invoicing' ); ?>">
705
                                        <?php if ( empty( $GLOBALS['aui_bs5'] ) ) : ?>
706
                                            <span aria-hidden="true">×</span>
707
                                        <?php endif; ?>
708
                                    </button>
709
                                </div>
710
                                <div class="modal-body">
711
                                    <table class="widefat">
712
                                        <thead>
713
                                            <tr>
714
                                                <th class="pl-0 text-left"><?php esc_html_e( 'Item', 'invoicing' ); ?></th>
715
                                                <th class="pr-0 text-right hide-if-amount">
716
                                                    <span class="getpaid-hide-if-hours"><?php esc_html_e( 'Quantity', 'invoicing' ); ?></span>
717
                                                    <span class="getpaid-hide-if-quantity"><?php esc_html_e( 'Hours', 'invoicing' ); ?></span>
718
                                                </th>
719
                                            </tr>
720
                                        </thead>
721
										<tbody>
722
								            <tr>
723
									            <td class="pl-0 text-left">
724
                                                    <select class="regular-text getpaid-add-invoice-item-select">
725
                                                        <option value="" selected="selected" disabled><?php esc_html_e( 'Select an item…', 'invoicing' ); ?></option>
726
                                                        <?php foreach ( get_posts( $item_args ) as $item ) : ?>
727
                                                        <option value="<?php echo (int) $item->ID; ?>"><?php echo esc_html( $item->post_title ); ?></option>
728
                                                        <?php endforeach; ?>
729
                                                    </select>
730
                                                </td>
731
									            <td class="pr-0 text-right hide-if-amount">
732
                                                    <input type="number" class="w100" step="1" min="1" autocomplete="off" value="1" placeholder="1">
733
                                                </td>
734
                                            </tr>
735
							            </tbody>
736
						            </table>
737
                                </div>
738
                                <div class="modal-footer">
739
                                    <button type="button" class="btn btn-secondary getpaid-cancel" data-dismiss="modal"><?php esc_html_e( 'Cancel', 'invoicing' ); ?></button>
740
                                    <button type="button" class="btn btn-primary getpaid-add" data-dismiss="modal"><?php esc_html_e( 'Add', 'invoicing' ); ?></button>
741
                                </div>
742
                            </div>
743
                        </div>
744
                    </div>
745
746
                    <!-- Create invoice item -->
747
                    <div class="modal fade" id="getpaid-create-invoice-item" tabindex="-1" role="dialog" aria-labelledby="getpaid-create-invoice-item-label" aria-hidden="true">
748
                        <div class="modal-dialog modal-dialog-centered" role="document">
749
                            <div class="modal-content">
750
                                <div class="modal-header">
751
                                    <h5 class="modal-title" id="getpaid-create-invoice-item-label"><?php esc_html_e( 'Create Item', 'invoicing' ); ?></h5>
752
                                    <button type="button" class="close btn-close" data-dismiss="modal" aria-label="<?php esc_html_e( 'Close', 'invoicing' ); ?>">
753
                                        <?php if ( empty( $GLOBALS['aui_bs5'] ) ) : ?>
754
                                            <span aria-hidden="true">×</span>
755
                                        <?php endif; ?>
756
                                    </button>
757
                                </div>
758
                                <div class="modal-body">
759
                                    <div class="getpaid-create-item-div">
760
                                        <input type="hidden" name="id" value="new" class="form-control form-control-sm item-id">
761
                                        <label class="form-group mb-3 w-100">
762
                                            <span><?php esc_html_e( 'Name', 'invoicing' ); ?></span>
763
                                            <input type="text" name="name" placeholder="<?php esc_attr_e( 'Item Name', 'invoicing' ); ?>" class="form-control form-control-sm item-name">
764
                                        </label>
765
                                        <label class="form-group mb-3 w-100">
766
                                            <span class="getpaid-hide-if-hours getpaid-hide-if-quantity item-price"><?php esc_html_e( 'Amount', 'invoicing' ); ?></span>
767
                                            <span class="hide-if-amount"><?php esc_html_e( 'Price', 'invoicing' ); ?></span>
768
                                            <input type="text" name="price" placeholder="<?php echo esc_attr( wpinv_sanitize_amount( 0 ) ); ?>" class="form-control form-control-sm item-price">
769
                                        </label>
770
                                        <label class="form-group mb-3 w-100 hide-if-amount">
771
                                            <span><?php esc_html_e( 'Quantity', 'invoicing' ); ?></span>
772
                                            <input type="text" name="quantity" placeholder="1" class="form-control form-control-sm item-quantity">
773
                                        </label>
774
                                        <label class="form-group mb-3 w-100">
775
                                            <span><?php esc_html_e( 'Item Description', 'invoicing' ); ?></span>
776
                                            <textarea name="description" placeholder="<?php esc_attr_e( 'Enter a description for this item', 'invoicing' ); ?>" class="form-control item-description"></textarea>
777
                                        </label>
778
                                    </div>
779
                                </div>
780
                                <div class="modal-footer">
781
                                    <button type="button" class="btn btn-secondary getpaid-cancel" data-dismiss="modal"><?php esc_html_e( 'Cancel', 'invoicing' ); ?></button>
782
                                    <button type="button" class="btn btn-primary getpaid-save" data-dismiss="modal"><?php esc_html_e( 'Create', 'invoicing' ); ?></button>
783
                                </div>
784
                            </div>
785
                        </div>
786
                    </div>
787
788
                    <!-- Edit invoice item -->
789
                    <div class="modal fade" id="getpaid-edit-invoice-item" tabindex="-1" role="dialog" aria-labelledby="getpaid-edit-invoice-item-label" aria-hidden="true">
790
                        <div class="modal-dialog modal-dialog-centered" role="document">
791
                            <div class="modal-content">
792
                                <div class="modal-header">
793
                                    <h5 class="modal-title" id="getpaid-edit-invoice-item-label"><?php esc_html_e( 'Edit Item', 'invoicing' ); ?></h5>
794
                                    <button type="button" class="close close" data-dismiss="modal" aria-label="<?php esc_html_e( 'Close', 'invoicing' ); ?>">
795
                                        <?php if ( empty( $GLOBALS['aui_bs5'] ) ) : ?>
796
                                            <span aria-hidden="true">×</span>
797
                                        <?php endif; ?>
798
                                    </button>
799
                                </div>
800
                                <div class="modal-body">
801
                                    <div class="getpaid-edit-item-div">
802
                                        <input type="hidden" name="id" class="form-control form-control-sm item-id">
803
                                        <label class="form-group mb-3 w-100">
804
                                            <span><?php esc_html_e( 'Name', 'invoicing' ); ?></span>
805
                                            <input type="text" name="name" placeholder="<?php esc_attr_e( 'Item Name', 'invoicing' ); ?>" class="form-control form-control-sm item-name">
806
                                        </label>
807
                                        <label class="form-group mb-3 w-100">
808
                                            <span class="getpaid-hide-if-hours getpaid-hide-if-quantity item-price"><?php esc_html_e( 'Amount', 'invoicing' ); ?></span>
809
                                            <span class="hide-if-amount"><?php esc_html_e( 'Price', 'invoicing' ); ?></span>
810
                                            <input type="text" name="price" placeholder="<?php wpinv_sanitize_amount( 0 ); ?>" class="form-control form-control-sm item-price">
811
                                        </label>
812
                                        <label class="form-group mb-3 w-100 hide-if-amount">
813
                                            <span><?php esc_html_e( 'Quantity', 'invoicing' ); ?></span>
814
                                            <input type="text" name="quantity" placeholder="1" class="form-control form-control-sm item-quantity">
815
                                        </label>
816
                                        <label class="form-group mb-3 w-100">
817
                                            <span><?php esc_html_e( 'Item Description', 'invoicing' ); ?></span>
818
                                            <textarea name="description" placeholder="<?php esc_attr_e( 'Enter a description for this item', 'invoicing' ); ?>" class="form-control item-description"></textarea>
819
                                        </label>
820
                                    </div>
821
                                </div>
822
                                <div class="modal-footer">
823
                                    <button type="button" class="btn btn-secondary getpaid-cancel" data-dismiss="modal"><?php esc_html_e( 'Cancel', 'invoicing' ); ?></button>
824
                                    <button type="button" class="btn btn-primary getpaid-save" data-dismiss="modal"><?php esc_html_e( 'Save', 'invoicing' ); ?></button>
825
                                </div>
826
                            </div>
827
                        </div>
828
                    </div>
829
                </div>
830
831
        <?php
832
    }
833
}
834