diff --git a/app/Filament/Resources/InvoiceValidationResource.php b/app/Filament/Resources/InvoiceValidationResource.php index eec47a3..f98bff0 100644 --- a/app/Filament/Resources/InvoiceValidationResource.php +++ b/app/Filament/Resources/InvoiceValidationResource.php @@ -3,13 +3,21 @@ namespace App\Filament\Resources; use App\Filament\Resources\InvoiceValidationResource\Pages; +use App\Imports\ExcelImport; use App\Models\InvoiceValidation; +use App\Models\Plant; use App\Models\StickerMaster; +use Filament\Actions\Action as FilamentActionsAction; use Filament\Actions\CreateAction; use Filament\Forms; +use Filament\Forms\Components\Actions\Action as ActionsAction; use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\Section; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\ToggleButtons; use Filament\Forms\Form; +use Filament\Forms\Get; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Table; @@ -20,7 +28,11 @@ use Filament\Notifications\Notification; use Filament\Tables\Actions\Action; use Illuminate\Support\Facades\Storage; use Maatwebsite\Excel\Facades\Excel; -use Livewire\Livewire; // Ensure this is imported +use Livewire\Livewire; +use Str; + + + class InvoiceValidationResource extends Resource { @@ -45,117 +57,842 @@ class InvoiceValidationResource extends Resource Section::make('') ->schema([ - Forms\Components\Select::make('plant_id') - ->relationship('plant', 'name') - ->required(), - - Forms\Components\TextInput::make('invoice_number') + Forms\Components\Select::make('plant_id') + ->relationship('plant', 'name') ->required() - ->label('Invoice Number') + // ->preload() + // ->nullable(), + ->reactive() ->columnSpan(1) + ->default(function () { + return optional(InvoiceValidation::latest()->first())->plant_id; + }) + ->disabled(fn (Get $get) => !empty($get('id'))) + // ->afterStateUpdated(fn ($set) => $set('block_id', null) & $set('name', null) & $set('start_time', null) & $set('duration', null) & $set('end_time', null)) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $plantId = $get('plant_id'); + $set('update_invoice', null); + // Ensure `linestop_id` is not cleared + if (!$plantId) { + $set('ivPlantError', 'Please select a plant first.'); + return; + } + else + { + $set('ivPlantError', null); + } + }) + ->extraAttributes(fn ($get) => [ + 'class' => $get('ivPlantError') ? 'border-red-500' : '', + ]) + ->hint(fn ($get) => $get('ivPlantError') ? $get('ivPlantError') : null) + ->hintColor('danger'), + + Forms\Components\TextInput::make('invoice_number') + ->label('Invoice Number') + ->required() + ->reactive() + ->columnSpan(1) + ->readOnly(fn (callable $get) => !empty($get('serial_number'))) + //->disabled(fn (Get $get) => !empty($get('serial_number'))) ->extraAttributes([ 'x-data' => '{ value: "" }', 'x-model' => 'value', 'x-on:keydown.enter.prevent' => '$wire.processInvoice(value)', - ]), + ]) + // ->afterStateHydrated(function (TextInput $component, string $state) { + // $component->state(ucwords($state)); + // }) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $invNo = $get('invoice_number'); + $set('serial_number', null); + $set('update_invoice', null); + // if (!$invNo) { return; } else { } + }), - Forms\Components\TextInput::make('serial_number') + Forms\Components\TextInput::make('serial_number') + ->label('Serial Number') + ->reactive() + ->readOnly(fn (callable $get) => empty($get('invoice_number'))) + //->disabled(fn (Get $get) => empty($get('invoice_number'))) ->extraAttributes([ 'x-data' => '{ value: "" }', 'x-model' => 'value', 'wire:keydown.enter.prevent' => 'processSerialNumber(value)', // Using wire:keydown ]) - ->columnSpan(1), - Forms\Components\TextInput::make('total_quantity') ->label('Total Quantity') + ->readOnly(true) ->columnSpan(1), Forms\Components\TextInput::make('scanned_quantity') ->label('Scanned Quantity') + ->readOnly(true) ->columnSpan(1), + ToggleButtons::make('update_invoice') + ->label('Update Invoice?') + ->boolean() + ->grouped() + ->reactive() + ->hidden(fn (callable $get) => ($get('invoice_number') == null || $get('update_invoice') === '0') || !empty($get('serial_number'))) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + if(!$get('plant_id')) + { + $set('update_invoice', null); + return; + } + if($get('update_invoice') === "1") + { + $totQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->where('plant_id', $get('plant_id'))->count(); + if($totQuan <= 0) + { + $set('update_invoice', null); + return; + } + + $totMQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->whereNotNull('quantity')->where('plant_id', $get('plant_id'))->count(); + $scanMQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $get('plant_id'))->count(); + $scanSQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->where('scanned_status', 'Scanned')->where('plant_id', $get('plant_id'))->count(); + + if($totMQuan > 0) + { + if ($totQuan === $scanMQuan) + { + $set('update_invoice', null); + return; + } + } + else + { + if ($totQuan === $scanSQuan) + { + $set('update_invoice', null); + return; + } + } + } + }) + ->disabled(fn (Get $get) => empty($get('invoice_number'))), + Forms\Components\TextInput::make('id') + ->hidden() + ->readOnly(true), ]) ->columns(5), ]); } + + public static function table(Table $table): Table { + return $table ->columns([ Tables\Columns\TextColumn::make('id') ->label('ID') ->numeric() ->sortable(), - Tables\Columns\TextColumn::make('stickerMaster.id') - ->numeric() + Tables\Columns\TextColumn::make('invoice_number') + ->label('Invoice Number') ->sortable(), - Tables\Columns\TextColumn::make('plant.name') - ->numeric() + Tables\Columns\TextColumn::make('stickerMaster.item.code') + ->label('Material Code') + ->sortable(), + Tables\Columns\TextColumn::make('serial_number') + ->label('Serial Number') + ->sortable(), + Tables\Columns\TextColumn::make('motor_scanned_status') + ->label('Motor Scanned Status') + ->sortable(), + Tables\Columns\TextColumn::make('pump_scanned_status') + ->label('Pump Scanned Status') + ->sortable(), + Tables\Columns\TextColumn::make('scanned_status_set') + ->label('Pump Set Scanned Status') + ->sortable(), + Tables\Columns\TextColumn::make('capacitor_scanned_status') + ->label('Capacitor Scanned Status') + ->sortable(), + Tables\Columns\TextColumn::make('scanned_status') + ->label('Scanned Status') + ->sortable(), + Tables\Columns\TextColumn::make('panel_box_supplier') + ->label('Panel Box Supplier') + ->sortable(), + Tables\Columns\TextColumn::make('panel_box_serial_number') + ->label('Panel Box Serial Number') ->sortable(), Tables\Columns\TextColumn::make('load_rate') + ->label('Load Rate') ->numeric() ->sortable(), + Tables\Columns\TextColumn::make('upload_status') + ->label('Upload Status') + ->sortable(), + Tables\Columns\TextColumn::make('batch_number') + ->label('Batch Number') + ->sortable(), + Tables\Columns\TextColumn::make('quantity') + ->label('Quantity') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('operator_id') + ->label('Operator ID') + ->sortable(), + Tables\Columns\TextColumn::make('plant.name') + ->label('Plant') + ->sortable(), + Tables\Columns\TextColumn::make('created_at') + ->label('Created At') + ->dateTime() + ->sortable(), + Tables\Columns\TextColumn::make('updated_at') + ->label('Updated At') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('deleted_at') + ->label('Deleted At') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), ]) + ->headerActions([ + + // Action::make('plant_id') + // ->label('Select Plant') + // ->form([ + // Select::make('plant_id') + // ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs + // ->label('Select Plant') + // ->required() + // ->reactive() + // ]), + Tables\Actions\Action::make('Import Serial Number') - ->label('Import Serial Number') + ->label('Import Serial Invoice') ->form([ + Select::make('plant_id') + ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs + ->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) // prevent auto-storing, we will store manually + ->reactive() + ->required() ->disk('local') //'local' refers to the local storage disk defined in config/filesystems.php, typically pointing to storage/app. - ->directory('uploads/temp'), //storage/app/uploads/temp + ->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']; + // Get original filename $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx // Store manually using storeAs to keep original name $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path + // uploads/temp/3RA0018735.xlsx + + $fullPath = Storage::disk('local')->path($path); + // /home/iot-dev/projects/pds/storage/app/private/uploads/temp/3RA0018735.xlsx + + $totQuan = InvoiceValidation::where('invoice_number', $originalName)->where('plant_id', $plantId)->count(); + $scanSQuan = InvoiceValidation::where('invoice_number', $originalName)->where('scanned_status', 'Scanned')->where('plant_id', $plantId)->count(); + + if($totQuan == $scanSQuan && $totQuan > 0) + { + Notification::make() + ->title('Serial invoice already completed the scanning process for selected plant.') + ->danger() + ->send(); + + if ($disk->exists($path)) + { + $disk->delete($path); + } + return; + } + + 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 'Serial Invoice' file to proceed..!") + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $invalidMatCodes = []; + $invalidSerialCodes=[]; + $materialCodes = []; + $missingSerials = []; + $duplicateSerials = []; + $seenSerialNumbers = []; + $validRowsFound = false; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $materialCode = trim($row[0]); + $serialNumber = trim($row[1]); + + if (empty($materialCode) && empty($serialNumber)) { + continue; + } + + if (!empty($materialCode)) + { + if(Str::length($materialCode) < 6 || !ctype_alnum($materialCode)) + { + $invalidMatCodes[] = $materialCode; + + } + else + { + + if (empty($serialNumber)) { + $missingSerials[] = $materialCode; + + } + else if(Str::length($serialNumber) < 9 || !ctype_alnum($serialNumber)) + { + $invalidSerialCodes[] = $serialNumber; + } + else + { + if (in_array($serialNumber, $seenSerialNumbers)) { + $duplicateSerials[] = $serialNumber; + } else { + $seenSerialNumbers[] = $serialNumber; + $materialCodes[] = $materialCode; + $validRowsFound = true; + } + } + } + } + else + { + continue; + } + } + + $uniqueInvalidCodes = array_unique($invalidMatCodes); + + $uniqueMissingSerials = array_unique($missingSerials); + + $uniqueSerialCodes = array_unique($invalidSerialCodes); + + $duplicateSerialCodes = array_unique($duplicateSerials); + + + if (!empty($uniqueInvalidCodes)) { + Notification::make() + ->title('Invalid Item Codes') + ->body('The following item codes should contain minimum 6 digit alpha numeric values:
' . implode(', ', $uniqueInvalidCodes)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + else if (!empty($uniqueMissingSerials)) { + Notification::make() + ->title('Missing Serial Numbers') + ->body("The following item codes doesn't have valid serial number:
" . implode(', ', $uniqueMissingSerials)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + else if (!empty($uniqueSerialCodes)) { + Notification::make() + ->title('Invalid Serial Number') + ->body('The following serial numbers should contain minimum 9 digit alpha numeric values:
' . implode(', ', $uniqueSerialCodes)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + else if (!empty($duplicateSerialCodes)) { + Notification::make() + ->title('Duplicate Serial Numbers') + ->body('The following serial numbers are already exist in database:
' . implode(', ', $duplicateSerialCodes)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + if (!$validRowsFound) { + Notification::make() + ->title('Invalid Serial Invoice') + ->danger() // This makes the notification red to indicate an error + ->body('Uploaded Excel sheet is empty or
contains no valid data.') + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $uniqueCodes = array_unique($materialCodes); + + $matchedItems = StickerMaster::with('item') + ->whereHas('item', function ($query) use ($uniqueCodes) { + $query->whereIn('code', $uniqueCodes); + }) + ->get(); + + $matchedCodes = $matchedItems->pluck('item.code')->toArray(); + + $missingCodes = array_diff($uniqueCodes, $matchedCodes); + + if (!empty($missingCodes)) + { + $missingCount = count($missingCodes); + + $message = $missingCount > 10 ? "'$missingCount' item codes are not found in database." : 'The following item codes are not found in database:
' . implode(', ', $missingCodes); + + Notification::make() + ->title('Unknown Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + // Check which codes have a material_type set (not null) + $invalidCodes = $matchedItems + ->filter(fn ($sticker) => !empty($sticker->material_type)) //filter invalid + ->pluck('item.code') + ->toArray(); + + if (count($invalidCodes) > 10) + { + Notification::make() + ->title('Invalid item codes found') + ->body('' . count($invalidCodes) . 'item codes found have material type.') + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + else if(count($invalidCodes) > 0) + { + Notification::make() + ->title('Invalid item codes found') + ->body('Material invoice Item Codes found : ' . implode(', ', $invalidCodes)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + else + { + // Save full file path to session + session(['uploaded_invoice_path' => $fullPath]); + Notification::make() + ->title('Serial invoice imported successfully.') + ->success() + ->send(); + } + } + }), + + Tables\Actions\Action::make('Import Invoice Material') + ->label('Import Material Invoice') + ->form([ + + Select::make('plant_id') + ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs + ->label('Select Plant') + ->required() + ->reactive() + ->default(function () { + return optional(InvoiceValidation::latest()->first())->plant_id; + }) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('invoice_material', null); + }), + + + FileUpload::make('invoice_material') + ->label('Invoice Material') + ->required() + ->preserveFilenames() + ->reactive() // <- this keeps the original filename + ->storeFiles(false) // prevent auto-storing + ->disk('local') + ->visible(fn (Get $get) => !empty($get('plant_id'))) + ->directory('uploads/temp') + + ]) + + ->action(function (array $data) { + $uploadedFile = $data['invoice_material']; + + $plantId = $data['plant_id']; // Access the selected plant_id + + $disk = Storage::disk('local'); + + // Get original filename + $originalName = $uploadedFile->getClientOriginalName(); + + $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); $fullPath = Storage::disk('local')->path($path); - // Save full file path to session - session(['uploaded_invoice_path' => $fullPath]); + $totQuan = InvoiceValidation::where('invoice_number', $originalName)->where('plant_id', $plantId)->count(); + $scanMQuan = InvoiceValidation::where('invoice_number', $originalName)->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $plantId)->count(); - // session()->flash('just_uploaded_invoice', true); // 👈 add this + if($totQuan == $scanMQuan && $totQuan > 0) + { + Notification::make() + ->title('Material invoice already completed the scanning process for selected plant.') + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } - Notification::make() - ->title('File Uploaded. Continue in Create Page.') - ->success() - ->send(); + 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 'Material Invoice' file to proceed..!") + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $invalidMatCodes = []; + $materialCodes = []; + $missingQuantities = []; + $invalidMatQuan = []; + $invalidMaterialQuan = []; + $validRowsFound = false; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $materialCode = trim($row[0]); + $materialQuantity = trim($row[1]); + + if (empty($materialCode) && empty($materialQuantity)) { + continue; + } + + if (!empty($materialCode)) { + if(Str::length($materialCode) < 6 || !ctype_alnum($materialCode)) + { + $invalidMatCodes[] = $materialCode; + } + else + { + if($materialQuantity == 0) + { + $invalidMaterialQuan[] = $materialCode; + } + else if (empty($materialQuantity)) + { + $missingQuantities[] = $materialCode; + } + else if(!is_numeric($materialQuantity)) + { + $invalidMatQuan[] = $materialCode; + } + else + { + $materialCodes[] = $materialCode; + $validRowsFound = true; + } + } + } + else + { + continue; + } + } + + $uniqueInvalidCodes = array_unique($invalidMatCodes); + $uniqueaplhaMat = array_unique($invalidMatQuan); + $uniqueZeroMat = array_unique($invalidMaterialQuan); + $uniqueEmptyMat = array_unique($missingQuantities); + + if (!empty($uniqueInvalidCodes)) { + Notification::make() + ->title('Invalid Item Codes') + ->body('The following item codes should contain minimum 6 digit alpha numeric values:
' . implode(', ', $uniqueInvalidCodes)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + if (!empty($uniqueaplhaMat)) { + Notification::make() + ->title('Invalid Material Quantity') + ->body("The following item codes material quantity must be a numeric values :
" . implode(', ', $uniqueaplhaMat)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + if (!empty($uniqueZeroMat)) { + Notification::make() + ->title('Invalid Material Quantity') + ->body("The following item codes material quantity should be greater than 0:
" . implode(', ', $uniqueZeroMat)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + if (!empty($uniqueEmptyMat)) { + Notification::make() + ->title('Missing Material Quantity') + ->body("The following item codes doesn't have valid material quantity:
" . implode(', ', $uniqueEmptyMat)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + if (!$validRowsFound) { + Notification::make() + ->title('Invalid Material Invoice') + ->danger() // This makes the notification red to indicate an error + ->body('Uploaded Excel sheet is empty or
contains no valid data.') + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $uniqueCodes = array_unique($materialCodes); + + $matchedItems = StickerMaster::with('item') + ->whereHas('item', function ($query) use ($uniqueCodes) { + $query->whereIn('code', $uniqueCodes); + }) + ->get(); + + $matchedCodes = $matchedItems->pluck('item.code')->toArray(); + + $missingCodes = array_diff($uniqueCodes, $matchedCodes); + + if (!empty($missingCodes)) + { + $missingCount = count($missingCodes); + + $message = $missingCount > 10 + ? "'$missingCount' Item Codes are not found in sticker master." + : 'Item Codes are not found in sticker master:
' . implode(', ', $missingCodes); + + Notification::make() + ->title('Unknown Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $invalidCodes = $matchedItems + ->filter(fn ($sticker) => empty($sticker->material_type)) //filter invalid + ->pluck('item.code') + ->toArray(); + + if (count($invalidCodes) > 10) + { + Notification::make() + ->title('Invalid item codes found') + ->body('' . count($invalidCodes) . 'invalid item codes found have serial number.') + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + else if(count($invalidCodes) > 0) + { + Notification::make() + ->title('Invalid item codes found') + ->body('Serial invoice Item Codes found : ' . implode(', ', $invalidCodes)) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $nonNumericQtyCodes = []; + $zeroQtyCodes = []; + $notDivisibleCodes = []; + + foreach ($matchedItems as $sticker) + { + $code = $sticker->item->code; + $materialType = $sticker->material_type; + + if ($materialType == 2) + { + $bundleQty = $sticker->bundle_quantity ?? 0; + $totalExcelQty = 0; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $excelCode = trim($row[0]); + $excelMatQty = trim($row[1]); + + + if ($excelCode === $code && is_numeric($excelMatQty)) { + $totalExcelQty += $excelMatQty; // Sum up the quantities + } + } + + if ($totalExcelQty === 0) { + $zeroQtyCodes[] = $code; + } elseif (!is_numeric($totalExcelQty)) { + $nonNumericQtyCodes[] = $code; // Here you may want to check divisibility condition too + } elseif ($bundleQty != 0 && $totalExcelQty % $bundleQty !== 0) { + $notDivisibleCodes[] = $code; + } + } + } + + $showValidationNotification = function(array $codes, string $message) { + if (count($codes) === 0) return; + + $uniqueCodes = array_unique($codes); + $codeList = implode(', ', $uniqueCodes); + + Notification::make() + ->title('Invalid Bundle Quantity') + ->body("$message
$codeList") + ->danger() + ->send(); + }; + + $showValidationNotification($nonNumericQtyCodes, "The following item codes contains invalid bundle quantity:"); + $showValidationNotification($zeroQtyCodes, "The following item codes quantity should be greater than '0':"); + $showValidationNotification($notDivisibleCodes, "The following item codes quantity is not divisible by bundle quantity."); + + if ($nonNumericQtyCodes || $zeroQtyCodes || $notDivisibleCodes) { + if ($disk->exists($path)) + { + $disk->delete($path); + } + return; + } + else + { + // Save full file path to session + session(['uploaded_material_invoice' => $fullPath]); + Notification::make() + ->title('Material invoice imported successfully.') + ->success() + ->send(); + } + + } }), + ]) - Tables\Actions\Action::make('Import Invoice Material') - ->label('Import Invoice Material') - ->form([ - FileUpload::make('invoice_material') - ->label('Invoice Material') - ->required(), - ]) + ->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(), + ]), ]); - - // ->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(), - // ]), - // ]); } public static function getRelations(): array