From ced01440f54a320003e7c6902c06082389f21a81 Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Sun, 29 Jun 2025 16:17:44 +0530 Subject: [PATCH] Added chart for invoice quantity --- .../Pages/InvoiceQuantityDashboard.php | 70 ++++ app/Filament/Widgets/InvoiceQuantity.php | 324 ++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 app/Filament/Pages/InvoiceQuantityDashboard.php create mode 100644 app/Filament/Widgets/InvoiceQuantity.php diff --git a/app/Filament/Pages/InvoiceQuantityDashboard.php b/app/Filament/Pages/InvoiceQuantityDashboard.php new file mode 100644 index 0000000..1b55a27 --- /dev/null +++ b/app/Filament/Pages/InvoiceQuantityDashboard.php @@ -0,0 +1,70 @@ +forget(['selec_plant', 'select_invoice']); + $this->filtersForm->fill([ + 'plant' => null, + 'invoice' => null, + ]); + } + + + public function filtersForm(Form $form): Form + { + return $form + ->statePath('filters') // Explicitly set where to store form data + ->schema([ + Select::make('plant') + ->options(Plant::pluck('name', 'id')) + ->label('Select Plant') + ->reactive() + ->afterStateUpdated(function ($state) { + session(['selec_plant' => $state]); + $this->dispatch('invoiceChart'); + }), + Select::make('invoice') + ->options([ + 'serial_invoice' => 'Serial Invoice', + 'individual_material' => 'Individual Material Invoice', + 'bundle_material' => 'Bundle Material Invoice', + ]) + ->label('Select Invoice') + ->reactive() + ->default(0) + ->afterStateUpdated(function ($state) { + session(['select_invoice' => $state]); + $this->dispatch('invoiceChart'); + }) + ]) + ->columns(2); + } + public static function getNavigationLabel(): string + { + return 'Invoice Quantity'; + } + + public static function canAccess(): bool + { + return Auth::check() && Auth::user()->can('view invoice serial quantity dashboard'); + } +} diff --git a/app/Filament/Widgets/InvoiceQuantity.php b/app/Filament/Widgets/InvoiceQuantity.php new file mode 100644 index 0000000..bb6b6c9 --- /dev/null +++ b/app/Filament/Widgets/InvoiceQuantity.php @@ -0,0 +1,324 @@ +filter; // Assuming filter is passed and activeFilter can be 'yesterday', 'this_week', 'this_month' + + if (!$selectedPlant || !$selectedInvoice) { + return [ + 'datasets' => [], + 'labels' => [], + ]; + } + + // Define the date range based on the active filter + if ($activeFilter == 'yesterday') { + $startDate = now()->subDay()->setTime(8, 0, 0); + $endDate = now()->setTime(8, 0, 0); + } elseif ($activeFilter == 'this_week') { + $startDate = now()->startOfWeek()->setTime(8, 0, 0); + $endDate = now()->endOfWeek()->addDay()->setTime(8, 0, 0); + } elseif ($activeFilter == 'this_month') { + $startDate = now()->startOfMonth()->setTime(8, 0, 0); + $endDate = now()->endOfMonth()->setTime(8, 0, 0); + } else { + $startDate = now()->setTime(8, 0, 0); + $endDate = now()->copy()->addDay()->setTime(8, 0, 0); + } + + if ($selectedInvoice == 'individual_material') + { + + $totalInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('quantity', 1) + ->whereBetween('created_at', [$startDate, $endDate]) + ->count(); + + $scannedInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('quantity', 1) + ->whereNotNull('serial_number') + ->where('serial_number','!=', '') + ->whereBetween('updated_at', [$startDate, $endDate]) + ->count(); + + } + elseif ($selectedInvoice == 'serial_invoice') + { + $totalInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('quantity', null) + ->whereBetween('created_at', [$startDate, $endDate]) + ->count(); + + $scannedInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('scanned_status', 'Scanned') + ->where(function($query) { + $query->whereNull('quantity') + ->orWhere('quantity', 0); + }) + ->whereBetween('updated_at', [$startDate, $endDate]) + ->count(); + + } + elseif ($selectedInvoice == 'bundle_material') + { + $totalInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('quantity', '>', 1) + ->whereBetween('created_at', [$startDate, $endDate]) + ->count(); + + $scannedInvoicesCount = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('quantity', '>', 1) + ->whereNotNull('serial_number') + ->where('serial_number','!=', '') + ->whereBetween('updated_at', [$startDate, $endDate]) + ->count(); + } + + // Prepare the chart data + $labels = []; // Labels for each bar + $datasets = []; // Datasets for the chart + + if (in_array($activeFilter, ['yesterday'])) { + $labels = ['Total Invoices', 'Scanned Invoices']; + $datasets = [[ + 'label' => 'Invoices', + 'data' => [$totalInvoicesCount, $scannedInvoicesCount], + 'backgroundColor' => ['rgba(75, 192, 192, 1)', 'rgba(23, 211, 80, 1)'], + 'fill' => false, + ]]; + } + + elseif ($activeFilter == 'this_week') + { + $daysOfWeek = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + $TotalInvoicesPerDay = array_fill(0, 7, 0); + $scannedInvoicesPerDay = array_fill(0, 7, 0); + + for ($index = 0; $index < 7; $index++) { + $dayStart = now()->startOfWeek()->addDays($index)->setTime(8, 0, 0); + $dayEnd = $dayStart->copy()->addDay()->setTime(8, 0, 0); + + $query = InvoiceValidation::where('plant_id', $selectedPlant); + + // Build completedQuery with only 'invoice_number' in select + $completedQuery = InvoiceValidation::select('invoice_number') + ->where('plant_id', $selectedPlant); + + if ($selectedInvoice == 'individual_material') + { + $query->where('quantity', 1)->whereBetween('created_at', [$dayStart, $dayEnd]); + + $completedQuery->where('quantity', 1) + ->whereBetween('updated_at', [$dayStart, $dayEnd]) + ->whereNotNull('serial_number') + ->where('serial_number', '!=', ''); + } + elseif ($selectedInvoice == 'serial_invoice') + { + $query->whereNull('quantity')->whereBetween('created_at', [$dayStart, $dayEnd]); + $completedQuery = InvoiceValidation::where('plant_id', $selectedPlant) + ->where('scanned_status', 'Scanned') + ->where(function($query) { + $query->whereNull('quantity') + ->orWhere('quantity', 0); + }) + ->whereBetween('updated_at', [$dayStart, $dayEnd]); + } + elseif ($selectedInvoice == 'bundle_material') + { + $query->where('quantity', '>', 1)->whereBetween('created_at', [$dayStart, $dayEnd]); + + $completedQuery->where('quantity', '>', 1) + ->whereBetween('updated_at', [$dayStart, $dayEnd]) + ->whereNotNull('serial_number') + ->where('serial_number', '!=', ''); + } + + // Imported invoices count (distinct invoice_number) + $TotalInvoicesPerDay[$index] = $query->count(); + + $scannedInvoicesPerDay[$index] = $completedQuery->count(); + + //dd($TotalInvoicesPerDay, $scannedInvoicesPerDay); + } + + $labels = $daysOfWeek; + $datasets = [ + [ + 'label' => 'Total Invoices', + 'data' => $TotalInvoicesPerDay, + 'backgroundColor' => 'rgba(75, 192, 192, 1)', + ], + [ + 'label' => 'Scanned Invoices', + 'data' => $scannedInvoicesPerDay, + 'backgroundColor' => 'rgba(23, 211, 80, 1)', + ], + ]; + } + elseif ($activeFilter == 'this_month') + { + $startOfMonth = now()->startOfMonth()->setTime(8, 0, 0); + $endOfMonth = now()->endOfMonth()->addDay()->setTime(8, 0, 0); // include full last day + $monthName = $startOfMonth->format('M'); + + // Prepare weekly labels like "May(1-7)", "May(8-14)", etc. + $labels = []; + $weekStart = $startOfMonth->copy(); + $TotalInvoicesPerWeek = []; + $scannedInvoicesPerWeek = []; + + $weekIndex = 0; + while ($weekStart < $endOfMonth) { + $weekEnd = $weekStart->copy()->addDays(7); + $startDay = $weekStart->format('j'); + $weekEndLimit = $weekEnd->copy()->subDay(); + $actualEnd = $weekEndLimit->greaterThan($endOfMonth) ? $endOfMonth : $weekEndLimit; + $endDay = $actualEnd->format('j'); + + $labels[] = "{$monthName}({$startDay}-{$endDay})"; + + $queryImported = InvoiceValidation::where('plant_id', $selectedPlant) + ->whereBetween('created_at', [$weekStart, $weekEnd]); + + if ($selectedInvoice == 'individual_material') + { + $queryImported->where('quantity', 1); + } + elseif ($selectedInvoice == 'serial_invoice') + { + $queryImported->whereNull('quantity'); + } + elseif ($selectedInvoice == 'bundle_material') + { + $queryImported->where('quantity', '>', 1); + } + + $TotalInvoicesPerWeek[$weekIndex] = $queryImported->count(); + + // --- Completed --- + $queryCompleted = InvoiceValidation::select('invoice_number') + ->where('plant_id', $selectedPlant) + ->whereBetween('updated_at', [$weekStart, $weekEnd]); + + if ($selectedInvoice == 'individual_material') { + $queryCompleted->where('quantity', 1) + ->whereNotNull('serial_number') + ->where('serial_number', '!=', ''); + } elseif ($selectedInvoice == 'serial_invoice') { + $queryCompleted->whereNull('quantity') + ->where('scanned_status', 'Scanned') + ->where(function($query) { + $query->whereNull('quantity') + ->orWhere('quantity', 0); + }); + } elseif ($selectedInvoice == 'bundle_material') { + $queryCompleted->where('quantity', '>', 1) + ->whereNotNull('serial_number') + ->where('serial_number', '!=', ''); + } + + $scannedInvoicesPerWeek[$weekIndex] = $queryCompleted->count(); + + // Move to next week + $weekStart = $weekEnd; + $weekIndex++; + } + + $datasets = [ + [ + 'label' => 'Total Invoices', + 'data' => $TotalInvoicesPerWeek, + 'backgroundColor' => 'rgba(75, 192, 192, 1)', + ], + [ + 'label' => 'Scanned Invoices', + 'data' => $scannedInvoicesPerWeek, + 'backgroundColor' => 'rgba(23, 211, 80, 1)', + ], + ]; + } + else + { + $labels = ['Total Invoices', 'Scanned Invoices']; + $datasets = [[ + 'label' => 'Invoices', + 'data' => [$totalInvoicesCount, $scannedInvoicesCount], + 'backgroundColor' => ['rgba(75, 192, 192, 1)', 'rgba(23, 211, 80, 1)'], + 'fill' => false, + ]]; + } + + foreach ($datasets as &$dataset) + { + $dataset['data'] = array_map(function ($value) { + return ($value == 0 || is_null($value)) ? null : $value; + }, $dataset['data']); + } + + return [ + 'datasets' => $datasets, + 'labels' => $labels, + ]; + } + + protected function getType(): string + { + return 'bar'; + } + + protected function getOptions(): array + { + return [ + 'plugins' => [ + 'datalabels' => [ + 'anchor' => 'start', + 'align' => 'start', + 'offset' => -15, + 'color' => '#000', + 'font' => [ + 'weight' => 'bold', + ], + 'formatter' => RawJs::make('function(value) { + return value; + }'), + ], + ], + 'scales' => [ + 'y' => [ + 'beginAtZero' => true, + 'ticks' => [ + 'stepSize' => 1, + ], + ], + ], + ]; + } + + protected function getFilters(): ?array + { + return [ + 'today' => 'Today', + 'yesterday' => 'Yesterday', + 'this_week'=> 'This Week', + 'this_month'=> 'This Month', + ]; + } +}