You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InvoiceOverview.php 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <?php
  2. namespace App\Filament\Company\Resources\Sales\InvoiceResource\Widgets;
  3. use App\Enums\Accounting\InvoiceStatus;
  4. use App\Filament\Company\Resources\Sales\InvoiceResource\Pages\ListInvoices;
  5. use App\Utilities\Currency\CurrencyConverter;
  6. use Filament\Widgets\Concerns\InteractsWithPageTable;
  7. use Filament\Widgets\StatsOverviewWidget as BaseWidget;
  8. use Filament\Widgets\StatsOverviewWidget\Stat;
  9. use Illuminate\Support\Number;
  10. class InvoiceOverview extends BaseWidget
  11. {
  12. use InteractsWithPageTable;
  13. protected static ?string $pollingInterval = null;
  14. protected function getTablePage(): string
  15. {
  16. return ListInvoices::class;
  17. }
  18. protected function getStats(): array
  19. {
  20. $outstandingInvoices = $this->getPageTableQuery()
  21. ->whereNotIn('status', [
  22. InvoiceStatus::Paid,
  23. InvoiceStatus::Void,
  24. InvoiceStatus::Draft,
  25. InvoiceStatus::Overpaid,
  26. ]);
  27. $amountOutstanding = $outstandingInvoices
  28. ->clone()
  29. ->sum('amount_due');
  30. $amountOverdue = $outstandingInvoices
  31. ->clone()
  32. ->where('status', InvoiceStatus::Overdue)
  33. ->sum('amount_due');
  34. $amountDueWithin30Days = $outstandingInvoices
  35. ->clone()
  36. ->where('due_date', '>=', today())
  37. ->where('due_date', '<=', today()->addDays(30))
  38. ->sum('amount_due');
  39. $validInvoices = $this->getPageTableQuery()
  40. ->whereNotIn('status', [
  41. InvoiceStatus::Void,
  42. InvoiceStatus::Draft,
  43. ]);
  44. $totalValidInvoiceAmount = $validInvoices->clone()->sum('amount_due');
  45. $totalValidInvoiceCount = $validInvoices->clone()->count();
  46. $averageInvoiceTotal = $totalValidInvoiceCount > 0 ? $totalValidInvoiceAmount / $totalValidInvoiceCount : 0;
  47. $averagePaymentTime = $this->getPageTableQuery()
  48. ->withWhereHas('statusHistories', function ($query) {
  49. $query->where('new_status', InvoiceStatus::Paid);
  50. })
  51. ->selectRaw('AVG(TIMESTAMPDIFF(DAY, date, (
  52. SELECT changed_at
  53. FROM invoice_status_histories
  54. WHERE invoice_status_histories.invoice_id = invoices.id
  55. AND status = ?
  56. LIMIT 1
  57. ))) as avg_days', [InvoiceStatus::Paid])
  58. ->value('avg_days');
  59. return [
  60. Stat::make('Total Outstanding', CurrencyConverter::formatCentsToMoney($amountOutstanding))
  61. ->description('Includes ' . CurrencyConverter::formatCentsToMoney($amountOverdue) . ' overdue'),
  62. Stat::make('Due Within 30 Days', CurrencyConverter::formatCentsToMoney($amountDueWithin30Days)),
  63. Stat::make('Average Payment Time', Number::format($averagePaymentTime ?? 0, maxPrecision: 1) . ' days')
  64. ->description('From invoice date to payment received'),
  65. Stat::make('Average Invoice Total', CurrencyConverter::formatCentsToMoney($averageInvoiceTotal))
  66. ->description('Excludes void and draft invoices'),
  67. ];
  68. }
  69. }