schema([ Section::make('') ->schema([ Forms\Components\Select::make('plant_id') ->label('Plant') ->reactive() ->relationship('plant', 'name') ->options(function (callable $get) { $userHas = Filament::auth()->user()->plant_id; return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray(); }) ->disabled(fn (Get $get) => $get('invoice_number')) ->required() ->afterStateUpdated(function ($state, callable $set, callable $get) { $plantId = $get('plant_id'); if ($plantId) { $set('plant', $plantId); $set('invoice_number', null); $set('pallet_number', null); $set('serial_number', null); $set('sno_quantity', 0); $set('scan_quantity', 0); $set('pend_quantity', 0); } else { $set('plant', null); $set('invoice_number', null); $set('pallet_number', null); $set('serial_number', null); $set('sno_quantity', 0); $set('scan_quantity', 0); $set('pend_quantity', 0); } }), Forms\Components\Hidden::make('plant') ->reactive(), Forms\Components\TextInput::make('invoice_number') ->label('Scan Invoice No') ->required() ->reactive() ->extraAttributes([ 'x-data' => '{ value: "" }', 'x-model' => 'value', 'x-on:keydown.enter.prevent' => '$wire.processinvoiceSNo()', ]) ->readOnly(fn (callable $get) => !$get('plant') || $get('pallet_number') || $get('serial_number')) ->afterStateUpdated(function ($state, callable $set, callable $get) { $plantId = $get('plant'); $invNo = $get('invoice_number'); $snoCount = 0; $pendingCount = 0; $scannedCount = 0; if (!$plantId) { $set('invoice_number', null); $set('pallet_number', null); } else if ($invNo) { $snoCount = LocatorInvoiceValidation::where('plant_id', $plantId)->where('invoice_number', $invNo)->count(); $pendingCount = LocatorInvoiceValidation::where('invoice_number', $invNo)->where('plant_id', $plantId)->whereNull('scanned_status')->orWhere('scanned_status', '=', '')->count(); $scannedCount = LocatorInvoiceValidation::where('invoice_number', $invNo)->where('plant_id', $plantId)->where('scanned_status', '=', 'Scanned')->count(); } $set('update_invoice', null); $set('pallet_number', null); $set('serial_number', null); $set('sno_quantity', $snoCount); $set('scan_quantity', $scannedCount); $set('pend_quantity', $pendingCount); }), Forms\Components\TextInput::make('pallet_number') ->label('Scan Pallet No') ->reactive() ->minLength(10) // ->readOnly(fn (callable $get) => !$get('plant') || !$get('invoice_number') || $get('serial_number')) ->readOnly(function (callable $get) { $invoiceNumber = $get('invoice_number'); $plantId = $get('plant'); $invoiceExist = false; if (!empty($invoiceNumber) && !empty($plantId)) { $records = LocatorInvoiceValidation::where('plant_id', $plantId) ->where('invoice_number', $invoiceNumber) ->get(); $allScanned = true; foreach ($records as $record) { if (($record->scanned_status == null) || trim($record->scanned_status) == '') { $allScanned = false; break; } } if (count($records) > 0 && !$allScanned) { $invoiceExist = true; } } return $invoiceExist == false || !$get('plant') || !$get('invoice_number') || $get('serial_number'); }) ->extraAttributes([ 'wire:keydown.enter.prevent' => 'processPalletNo()', ]) ->afterStateUpdated(function ($state, callable $set, callable $get) { $plantId = $get('plant'); if (!$plantId) { $set('invoice_number', null); $set('pallet_number', null); } $set('update_locator_invoice', null); }), Forms\Components\TextInput::make('serial_number') ->label('Scan Serial No') ->reactive() ->minLength(9) // ->readOnly(fn (callable $get) => !$get('plant') || !$get('invoice_number') || $get('pallet_number')) ->readOnly(function (callable $get) { $invoiceNumber = $get('invoice_number'); $plantId = $get('plant'); $invoiceExist = false; if (!empty($invoiceNumber) && !empty($plantId)) { $records = LocatorInvoiceValidation::where('plant_id', $plantId) ->where('invoice_number', $invoiceNumber) ->get(); $allScanned = true; foreach ($records as $record) { if (($record->scanned_status == null) || trim($record->scanned_status) == '') { $allScanned = false; break; } } if (count($records) > 0 && !$allScanned) { $invoiceExist = true; } } return $invoiceExist == false || !$get('plant') || !$get('invoice_number') || $get('pallet_number'); }) ->extraAttributes([ 'x-data' => '{ value: "" }', 'x-model' => 'value', 'x-on:keydown.enter.prevent' => '$wire.processSerialNo()', ]), Forms\Components\TextInput::make('sno_quantity') ->label('Invoice Quantity') ->default(0) ->readOnly(), Forms\Components\TextInput::make('scan_quantity') ->label('Scanned Quantity') ->default(0) ->readOnly(), Forms\Components\TextInput::make('pend_quantity') ->label('Pending Quantity') ->default(0) ->readOnly(), //Forms\Components\View::make('forms.components.update-invoice-button'), ToggleButtons::make('update_invoice') ->label('Update Invoice?') ->boolean() ->grouped() ->reactive() ->hidden(function (callable $get) { $invoiceNumber = $get('invoice_number'); $plantId = $get('plant'); $invoiceExist = false; if (!empty($invoiceNumber) && !empty($plantId)) { $records = LocatorInvoiceValidation::where('plant_id', $plantId) ->where('invoice_number', $invoiceNumber) ->get(); $allScanned = true; foreach ($records as $record) { if (($record->scanned_status == null) || trim($record->scanned_status) == '') { $allScanned = false; break; } } if (count($records) > 0 && !$allScanned) { $invoiceExist = true; } } return $get('update_invoice') == '0' || $invoiceExist == false || !empty($get('pallet_number')) || !empty($get('serial_number')); //$get('invoice_number') == null }), Forms\Components\TextInput::make('id') ->hidden() ->readOnly(), ToggleButtons::make('update_locator_invoice') ->label('Update Partial Pallet?') ->boolean() ->grouped() ->reactive() ->hidden(function (callable $get) { $palletNumber = $get('pallet_number'); $plantId = $get('plant'); $isPalletValid = false; if (!empty($palletNumber) && !empty($plantId)) { $pallet = PalletValidation::where('plant_id', $plantId) ->where('pallet_number', $palletNumber) ->first(); $isPalletValid = $pallet !== null; } return !$isPalletValid || $get('update_locator_invoice') == '0' || !empty($get('serial_number')); }) ->afterStateUpdated(function ($state, callable $set, callable $get, $livewire) { $plantId = $get('plant'); $palletNumber = $get('pallet_number'); $serialNumber = $get('serial_number'); $invoiceNumber = $get('invoice_number'); $operatorName = Filament::auth()->user()->name; if ($state !== '1') { $set('update_locator_invoice', '0'); $set('pallet_number', null); return; } $palletRecord = PalletValidation::where('plant_id', $plantId) ->where('pallet_number', $palletNumber) ->first(); if (!$palletRecord) { Notification::make() ->title("Pallet number '{$palletNumber}' does not exist.") ->danger() ->duration(5000) ->send(); return; } $palletRecords = PalletValidation::where('plant_id', $plantId) ->where('pallet_number', $palletNumber) ->get(); $allCompleted = true; foreach ($palletRecords as $record) { if ($record->pallet_status != 'Completed') { $allCompleted = false; break; } } if (!$allCompleted) { Notification::make() ->title("Pallet number '{$palletNumber}' is not completed in masters") ->danger() ->duration(5000) ->send(); return; } // if ($allCompleted) // { // $serialNumbers = $palletRecords->pluck('serial_number') // ->map(function ($serial) { // return trim($serial); // }) // ->all(); // $InvoiceSerialNumbers = LocatorInvoiceValidation::where('plant_id', $plantId) // ->where('invoice_number', $invoiceNumber) // ->pluck('serial_number') // ->all(); // $missingSerialNumbers = array_diff($InvoiceSerialNumbers, $serialNumbers); // $allmatchedSerialNumbers = array_unique(array_merge($InvoiceSerialNumbers, $serialNumbers)); // if (!empty($missingSerialNumbers)) // { // $matchedSerialNumbers = array_diff($serialNumbers, $missingSerialNumbers); // foreach ($matchedSerialNumbers as $serial) // { // $invoiceRecord = LocatorInvoiceValidation::where('plant_id', $plantId) // ->where('invoice_number', $invoiceNumber) // ->where('serial_number', $serial) // ->first(); // if ($invoiceRecord) // { // $invoiceRecord->scanned_status = 'Scanned'; // $invoiceRecord->pallet_number = $palletNumber; // $invoiceRecord->scanned_at = now(); // $invoiceRecord->scanned_by = $operatorName; // $invoiceRecord->save(); // Notification::make() // ->title("Pallet number '{$palletNumber}' scanned successfully") // ->success() // ->duration(800) // ->send(); // } // PalletValidation::where('plant_id', $plantId) // ->where('pallet_number', $palletNumber) // ->where('serial_number', $serial) // ->forceDelete(); // $livewire('loadData', $invoiceNumber, $plantId); // } // } // else // { // foreach ($allmatchedSerialNumbers as $serial) // { // $invoiceRecord = LocatorInvoiceValidation::where('plant_id', $plantId) // ->where('invoice_number', $invoiceNumber) // ->where('serial_number', $serial) // ->first(); // if ($invoiceRecord) // { // $invoiceRecord->scanned_status = 'Scanned'; // $invoiceRecord->pallet_number = $palletNumber; // $invoiceRecord->scanned_at = now(); // $invoiceRecord->scanned_by = $operatorName; // $invoiceRecord->save(); // Notification::make() // ->title("Pallet number '{$palletNumber}' scanned successfully") // ->success() // ->duration(800) // ->send(); // } // PalletValidation::where('plant_id', $plantId) // ->where('pallet_number', $palletNumber) // ->where('serial_number', $serial) // ->forceDelete(); // $this->dispatch('loadData', $invoiceNumber, $plantId); // } // } // } }) ]) ->columns(5), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('No.') ->label('No.') ->alignCenter() ->getStateUsing(function ($record, $livewire, $column, $rowLoop) { $paginator = $livewire->getTableRecords(); $perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10; $currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1; return ($currentPage - 1) * $perPage + $rowLoop->iteration; }), Tables\Columns\TextColumn::make('plant.name') ->label('Plant') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('invoice_number') ->label('Invoice Number') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('serial_number') ->label('Serial Number') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('pallet_number') ->label('Pallet Number') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('locator_number') ->label('Locator Number') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('scanned_status') ->label('Scanned Status') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('upload_status') ->label('Upload Status') ->alignCenter(), Tables\Columns\TextColumn::make('created_by') ->label('Created By') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->dateTime() ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('updated_by') ->label('Updated By') ->alignCenter() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->label('Updated At') ->dateTime() ->alignCenter() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('scanned_by') ->label('Scanned By') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('scanned_at') ->label('Scanned At') ->dateTime() ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('deleted_at') ->dateTime() ->alignCenter() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->headerActions([ Tables\Actions\Action::make('import_invoice') ->label('Import Invoice') ->form([ Select::make('plant_id') ->options(Plant::pluck('name', 'id')->toArray()) ->label('Select Plant') ->required() ->default(function () { return optional(InvoiceValidation::latest()->first())->plant_id; }) ->afterStateUpdated(function ($state, callable $set, callable $get) { $set('invoice_serial_number', null); }) ->reactive(), FileUpload::make('invoice_serial_number') ->label('Invoice Serial Number') // ->required() ->preserveFilenames() // <- this keeps the original filename ->storeFiles(false) ->reactive() ->required() ->disk('local') ->visible(fn (Get $get) => !empty($get('plant_id'))) ->directory('uploads/temp'), ]) ->action(function (array $data) { $uploadedFile = $data['invoice_serial_number']; $disk = Storage::disk('local'); $plantId = $data['plant_id']; $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx $invoiceNumber = pathinfo($originalName, PATHINFO_FILENAME); // $invoiceNumber = trim(str_replace('.xlsx', '', $originalName)); // $originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME); $folderPath = Configuration::where('c_name', 'INVOICE_FOLDER_PATH') ->value('c_value'); $fullFolderPath = "uploads/$folderPath"; // Check if the folder exists, if not, create it if (!Storage::disk('local')->exists($fullFolderPath)) { Storage::disk('local')->makeDirectory($fullFolderPath); } $path = $uploadedFile->storeAs($fullFolderPath, $originalName, 'local'); $fullPath = Storage::disk('local')->path($path); if ($fullPath && file_exists($fullPath)) { $rows = Excel::toArray(null, $fullPath)[0]; if((count($rows) - 1) <= 0) { Notification::make() ->title('Invalid Locator Invoice Found') ->body('Uploaded excel sheet is empty or
contains no valid data.') ->danger() ->duration(5000) ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $invalidSerialCodes=[]; $duplicateSerials = []; $seenSerialNumbers = []; $validRowsFound = false; foreach ($rows as $index => $row) { if ($index === 0) continue; // Skip header $serialNumber = trim($row[0]); if (empty($serialNumber)) { continue; } else { if(Str::length($serialNumber) < 9 || Str::length($serialNumber) > 20 || !ctype_alnum($serialNumber)) { $invalidSerialCodes[] = $serialNumber; } else { if (in_array($serialNumber, $seenSerialNumbers)) { $duplicateSerials[] = $serialNumber; } else { $seenSerialNumbers[] = $serialNumber; $validRowsFound = true; } } } } $uniqueSerialCodes = array_unique($invalidSerialCodes); if (!empty($uniqueSerialCodes)) { Notification::make() ->title('Invalid Serial Numbers Found') ->body('The following serial numbers should contain minimum 9 digit (and maximum 20 digit) alpha numeric values:
' . implode(', ', $uniqueSerialCodes)) ->danger() ->duration(5000) ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $duplicateSerialCodes = array_unique($duplicateSerials); if (!empty($duplicateSerialCodes)) { Notification::make() ->title('Duplicate Serial Numbers Found') ->body('The following serial numbers are already exist in imported excel:
' . implode(', ', $duplicateSerialCodes)) ->danger() ->duration(5000) ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } if (!$validRowsFound) { Notification::make() ->title('Invalid Locator Invoice Found') ->body('Uploaded excel sheet is empty or
contains no valid data.') ->danger() ->duration(5000) ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $serialsToCheck = $seenSerialNumbers; $existingSerials = LocatorInvoiceValidation::whereIn('serial_number', $serialsToCheck) ->where('invoice_number', '!=', $invoiceNumber) ->where('plant_id', $plantId) ->pluck('serial_number') ->toArray(); if (!empty($existingSerials)) { Notification::make() ->title('Duplicate Serial Numbers Found') ->body('The following serial numbers already exist with a different invoice number:
' . implode(', ', $existingSerials)) ->danger() ->duration(5000) ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } else { // Save full file path to session session(['uploaded_invoice_path' => $fullPath]); Notification::make() ->title('Success: Invoice imported successfully.') ->success() ->duration(800) ->send(); } } }) ->visible(function() { return Filament::auth()->user()->can('view import dispatch serial invoice validation'); }), ImportAction::make() ->importer(LocatorInvoiceValidationImporter::class) ->label('Import Locator Invoice') ->color('warning') ->visible(function() { return Filament::auth()->user()->can('view import locator invoice validation'); }), ExportAction::make() ->exporter(LocatorInvoiceValidationExporter::class) ->label('Export Locator Invoice') ->color('warning') ->visible(function() { return Filament::auth()->user()->can('view export locator invoice validation'); }), ]) // ->filters([ // Tables\Filters\TrashedFilter::make(), // ]) ->filters([ Tables\Filters\TrashedFilter::make(), Filter::make('advanced_filters') ->label('Advanced Filters') ->form([ Select::make('Plant') ->label('Select Plant') ->nullable() ->options(function () { return Plant::pluck('name', 'id'); }) ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get): void { $set('pallet_number', null); $set('invoice_number', null); $set('serial_number', null); $set('scanned_status', null); $set('locator_number', null); $set('created_from', null); $set('created_to', null); $set('created_by', null); $set('scanned_from', null); $set('scanned_to', null); $set('scanned_by', null); }), Select::make('invoice_number') ->label('Invoice Number') ->options(function (callable $get) { $plantId = $get('Plant'); if (!$plantId) { return []; } return LocatorInvoiceValidation::where('plant_id', $plantId) ->whereNotNull('invoice_number') ->where('invoice_number','!=', '') ->orderBy('invoice_number', 'asc') ->get() ->unique('invoice_number') ->pluck('invoice_number', 'invoice_number') ->toArray(); }) ->searchable() ->reactive(), TextInput::make('serial_number') ->label('Serial Number') ->placeholder(placeholder: 'Enter Serial Number'), Select::make('pallet_number') ->label('Pallet Number') ->options(function (callable $get) { $plantId = $get('Plant'); if (!$plantId) { return []; } return LocatorInvoiceValidation::where('plant_id', $plantId) ->whereNotNull('pallet_number') ->where('pallet_number','!=', '') ->orderBy('pallet_number', 'asc') ->get() ->unique('pallet_number') ->pluck('pallet_number', 'pallet_number') ->toArray(); }) ->searchable() ->reactive(), Select::make('locator_number') ->label('Locator Number') ->options(function (callable $get) { $plantId = $get('Plant'); if (!$plantId) { return []; } return LocatorInvoiceValidation::where('plant_id', $plantId) ->whereNotNull('locator_number') ->where('locator_number','!=', '') ->orderBy('locator_number', 'asc') ->get() ->unique('locator_number') ->pluck('locator_number', 'locator_number') ->toArray(); }) ->searchable() ->reactive(), Select::make('scanned_status') ->label('Scanned Status') ->options([ 'Scanned' => 'Scanned', ]), DateTimePicker::make(name: 'created_from') ->label('Created From') ->placeholder(placeholder: 'Select From DateTime') ->reactive() ->native(false), DateTimePicker::make('created_to') ->label('Created To') ->placeholder(placeholder: 'Select To DateTime') ->reactive() ->native(false), TextInput::make('created_by') ->label('Created By') ->placeholder(placeholder: 'Enter Created By'), DateTimePicker::make(name: 'scanned_from') ->label('Scanned From') ->placeholder(placeholder: 'Select From DateTime') ->reactive() ->native(false), DateTimePicker::make('scanned_to') ->label('Scanned To') ->placeholder(placeholder: 'Select To DateTime') ->reactive() ->native(false), TextInput::make('scanned_by') ->label('Scanned By') ->placeholder(placeholder: 'Enter Scanned By'), ]) ->query(function ($query, array $data) { // Hide all records initially if no filters are applied if (empty($data['Plant']) && empty($data['invoice_number']) && empty($data['serial_number']) && empty($data['pallet_number']) && empty($data['locator_number']) && empty($data['scanned_status']) && empty($data['created_from']) && empty($data['created_to']) && empty($data['created_by']) && empty($data['scanned_from']) && empty($data['scanned_to']) && empty($data['scanned_by'])) { return $query->whereRaw('1 = 0'); } if (!empty($data['Plant'])) { //$plant = $data['Plant'] ?? null $query->where('plant_id', $data['Plant']); } if (!empty($data['invoice_number'])) { $query->where('invoice_number', $data['invoice_number']); } if (!empty($data['serial_number'])) { $query->where('serial_number', $data['serial_number']); } if (!empty($data['pallet_number'])) { $query->where('pallet_number', $data['pallet_number']); } if (!empty($data['locator_number'])) { $query->where('locator_number', $data['locator_number']); } if (!empty($data['scanned_status'])) { $query->where('scanned_status', $data['scanned_status']); } if (!empty($data['created_from'])) { $query->where('created_at', '>=', $data['created_from']); } if (!empty($data['created_to'])) { $query->where('created_at', '<=', $data['created_to']); } if (!empty($data['created_by'])) { $query->where('created_by', $data['created_by']); } if (!empty($data['scanned_from'])) { $query->where('scanned_at', '>=', $data['scanned_from']); } if (!empty($data['scanned_to'])) { $query->where('scanned_at', '<=', $data['scanned_to']); } if (!empty($data['scanned_by'])) { $query->where('scanned_by', $data['scanned_by']); } }) ->indicateUsing(function (array $data) { $indicators = []; if (!empty($data['Plant'])) { $indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name'); } if (!empty($data['invoice_number'])) { $indicators[] = 'Invoice Number: ' . $data['invoice_number']; } if (!empty($data['serial_number'])) { $indicators[] = 'Serial Number: ' . $data['serial_number']; } if (!empty($data['pallet_number'])) { $indicators[] = 'Pallet Number: ' . $data['pallet_number']; } if (!empty($data['locator_number'])) { $indicators[] = 'Locator Number: ' . $data['locator_number']; } if (!empty($data['scanned_status'])) { $indicators[] = 'Scanned Status: ' . $data['scanned_status']; } if (!empty($data['created_from'])) { $indicators[] = 'From: ' . $data['created_from']; } if (!empty($data['created_to'])) { $indicators[] = 'To: ' . $data['created_to']; } if (!empty($data['created_by'])) { $indicators[] = 'Created By: ' . $data['created_by']; } if (!empty($data['scanned_from'])) { $indicators[] = 'Scanned From: ' . $data['scanned_from']; } if (!empty($data['scanned_to'])) { $indicators[] = 'Scanned To: ' . $data['scanned_to']; } if (!empty($data['scanned_by'])) { $indicators[] = 'Scanned By: ' . $data['scanned_by']; } return $indicators; }) ]) ->filtersFormMaxHeight('280px') ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), Tables\Actions\ForceDeleteBulkAction::make(), Tables\Actions\RestoreBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ // ]; } public static function getNavigationLabel(): string { return 'Scan Invoice'; } public static function getPages(): array { return [ 'index' => Pages\ListLocatorInvoiceValidations::route('/'), 'create' => Pages\CreateLocatorInvoiceValidation::route('/create'), 'view' => Pages\ViewLocatorInvoiceValidation::route('/{record}'), 'edit' => Pages\EditLocatorInvoiceValidation::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery() ->withoutGlobalScopes([ SoftDeletingScope::class, ]); } }