schema([ Section::make('') ->schema([ Forms\Components\Select::make('plant_id') ->label('Plant') ->relationship('plant', 'name') ->required(), Forms\Components\TextInput::make('qr_code') ->label('QR Code'), Forms\Components\DateTimePicker::make('scanned_at') ->label('Scanned At'), Forms\Components\TextInput::make('scanned_by') ->label('Scanned By'), Forms\Components\Hidden::make('created_by') ->label('Created By') ->default(Filament::auth()->user()?->name), Forms\Components\Hidden::make('updated_by') ->default(Filament::auth()->user()?->name), ]) ->columns(4), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('No.') ->label('No.') ->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.code') ->label('Plant') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('qr_code') ->label('QR Code') ->alignCenter() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('scanned_at') ->label('Scanned At') ->alignCenter() ->dateTime() ->sortable(), Tables\Columns\TextColumn::make('scanned_by') ->label('Scanned By') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable(), //->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_by') ->label('Created By') ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('updated_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('deleted_at') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\TrashedFilter::make(), ]) ->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(), ]), ]) ->headerActions([ Tables\Actions\Action::make('Import Invoice Out Data') ->label('Import Invoice Out Data') ->form([ FileUpload::make('invoice_data_file') ->label('Invoice Out Data') // ->required() ->preserveFilenames() ->storeFiles(false) ->reactive() ->required() ->disk('local') //->visible(fn (Get $get) => !empty($get('plant_id'))) ->directory('uploads/temp'), ]) ->action(function (array $data) { $uploadedFile = $data['invoice_data_file']; $disk = Storage::disk('local'); $user = Filament::auth()->user(); $operatorName = $user->name; // Get original filename $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx $originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME); // Store manually using storeAs to keep original name $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path $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('Records Not Found') ->body("Import the valid 'Invoice Data' file to proceed..!") ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $invalidPlantCode = []; $invalidPlaCoFound = []; $invalidqrCode = []; $invalidScannedAt = []; $invalidScannedBy = []; $invalidUser = []; $userNotFound = []; foreach ($rows as $index => $row) { if ($index == 0) continue; // Skip header $plantCode = trim($row[0]); $qrCode = trim($row[1]); $scannedAt = trim($row[2]); $scannedby = trim($row[3]); //$createdBy = trim($row[4]); if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}"; if (empty($qrCode)) $invalidqrCode[] = "Row {$index}"; if (empty($scannedAt)) $invalidScannedAt[] = "Row {$index}"; if (empty($scannedby)) $invalidScannedBy[] = "Row {$index}"; //if (empty($createdBy)) $invalidUser[] = "Row {$index}"; if (strlen($plantCode) < 4) { $invalidPlantCode[] = $plantCode; } else if(!Plant::where('code', $plantCode)->first()) { $invalidPlaCoFound[] = $plantCode; } // else if(!User::where('name', $createdBy)->first()) // { // $userNotFound[] = $createdBy; // } } if (!empty($invalidqrCode) || !empty($invalidScannedAt) || !empty($invalidScannedBy) || !empty($invalidUser)) { $errorMsg = ''; if (!empty($invalidqrCode)) $errorMsg .= 'Missing Qr code in rows: '.implode(', ', $invalidqrCode) . '
'; if (!empty($invalidScannedAt)) $errorMsg .= 'Missing Scanned At in rows: '.implode(', ', $invalidScannedAt) . '
'; if (!empty($invalidScannedBy)) $errorMsg .= 'Missing Scanned By in rows: '.implode(', ', $invalidScannedBy) . '
'; //if (!empty($invalidUser)) $errorMsg .= 'Missing User in rows: '.implode(', ', $invalidUser) . '
'; Notification::make() ->title('Missing Mandatory Fields') ->body($errorMsg) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } if (!empty($invalidPlantCode)) { $invalidPlantCode = array_unique($invalidPlantCode); Notification::make() ->title('Invalid Plant Codes') ->body('The following plant codes should contain minimum 4 digits:
' . implode(', ', $invalidPlantCode)) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } if (!empty($invalidPlaCoFound)) { $invalidPlaCoFound = array_unique($invalidPlaCoFound); Notification::make() ->title('Invalid Plant Codes') ->body('The following plant codes not found in plants:
' . implode(', ', $invalidPlaCoFound)) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } if (!empty($userNotFound)) { $userNotFound = array_unique($userNotFound); Notification::make() ->title('Invalid User') ->body('The following user not found:
' . implode(', ', $userNotFound)) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $successCount = 0; $failCount = 0; $lastErrorMessage = null; foreach ($rows as $index => $row) { if ($index == 0) continue; $plantCode = trim($row[0]); $qrcode = trim($row[1]); $scannedAt = trim($row[2]); $scannedBy = trim($row[3]); try { $plant = Plant::where('code', $plantCode)->first(); $formattedDate = null; if (!empty($scannedAt)) { try { $formattedDate = Carbon::createFromFormat('d-m-Y H:i:s', $scannedAt) ->format('Y-m-d H:i:s'); } catch (\Exception $e) { throw new \Exception("Invalid date format: {$scannedAt}"); } } $inserted = InvoiceOutValidation::create([ 'plant_id' => $plant->id, 'qr_code' => $qrcode, 'scanned_at' => $formattedDate, 'scanned_by' => $scannedBy, 'created_by' => $operatorName, ]); if ($inserted) { $successCount++; } else { $failCount++; } } catch (\Exception $e) { //$failCount++; $lastErrorMessage = $e->getMessage(); } } if($successCount > 0) { Notification::make() ->title('Import Success') ->body("Successfully inserted: {$successCount} records") ->success() ->send(); } else { $errorText = $lastErrorMessage ? "Failed to insert any records. Error: {$lastErrorMessage}" : "Failed to insert any records. Unknown error."; Notification::make() ->title('Import Failed') ->body($errorText) ->danger() ->send(); } } }) ->visible(function() { return Filament::auth()->user()->can('view import invoice out validation'); }), ExportAction::make() ->exporter(InvoiceOutValidationExporter::class) ->visible(function() { return Filament::auth()->user()->can('view export invoice out validation'); }), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListInvoiceOutValidations::route('/'), 'create' => Pages\CreateInvoiceOutValidation::route('/create'), 'view' => Pages\ViewInvoiceOutValidation::route('/{record}'), 'edit' => Pages\EditInvoiceOutValidation::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery() ->withoutGlobalScopes([ SoftDeletingScope::class, ]); } }