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 | includes/Traits/PaymentCalculationTrait.php +48 -10 2.1.102.4.0 View file →
@@ -49,8 +49,30 @@
49 49 return $total_payments;
50 50 }
51 51
52 52 /**
53 + * Amount of the most recently completed payment on an invoice.
54 + *
55 + * @param int $invoice_id
56 + * @return float Zero when there is none.
57 + */
58 + private function latestCompletedPaymentAmount($invoice_id): float
59 + {
60 + $payments = get_posts([
61 + 'post_type' => 'easy_invoice_payment',
62 + 'post_status' => 'publish',
63 + 'numberposts' => 1,
64 + 'orderby' => 'date',
65 + 'order' => 'DESC',
66 + 'meta_query' => [
67 + ['key' => '_invoice_id', 'value' => $invoice_id, 'compare' => '='],
68 + ['key' => '_status', 'value' => 'completed', 'compare' => '='],
69 + ],
70 + ]);
71 + return $payments ? (float) get_post_meta($payments[0]->ID, '_amount', true) : 0.0;
72 + }
73 +
74 + /**
53 75 * Check if invoice should be marked as paid based on total payments
54 76 *
55 77 * @param int $invoice_id
56 78 * @param \EasyInvoice\Models\Invoice $invoice
@@ -58,11 +80,13 @@
58 80 */
59 81 private function shouldMarkInvoiceAsPaid($invoice_id, $invoice): bool
60 82 {
61 83 $total_payments = $this->calculateTotalPaymentsForInvoice($invoice_id);
62 - $invoice_total = $invoice->getTotal();
63 -
64 - return $total_payments >= $invoice_total;
84 + $invoice_total = (float) $invoice->getTotal();
85 + // Credit notes reduce what is owed, so they count towards settlement.
86 + $credited = class_exists('\\EasyInvoice\\Services\\InvoiceBalance') ? \EasyInvoice\Services\InvoiceBalance::credited((int) $invoice_id) : 0.0;
87 +
88 + return $total_payments + $credited + 0.005 >= $invoice_total;
65 89 }
66 90
67 91 /**
68 92 * Update invoice status to paid only if total payments are sufficient
@@ -88,9 +112,11 @@
88 112 // Trigger hook when invoice is marked as paid (for email notifications, etc.)
89 113 // Get payment method and transaction ID from the most recent payment
90 114 $payment_method = get_post_meta($invoice_id, '_payment_method', true) ?: $gateway_name ?: 'online';
91 115 $transaction_id = get_post_meta($invoice_id, '_transaction_id', true) ?: '';
92 - $payment_amount = $invoice->getTotal();
116 + // The receipt names the payment that settled the invoice, which
117 + // is the whole total only when it was paid in one go.
118 + $payment_amount = $this->latestCompletedPaymentAmount($invoice_id) ?: $invoice->getTotal();
93 119
94 120 do_action('easy_invoice_payment_completed', $invoice_id, $invoice, [
95 121 'payment_method' => $payment_method,
96 122 'gateway_name' => $gateway_name,
@@ -99,15 +125,27 @@
99 125 ]);
100 126
101 127 return true;
102 128 } else {
103 - // Log that status remains unchanged
104 - if (method_exists($this, 'log')) {
105 - $this->log("Invoice #$invoice_id status remains unchanged - partial payment received", 'info');
106 - } else {
107 - error_log("Easy Invoice: Invoice #$invoice_id status remains unchanged - partial payment received");
129 + // Something has been received but not everything: say so, unless
130 + // the invoice is in a state that should not change (draft,
131 + // cancelled) or already reads as part paid.
132 + $current = strtolower((string) $invoice->getStatus());
133 + $received = $this->calculateTotalPaymentsForInvoice($invoice_id);
134 + if (in_array($current, ['available', 'unpaid', 'overdue'], true) && $received > 0) {
135 + $invoice->setStatus('partial');
136 + $invoice->save();
108 137 }
109 -
138 + if ($received > 0) {
139 + /** This action is documented in includes/Controllers/PaymentController.php */
140 + do_action('easy_invoice_payment_received', $invoice_id, $invoice, [
141 + 'payment_method' => get_post_meta($invoice_id, '_payment_method', true) ?: $gateway_name ?: 'online',
142 + 'gateway_name' => $gateway_name,
143 + 'transaction_id' => get_post_meta($invoice_id, '_transaction_id', true) ?: '',
144 + 'amount' => $this->latestCompletedPaymentAmount($invoice_id),
145 + ]);
146 + }
147 +
110 148 return false;
111 149 }
112 150 }
113 151 }