Skip to content

Commit 02e4326

Browse files
committed
Add stats widgets for all resources
1 parent db78646 commit 02e4326

14 files changed

Lines changed: 508 additions & 0 deletions

File tree

src/Resources/InvoiceResource.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use SapB1\Toolkit\Filament\Actions\UploadAttachmentAction;
2525
use SapB1\Toolkit\Filament\Actions\ViewDocumentFlowAction;
2626
use SapB1\Toolkit\Filament\Resources\InvoiceResource\Pages;
27+
use SapB1\Toolkit\Filament\Resources\InvoiceResource\Widgets;
2728
use SapB1\Toolkit\Filament\SapB1FilamentPlugin;
2829
use SapB1\Toolkit\Models\Sales\Invoice;
2930
use SapB1\Toolkit\Services\DocumentActionService;
@@ -434,6 +435,14 @@ public static function getRelations(): array
434435
return [];
435436
}
436437

438+
public static function getWidgets(): array
439+
{
440+
return [
441+
Widgets\InvoiceStatsWidget::class,
442+
Widgets\AgingChartWidget::class,
443+
];
444+
}
445+
437446
public static function getPages(): array
438447
{
439448
return [

src/Resources/InvoiceResource/Pages/ListInvoices.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88
use Filament\Resources\Components\Tab;
99
use Filament\Resources\Pages\ListRecords;
1010
use SapB1\Toolkit\Filament\Resources\InvoiceResource;
11+
use SapB1\Toolkit\Filament\Resources\InvoiceResource\Widgets\AgingChartWidget;
12+
use SapB1\Toolkit\Filament\Resources\InvoiceResource\Widgets\InvoiceStatsWidget;
1113

1214
class ListInvoices extends ListRecords
1315
{
1416
protected static string $resource = InvoiceResource::class;
1517

18+
protected function getHeaderWidgets(): array
19+
{
20+
return [
21+
InvoiceStatsWidget::class,
22+
AgingChartWidget::class,
23+
];
24+
}
25+
1626
protected function getHeaderActions(): array
1727
{
1828
return [
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SapB1\Toolkit\Filament\Resources\InvoiceResource\Widgets;
6+
7+
use Exception;
8+
use Filament\Widgets\ChartWidget;
9+
use Illuminate\Support\Facades\Cache;
10+
use SapB1\Toolkit\Services\ReportingService;
11+
12+
class AgingChartWidget extends ChartWidget
13+
{
14+
protected ?string $heading = null;
15+
16+
protected int|string|array $columnSpan = 1;
17+
18+
public function getHeading(): ?string
19+
{
20+
return __('sapb1-filament::resources.invoice.widgets.aging_chart');
21+
}
22+
23+
protected function getData(): array
24+
{
25+
$data = Cache::remember('sapb1_invoice_aging', 300, function (): array {
26+
try {
27+
/** @var ReportingService $service */
28+
$service = app(ReportingService::class);
29+
$aging = $service->getAgingReport();
30+
31+
return $aging['summary'] ?? [
32+
'current' => 0,
33+
'1-30' => 0,
34+
'31-60' => 0,
35+
'61-90' => 0,
36+
'over90' => 0,
37+
];
38+
} catch (Exception) {
39+
return [
40+
'current' => 0,
41+
'1-30' => 0,
42+
'31-60' => 0,
43+
'61-90' => 0,
44+
'over90' => 0,
45+
];
46+
}
47+
});
48+
49+
return [
50+
'datasets' => [
51+
[
52+
'label' => __('sapb1-filament::resources.invoice.widgets.outstanding'),
53+
'data' => [
54+
$data['current'] ?? 0,
55+
$data['1-30'] ?? 0,
56+
$data['31-60'] ?? 0,
57+
$data['61-90'] ?? 0,
58+
$data['over90'] ?? 0,
59+
],
60+
'backgroundColor' => ['#10b981', '#f59e0b', '#f97316', '#ef4444', '#7f1d1d'],
61+
],
62+
],
63+
'labels' => [
64+
__('sapb1-filament::resources.invoice.widgets.aging_current'),
65+
'1-30',
66+
'31-60',
67+
'61-90',
68+
'90+',
69+
],
70+
];
71+
}
72+
73+
protected function getType(): string
74+
{
75+
return 'bar';
76+
}
77+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SapB1\Toolkit\Filament\Resources\InvoiceResource\Widgets;
6+
7+
use Exception;
8+
use Filament\Widgets\StatsOverviewWidget;
9+
use Filament\Widgets\StatsOverviewWidget\Stat;
10+
use Illuminate\Support\Facades\Cache;
11+
use SapB1\Toolkit\Models\Sales\Invoice;
12+
13+
class InvoiceStatsWidget extends StatsOverviewWidget
14+
{
15+
protected ?string $pollingInterval = null;
16+
17+
protected int|string|array $columnSpan = 'full';
18+
19+
protected function getStats(): array
20+
{
21+
$stats = Cache::remember('sapb1_invoice_stats', 300, function (): array {
22+
try {
23+
$firstOfMonth = now()->startOfMonth()->format('Y-m-d');
24+
$today = now()->format('Y-m-d');
25+
26+
$totalThisMonth = Invoice::query()
27+
->where('DocDate', '>=', $firstOfMonth)
28+
->count();
29+
30+
$invoicesThisMonth = Invoice::query()
31+
->where('DocDate', '>=', $firstOfMonth)
32+
->select(['DocTotal'])
33+
->get();
34+
35+
$totalRevenue = (float) $invoicesThisMonth->sum('DocTotal');
36+
37+
$openInvoices = Invoice::query()
38+
->where('DocumentStatus', 'bost_Open')
39+
->select(['DocTotal', 'PaidToDate'])
40+
->get();
41+
42+
$outstanding = 0.0;
43+
44+
foreach ($openInvoices as $inv) {
45+
$outstanding += (float) ($inv->DocTotal ?? 0) - (float) ($inv->PaidToDate ?? 0);
46+
}
47+
48+
$overdueCount = Invoice::query()
49+
->where('DocDueDate', '<', $today)
50+
->where('DocumentStatus', 'bost_Open')
51+
->count();
52+
53+
return [
54+
'total' => $totalThisMonth,
55+
'revenue' => $totalRevenue,
56+
'outstanding' => $outstanding,
57+
'overdue' => $overdueCount,
58+
];
59+
} catch (Exception) {
60+
return ['total' => 0, 'revenue' => 0, 'outstanding' => 0, 'overdue' => 0];
61+
}
62+
});
63+
64+
return [
65+
Stat::make(
66+
__('sapb1-filament::resources.invoice.widgets.total_this_month'),
67+
(string) $stats['total'],
68+
)->icon('heroicon-o-document-text'),
69+
70+
Stat::make(
71+
__('sapb1-filament::resources.invoice.widgets.total_revenue'),
72+
number_format((float) $stats['revenue'], 2).' TRY',
73+
)->icon('heroicon-o-banknotes'),
74+
75+
Stat::make(
76+
__('sapb1-filament::resources.invoice.widgets.outstanding'),
77+
number_format((float) $stats['outstanding'], 2).' TRY',
78+
)
79+
->icon('heroicon-o-exclamation-triangle')
80+
->color($stats['outstanding'] > 0 ? 'danger' : 'success'),
81+
82+
Stat::make(
83+
__('sapb1-filament::resources.invoice.widgets.overdue'),
84+
(string) $stats['overdue'],
85+
)
86+
->icon('heroicon-o-clock')
87+
->color($stats['overdue'] > 0 ? 'danger' : 'success'),
88+
];
89+
}
90+
}

src/Resources/ItemResource.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use SapB1\Toolkit\Filament\Actions\CheckStockAction;
2121
use SapB1\Toolkit\Filament\Actions\UploadAttachmentAction;
2222
use SapB1\Toolkit\Filament\Resources\ItemResource\Pages;
23+
use SapB1\Toolkit\Filament\Resources\ItemResource\Widgets;
2324
use SapB1\Toolkit\Filament\SapB1FilamentPlugin;
2425
use SapB1\Toolkit\Models\Inventory\Item;
2526
use SapB1\Toolkit\Services\BatchService;
@@ -405,6 +406,13 @@ public static function getRelations(): array
405406
return [];
406407
}
407408

409+
public static function getWidgets(): array
410+
{
411+
return [
412+
Widgets\ItemStatsWidget::class,
413+
];
414+
}
415+
408416
public static function getPages(): array
409417
{
410418
return [

src/Resources/ItemResource/Pages/ListItems.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@
88
use Filament\Resources\Components\Tab;
99
use Filament\Resources\Pages\ListRecords;
1010
use SapB1\Toolkit\Filament\Resources\ItemResource;
11+
use SapB1\Toolkit\Filament\Resources\ItemResource\Widgets\ItemStatsWidget;
1112

1213
class ListItems extends ListRecords
1314
{
1415
protected static string $resource = ItemResource::class;
1516

17+
protected function getHeaderWidgets(): array
18+
{
19+
return [
20+
ItemStatsWidget::class,
21+
];
22+
}
23+
1624
protected function getHeaderActions(): array
1725
{
1826
return [
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SapB1\Toolkit\Filament\Resources\ItemResource\Widgets;
6+
7+
use Exception;
8+
use Filament\Widgets\StatsOverviewWidget;
9+
use Filament\Widgets\StatsOverviewWidget\Stat;
10+
use Illuminate\Support\Facades\Cache;
11+
use SapB1\Toolkit\Models\Inventory\Item;
12+
13+
class ItemStatsWidget extends StatsOverviewWidget
14+
{
15+
protected ?string $pollingInterval = null;
16+
17+
protected int|string|array $columnSpan = 'full';
18+
19+
protected function getStats(): array
20+
{
21+
$stats = Cache::remember('sapb1_item_stats', 300, function (): array {
22+
try {
23+
$total = Item::query()->count();
24+
$active = Item::query()->where('Valid', 'tYES')->count();
25+
$zeroStock = Item::query()->where('QuantityOnStock', '<=', 0)->count();
26+
27+
return [
28+
'total' => $total,
29+
'active' => $active,
30+
'zero_stock' => $zeroStock,
31+
];
32+
} catch (Exception) {
33+
return ['total' => 0, 'active' => 0, 'zero_stock' => 0];
34+
}
35+
});
36+
37+
return [
38+
Stat::make(
39+
__('sapb1-filament::resources.item.widgets.total_items'),
40+
(string) $stats['total'],
41+
)->icon('heroicon-o-cube'),
42+
43+
Stat::make(
44+
__('sapb1-filament::resources.item.widgets.active_items'),
45+
(string) $stats['active'],
46+
)
47+
->icon('heroicon-o-check-circle')
48+
->color('success'),
49+
50+
Stat::make(
51+
__('sapb1-filament::resources.item.widgets.zero_stock'),
52+
(string) $stats['zero_stock'],
53+
)
54+
->icon('heroicon-o-exclamation-triangle')
55+
->color($stats['zero_stock'] > 0 ? 'danger' : 'success'),
56+
];
57+
}
58+
}

src/Resources/OrderResource.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use SapB1\Toolkit\Filament\Actions\UploadAttachmentAction;
2525
use SapB1\Toolkit\Filament\Actions\ViewDocumentFlowAction;
2626
use SapB1\Toolkit\Filament\Resources\OrderResource\Pages;
27+
use SapB1\Toolkit\Filament\Resources\OrderResource\Widgets;
2728
use SapB1\Toolkit\Filament\SapB1FilamentPlugin;
2829
use SapB1\Toolkit\Models\Sales\Order;
2930
use SapB1\Toolkit\Services\DocumentActionService;
@@ -437,6 +438,14 @@ public static function getRelations(): array
437438
return [];
438439
}
439440

441+
public static function getWidgets(): array
442+
{
443+
return [
444+
Widgets\OrderStatsWidget::class,
445+
Widgets\OrdersByStatusWidget::class,
446+
];
447+
}
448+
440449
public static function getPages(): array
441450
{
442451
return [

src/Resources/OrderResource/Pages/ListOrders.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88
use Filament\Resources\Components\Tab;
99
use Filament\Resources\Pages\ListRecords;
1010
use SapB1\Toolkit\Filament\Resources\OrderResource;
11+
use SapB1\Toolkit\Filament\Resources\OrderResource\Widgets\OrdersByStatusWidget;
12+
use SapB1\Toolkit\Filament\Resources\OrderResource\Widgets\OrderStatsWidget;
1113

1214
class ListOrders extends ListRecords
1315
{
1416
protected static string $resource = OrderResource::class;
1517

18+
protected function getHeaderWidgets(): array
19+
{
20+
return [
21+
OrderStatsWidget::class,
22+
OrdersByStatusWidget::class,
23+
];
24+
}
25+
1626
protected function getHeaderActions(): array
1727
{
1828
return [

0 commit comments

Comments
 (0)