From 10e595a4a3455dc40e2a4d1151d0bebd647401e2 Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Tue, 30 Dec 2025 14:26:13 +0530 Subject: [PATCH] Added Sticker Validation resource pages --- .../Resources/StickerValidationResource.php | 165 ++++++++++ .../Pages/CreateStickerValidation.php | 298 ++++++++++++++++++ .../Pages/EditStickerValidation.php | 22 ++ .../Pages/ListStickerValidations.php | 19 ++ .../Pages/ViewStickerValidation.php | 19 ++ 5 files changed, 523 insertions(+) create mode 100644 app/Filament/Resources/StickerValidationResource.php create mode 100644 app/Filament/Resources/StickerValidationResource/Pages/CreateStickerValidation.php create mode 100644 app/Filament/Resources/StickerValidationResource/Pages/EditStickerValidation.php create mode 100644 app/Filament/Resources/StickerValidationResource/Pages/ListStickerValidations.php create mode 100644 app/Filament/Resources/StickerValidationResource/Pages/ViewStickerValidation.php diff --git a/app/Filament/Resources/StickerValidationResource.php b/app/Filament/Resources/StickerValidationResource.php new file mode 100644 index 0000000..273e6a2 --- /dev/null +++ b/app/Filament/Resources/StickerValidationResource.php @@ -0,0 +1,165 @@ +schema([ + Section::make('') + ->schema([ + Forms\Components\Select::make('plant_id') + ->label('Plant') + ->reactive() + ->relationship('plant', 'name') + ->required(), + Forms\Components\Select::make('machine_id') + ->label('Work Center') + ->required() + ->reactive() + ->options(function (callable $get) { + $plantId = $get('plant_id'); + if (empty($plantId)) { + return []; + } + return Machine::where('plant_id', $plantId)->pluck('work_center', 'id'); + }) + ->searchable(), + Forms\Components\TextInput::make('production_order') + ->label('Production Order') + ->reactive() + ->extraAttributes([ + 'id' => 'production_order_input', + 'x-data' => '{ value: "" }', + 'x-model' => 'value', + 'wire:keydown.enter.prevent' => 'processProOrder(value)', + ]), + Forms\Components\TextInput::make('serial_number') + ->label('Serial Number') + ->reactive() + ->extraAttributes([ + 'id' => 'serial_number_input', + 'x-data' => '{ value: "" }', + 'x-model' => 'value', + 'wire:keydown.enter.prevent' => 'processSno(value)', + ]), + Forms\Components\Hidden::make('created_by') + ->label('Created By') + ->default(Filament::auth()->user()?->name), + Forms\Components\Hidden::make('updated_by') + ->label('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('machine.work_center') + ->label('Work Center') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('production_order') + ->label('Production Order') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('serial_number') + ->label('Serial Number') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('status') + ->label('Status') + ->alignCenter() + ->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(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListStickerValidations::route('/'), + 'create' => Pages\CreateStickerValidation::route('/create'), + 'view' => Pages\ViewStickerValidation::route('/{record}'), + 'edit' => Pages\EditStickerValidation::route('/{record}/edit'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } +} diff --git a/app/Filament/Resources/StickerValidationResource/Pages/CreateStickerValidation.php b/app/Filament/Resources/StickerValidationResource/Pages/CreateStickerValidation.php new file mode 100644 index 0000000..37b33f8 --- /dev/null +++ b/app/Filament/Resources/StickerValidationResource/Pages/CreateStickerValidation.php @@ -0,0 +1,298 @@ +getCancelFormAction(), + ]; + } + + protected function getRedirectUrl(): string + { + return $this->getResource()::getUrl('create'); + } + + + public function processProOrder($value) + { + $plantId = $this->form->getState()['plant_id']; + + $this->plantId = $plantId; + + $this->ref_number = $value; + + $this->dispatch('refreshEmptySticker', $plantId, $value); + + $this->dispatch('focus-serial-number'); + } + + public function processSno($serNo) + { + $plantId = $this->form->getState()['plant_id']; + + $this->plantId = $plantId; + + $workCenter = $this->form->getState()['machine_id']; + + $this->workCenter = $workCenter; + + $this->ref_number = $this->form->getState()['production_order']; + + $this->serNo = $serNo; + + $user = Filament::auth()->user(); + + $operatorName = $user->name; + + if (! preg_match('/^([a-zA-Z0-9]{6,})\|([1-9][a-zA-Z0-9]{8,})\|?$/', $this->serNo, $matches)) { + Notification::make() + ->danger() + ->title('Invalid Serial QR Format') + ->body('Scan valid Serial QR code proceed!
Sample formats are:
123456|1234567890123| OR 123456|1234567890123') + ->seconds(3) + ->send(); + + $this->dispatch('playWarnSound'); + + $this->form->fill([ + 'plant_id' => $this->plantId, + 'machine_id' => $this->workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + + $this->dispatch('focus-serial-number'); + + return; + } + + if (preg_match('/^([a-zA-Z0-9]{6,})\|([1-9][a-zA-Z0-9]{8,})\|?$/', $this->serNo, $matches)) { + $itemCode = $matches[1]; + $serialNumber = $matches[2]; + + $recFound = ProductionQuantity::where('plant_id', $this->plantId) + ->where('production_order', $this->ref_number) + ->where('serial_number', $serialNumber) + ->first(); + + if(!$recFound){ + Notification::make() + ->danger() + ->title('Unknown Serial Number') + ->body("Scanned serial number '$serialNumber' not found for the given plant and production order") + ->seconds(3) + ->send(); + $this->form->fill([ + 'plant_id' => $this->plantId, + 'machine_id' => $this->workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + return; + } + + $duplicate = StickerValidation::where('plant_id', $this->plantId) + ->where('production_order', $this->ref_number) + ->where('serial_number', $serialNumber) + ->first(); + + if ($duplicate) { + Notification::make() + ->danger() + ->title('Duplicate Serial Number') + ->body("Serial number $serialNumber already exists for this plant and production order!") + ->seconds(3) + ->send(); + + $this->form->fill([ + 'plant_id' => $this->plantId, + 'machine_id' => $this->workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + return; + } + + $itemC = Item::where('code', $itemCode) + ->where('plant_id',$this->plantId) + ->first(); + + $itemId = $itemC->id; + + $item = ItemCharacteristic::where('item_id', $itemId) + ->where('plant_id',$this->plantId) + ->first(); + + $itemI = $item->id; + + $mapping = StickerMappingMaster::where('plant_id', $this->plantId) + ->where('item_characteristic_id', $itemI) + ->first(); + + if (!$mapping) { + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No sticker mapping found for this item and plant.") + ->send(); + return; + } + + $stickers = []; + + for ($i = 1; $i <= 8; $i++) { + $machineColumn = "sticker{$i}_machine_id"; + $ipColumn = "sticker{$i}_print_ip"; + $stickerColumn = "sticker_structure{$i}_id"; + $itemColumn = "item_characteristic_id"; + + if ( + !empty($mapping->$machineColumn) && + !empty($mapping->$stickerColumn) + ) { + $stickers[] = [ + 'machine_id' => $mapping->$machineColumn, + 'sticker_id' => $mapping->$stickerColumn, + 'item_characteristic' => $mapping->$itemColumn, + 'print_ip' => $mapping->$ipColumn, + ]; + } + } + + if (empty($stickers)) { + Notification::make() + ->danger() + ->title('No Sticker Configuration Found') + ->body('No sticker and machine mappings configured for this item and plant.') + ->send(); + return; + } + + $urls = []; + + foreach ($stickers as $sticker) { + $urls[] = route('stickers1.pdf', [ + 'stickerId' => $sticker['sticker_id'], + 'plant_id' => $this->plantId, + 'item_characteristic_id' => $sticker['item_characteristic'], + 'serial_number' => $serialNumber, + ]); + } + + $this->dispatch('open-stickers-sequence', urls: $urls); + + // $pdfPath = storage_path('app/private/uploads/StickerTemplateOcr/multi.pdf'); + + // if (! file_exists($pdfPath)) { + // Notification::make() + // ->danger() + // ->title('Pdf Not Found') + // ->body("pdf file not exist.") + // ->send(); + // return; + // } + + // if (! $printerName) { + // Notification::make() + // ->danger() + // ->title('Printer Not Found') + // ->body("No CUPS printer configured for IP: $iotsPrintIp") + // ->send(); + // return; + // } + + // putenv('CUPS_SERVER=printer.iotsignin.com'); + + // $cmd = "lp -d " . escapeshellarg($printerName) + // . " -o fit-to-page " + // . escapeshellarg($pdfPath); + + // exec($cmd, $out, $status); + + // if ($status != 0) { + // Notification::make() + // ->danger() + // ->title('Print Failed') + // ->body('CUPS print command failed.') + // ->send(); + // return; + // } + + //dd($iotsPrintIp, $matchedSticker); + + StickerValidation::create([ + 'plant_id' => $this->plantId, + 'machine_id' => $this->workCenter, + 'production_order' => $this->ref_number ?? null, + 'serial_number' => $serialNumber, + 'status' => 'Printed', + // 'sticker_id' => $matchedSticker, + 'created_by' => $operatorName, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Notification::make() + ->success() + ->title('Sticker Recorded') + ->body("Item: $itemCode, Serial: $serialNumber recorded successfully!") + ->seconds(3) + ->send(); + + $this->form->fill([ + 'plant_id' => $this->plantId, + 'machine_id' => $this->workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + + $this->dispatch('refreshEmptySticker', $plantId, $this->ref_number); + + } + + } + + private function getPrinterNameByIp(string $ip): ?string + { + exec('lpstat -v', $output); + + foreach ($output as $line) { + // Example: + // device for TSC_WC_01: socket://192.168.1.50:9100 + if (str_contains($line, $ip)) { + preg_match('/device for (.+?):/', $line, $matches); + return $matches[1] ?? null; + } + } + + return null; + } + +} diff --git a/app/Filament/Resources/StickerValidationResource/Pages/EditStickerValidation.php b/app/Filament/Resources/StickerValidationResource/Pages/EditStickerValidation.php new file mode 100644 index 0000000..a783f95 --- /dev/null +++ b/app/Filament/Resources/StickerValidationResource/Pages/EditStickerValidation.php @@ -0,0 +1,22 @@ +