PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.1
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.1
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
easy-invoice / templates / payments / new.php

new.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.4.1, at templates/payments/new.php

227 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * New Payment Template
4 *
5 * @package Easy_Invoice
6 */
7
8 namespace EasyInvoice\Templates\Payments;
9
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14 use EasyInvoice\Models\Invoice;
15 ?>
16
17 <div class="p-8">
18 <div class="flex justify-between items-center mb-6">
19 <h1 class="text-2xl font-bold text-gray-900">
20 <?php esc_html_e('Add New Payment', 'easy-invoice'); ?>
21 </h1>
22 <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-payments')); ?>"
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">
24 <?php esc_html_e('Back to Payments', 'easy-invoice'); ?>
25 </a>
26 </div>
27
28 <div class="bg-white shadow overflow-hidden sm:rounded-lg">
29 <form method="post" action="<?php echo esc_url(admin_url('admin-ajax.php')); ?>" id="new-payment-form" class="space-y-6 p-6">
30 <?php wp_nonce_field('easy_invoice_payment', 'payment_nonce'); ?>
31 <input type="hidden" name="action" value="easy_invoice_record_payment">
32
33 <div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
34 <div>
35 <label for="invoice_id" class="block text-sm font-medium text-gray-700">
36 <?php esc_html_e('Invoice', 'easy-invoice'); ?> <span class="text-red-500">*</span>
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">
39 <select name="invoice_id" id="invoice_id" required
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">
41 <option value=""><?php esc_html_e('Select Invoice', 'easy-invoice'); ?></option>
42 <?php
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 );
78 }
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' ) );
83 }
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 );
86 printf(
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 ) )
92 );
93 }
94 ?>
95 </select>
96 </div>
97
98 <div>
99 <label for="payment_method" class="block text-sm font-medium text-gray-700">
100 <?php esc_html_e('Payment Method', 'easy-invoice'); ?> <span class="text-red-500">*</span>
101 </label>
102 <select name="payment_method" id="payment_method" required
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">
104 <option value=""><?php esc_html_e('Select Payment Method', 'easy-invoice'); ?></option>
105 <?php
106 // Get available payment gateways (sorted)
107 $gateway_manager = \EasyInvoice\EasyInvoice::getInstance()->getGatewayManager();
108 $enabled_gateways = $gateway_manager->getEnabledGateways();
109
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.
113 $available_methods = [
114 'cash' => __('Cash', 'easy-invoice'),
115 'cheque' => __('Cheque', 'easy-invoice'),
116 'bank_transfer' => __('Bank transfer', 'easy-invoice'),
117 'other' => __('Other', 'easy-invoice'),
118 ];
119
120 // Add enabled gateways only (already sorted)
121 foreach ($enabled_gateways as $gateway_id => $gateway) {
122 $available_methods[$gateway_id] = $gateway_manager->getGatewayDisplayName($gateway_id);
123 }
124
125 foreach ($available_methods as $method_id => $method_name) {
126 printf(
127 '<option value="%s">%s</option>',
128 esc_attr($method_id),
129 esc_html($method_name)
130 );
131 }
132 ?>
133 </select>
134 </div>
135
136 <div>
137 <label for="amount" class="block text-sm font-medium text-gray-700">
138 <?php esc_html_e('Amount', 'easy-invoice'); ?> <span class="text-red-500">*</span>
139 </label>
140 <div class="mt-1 relative rounded-md shadow-sm">
141 <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
142 <span class="text-gray-500 sm:text-sm"><?php echo esc_html(get_option('easy_invoice_currency_symbol', '$')); ?></span>
143 </div>
144 <input type="number" name="amount" id="amount" step="0.01" required
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"
146 placeholder="0.00">
147 </div>
148 </div>
149
150 <div>
151 <label for="payment_date" class="block text-sm font-medium text-gray-700">
152 <?php esc_html_e('Payment Date', 'easy-invoice'); ?> <span class="text-red-500">*</span>
153 </label>
154 <input type="date" name="payment_date" id="payment_date"
155 value="<?php echo esc_attr(current_time('Y-m-d')); ?>" required
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">
157 </div>
158
159 <div class="sm:col-span-2">
160 <label for="notes" class="block text-sm font-medium text-gray-700">
161 <?php esc_html_e('Notes', 'easy-invoice'); ?>
162 </label>
163 <div class="mt-1">
164 <textarea name="notes" id="notes" rows="3"
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"
166 placeholder="<?php echo esc_js(__('Add any additional notes about this payment...', 'easy-invoice')); ?>"></textarea>
167 </div>
168 </div>
169 </div>
170
171 <div class="pt-5">
172 <div class="flex justify-end">
173 <button type="submit"
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">
175 <?php esc_html_e('Add Payment', 'easy-invoice'); ?>
176 </button>
177 </div>
178 </div>
179 </form>
180 </div>
181 </div>
182
183 <script>
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 });
191 // Update amount when invoice is selected
192 $('#invoice_id').on('change', function() {
193 var selectedOption = $(this).find('option:selected');
194 var amount = selectedOption.text().split(' - ')[1];
195 if (amount) {
196 $('#amount').val(amount.replace(/[^0-9.-]+/g, ''));
197 }
198 });
199
200 if ($('#invoice_id').val()) { $('#invoice_id').trigger('change'); }
201
202 // Form submission
203 $('#new-payment-form').on('submit', function(e) {
204 e.preventDefault();
205
206 var formData = new FormData(this);
207
208 $.ajax({
209 url: $(this).attr('action'),
210 type: 'POST',
211 data: formData,
212 processData: false,
213 contentType: false,
214 success: function(response) {
215 if (response.success) {
216 window.location.href = '<?php echo esc_url(admin_url('admin.php?page=easy-invoice-payments')); ?>';
217 } else {
218 EasyInvoiceToast.error(response.data.message || '<?php echo esc_js(__('An error occurred', 'easy-invoice')); ?>');
219 }
220 },
221 error: function() {
222 EasyInvoiceToast.error('<?php echo esc_js(__('An error occurred', 'easy-invoice')); ?>');
223 }
224 });
225 });
226 });
227 </script>