PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.0
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
← All changes | templates/payments/new.php +84 -79 2.1.12.4.0 View file →
@@ -6,8 +6,12 @@
6 6 */
7 7
8 8 namespace EasyInvoice\Templates\Payments;
9 9
10 +
11 +if ( ! defined( 'ABSPATH' ) ) {
12 + exit;
13 +}
10 14 use EasyInvoice\Models\Invoice;
11 15 ?>
12 16
13 17 <div class="p-8">
@@ -12,88 +16,80 @@
12 16
13 17 <div class="p-8">
14 18 <div class="flex justify-between items-center mb-6">
15 19 <h1 class="text-2xl font-bold text-gray-900">
16 - <?php _e('Add New Payment', 'easy-invoice'); ?>
20 + <?php esc_html_e('Add New Payment', 'easy-invoice'); ?>
17 21 </h1>
18 - <a href="<?php echo admin_url('admin.php?page=easy-invoice-payments'); ?>"
22 + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-payments')); ?>"
19 23 class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
20 - <?php _e('Back to Payments', 'easy-invoice'); ?>
24 + <?php esc_html_e('Back to Payments', 'easy-invoice'); ?>
21 25 </a>
22 26 </div>
23 27
24 28 <div class="bg-white shadow overflow-hidden sm:rounded-lg">
25 - <form method="post" action="<?php echo admin_url('admin-ajax.php'); ?>" id="new-payment-form" class="space-y-6 p-6">
29 + <form method="post" action="<?php echo esc_url(admin_url('admin-ajax.php')); ?>" id="new-payment-form" class="space-y-6 p-6">
26 30 <?php wp_nonce_field('easy_invoice_payment', 'payment_nonce'); ?>
27 - <input type="hidden" name="action" value="easy_invoice_process_payment">
31 + <input type="hidden" name="action" value="easy_invoice_record_payment">
28 32
29 33 <div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
30 - <!-- Invoice Selection -->
31 34 <div>
32 35 <label for="invoice_id" class="block text-sm font-medium text-gray-700">
33 - <?php _e('Invoice', 'easy-invoice'); ?> <span class="text-red-500">*</span>
36 + <?php esc_html_e('Invoice', 'easy-invoice'); ?> <span class="text-red-500">*</span>
34 37 </label>
38 + <input type="search" id="invoice_filter" class="mt-1 mb-2 block w-full border border-gray-300 rounded-md py-2 px-3 sm:text-sm" placeholder="<?php esc_attr_e( 'Type an invoice number or title to filter the list', 'easy-invoice' ); ?>" autocomplete="off">
35 39 <select name="invoice_id" id="invoice_id" required
36 40 class="mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md">
37 - <option value=""><?php _e('Select Invoice', 'easy-invoice'); ?></option>
41 + <option value=""><?php esc_html_e('Select Invoice', 'easy-invoice'); ?></option>
38 42 <?php
39 - $invoices = get_posts(array(
40 - 'post_type' => 'easy_invoice',
41 - 'posts_per_page' => -1,
42 - 'post_status' => 'publish',
43 - 'orderby' => 'date',
44 - 'order' => 'DESC',
45 - 'meta_query' => array(
46 - 'relation' => 'OR',
47 - array(
48 - 'key' => '_payment_status',
49 - 'value' => 'unpaid',
50 - 'compare' => '='
51 - ),
52 - array(
53 - 'key' => '_payment_status',
54 - 'compare' => 'NOT EXISTS'
55 - ),
56 - array(
57 - 'key' => '_payment_status',
58 - 'value' => '',
59 - 'compare' => '='
60 - )
61 - )
62 - ));
63 -
64 - foreach ($invoices as $post) {
65 - $invoice = new Invoice($post);
66 -
67 - // Get invoice number - try different methods
68 - $invoice_number = $invoice->getNumber();
69 - if (empty($invoice_number)) {
70 - $invoice_number = get_post_meta($invoice->getId(), '_easy_invoice_number', true);
43 + // Only invoices that can still take a payment, newest first, and
44 + // never the whole table: a shop with ten thousand invoices used
45 + // to get every one of them instantiated into this list. The
46 + // balance shown is what is still due, primed in two queries.
47 + $ei_open_statuses = [ 'available', 'unpaid', 'overdue', 'partial', 'pending_verification', 'sent' ];
48 + $ei_open_statuses = apply_filters( 'easy_invoice_payment_form_open_statuses', $ei_open_statuses );
49 + $ei_preselect = isset( $_GET['invoice_id'] ) ? absint( $_GET['invoice_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
50 + $ei_limit = (int) apply_filters( 'easy_invoice_payment_form_invoice_limit', 300 );
51 + $ei_open_ids = get_posts( [
52 + 'post_type' => 'easy_invoice',
53 + 'post_status' => 'publish',
54 + 'posts_per_page' => $ei_limit,
55 + 'orderby' => 'date',
56 + 'order' => 'DESC',
57 + 'fields' => 'ids',
58 + 'meta_query' => [ [ 'key' => '_easy_invoice_status', 'value' => $ei_open_statuses, 'compare' => 'IN' ] ],
59 + ] );
60 + if ( $ei_preselect && ! in_array( $ei_preselect, $ei_open_ids, true ) && 'easy_invoice' === get_post_type( $ei_preselect ) ) {
61 + array_unshift( $ei_open_ids, $ei_preselect );
62 + }
63 + $ei_open_ids = array_map( 'intval', $ei_open_ids );
64 + if ( $ei_open_ids ) {
65 + update_meta_cache( 'post', $ei_open_ids );
66 + _prime_post_caches( $ei_open_ids, false, false );
67 + \EasyInvoice\Services\InvoiceBalance::prime( $ei_open_ids );
68 + }
69 + foreach ( $ei_open_ids as $ei_id ) {
70 + // Read the option straight from the primed meta cache. Building an
71 + // Invoice model per row (items, totals) cost ~2 s for 300 options.
72 + $invoice_number = (string) get_post_meta( $ei_id, '_easy_invoice_number', true ) ?: 'INV-' . $ei_id;
73 + $ei_cached = get_post_meta( $ei_id, \EasyInvoice\Services\InvoiceTotalsCache::META_TOTAL, true );
74 + if ( '' === (string) $ei_cached ) {
75 + $ei_model = new Invoice( $ei_id ); // not backfilled yet: compute once and store
76 + $ei_cached = $ei_model->getTotal();
77 + \EasyInvoice\Services\InvoiceTotalsCache::store( $ei_model );
71 78 }
72 - if (empty($invoice_number)) {
73 - $invoice_number = 'INV-' . $invoice->getId();
79 + $ei_due = max( 0, (float) $ei_cached - \EasyInvoice\Services\InvoiceBalance::paid( $ei_id ) - \EasyInvoice\Services\InvoiceBalance::credited( $ei_id ) );
80 + $ei_currency = strtoupper( (string) get_post_meta( $ei_id, '_easy_invoice_currency_code', true ) );
81 + if ( '' === $ei_currency || 'GLOBAL' === $ei_currency ) {
82 + $ei_currency = strtoupper( (string) get_option( 'easy_invoice_currency_code', 'USD' ) );
74 83 }
75 -
76 - // Get total amount
77 - $total = $invoice->getTotal();
78 - if (empty($total)) {
79 - $total = get_post_meta($invoice->getId(), '_easy_invoice_total', true);
80 - }
81 - if (empty($total)) {
82 - $total = 0;
83 - }
84 -
85 - // Get currency symbol
86 - $currency_symbol = $invoice->getCurrencySymbol();
87 - if (empty($currency_symbol)) {
88 - $currency_symbol = get_option('easy_invoice_currency_symbol', '$');
89 - }
90 -
84 + $currency_symbol = \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol( $ei_currency ) ?: get_option( 'easy_invoice_currency_symbol', '$' );
85 + $ei_title = (string) get_post_field( 'post_title', $ei_id );
91 86 printf(
92 - '<option value="%d">%s - %s</option>',
93 - $invoice->getId(),
94 - esc_html($invoice_number),
95 - esc_html($currency_symbol . number_format($total, 2))
87 + '<option value="%d"%s>%s - %s</option>',
88 + (int) $ei_id,
89 + selected( $ei_preselect, $ei_id, false ),
90 + esc_html( $invoice_number . ( '' !== $ei_title && $ei_title !== $invoice_number ? ' · ' . wp_html_excerpt( $ei_title, 40, '…' ) : '' ) ),
91 + esc_html( $currency_symbol . number_format( $ei_due, 2 ) )
96 92 );
97 93 }
98 94 ?>
99 95 </select>
@@ -98,16 +94,15 @@
98 94 ?>
99 95 </select>
100 96 </div>
101 97
102 - <!-- Payment Method -->
103 98 <div>
104 99 <label for="payment_method" class="block text-sm font-medium text-gray-700">
105 - <?php _e('Payment Method', 'easy-invoice'); ?> <span class="text-red-500">*</span>
100 + <?php esc_html_e('Payment Method', 'easy-invoice'); ?> <span class="text-red-500">*</span>
106 101 </label>
107 102 <select name="payment_method" id="payment_method" required
108 103 class="mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md">
109 - <option value=""><?php _e('Select Payment Method', 'easy-invoice'); ?></option>
104 + <option value=""><?php esc_html_e('Select Payment Method', 'easy-invoice'); ?></option>
110 105 <?php
111 106 // Get available payment gateways (sorted)
112 107 $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager();
113 108 $enabled_gateways = $gateway_manager->getEnabledGateways();
@@ -112,10 +107,15 @@
112 107 $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager();
113 108 $enabled_gateways = $gateway_manager->getEnabledGateways();
114 109
115 110 // Show only enabled gateways and manual options
111 + // How the money arrived. Cash and cheque are always
112 + // possible whether or not a gateway for them is on.
116 113 $available_methods = [
117 - 'manual' => __('Manual', 'easy-invoice'),
114 + 'cash' => __('Cash', 'easy-invoice'),
115 + 'cheque' => __('Cheque', 'easy-invoice'),
116 + 'bank_transfer' => __('Bank transfer', 'easy-invoice'),
117 + 'other' => __('Other', 'easy-invoice'),
118 118 ];
119 119
120 120 // Add enabled gateways only (already sorted)
121 121 foreach ($enabled_gateways as $gateway_id => $gateway) {
@@ -132,16 +132,15 @@
132 132 ?>
133 133 </select>
134 134 </div>
135 135
136 - <!-- Amount -->
137 136 <div>
138 137 <label for="amount" class="block text-sm font-medium text-gray-700">
139 - <?php _e('Amount', 'easy-invoice'); ?> <span class="text-red-500">*</span>
138 + <?php esc_html_e('Amount', 'easy-invoice'); ?> <span class="text-red-500">*</span>
140 139 </label>
141 140 <div class="mt-1 relative rounded-md shadow-sm">
142 141 <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
143 - <span class="text-gray-500 sm:text-sm"><?php echo get_option('easy_invoice_currency_symbol', '$'); ?></span>
142 + <span class="text-gray-500 sm:text-sm"><?php echo esc_html(get_option('easy_invoice_currency_symbol', '$')); ?></span>
144 143 </div>
145 144 <input type="number" name="amount" id="amount" step="0.01" required
146 145 class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 pl-7 pr-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
147 146 placeholder="0.00">
@@ -147,27 +146,25 @@
147 146 placeholder="0.00">
148 147 </div>
149 148 </div>
150 149
151 - <!-- Payment Date -->
152 150 <div>
153 151 <label for="payment_date" class="block text-sm font-medium text-gray-700">
154 - <?php _e('Payment Date', 'easy-invoice'); ?> <span class="text-red-500">*</span>
152 + <?php esc_html_e('Payment Date', 'easy-invoice'); ?> <span class="text-red-500">*</span>
155 153 </label>
156 154 <input type="date" name="payment_date" id="payment_date"
157 - value="<?php echo date('Y-m-d'); ?>" required
155 + value="<?php echo esc_attr(current_time('Y-m-d')); ?>" required
158 156 class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
159 157 </div>
160 158
161 - <!-- Notes -->
162 159 <div class="sm:col-span-2">
163 160 <label for="notes" class="block text-sm font-medium text-gray-700">
164 - <?php _e('Notes', 'easy-invoice'); ?>
161 + <?php esc_html_e('Notes', 'easy-invoice'); ?>
165 162 </label>
166 163 <div class="mt-1">
167 164 <textarea name="notes" id="notes" rows="3"
168 165 class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
169 - placeholder="<?php _e('Add any additional notes about this payment...', 'easy-invoice'); ?>"></textarea>
166 + placeholder="<?php echo esc_js(__('Add any additional notes about this payment...', 'easy-invoice')); ?>"></textarea>
170 167 </div>
171 168 </div>
172 169 </div>
173 170
@@ -174,9 +171,9 @@
174 171 <div class="pt-5">
175 172 <div class="flex justify-end">
176 173 <button type="submit"
177 174 class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
178 - <?php _e('Add Payment', 'easy-invoice'); ?>
175 + <?php esc_html_e('Add Payment', 'easy-invoice'); ?>
179 176 </button>
180 177 </div>
181 178 </div>
182 179 </form>
@@ -184,8 +181,14 @@
184 181 </div>
185 182
186 183 <script>
187 184 jQuery(document).ready(function($) {
185 + // Filter the (capped) invoice list as the user types.
186 + var $invoiceOptions = $('#invoice_id option');
187 + $('#invoice_filter').on('input', function() {
188 + var q = $(this).val().toLowerCase();
189 + $invoiceOptions.each(function() { var t = $(this).text().toLowerCase(); $(this).toggle(!q || !this.value || t.indexOf(q) !== -1); });
190 + });
188 191 // Update amount when invoice is selected
189 192 $('#invoice_id').on('change', function() {
190 193 var selectedOption = $(this).find('option:selected');
191 194 var amount = selectedOption.text().split(' - ')[1];
@@ -193,8 +196,10 @@
193 196 $('#amount').val(amount.replace(/[^0-9.-]+/g, ''));
194 197 }
195 198 });
196 199
200 + if ($('#invoice_id').val()) { $('#invoice_id').trigger('change'); }
201 +
197 202 // Form submission
198 203 $('#new-payment-form').on('submit', function(e) {
199 204 e.preventDefault();
200 205
@@ -207,16 +212,16 @@
207 212 processData: false,
208 213 contentType: false,
209 214 success: function(response) {
210 215 if (response.success) {
211 - window.location.href = '<?php echo admin_url('admin.php?page=easy-invoice-payments'); ?>';
216 + window.location.href = '<?php echo esc_url(admin_url('admin.php?page=easy-invoice-payments')); ?>';
212 217 } else {
213 - EasyInvoiceToast.error(response.data.message || '<?php _e('An error occurred', 'easy-invoice'); ?>');
218 + EasyInvoiceToast.error(response.data.message || '<?php echo esc_js(__('An error occurred', 'easy-invoice')); ?>');
214 219 }
215 220 },
216 221 error: function() {
217 - EasyInvoiceToast.error('<?php _e('An error occurred', 'easy-invoice'); ?>');
222 + EasyInvoiceToast.error('<?php echo esc_js(__('An error occurred', 'easy-invoice')); ?>');
218 223 }
219 224 });
220 225 });
221 226 });
222 227 </script>