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
← All changes | templates/reports-page.php +148 -117 2.3.42.4.1 View file →
@@ -30,16 +30,16 @@
30 30 <div class="p-8">
31 31 <div class="ei-app-page-header bg-white border-b border-gray-200 px-6" style="margin-left: -2rem; margin-top: -2rem; padding-left:2rem; padding-right:2rem; margin-right: -2rem;">
32 32 <div class="flex items-center justify-between">
33 33 <div>
34 - <h1 class="text-2xl font-bold text-gray-900">Reports</h1>
35 - <p class="mt-1 text-sm text-gray-500">Comprehensive insights and analytics</p>
34 + <h1 class="text-2xl font-bold text-gray-900"><?php esc_html_e('Reports', 'easy-invoice'); ?></h1>
35 + <p class="mt-1 text-sm text-gray-500"><?php esc_html_e('Comprehensive insights and analytics', 'easy-invoice'); ?></p>
36 36 </div>
37 37 <div class="flex items-center space-x-3">
38 - <form method="get" action="<?php echo admin_url('admin.php'); ?>" class="flex space-x-2">
38 + <form method="get" action="<?php echo esc_url(admin_url('admin.php')); ?>" class="flex space-x-2">
39 39 <input type="hidden" name="page" value="easy-invoice-reports">
40 40 <div class="flex items-center">
41 - <label for="start_date" class="mr-2 text-sm font-medium text-gray-700">From:</label>
41 + <label for="start_date" class="mr-2 text-sm font-medium text-gray-700"><?php esc_html_e('From:', 'easy-invoice'); ?></label>
42 42 <input type="date" id="start_date" name="start_date" value="<?php echo esc_attr($start_date); ?>" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm transition-colors duration-200">
43 43 </div>
44 44 <div class="flex items-center">
45 45 <label for="end_date" class="mr-2 text-sm font-medium text-gray-700">To:</label>
@@ -65,9 +65,9 @@
65 65 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
66 66 </svg>
67 67 </div>
68 68 <div>
69 - <h3 class="text-sm font-medium text-gray-500">Total Revenue</h3>
69 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e('Revenue (paid invoices in period, net of credits)', 'easy-invoice'); ?></h3>
70 70 <?php if (is_array($summary_stats['total_revenue']) && !empty($summary_stats['total_revenue'])): ?>
71 71 <div class="mt-1">
72 72 <?php
73 73 $currency_count = count($summary_stats['total_revenue']);
@@ -76,10 +76,10 @@
76 76 // Get currency code from the data array or use a fallback
77 77 $currency_code = isset($data['currency_code']) ? $data['currency_code'] : 'USD';
78 78 ?>
79 79 <div class="<?php echo $currency_count > 1 ? 'text-sm' : 'text-lg'; ?> font-bold text-gray-900 <?php echo !$is_last ? 'mb-1' : ''; ?>">
80 - <?php echo $data['symbol'] . number_format($data['amount'], 2); ?>
81 - <span class="text-xs font-normal text-gray-500"><?php echo strtoupper($currency_code ?? 'USD'); ?></span>
80 + <?php echo esc_html(easy_invoice_format_money($data['amount'], null, (string) ($currency_code ?? 'USD'))); ?>
81 + <span class="text-xs font-normal text-gray-500"><?php echo esc_html(strtoupper($currency_code ?? 'USD')); ?></span>
82 82 </div>
83 83 <?php endforeach; ?>
84 84 </div>
85 85 <?php else: ?>
@@ -96,9 +96,9 @@
96 96 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
97 97 </svg>
98 98 </div>
99 99 <div>
100 - <h3 class="text-sm font-medium text-gray-500">Total Invoices</h3>
100 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e('Total Invoices', 'easy-invoice'); ?></h3>
101 101 <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo esc_html($summary_stats['total_invoices']); ?></p>
102 102 </div>
103 103 </div>
104 104 </div>
@@ -113,9 +113,9 @@
113 113 <path d="M16.32 11.6722C18.36 11.6722 20 10.0322 20 7.99219C20 5.95219 18.36 4.31219 16.32 4.31219" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
114 114 </svg>
115 115 </div>
116 116 <div>
117 - <h3 class="text-sm font-medium text-gray-500">Active Clients</h3>
117 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e('Invoiced Clients', 'easy-invoice'); ?></h3>
118 118 <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo esc_html($summary_stats['active_clients']); ?></p>
119 119 </div>
120 120 </div>
121 121 </div>
@@ -127,10 +127,10 @@
127 127 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
128 128 </svg>
129 129 </div>
130 130 <div>
131 - <h3 class="text-sm font-medium text-gray-500">Average Payment Time</h3>
132 - <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo esc_html($summary_stats['avg_payment_time']); ?> days</p>
131 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e('Average Payment Time', 'easy-invoice'); ?></h3>
132 + <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo null === $summary_stats['avg_payment_time'] ? '&mdash;' : esc_html($summary_stats['avg_payment_time']) . ' ' . esc_html__('days', 'easy-invoice'); ?></p>
133 133 </div>
134 134 </div>
135 135 </div>
136 136 </div>
@@ -136,9 +136,9 @@
136 136 </div>
137 137
138 138 <div class="grid grid-cols-1 gap-5 lg:grid-cols-2 mb-8">
139 139 <div class="bg-white shadow rounded-lg p-6">
140 - <h2 class="text-lg font-medium text-gray-900 mb-4">Monthly Revenue</h2>
140 + <h2 class="text-lg font-medium text-gray-900 mb-4"><?php esc_html_e('Monthly Revenue (payments received, last 12 months)', 'easy-invoice'); ?></h2>
141 141 <div class="h-64">
142 142 <canvas id="revenue-chart"></canvas>
143 143 </div>
144 144 </div>
@@ -143,9 +143,9 @@
143 143 </div>
144 144 </div>
145 145
146 146 <div class="bg-white shadow rounded-lg p-6">
147 - <h2 class="text-lg font-medium text-gray-900 mb-4">Invoice Status</h2>
147 + <h2 class="text-lg font-medium text-gray-900 mb-4"><?php esc_html_e('Invoice Status', 'easy-invoice'); ?></h2>
148 148 <div class="h-64 flex items-center justify-center">
149 149 <div class="w-48 h-48 relative">
150 150 <canvas id="status-chart"></canvas>
151 151 </div>
@@ -152,12 +152,18 @@
152 152 <div class="ml-8">
153 153 <?php
154 154 $statusColors = [
155 155 'Paid' => 'bg-green-500',
156 + 'Partial' => 'bg-blue-500',
156 157 'Unpaid' => 'bg-yellow-500',
157 158 'Overdue' => 'bg-red-500',
158 - 'Draft' => 'bg-gray-500'
159 + 'Draft' => 'bg-gray-300',
160 + 'Canceled' => 'bg-gray-500'
159 161 ];
162 + $ei_status_names = [
163 + 'paid' => __('Paid', 'easy-invoice'), 'partial' => __('Partially paid', 'easy-invoice'), 'unpaid' => __('Unpaid', 'easy-invoice'),
164 + 'overdue' => __('Overdue', 'easy-invoice'), 'draft' => __('Draft', 'easy-invoice'), 'canceled' => __('Cancelled', 'easy-invoice'),
165 + ];
160 166
161 167 if (isset($invoice_status['percentages']) && isset($invoice_status['counts'])) {
162 168 foreach ($invoice_status['percentages'] as $status => $percentage) {
163 169 $color = isset($statusColors[ucfirst($status)]) ? $statusColors[ucfirst($status)] : 'bg-gray-500';
@@ -163,9 +169,9 @@
163 169 $color = isset($statusColors[ucfirst($status)]) ? $statusColors[ucfirst($status)] : 'bg-gray-500';
164 170 $count = isset($invoice_status['counts'][$status]) ? $invoice_status['counts'][$status] : 0;
165 171 echo '<div class="flex items-center mb-2">';
166 172 echo '<div class="w-4 h-4 rounded-full ' . esc_attr($color) . ' mr-2"></div>';
167 - echo '<span class="text-sm text-gray-600">' . esc_html(ucfirst($status)) . ' (' . esc_html($percentage) . '% - ' . esc_html($count) . ')</span>';
173 + echo '<span class="text-sm text-gray-600">' . esc_html($ei_status_names[$status] ?? ucfirst($status)) . ' (' . esc_html($percentage) . '% - ' . esc_html($count) . ')</span>';
168 174 echo '</div>';
169 175 }
170 176 }
171 177 ?>
@@ -175,9 +181,9 @@
175 181 </div>
176 182
177 183 <div class="bg-white shadow rounded-lg mb-8">
178 184 <div class="px-6 py-4 border-b border-gray-200">
179 - <h2 class="text-lg font-medium text-gray-900">Top Clients by Revenue</h2>
185 + <h2 class="text-lg font-medium text-gray-900"><?php esc_html_e('Top Clients by Revenue', 'easy-invoice'); ?></h2>
180 186 </div>
181 187 <div class="overflow-x-auto">
182 188 <table class="min-w-full divide-y divide-gray-200">
183 189 <thead class="bg-gray-50">
@@ -228,10 +234,10 @@
228 234 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
229 235 <?php if (isset($client['total_amount']) && is_array($client['total_amount']) && !empty($client['total_amount'])): ?>
230 236 <?php foreach ($client['total_amount'] as $currency => $currency_data): ?>
231 237 <div>
232 - <?php echo $currency_data['symbol'] . number_format($currency_data['amount'], 2); ?>
233 - <span class="text-xs text-gray-500"><?php echo $currency; ?></span>
238 + <?php echo esc_html(easy_invoice_format_money($currency_data['amount'], null, (string) $currency)); ?>
239 + <span class="text-xs text-gray-500"><?php echo esc_html($currency); ?></span>
234 240 </div>
235 241 <?php endforeach; ?>
236 242 <?php else: ?>
237 243 $0.00
@@ -240,9 +246,9 @@
240 246 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
241 247 <?php echo esc_html($client['total_invoices']); ?> invoices
242 248 </td>
243 249 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
244 - <?php echo !empty($client['last_invoice']) ? date('M d, Y', strtotime($client['last_invoice'])) : 'N/A'; ?>
250 + <?php echo esc_html(!empty($client['last_invoice']) ? gmdate('M d, Y', strtotime($client['last_invoice'])) : 'N/A'); ?>
245 251 </td>
246 252
247 253
248 254 <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
@@ -251,9 +257,9 @@
251 257 </tr>
252 258 <?php endforeach; ?>
253 259 <?php else: ?>
254 260 <tr>
255 - <td colspan="5" class="px-6 py-4 text-center text-gray-500">No client data available</td>
261 + <td colspan="5" class="px-6 py-4 text-center text-gray-500"><?php esc_html_e('No client data available', 'easy-invoice'); ?></td>
256 262 </tr>
257 263 <?php endif; ?>
258 264 </tbody>
259 265 </table>
@@ -259,12 +265,25 @@
259 265 </table>
260 266 </div>
261 267 </div>
262 268
269 + <?php
270 + /**
271 + * Fires between the summary charts and the detailed reports.
272 + *
273 + * Chart.js is on the page as the `chartjs` handle. The Pro Reports
274 + * addon adds the profit & loss statement here.
275 + *
276 + * @param string $start_date Y-m-d.
277 + * @param string $end_date Y-m-d.
278 + */
279 + do_action('easy_invoice_reports_after_summary', $start_date, $end_date);
280 + ?>
281 +
263 282 <div class="bg-white shadow rounded-lg">
264 283 <div class="border-b border-gray-200">
265 284 <div class="flex items-center justify-between px-6 py-3">
266 - <h2 class="text-lg font-medium text-gray-900">Detailed Reports</h2>
285 + <h2 class="text-lg font-medium text-gray-900"><?php esc_html_e('Detailed Reports', 'easy-invoice'); ?></h2>
267 286 <div>
268 287 <button id="export-detailed-report" class="inline-flex items-center px-3 py-2 border border-transparent text-sm font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
269 288 <i class="fas fa-download mr-2"></i> Export
270 289 </button>
@@ -283,13 +302,13 @@
283 302 <div id="payment-report-content" class="tab-content block" style="display: block !important;">
284 303 <div class="p-4 bg-gray-50 border-b">
285 304 <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
286 305 <div class="bg-white p-4 rounded-md shadow-sm">
287 - <div class="text-sm text-gray-500">Total Payments</div>
306 + <div class="text-sm text-gray-500"><?php esc_html_e('Total Payments', 'easy-invoice'); ?></div>
288 307 <div class="text-xl font-bold"><?php echo esc_html($payment_report['count']); ?></div>
289 308 </div>
290 309 <div class="bg-white p-4 rounded-md shadow-sm">
291 - <div class="text-sm text-gray-500">Total Amount</div>
310 + <div class="text-sm text-gray-500"><?php esc_html_e('Total Amount', 'easy-invoice'); ?></div>
292 311 <div class="text-lg font-bold">
293 312 <?php
294 313 // Calculate total amount from all payment methods and currencies
295 314 $total_amounts_by_currency = [];
@@ -311,10 +330,10 @@
311 330
312 331 if (!empty($total_amounts_by_currency)): ?>
313 332 <?php foreach ($total_amounts_by_currency as $currency => $data): ?>
314 333 <div class="text-sm">
315 - <?php echo $data['symbol'] . number_format($data['amount'], 2); ?>
316 - <span class="text-xs text-gray-500"><?php echo $currency; ?></span>
334 + <?php echo esc_html(easy_invoice_format_money($data['amount'], null, (string) $currency)); ?>
335 + <span class="text-xs text-gray-500"><?php echo esc_html($currency); ?></span>
317 336 </div>
318 337 <?php endforeach; ?>
319 338 <?php else: ?>
320 339 $0.00
@@ -321,9 +340,9 @@
321 340 <?php endif; ?>
322 341 </div>
323 342 </div>
324 343 <div class="bg-white p-4 rounded-md shadow-sm">
325 - <div class="text-sm text-gray-500">Average Payment</div>
344 + <div class="text-sm text-gray-500"><?php esc_html_e('Average Payment', 'easy-invoice'); ?></div>
326 345 <div class="text-lg font-bold">
327 346 <?php
328 347 // Calculate average payments by currency
329 348 $average_amounts_by_currency = [];
@@ -352,9 +371,9 @@
352 371
353 372 if (!empty($average_amounts_by_currency)): ?>
354 373 <?php foreach ($average_amounts_by_currency as $currency => $data): ?>
355 374 <div class="text-sm">
356 - <?php echo $data['symbol'] . number_format($data['amount'], 2); ?>
375 + <?php echo esc_html(easy_invoice_format_money($data['amount'], null, (string) $currency)); ?>
357 376 <span class="text-xs text-gray-500">
358 377 <?php
359 378 $display_currency = $currency;
360 379 if ($display_currency === 'GLOBAL') {
@@ -365,9 +384,9 @@
365 384 </span>
366 385 </div>
367 386 <?php endforeach; ?>
368 387 <?php elseif ($payment_count > 0): ?>
369 - <span class="text-sm text-gray-500">No currency data</span>
388 + <span class="text-sm text-gray-500"><?php esc_html_e('No currency data', 'easy-invoice'); ?></span>
370 389 <?php else: ?>
371 390 $0.00
372 391 <?php endif; ?>
373 392 </div>
@@ -375,9 +394,9 @@
375 394 </div>
376 395 </div>
377 396
378 397 <div class="p-4">
379 - <h3 class="text-md font-medium text-gray-700 mb-3">Payment Methods Distribution</h3>
398 + <h3 class="text-md font-medium text-gray-700 mb-3"><?php esc_html_e('Payment Methods Distribution', 'easy-invoice'); ?></h3>
380 399 <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
381 400 <div class="bg-white p-4 rounded-md shadow-sm">
382 401 <canvas id="payment-methods-chart" height="200"></canvas>
383 402 </div>
@@ -384,11 +403,11 @@
384 403 <div class="bg-white p-4 rounded-md shadow-sm">
385 404 <table class="min-w-full divide-y divide-gray-200">
386 405 <thead>
387 406 <tr>
388 - <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Method</th>
389 - <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Count</th>
390 - <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
407 + <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Method', 'easy-invoice'); ?></th>
408 + <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Count', 'easy-invoice'); ?></th>
409 + <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Amount', 'easy-invoice'); ?></th>
391 410 </tr>
392 411 </thead>
393 412 <tbody>
394 413 <?php
@@ -405,10 +424,10 @@
405 424 <td class="px-3 py-2 whitespace-nowrap text-sm text-right text-gray-900">
406 425 <?php if (isset($data['amounts_by_currency']) && !empty($data['amounts_by_currency'])): ?>
407 426 <?php foreach ($data['amounts_by_currency'] as $currency => $currency_data): ?>
408 427 <div class="text-xs">
409 - <?php echo $currency_data['symbol'] . number_format($currency_data['amount'], 2); ?>
410 - <span class="text-xs text-gray-500"><?php echo $currency; ?></span>
428 + <?php echo esc_html(easy_invoice_format_money($currency_data['amount'], null, (string) $currency)); ?>
429 + <span class="text-xs text-gray-500"><?php echo esc_html($currency); ?></span>
411 430 </div>
412 431 <?php endforeach; ?>
413 432 <?php else: ?>
414 433 $0.00
@@ -419,9 +438,9 @@
419 438 endforeach;
420 439 else:
421 440 ?>
422 441 <tr>
423 - <td colspan="3" class="px-3 py-4 text-center text-sm text-gray-500">No payment method data available</td>
442 + <td colspan="3" class="px-3 py-4 text-center text-sm text-gray-500"><?php esc_html_e('No payment method data available', 'easy-invoice'); ?></td>
424 443 </tr>
425 444 <?php endif; ?>
426 445 </tbody>
427 446 </table>
@@ -429,20 +448,20 @@
429 448 </div>
430 449 </div>
431 450
432 451 <div class="p-4">
433 - <h3 class="text-md font-medium text-gray-700 mb-3">Recent Payments</h3>
452 + <h3 class="text-md font-medium text-gray-700 mb-3"><?php esc_html_e('Recent Payments', 'easy-invoice'); ?></h3>
434 453 <div class="overflow-x-auto">
435 454 <table class="min-w-full divide-y divide-gray-200">
436 455 <thead class="bg-gray-50">
437 456 <tr>
438 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
439 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Invoice</th>
440 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
441 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Method</th>
442 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
443 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Transaction ID</th>
444 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
457 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Date', 'easy-invoice'); ?></th>
458 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Invoice', 'easy-invoice'); ?></th>
459 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Amount', 'easy-invoice'); ?></th>
460 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Method', 'easy-invoice'); ?></th>
461 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Status', 'easy-invoice'); ?></th>
462 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Transaction ID', 'easy-invoice'); ?></th>
463 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Actions', 'easy-invoice'); ?></th>
445 464 </tr>
446 465 </thead>
447 466 <tbody class="bg-white divide-y divide-gray-200">
448 467 <?php if (!empty($payment_report['payments'])) : ?>
@@ -448,17 +467,21 @@
448 467 <?php if (!empty($payment_report['payments'])) : ?>
449 468 <?php foreach ($payment_report['payments'] as $payment): ?>
450 469 <tr class="hover:bg-gray-50">
451 470 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500">
452 - <?php echo date('M d, Y', strtotime($payment['date'])); ?>
471 + <?php echo esc_html(gmdate('M d, Y', strtotime($payment['date']))); ?>
453 472 </td>
454 473 <td class="px-4 py-3 whitespace-nowrap">
455 - <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice&action=edit&id=' . $payment['invoice_id'])); ?>" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium">
474 + <?php if (!empty($payment['invoice_id'])) : ?>
475 + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-builder&invoice_id=' . (int) $payment['invoice_id'])); ?>" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium">
456 476 <?php echo esc_html($payment['invoice_number']); ?>
457 477 </a>
478 + <?php else : ?>
479 + <span class="text-sm text-gray-500"><?php echo esc_html($payment['invoice_number'] ?: '—'); ?></span>
480 + <?php endif; ?>
458 481 </td>
459 482 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
460 - <?php echo esc_html($payment['currency_symbol'] . number_format($payment['amount'], 2)); ?>
483 + <?php echo esc_html(easy_invoice_format_money($payment['amount'], null, (string) ($payment['currency'] ?? ''))); ?>
461 484 </td>
462 485 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500">
463 486 <?php echo esc_html(ucfirst($payment['payment_method'])); ?>
464 487 </td>
@@ -486,9 +509,9 @@
486 509 </tr>
487 510 <?php endforeach; ?>
488 511 <?php else: ?>
489 512 <tr>
490 - <td colspan="7" class="px-4 py-4 text-center text-gray-500">No payment records found for the selected period</td>
513 + <td colspan="7" class="px-4 py-4 text-center text-gray-500"><?php esc_html_e('No payment records found for the selected period', 'easy-invoice'); ?></td>
491 514 </tr>
492 515 <?php endif; ?>
493 516 </tbody>
494 517 </table>
@@ -499,13 +522,13 @@
499 522 <div id="invoice-report-content" class="tab-content hidden" style="display: none;">
500 523 <div class="p-4 bg-gray-50 border-b">
501 524 <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
502 525 <div class="bg-white p-4 rounded-md shadow-sm">
503 - <div class="text-sm text-gray-500">Total Invoices</div>
526 + <div class="text-sm text-gray-500"><?php esc_html_e('Total Invoices', 'easy-invoice'); ?></div>
504 527 <div class="text-xl font-bold"><?php echo esc_html($invoice_report['count']); ?></div>
505 528 </div>
506 529 <div class="bg-white p-4 rounded-md shadow-sm">
507 - <div class="text-sm text-gray-500">Total Amount</div>
530 + <div class="text-sm text-gray-500"><?php esc_html_e('Total Amount', 'easy-invoice'); ?></div>
508 531 <div class="text-lg font-bold">
509 532 <?php
510 533 // Display total amounts by currency
511 534 if (isset($invoice_report['total_amounts_by_currency']) && !empty($invoice_report['total_amounts_by_currency'])): ?>
@@ -510,9 +533,9 @@
510 533 // Display total amounts by currency
511 534 if (isset($invoice_report['total_amounts_by_currency']) && !empty($invoice_report['total_amounts_by_currency'])): ?>
512 535 <?php foreach ($invoice_report['total_amounts_by_currency'] as $currency => $currency_data): ?>
513 536 <div class="text-sm">
514 - <?php echo $currency_data['symbol'] . number_format($currency_data['amount'], 2); ?>
537 + <?php echo esc_html(easy_invoice_format_money($currency_data['amount'], null, (string) $currency)); ?>
515 538 <span class="text-xs text-gray-500">
516 539 <?php
517 540 $display_currency = $currency;
518 541 if ($display_currency === 'GLOBAL') {
@@ -528,9 +551,9 @@
528 551 <?php endif; ?>
529 552 </div>
530 553 </div>
531 554 <div class="bg-white p-4 rounded-md shadow-sm">
532 - <div class="text-sm text-gray-500">Average Invoice</div>
555 + <div class="text-sm text-gray-500"><?php esc_html_e('Average Invoice', 'easy-invoice'); ?></div>
533 556 <div class="text-lg font-bold">
534 557 <?php
535 558 // Calculate average amounts by currency
536 559 if (isset($invoice_report['total_amounts_by_currency']) && !empty($invoice_report['total_amounts_by_currency']) && $invoice_report['count'] > 0): ?>
@@ -537,9 +560,9 @@
537 560 <?php foreach ($invoice_report['total_amounts_by_currency'] as $currency => $currency_data): ?>
538 561 <div class="text-sm">
539 562 <?php
540 563 $avg_amount = $currency_data['amount'] / $invoice_report['count'];
541 - echo $currency_data['symbol'] . number_format($avg_amount, 2);
564 + echo esc_html(easy_invoice_format_money($avg_amount, null, (string) $currency));
542 565 ?>
543 566 <span class="text-xs text-gray-500">
544 567 <?php
545 568 $display_currency = $currency;
@@ -559,9 +582,9 @@
559 582 </div>
560 583 </div>
561 584
562 585 <div class="p-4">
563 - <h3 class="text-md font-medium text-gray-700 mb-3">Invoice Status Distribution</h3>
586 + <h3 class="text-md font-medium text-gray-700 mb-3"><?php esc_html_e('Invoice Status Distribution', 'easy-invoice'); ?></h3>
564 587 <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
565 588 <div class="bg-white p-4 rounded-md shadow-sm">
566 589 <canvas id="invoice-status-chart" height="200"></canvas>
567 590 </div>
@@ -568,22 +591,23 @@
568 591 <div class="bg-white p-4 rounded-md shadow-sm">
569 592 <table class="min-w-full divide-y divide-gray-200">
570 593 <thead>
571 594 <tr>
572 - <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
573 - <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Count</th>
574 - <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
595 + <th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Status', 'easy-invoice'); ?></th>
596 + <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Count', 'easy-invoice'); ?></th>
597 + <th class="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Amount', 'easy-invoice'); ?></th>
575 598 </tr>
576 599 </thead>
577 600 <tbody>
578 601 <?php
579 602 $status_list = [
580 - 'paid' => 'Paid',
581 - 'unpaid' => 'Unpaid',
582 - 'overdue' => 'Overdue',
583 - 'draft' => 'Draft',
584 - 'canceled' => 'Canceled',
585 - 'other' => 'Other'
603 + 'paid' => __('Paid', 'easy-invoice'),
604 + 'partial' => __('Partially paid', 'easy-invoice'),
605 + 'unpaid' => __('Unpaid', 'easy-invoice'),
606 + 'overdue' => __('Overdue', 'easy-invoice'),
607 + 'draft' => __('Draft', 'easy-invoice'),
608 + 'canceled' => __('Cancelled', 'easy-invoice'),
609 + 'other' => __('Other', 'easy-invoice')
586 610 ];
587 611
588 612 foreach ($status_list as $status_key => $status_label) :
589 613 $status_data = isset($invoice_report['by_status'][$status_key]) ? $invoice_report['by_status'][$status_key] : ['amount' => 0, 'count' => 0];
@@ -598,9 +622,9 @@
598 622 <td class="px-3 py-2 whitespace-nowrap text-sm text-right text-gray-900">
599 623 <?php if (isset($status_data['amounts_by_currency']) && !empty($status_data['amounts_by_currency'])): ?>
600 624 <?php foreach ($status_data['amounts_by_currency'] as $currency => $currency_data): ?>
601 625 <div class="text-xs">
602 - <?php echo $currency_data['symbol'] . number_format($currency_data['amount'], 2); ?>
626 + <?php echo esc_html(easy_invoice_format_money($currency_data['amount'], null, (string) $currency)); ?>
603 627 <span class="text-xs text-gray-500">
604 628 <?php
605 629 $display_currency = $currency;
606 630 if ($display_currency === 'GLOBAL') {
@@ -623,20 +647,20 @@
623 647 </div>
624 648 </div>
625 649
626 650 <div class="p-4">
627 - <h3 class="text-md font-medium text-gray-700 mb-3">Recent Invoices</h3>
651 + <h3 class="text-md font-medium text-gray-700 mb-3"><?php esc_html_e('Recent Invoices', 'easy-invoice'); ?></h3>
628 652 <div class="overflow-x-auto">
629 653 <table class="min-w-full divide-y divide-gray-200">
630 654 <thead class="bg-gray-50">
631 655 <tr>
632 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
633 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th>
656 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Date', 'easy-invoice'); ?></th>
657 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Due Date', 'easy-invoice'); ?></th>
634 658 <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Invoice #</th>
635 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Client</th>
636 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
637 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
638 - <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
659 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Client', 'easy-invoice'); ?></th>
660 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Amount', 'easy-invoice'); ?></th>
661 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Status', 'easy-invoice'); ?></th>
662 + <th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e('Actions', 'easy-invoice'); ?></th>
639 663 </tr>
640 664 </thead>
641 665 <tbody class="bg-white divide-y divide-gray-200">
642 666 <?php if (!empty($invoice_report['invoices'])) : ?>
@@ -642,14 +666,14 @@
642 666 <?php if (!empty($invoice_report['invoices'])) : ?>
643 667 <?php foreach ($invoice_report['invoices'] as $invoice): ?>
644 668 <tr class="hover:bg-gray-50">
645 669 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500">
646 - <?php echo date('M d, Y', strtotime($invoice['issue_date'])); ?>
670 + <?php echo esc_html(gmdate('M d, Y', strtotime($invoice['issue_date']))); ?>
647 671 </td>
648 672 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500">
649 673 <?php
650 674 if (!empty($invoice['due_date']) && $invoice['due_date'] !== '0000-00-00' && $invoice['due_date'] !== '1970-01-01') {
651 - echo date('M d, Y', strtotime($invoice['due_date']));
675 + echo esc_html(gmdate('M d, Y', strtotime($invoice['due_date'])));
652 676 } else {
653 677 echo '-';
654 678 }
655 679 ?>
@@ -654,9 +678,9 @@
654 678 }
655 679 ?>
656 680 </td>
657 681 <td class="px-4 py-3 whitespace-nowrap">
658 - <a href="<?php echo esc_url(get_permalink($invoice['id'])); ?>" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium" target="_blank">
682 + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-builder&invoice_id=' . (int) $invoice['id'])); ?>" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium">
659 683 <?php echo esc_html($invoice['invoice_number']); ?>
660 684 </a>
661 685 </td>
662 686 <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
@@ -675,9 +699,9 @@
675 699 $display_currency = $invoice['currency'];
676 700 if ($display_currency === 'GLOBAL') {
677 701 $display_currency = get_option('easy_invoice_currency_code', 'USD');
678 702 }
679 - echo esc_html($invoice['currency_symbol'] . number_format($invoice['total'], 2)); ?>
703 + echo esc_html(easy_invoice_format_money($invoice['total'], null, (string) $display_currency)); ?>
680 704 <span class="text-xs text-gray-500"><?php echo esc_html(strtoupper($display_currency)); ?></span>
681 705 </td>
682 706 <td class="px-4 py-3 whitespace-nowrap">
683 707 <?php
@@ -685,8 +709,10 @@
685 709 if (in_array($invoice['status'], ['paid', 'completed'])) {
686 710 $status_class = 'bg-green-100 text-green-800';
687 711 } elseif ($invoice['status'] === 'unpaid') {
688 712 $status_class = 'bg-yellow-100 text-yellow-800';
713 + } elseif ($invoice['status'] === 'partial') {
714 + $status_class = 'bg-blue-100 text-blue-800';
689 715 } elseif ($invoice['status'] === 'overdue') {
690 716 $status_class = 'bg-red-100 text-red-800';
691 717 } elseif ($invoice['status'] === 'draft') {
692 718 $status_class = 'bg-gray-100 text-gray-800';
@@ -692,19 +718,19 @@
692 718 $status_class = 'bg-gray-100 text-gray-800';
693 719 }
694 720 ?>
695 721 <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full <?php echo esc_attr($status_class); ?>">
696 - <?php echo esc_html(ucfirst($invoice['status'])); ?>
722 + <?php echo esc_html($status_list[$invoice['status']] ?? ucfirst($invoice['status'])); ?>
697 723 </span>
698 724 </td>
699 725 <td class="px-4 py-3 whitespace-nowrap text-sm font-medium">
700 - <a href="<?php echo esc_url(get_permalink($invoice['id'])); ?>" class="text-indigo-600 hover:text-indigo-900" target="_blank">View</a>
726 + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-builder&invoice_id=' . (int) $invoice['id'])); ?>" class="text-indigo-600 hover:text-indigo-900">View</a>
701 727 </td>
702 728 </tr>
703 729 <?php endforeach; ?>
704 730 <?php else: ?>
705 731 <tr>
706 - <td colspan="7" class="px-4 py-4 text-center text-gray-500">No invoice records found for the selected period</td>
732 + <td colspan="7" class="px-4 py-4 text-center text-gray-500"><?php esc_html_e('No invoice records found for the selected period', 'easy-invoice'); ?></td>
707 733 </tr>
708 734 <?php endif; ?>
709 735 </tbody>
710 736 </table>
@@ -713,9 +739,14 @@
713 739 </div>
714 740 </div>
715 741 </div>
716 742
717 -<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
743 +<?php
744 +// Chart.js is enqueued as the 'chartjs' handle by ReportController::enqueueReportScripts()
745 +// from assets/js/vendors/chart.min.js. It was previously also pulled from jsDelivr here,
746 +// which both duplicated the local copy and broke the WordPress.org rule that all assets
747 +// ship inside the plugin. The guard below already waits for Chart to be defined.
748 +?>
718 749 <script>
719 750
720 751
721 752 // Monthly revenue chart
@@ -836,9 +867,9 @@
836 867 if (chartContainer) {
837 868 chartContainer.style.display = 'flex';
838 869 chartContainer.style.alignItems = 'center';
839 870 chartContainer.style.justifyContent = 'center';
840 - chartContainer.innerHTML = '<div class="text-red-500 text-center"><p>Error loading chart. Please refresh the page.</p></div>';
871 + chartContainer.innerHTML = '<div class="text-red-500 text-center"><p><?php esc_html_e('Error loading chart. Please refresh the page.', 'easy-invoice'); ?></p></div>';
841 872 }
842 873 }
843 874 } else {
844 875 const chartContainer = document.getElementById('revenue-chart');
@@ -845,9 +876,9 @@
845 876 if (chartContainer) {
846 877 chartContainer.style.display = 'flex';
847 878 chartContainer.style.alignItems = 'center';
848 879 chartContainer.style.justifyContent = 'center';
849 - chartContainer.innerHTML = '<div class="text-gray-500 text-center"><p>No revenue data available for the selected period.</p><p class="text-sm mt-2">Revenue data will appear here once payments are recorded.</p></div>';
880 + chartContainer.innerHTML = '<div class="text-gray-500 text-center"><p><?php esc_html_e('No revenue data available for the selected period.', 'easy-invoice'); ?></p><p class="text-sm mt-2"><?php esc_html_e('Revenue data will appear here once payments are recorded.', 'easy-invoice'); ?></p></div>';
850 881 }
851 882 return;
852 883 }
853 884 }
@@ -904,12 +935,23 @@
904 935
905 936 const statusLabels = <?php
906 937 $status_labels = [];
907 938 $status_data = [];
939 + $status_rgba = [];
940 + // Colours keyed by status so a slice keeps its colour whichever statuses are present.
941 + $ei_overview_colors = [
942 + 'paid' => 'rgba(34, 197, 94, 0.8)',
943 + 'partial' => 'rgba(59, 130, 246, 0.8)',
944 + 'unpaid' => 'rgba(234, 179, 8, 0.8)',
945 + 'overdue' => 'rgba(239, 68, 68, 0.8)',
946 + 'draft' => 'rgba(209, 213, 219, 0.8)',
947 + 'canceled' => 'rgba(107, 114, 128, 0.8)',
948 + ];
908 949 if (isset($invoice_status['percentages']) && is_array($invoice_status['percentages'])) {
909 950 foreach ($invoice_status['percentages'] as $status => $percentage) {
910 - $status_labels[] = ucfirst($status);
951 + $status_labels[] = $ei_status_names[$status] ?? ucfirst($status);
911 952 $status_data[] = $percentage;
953 + $status_rgba[] = $ei_overview_colors[$status] ?? 'rgba(156, 163, 175, 0.8)';
912 954 }
913 955 }
914 956 echo json_encode($status_labels);
915 957 ?>;
@@ -917,17 +959,10 @@
917 959 const statusData = <?php
918 960 echo json_encode($status_data);
919 961 ?>;
920 962
963 + const statusColors = <?php echo json_encode($status_rgba); ?>;
921 964
922 -
923 - const statusColors = [
924 - 'rgba(34, 197, 94, 0.8)', // Green for Paid
925 - 'rgba(234, 179, 8, 0.8)', // Yellow for Unpaid
926 - 'rgba(239, 68, 68, 0.8)', // Red for Overdue
927 - 'rgba(209, 213, 219, 0.8)' // Gray for Draft
928 - ];
929 -
930 965 try {
931 966 if (statusLabels.length === 0 || statusData.length === 0) {
932 967 return;
933 968 }
@@ -1044,33 +1079,25 @@
1044 1079 if (document.getElementById('invoice-status-chart')) {
1045 1080 const invoiceStatusData = <?php
1046 1081 $statuses = [];
1047 1082 $statusCounts = [];
1083 + // Colours keyed by status so a slice keeps its colour whichever statuses are present.
1048 1084 $statusChartColors = [
1049 - 'rgba(34, 197, 94, 0.8)', // Green for Paid
1050 - 'rgba(234, 179, 8, 0.8)', // Yellow for Unpaid
1051 - 'rgba(239, 68, 68, 0.8)', // Red for Overdue
1052 - 'rgba(209, 213, 219, 0.8)', // Gray for Draft
1053 - 'rgba(107, 114, 128, 0.8)', // Dark Gray for Canceled
1054 - 'rgba(156, 163, 175, 0.8)' // Medium Gray for Other
1085 + 'paid' => 'rgba(34, 197, 94, 0.8)',
1086 + 'partial' => 'rgba(59, 130, 246, 0.8)',
1087 + 'unpaid' => 'rgba(234, 179, 8, 0.8)',
1088 + 'overdue' => 'rgba(239, 68, 68, 0.8)',
1089 + 'draft' => 'rgba(209, 213, 219, 0.8)',
1090 + 'canceled' => 'rgba(107, 114, 128, 0.8)',
1091 + 'other' => 'rgba(156, 163, 175, 0.8)',
1055 1092 ];
1056 -
1057 - $status_list = [
1058 - 'paid' => 'Paid',
1059 - 'unpaid' => 'Unpaid',
1060 - 'overdue' => 'Overdue',
1061 - 'draft' => 'Draft',
1062 - 'canceled' => 'Canceled',
1063 - 'other' => 'Other'
1064 - ];
1065 -
1066 - $i = 0;
1093 + $statusColors = [];
1067 1094 foreach ($status_list as $status_key => $status_label) {
1068 1095 $status_data = $invoice_report['by_status'][$status_key] ?? ['count' => 0];
1069 1096 if ($status_data['count'] > 0) {
1070 1097 $statuses[] = $status_label;
1071 1098 $statusCounts[] = $status_data['count'];
1072 - $i++;
1099 + $statusColors[] = $statusChartColors[$status_key] ?? 'rgba(156, 163, 175, 0.8)';
1073 1100 }
1074 1101 }
1075 1102
1076 1103 echo json_encode([
@@ -1075,15 +1102,15 @@
1075 1102
1076 1103 echo json_encode([
1077 1104 'labels' => $statuses,
1078 1105 'data' => $statusCounts,
1079 - 'colors' => array_slice($statusChartColors, 0, $i)
1106 + 'colors' => $statusColors
1080 1107 ]);
1081 1108 ?>;
1082 1109
1083 1110 if (invoiceStatusData.labels && invoiceStatusData.labels.length > 0) {
1084 1111 const invoiceStatusCtx = document.getElementById('invoice-status-chart').getContext('2d');
1085 - new Chart(invoiceStatusCtx, {
1112 + window.easyInvoiceStatusChart = new Chart(invoiceStatusCtx, {
1086 1113 type: 'pie',
1087 1114 data: {
1088 1115 labels: invoiceStatusData.labels,
1089 1116 datasets: [{
@@ -1176,8 +1203,12 @@
1176 1203 setTimeout(() => {
1177 1204 targetTab.classList.remove('hidden');
1178 1205 targetTab.classList.add('block');
1179 1206 targetTab.style.display = 'block';
1207 + // The chart was built while its tab was display:none (zero size); size it now.
1208 + if (targetId === 'invoice-report-content' && window.easyInvoiceStatusChart) {
1209 + window.easyInvoiceStatusChart.resize();
1210 + }
1180 1211 }, 10);
1181 1212 } else {
1182 1213 // Fallback to payment report if target not found
1183 1214 if (paymentReportTab) {
@@ -1212,16 +1243,16 @@
1212 1243 // Add summary stats
1213 1244 csvContent += 'Summary Statistics\r\n';
1214 1245 <?php if (isset($summary_stats['total_revenue']) && is_array($summary_stats['total_revenue']) && !empty($summary_stats['total_revenue'])): ?>
1215 1246 <?php foreach ($summary_stats['total_revenue'] as $currency => $data): ?>
1216 - csvContent += 'Total Revenue (<?php echo $currency; ?>),<?php echo $data['symbol'] . number_format($data['amount'], 2); ?>\r\n';
1247 + csvContent += 'Total Revenue (<?php echo esc_js($currency); ?>),<?php echo esc_js($data['symbol'] . number_format($data['amount'], 2)); ?>\r\n';
1217 1248 <?php endforeach; ?>
1218 1249 <?php else: ?>
1219 1250 csvContent += 'Total Revenue,$0.00\r\n';
1220 1251 <?php endif; ?>
1221 - csvContent += 'Total Invoices,<?php echo isset($summary_stats['total_invoices']) ? $summary_stats['total_invoices'] : 0; ?>\r\n';
1222 - csvContent += 'Active Clients,<?php echo isset($summary_stats['active_clients']) ? $summary_stats['active_clients'] : 0; ?>\r\n';
1223 - csvContent += 'Average Payment Time,<?php echo isset($summary_stats['avg_payment_time']) ? $summary_stats['avg_payment_time'] : 0; ?> days\r\n\r\n';
1252 + csvContent += 'Total Invoices,<?php echo esc_js(isset($summary_stats['total_invoices']) ? $summary_stats['total_invoices'] : 0); ?>\r\n';
1253 + csvContent += 'Active Clients,<?php echo esc_js(isset($summary_stats['active_clients']) ? $summary_stats['active_clients'] : 0); ?>\r\n';
1254 + csvContent += 'Average Payment Time,<?php echo esc_js(isset($summary_stats['avg_payment_time']) ? $summary_stats['avg_payment_time'] : 0); ?> days\r\n\r\n';
1224 1255
1225 1256 // Add monthly revenue
1226 1257 csvContent += 'Monthly Revenue\r\n';
1227 1258 csvContent += 'Month,USD,EUR,Other Currencies\r\n';
@@ -1239,9 +1270,9 @@
1239 1270 }
1240 1271 }
1241 1272 $other_text = !empty($other_currencies) ? implode('; ', $other_currencies) : '';
1242 1273 ?>
1243 - csvContent += '<?php echo $month; ?>,$<?php echo number_format($usd_amount, 2); ?>,€<?php echo number_format($eur_amount, 2); ?>,"<?php echo addslashes($other_text); ?>"\r\n';
1274 + csvContent += '<?php echo esc_js($month); ?>,$<?php echo esc_js(number_format($usd_amount, 2)); ?>,€<?php echo esc_js(number_format($eur_amount, 2)); ?>,"<?php echo esc_js($other_text); ?>"\r\n';
1244 1275 <?php endforeach; ?>
1245 1276 <?php endif; ?>
1246 1277 csvContent += '\r\n';
1247 1278
@@ -1250,9 +1281,9 @@
1250 1281 csvContent += 'Status,Percentage,Count\r\n';
1251 1282 <?php if (isset($invoice_status['percentages']) && is_array($invoice_status['percentages'])): ?>
1252 1283 <?php foreach ($invoice_status['percentages'] as $status => $percentage): ?>
1253 1284 <?php $count = isset($invoice_status['counts'][$status]) ? $invoice_status['counts'][$status] : 0; ?>
1254 - csvContent += '<?php echo ucfirst($status); ?>,<?php echo $percentage; ?>%,<?php echo $count; ?>\r\n';
1285 + csvContent += '<?php echo esc_js(ucfirst($status)); ?>,<?php echo esc_js($percentage); ?>%,<?php echo esc_js($count); ?>\r\n';
1255 1286 <?php endforeach; ?>
1256 1287 <?php endif; ?>
1257 1288 csvContent += '\r\n';
1258 1289
@@ -1275,11 +1306,11 @@
1275 1306 $other_text = !empty($other_currencies) ? implode('; ', $other_currencies) : '';
1276 1307 $client_name = isset($client['name']) ? $client['name'] : 'Unknown';
1277 1308 $client_email = isset($client['email']) ? $client['email'] : '';
1278 1309 $total_invoices = isset($client['total_invoices']) ? $client['total_invoices'] : 0;
1279 - $last_invoice = isset($client['last_invoice']) && !empty($client['last_invoice']) ? date('Y-m-d', strtotime($client['last_invoice'])) : 'N/A';
1310 + $last_invoice = isset($client['last_invoice']) && !empty($client['last_invoice']) ? gmdate('Y-m-d', strtotime($client['last_invoice'])) : 'N/A';
1280 1311 ?>
1281 - csvContent += '<?php echo addslashes($client_name); ?>,<?php echo addslashes($client_email); ?>,$<?php echo number_format($usd_amount, 2); ?>,€<?php echo number_format($eur_amount, 2); ?>,"<?php echo addslashes($other_text); ?>",<?php echo $total_invoices; ?>,<?php echo $last_invoice; ?>\r\n';
1312 + csvContent += '<?php echo esc_js($client_name); ?>,<?php echo esc_js($client_email); ?>,$<?php echo esc_js(number_format($usd_amount, 2)); ?>,€<?php echo esc_js(number_format($eur_amount, 2)); ?>,"<?php echo esc_js($other_text); ?>",<?php echo esc_js($total_invoices); ?>,<?php echo esc_js($last_invoice); ?>\r\n';
1282 1313 <?php endforeach; ?>
1283 1314 <?php endif; ?>
1284 1315
1285 1316 // Create download link