schema([ Forms\Components\Select::make('plant_id') ->label('Plant') ->relationship('plant', 'name') ->required(), Forms\Components\TextInput::make('distribution_channel_desc') ->label('Distribution Channel Description') ->required(), Forms\Components\TextInput::make('customer_code') ->label('Customer Code') ->required(), Forms\Components\TextInput::make('document_number') ->label('Document Number') ->required(), Forms\Components\DatePicker::make('document_date') ->label('Document Date') ->required(), Forms\Components\TextInput::make('customer_trade_name') ->label('Customer Trade Name') ->required(), Forms\Components\TextInput::make('customer_location') ->label('Customer Location') ->required(), 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), ]); } 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() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('distribution_channel_desc') ->label('Distribution Channel Description') ->alignCenter() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('customer_code') ->label('Customer Code') ->alignCenter() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('document_number') ->label('Document Number') ->searchable() ->alignCenter() ->sortable(), Tables\Columns\TextColumn::make('document_date') ->label('Document Date') ->alignCenter() ->searchable() ->date() ->sortable(), Tables\Columns\TextColumn::make('customer_trade_name') ->label('Customer Trade Name') ->alignCenter() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('customer_location') ->label('Customer Location') ->alignCenter() ->searchable() ->sortable(), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->alignCenter() ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('updated_at') ->label('Updated At') ->alignCenter() ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('deleted_at') ->label('Deleted At') ->alignCenter() ->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 Data') ->label('Import Invoice Data') ->form([ FileUpload::make('invoice_data_file') ->label('Invoice Data File') // ->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 = []; $invalidDisChaDesc = []; $invalidCustomerCode = []; $invalidDocNo = []; $invalidDocDate = []; $invalidCusTradeName = []; $invalidCusLocation = []; $invalidUser = []; $userNotFound = []; $invalidPlantType = []; $seenPlantDoc = []; $duplicateEntries = []; $duplicateEntriesExcel = []; foreach ($rows as $index => $row) { if ($index == 0) continue; // Skip header $DisChaDesc = trim($row[3]); $plantCode = trim($row[4]); $CustomerCode = trim($row[5]); $DocNo = trim($row[6]); $DocDate = trim($row[7]); $CusTradeName = trim($row[9]); $CusLocation = trim($row[10]); // if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}"; if (empty($DisChaDesc)){ $invalidDisChaDesc[] = "Row {$index}"; } if (empty($CustomerCode)){ $invalidCustomerCode[] = "Row {$index}"; } if (empty($DocNo)) { $invalidDocNo[] = "Row {$index}"; } if (empty($CusTradeName)) { $invalidCusTradeName[] = "Row {$index}"; } if (empty($CusLocation)) { $invalidCusLocation[] = "Row {$index}"; } // if (empty($createdBy)) $invalidUser[] = "Row {$index}"; if (strlen($plantCode) < 4) { $invalidPlantCode[] = $plantCode; } if (!is_numeric($plantCode)) { $invalidPlantType[] = $plantCode; } else if(!Plant::where('code', $plantCode)->first()) { $invalidPlaCoFound[] = $plantCode; } // --- Find Plant by code --- $plant = Plant::where('code', $plantCode)->first(); //Duplicate Check in DB --- $exists = InvoiceDataValidation::where('plant_id', $plant->id) ->where('document_number', $DocNo) ->first(); if ($exists) { $duplicateEntries[] = "Duplicate found at Row {$index}: Document {$DocNo} already exists for Plant {$plant->name}"; } //Also check duplicates within the same file --- $uniqueKey = $plantCode . '_' . $DocNo; if (in_array($uniqueKey, $seenPlantDoc)) { $duplicateEntriesExcel[] = "Duplicate in file at Row {$index}: Document {$DocNo} already processed for Plant {$plant->name}"; } $seenPlantDoc[] = $uniqueKey; } if (!empty($invalidCustomerCode) || !empty($invalidDocNo) || !empty($invalidDocDate) || !empty($invalidCusTradeName) || !empty($invalidCusLocation)) { $errorMsg = ''; //if (!empty($invalidDisChaDesc)) $errorMsg .= 'Missing Distribution Channel Description in rows: ' . implode(', ', $invalidDisChaDesc) . '
'; if (!empty($invalidCustomerCode)) $errorMsg .= 'Missing Customer Code in rows: ' . implode(', ', $invalidCustomerCode) . '
'; if (!empty($invalidDocNo)) $errorMsg .= 'Missing Document Number in rows: ' . implode(', ', $invalidDocNo) . '
'; if (!empty($invalidDocDate)) $errorMsg .= 'Missing Document Date in rows: ' . implode(', ', $invalidDocDate) . '
'; if (!empty($invalidCusTradeName)) $errorMsg .= 'Missing Customer Trade Name in rows: ' . implode(', ', $invalidCusTradeName) . '
'; if (!empty($invalidCusLocation)) $errorMsg .= 'Missing Customer Location in rows: ' . implode(', ', $invalidCusLocation) . '
'; 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; } else if(!empty($invalidPlantType)) { $invalidPlantType = array_unique($invalidPlantType); Notification::make() ->title('Invalid Plant Codes') ->body('The following plant codes should contain numeric values:
' . implode(', ', $invalidPlantType)) ->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($plantCode) && !empty($DocNo)) { // $key = $plantCode . '|' . $DocNo; // if (isset($seenPlantDoc[$key])) { // // Duplicate found // $duplicateEntries[] = "Row {$index}: Duplicate document number '{$DocNo}' found in plant '{$plantCode}' (also in Row {$seenPlantDoc[$key]})"; // } else { // $seenPlantDoc[$key] = $index; // store first occurrence // } // } if(!empty($duplicateEntries)) { $errorMsg = 'Duplicate Entries found:
' . implode('
', $duplicateEntries); Notification::make() ->title('Duplicate Entries in Database') ->body($errorMsg) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } if(!empty($duplicateEntriesExcel)) { $errorMsg = 'Duplicate Entries found in the uploaded file:
' . implode('
', $duplicateEntriesExcel); Notification::make() ->title('Duplicate Entries in Uploaded File') ->body($errorMsg) ->danger() ->send(); if ($disk->exists($path)) { $disk->delete($path); } return; } $successCount = 0; $failCount = 0; foreach ($rows as $index => $row) { if ($index == 0) continue; $DisChaDesc = trim($row[3]); $plantCode = trim($row[4]); $CustomerCode = trim($row[5]); $DocNo = trim($row[6]); $DocDate = trim($row[7]); $CusTradeName = trim($row[9]); $CusLocation = trim($row[10]); try { $plant = Plant::where('code', $plantCode)->first(); if (!empty($DocDate)) { if (preg_match('/^\d{2}[-\/]\d{2}[-\/]\d{4}$/', $DocDate)) { [$day, $month, $year] = preg_split('/[-\/]/', $DocDate); $formattedDate = "{$year}-{$month}-{$day}"; } elseif (is_numeric($DocDate)) { $formattedDate = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($DocDate)->format('Y-m-d'); } else { $formattedDate = date('Y-m-d', strtotime($DocDate)); } } else { $formattedDate = null; } $inserted = InvoiceDataValidation::create([ 'plant_id' => $plant->id, 'distribution_channel_desc' => $DisChaDesc, 'customer_code' => $CustomerCode, 'document_number' => $DocNo, 'document_date' => $formattedDate, 'customer_trade_name' => $CusTradeName, 'customer_location' => $CusLocation, 'created_by' => $operatorName, ]); if ($inserted) { $successCount++; } else { $failCount++; } } catch (\Exception $e) { $failCount++; } } if($successCount > 0) { Notification::make() ->title('Import Summary') ->body("Successfully inserted: {$successCount} records") ->success() ->send(); } else { Notification::make() ->title('Import Summary') ->body("Failed to insert any records.") ->danger() ->send(); } } }) ->visible(function() { return Filament::auth()->user()->can('view import invoice data validation'); }), ExportAction::make() ->exporter(InvoiceDataValidationExporter::class) ->visible(function() { return Filament::auth()->user()->can('view export invoice data validation'); }), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListInvoiceDataValidations::route('/'), 'create' => Pages\CreateInvoiceDataValidation::route('/create'), 'view' => Pages\ViewInvoiceDataValidation::route('/{record}'), 'edit' => Pages\EditInvoiceDataValidation::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery() ->withoutGlobalScopes([ SoftDeletingScope::class, ]); } }