diff --git a/app/Filament/Resources/InvoiceValidationResource.php b/app/Filament/Resources/InvoiceValidationResource.php index 13a9817..45ba806 100644 --- a/app/Filament/Resources/InvoiceValidationResource.php +++ b/app/Filament/Resources/InvoiceValidationResource.php @@ -4,7 +4,10 @@ namespace App\Filament\Resources; use App\Filament\Resources\InvoiceValidationResource\Pages; use App\Models\InvoiceValidation; +use App\Models\StickerMaster; +use Filament\Actions\CreateAction; use Filament\Forms; +use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\Section; use Filament\Forms\Form; use Filament\Resources\Resource; @@ -13,8 +16,10 @@ use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; use Filament\Forms\Components\View; - - +use Filament\Notifications\Notification; +use Filament\Tables\Actions\Action; +use Illuminate\Support\Facades\Storage; +use Maatwebsite\Excel\Facades\Excel; class InvoiceValidationResource extends Resource { @@ -24,24 +29,18 @@ class InvoiceValidationResource extends Resource protected static ?string $navigationGroup = 'Invoice'; - public $enter_pressed = false; public static function form(Form $form): Form { return $form ->schema([ - Forms\Components\Hidden::make('sticker_master_id') - //->relationship('stickerMaster', 'id') - ->required(), + // Forms\Components\Hidden::make('sticker_master_id') + // //->relationship('stickerMaster', 'id') + // ->required(), - Section::make('') + Section::make('') ->schema([ - // FileUpload::make('excel_file') - // ->label('Choose Excel File') - // ->disk('local') - // ->columnSpan(1), - Forms\Components\Select::make('plant_id') ->relationship('plant', 'name') ->required(), @@ -57,7 +56,6 @@ class InvoiceValidationResource extends Resource ]), Forms\Components\TextInput::make('serial_number') - //->required() ->reactive() ->columnSpan(1), @@ -71,16 +69,11 @@ class InvoiceValidationResource extends Resource ]) ->columns(5), - // View::make('livewire.invoice-data-table') - // ->label('Invoice Details') - // ->viewData([ - // 'invoiceData' => fn ($get) => $get('invoice_data') ?? [], // Changed from invoiceData to invoice_data - // ]) - // ->columnSpan('full'), ]); } + public static function table(Table $table): Table { return $table @@ -98,35 +91,66 @@ class InvoiceValidationResource extends Resource Tables\Columns\TextColumn::make('load_rate') ->numeric() ->sortable(), - Tables\Columns\TextColumn::make('created_at') - ->dateTime() - ->sortable() - ->toggleable(isToggledHiddenByDefault: true), - 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 Serial Number') + ->label('Import Serial Number') + ->form([ + FileUpload::make('invoice_serial_number') + ->label('Invoice Serial Number') + ->preserveFilenames() // <- this keeps the original filename + ->storeFiles(false) // prevent auto-storing, we will store manually + ->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 + ]) + + ->action(function (array $data) { + $uploadedFile = $data['invoice_serial_number']; + + // 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 + + $fullPath = Storage::disk('local')->path($path); + + // Save full file path to session + session(['uploaded_invoice_path' => $fullPath]); + + // session()->flash('just_uploaded_invoice', true); // 👈 add this + + Notification::make() + ->title('File Uploaded. Continue in Create Page.') + ->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(), + // ]), + // ]); + } public static function getRelations(): array { diff --git a/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php b/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php index d2c5b3d..9e430eb 100644 --- a/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php +++ b/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php @@ -3,10 +3,14 @@ namespace App\Filament\Resources\InvoiceValidationResource\Pages; use App\Filament\Resources\InvoiceValidationResource; +use App\Livewire\InvoiceDataTable; +use App\Models\InvoiceValidation; +use App\Models\StickerMaster; use Illuminate\Contracts\View\View; use Filament\Resources\Pages\CreateRecord; use Filament\Notifications\Notification; - +use Maatwebsite\Excel\Facades\Excel; +use Livewire\Livewire; class CreateInvoiceValidation extends CreateRecord { @@ -18,103 +22,151 @@ class CreateInvoiceValidation extends CreateRecord public $invoice_data; + public $invoiceData = []; + public $scanned_quantity; public $total_quantity; + public string $invoiceNumber; + public $excel_file; + public function getFormActions(): array + { + return parent::getFormActions(); + } + public function processInvoice($invoiceNumber) { + // Get plant_id selected in the form + $plantId = $this->form->getState()['plant_id']; - $this->invoice_number = $invoiceNumber; - - // Check if the file is uploaded - if (!$this->excel_file) { - Notification::make() - ->title('No File Uploaded') - ->body("Please upload an Excel file to proceed with invoice: {$invoiceNumber}.") - ->danger() - ->persistent() - ->send(); - return; - } - - $localPath = $this->excel_file->getPath(); - - // Check if file exists - if (!file_exists($localPath)) { - Notification::make() - ->title('File Not Found') - ->body("No Excel file found for invoice: {$invoiceNumber}. Please ensure the file exists in your Downloads folder.") - ->danger() - ->persistent() - ->send(); - return; - } - - - try { - $rows = \Maatwebsite\Excel\Facades\Excel::toArray([], $localPath)[0] ?? []; - array_shift($rows); - - if (empty($rows)) { - Notification::make() - ->title('Empty File') - ->body('The Excel file contains no data rows') - ->danger() - ->send(); - return; - } - - $validRecords = []; - $invalidMaterials = []; - - foreach ($rows as $row) { - $materialCode = $row[0] ?? null; - $serialNumber = $row[1] ?? null; - - if (!\App\Models\StickerMaster::where('item_id', $materialCode)->exists()) { - $invalidMaterials[] = $materialCode; - continue; - } - - $validRecords[] = [ - 'material_code' => $materialCode, - 'serial_number' => $serialNumber, - 'invoice_number' => $invoiceNumber, - 'created_at' => now(), - 'updated_at' => now(), - ]; - } - - if (!empty($invalidMaterials)) { - Notification::make() - ->title('Invalid Materials') - ->body('These codes not found: ' . implode(', ', array_unique($invalidMaterials))) - ->danger() - ->send(); - return; - } - - \DB::table('invoice_validations')->insert($validRecords); - - $this->invoice_data = $validRecords; - $this->scanned_quantity = count($validRecords); - $this->total_quantity = count($validRecords); + $filePath = session('uploaded_invoice_path'); + if (!file_exists($filePath)) + { Notification::make() - ->title('Success') - ->body(count($validRecords) . ' records inserted successfully') - ->success() - ->send(); - } catch (\Exception $e) { - Notification::make() - ->title('Error') - ->body($e->getMessage()) + ->title('Excel File not found.') ->danger() ->send(); + return; + } + + // Extract filename without extension (e.g., "3RA0018732") + $uploadedFilename = pathinfo($filePath, PATHINFO_FILENAME); + + // Compare with invoice number + if ($uploadedFilename !== $invoiceNumber) { + Notification::make() + ->title("Uploaded file name does not match the invoice number.") + // ->body("Expected: {$invoiceNumber}.xlsx, but got: {$uploadedFilename}.xlsx") + ->danger() + ->send(); + return; + } + + if ($filePath && file_exists($filePath)) + { + // Now you can read/process the file here + $rows = Excel::toArray(null, $filePath)[0]; //0 means excel first sheet + + $materialCodes = []; + $serialNumbers = []; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $materialCode = trim($row[0]); + $serialNumber = trim($row[1]); + + if (!empty($materialCode)) { + $materialCodes[] = $materialCode; + } + if (!empty($serialNumber)) { + $serialNumbers[] = $serialNumber; + } + } + + $existingSerialNumbers = InvoiceValidation::whereIn('serial_number', $serialNumbers)->pluck('serial_number')->toArray(); + + // If there are duplicates, notify and stop the process + if (!empty($existingSerialNumbers)) { + Notification::make() + ->title('Duplicate Serial Numbers Found') + ->body('The following serial numbers already exist: ' . implode(', ', $existingSerialNumbers)) + ->danger() + ->send(); + return; + } + + $uniqueCodes = array_unique($materialCodes); + + $existingCodes = StickerMaster::with('item') + ->get() + ->pluck('item.code') + ->toArray(); + + $missingCodes = array_diff($uniqueCodes, $existingCodes); + + if (!empty($missingCodes)) { + Notification::make() + ->title('Material codes do not exist in Sticker Master') + ->body('Missing: ' . implode(', ', $missingCodes)) + ->danger() + ->send(); + return; + } + + $inserted = 0; + foreach ($rows as $index => $row) + { + if ($index === 0) continue; + + $materialCode = trim($row[0]); + $serialNumber = trim($row[1]); + + if (in_array($serialNumber, $existingSerialNumbers)) { + continue; // here duplicate serial numbers are skipped and new serial numbers are inserted + } + + $sticker = StickerMaster::whereHas('item', function ($query) use ($materialCode) { + $query->where('code', $materialCode); //Check if item.code matches Excel's materialCode + })->first(); + + if ($sticker) { + InvoiceValidation::create([ + 'sticker_master_id' => $sticker->id, + 'serial_number' => $serialNumber, + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + ]); + $inserted++; + } + } + + if ($inserted > 0) + { + Notification::make() + ->title("Import Successful") + ->body("$inserted records were inserted.") + ->success() + ->send(); + // Dispatch the event to refresh the Livewire component + $this->dispatch('refreshInvoiceData', invoiceNumber: $invoiceNumber); + + } + else + { + Notification::make() + ->title("Import Failed") + ->body("No new records were inserted.") + ->danger() + ->send(); + return; + } } } @@ -123,9 +175,5 @@ class CreateInvoiceValidation extends CreateRecord return 'Scan Invoice Validation'; } - // public function render(): View - // { - // return view('filament.resources.invoice-validation-resource.pages.create-invoice-validation'); - // } } diff --git a/app/Filament/Resources/InvoiceValidationResource/Pages/ListInvoiceValidations.php b/app/Filament/Resources/InvoiceValidationResource/Pages/ListInvoiceValidations.php index 7d75b64..0ff3f3e 100644 --- a/app/Filament/Resources/InvoiceValidationResource/Pages/ListInvoiceValidations.php +++ b/app/Filament/Resources/InvoiceValidationResource/Pages/ListInvoiceValidations.php @@ -4,6 +4,8 @@ namespace App\Filament\Resources\InvoiceValidationResource\Pages; use App\Filament\Resources\InvoiceValidationResource; use Filament\Actions; +use Filament\Actions\Action; +use Filament\Forms\Components\FileUpload; use Filament\Resources\Pages\ListRecords; class ListInvoiceValidations extends ListRecords @@ -16,4 +18,12 @@ class ListInvoiceValidations extends ListRecords Actions\CreateAction::make(), ]; } + + //to hide the data from the table + protected function getTableQuery(): \Illuminate\Database\Eloquent\Builder + { + return static::getResource()::getEloquentQuery()->whereRaw('1 = 0'); + } + + } diff --git a/app/Livewire/InvoiceDataTable.php b/app/Livewire/InvoiceDataTable.php index cfb176b..4645bc2 100644 --- a/app/Livewire/InvoiceDataTable.php +++ b/app/Livewire/InvoiceDataTable.php @@ -10,31 +10,44 @@ class InvoiceDataTable extends Component public $invoiceData = []; + public string $invoiceNumber = ''; + + public bool $hasSearched = false; + protected $listeners = ['refreshInvoiceData' => 'loadData']; - public function mount() + public function loadData($invoiceNumber) { - $this->loadData(); + $this->invoiceNumber = $invoiceNumber; + $this->hasSearched = true; - } + $this->invoiceData = InvoiceValidation::where('invoice_number', $this->invoiceNumber) + ->get() + ->map(function ($record) { + return [ + 'sticker_master_id' => $record->sticker_master_id, + 'serial_number' => $record->serial_number, + 'motor_scanned_status' => $record->motor_scanned_status, + 'pump_scanned_status' => $record->pump_scanned_status, + 'capacitor_scanned_status' => $record->capacitor_scanned_status, + 'scanned_status_set' => $record->scanned_status_set, + 'panel_box_supplier' => $record->panel_box_supplier, + 'panel_box_serial_number' => $record->panel_box_serial_number, + 'scanned_status' => $record->scanned_status, + ]; + }) - public function loadData() - { - $this->invoiceData = InvoiceValidation::all()->toArray(); + ->toArray(); + + //Loop through and replace 'code' using related StickerMaster > Item > code + foreach ($this->invoiceData as &$row) { + $stickerMaster = \App\Models\StickerMaster::with('item')->find($row['sticker_master_id'] ?? null); + $row['code'] = $stickerMaster?->item?->code ?? 'N/A'; + } } public function render() { - // Always fetch fresh data when Livewire re-renders (like via polling) - $invoiceData = InvoiceValidation::latest()->get(); - - return view('livewire.invoice-data-table', [ - 'invoiceData' => $invoiceData, - ]); - // return view('livewire.invoice-data-table', [ - // 'invoiceData' => $this->invoiceData, // <--- this is important - // ]); + return view('livewire.invoice-data-table'); } - - } diff --git a/resources/views/filament/resources/invoice-validation-resource/pages/create-invoice-validation.blade.php b/resources/views/filament/resources/invoice-validation-resource/pages/create-invoice-validation.blade.php index e238318..c614966 100644 --- a/resources/views/filament/resources/invoice-validation-resource/pages/create-invoice-validation.blade.php +++ b/resources/views/filament/resources/invoice-validation-resource/pages/create-invoice-validation.blade.php @@ -1,7 +1,36 @@ - +{{-- + +
{{ $this->form }} - {{-- @livewire('invoice-data-table') --}} - + + + @foreach ($this->getFormActions() as $action) + {{ $action }} + @endforeach + + + --}} + + + {{-- Form Section --}} +
+ {{ $this->form }} +
+ + {{-- Livewire Component (Invoice Table) --}} +
+ +
+ + {{-- Actions --}} +
+ + @foreach ($this->getFormActions() as $action) + {{ $action }} + @endforeach + +
+
diff --git a/resources/views/livewire/invoice-data-table.blade.php b/resources/views/livewire/invoice-data-table.blade.php index cdf33bd..e41456e 100644 --- a/resources/views/livewire/invoice-data-table.blade.php +++ b/resources/views/livewire/invoice-data-table.blade.php @@ -1,4 +1,4 @@ -
+{{--

INVOICE DATA TABLE

@@ -6,40 +6,170 @@
- - - - - - - - - - - - - - - - - @forelse ($invoiceData as $index => $row) - - - - - - - - - - - - - @empty +
+
NoMaterial CodeSerial NumberMotor Scanned StatusPump Scanned StatusCapacitor Scanned StatusScanned Status SetPanel Box SupplierPanel Box Serial NumberScanned Status
{{ $index + 1 }}{{ $row['material_code'] ?? 'N/A' }}{{ $row['serial_number'] ?? 'N/A' }}{{ $row['motor_scanned_status'] ?? 'N/A' }}{{ $row['pump_scanned_status'] ?? 'N/A' }}{{ $row['capacitor_scanned_status'] ?? 'N/A' }}{{ $row['scanned_status_set'] ?? 'N/A' }}{{ $row['panel_box_supplier'] ?? 'N/A' }}{{ $row['panel_box_serial_number'] ?? 'N/A' }}{{ $row['scanned_status'] ?? 'N/A' }}
+ - + + + + + + + + + + - @endforelse - -
No data available.NoMaterial CodeSerial NumberMotor Scanned StatusPump Scanned StatusCapacitor Scanned StatusScanned Status SetPanel Box SupplierPanel Box Serial NumberScanned Status
+ + + @forelse ($invoiceData as $index => $row) + + {{ $index + 1 }} + + {{ $row['code'] ?? 'N/A' }} + {{ $row['serial_number'] ?? 'N/A' }} + {{ $row['motor_scanned_status'] ?? 'N/A' }} + {{ $row['pump_scanned_status'] ?? 'N/A' }} + {{ $row['capacitor_scanned_status'] ?? 'N/A' }} + {{ $row['scanned_status_set'] ?? 'N/A' }} + {{ $row['panel_box_supplier'] ?? 'N/A' }} + {{ $row['panel_box_serial_number'] ?? 'N/A' }} + {{ $row['scanned_status'] ?? 'N/A' }} + + @empty + + No data available. + + @endforelse + + +
+ + --}} + + + +{{-- this is code for input box inisde the data grid --}} + + +{{--
+
+

INVOICE DATA TABLE

+
+
+
+
+ + + + @if($hasSearched) +
+ + + + + + + + + + + + + + + + + @forelse ($invoiceData as $index => $row) + + + + + + + + + + + + + @empty + + + + @endforelse + +
NoMaterial CodeSerial NumberMotor Scanned StatusPump Scanned StatusCapacitor Scanned StatusScanned Status SetPanel Box SupplierPanel Box Serial NumberScanned Status
{{ $index + 1 }}{{ $row['code'] ?? 'N/A' }}{{ $row['serial_number'] ?? 'N/A' }}{{ $row['motor_scanned_status'] ?? 'N/A' }}{{ $row['pump_scanned_status'] ?? 'N/A' }}{{ $row['capacitor_scanned_status'] ?? 'N/A' }}{{ $row['scanned_status_set'] ?? 'N/A' }}{{ $row['panel_box_supplier'] ?? 'N/A' }}{{ $row['panel_box_serial_number'] ?? 'N/A' }}{{ $row['scanned_status'] ?? 'N/A' }}
+ No data found for invoice number {{ $invoiceNumber }}. +
+
+ @endif +
--}} + + +
+
+

INVOICE DATA TABLE

+
+
+
+
+ + + @if($hasSearched) + +
+ + + + + + + + + + + + + + + + + @forelse ($invoiceData as $index => $row) + + + + + + + + + + + + + @empty + + + + @endforelse + +
NoMaterial CodeSerial NumberMotor Scanned StatusPump Scanned StatusCapacitor Scanned StatusScanned Status SetPanel Box SupplierPanel Box Serial NumberScanned Status
{{ $index + 1 }}{{ $row['code'] ?? 'N/A' }}{{ $row['serial_number'] ?? 'N/A' }}{{ $row['motor_scanned_status'] ?? 'N/A' }}{{ $row['pump_scanned_status'] ?? 'N/A' }}{{ $row['capacitor_scanned_status'] ?? 'N/A' }}{{ $row['scanned_status_set'] ?? 'N/A' }}{{ $row['panel_box_supplier'] ?? 'N/A' }}{{ $row['panel_box_serial_number'] ?? 'N/A' }}{{ $row['scanned_status'] ?? 'N/A' }}
+ No data found for invoice number {{ $invoiceNumber }}. +
+
+ @endif +
+