schema([ Forms\Components\Select::make('plant_id') ->relationship('plant', 'name') ->reactive() ->afterStateUpdated(fn (callable $set) => [ $set('item_id', null), $set('validationError', null), ]) ->required(), Forms\Components\Hidden::make('sticker_master_id') // ->relationship('stickerMaster', 'id') ->required(), Forms\Components\TextInput::make('production_order') ->required(), Forms\Components\TextInput::make('item_id') ->label('Item Code') ->placeholder('Scan the valid QR code') ->reactive() ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { // Reset visibility of all serial and part validation fields $serialFields = [ 'serial_number_motor', 'serial_number_pump', 'serial_number_pumpset', 'pack_slip_motor', 'pack_slip_pump', 'pack_slip_pumpset', 'name_plate_motor', 'name_plate_pump', 'name_plate_pumpset', 'tube_sticker_motor', 'tube_sticker_pump', 'tube_sticker_pumpset', 'warranty_card' ]; $partValidationColumns = [ 'part_validation1', 'part_validation2', 'part_validation3', 'part_validation4', 'part_validation5' ]; foreach ($serialFields as $field) { $set($field . '_visible', false); $set($field, null); } foreach ($partValidationColumns as $column) { $set($column . '_visible', false); $set($column, null); } // Proceed with validation logic for new scanned QR code if (!$state || trim($state) === '') { $set('validationError', null); return; } // Check if QR format contains '|' if (strpos($state, '|') === false) { $set('validationError', 'Scan valid QR code. (Ex: Item_Code|Serial_Number )'); return; } if (!preg_match('/^[a-zA-Z0-9]{6,}+\|[1-9][a-zA-Z0-9]{8,}+(\|)?$/', $state)) { if (strpos($state, '|') === false) { $set('validationError', 'Scan valid QR code. (Ex: Item_Code|Serial_Number )'); $set('item_id', null); $set('item_description', null); $set('serial_number', null); return; } else { $splits = explode('|', $state); $iCode = trim($splits[0]); $sNumber = isset($splits[1]) ? trim($splits[1]) : null; if (!ctype_alnum($iCode)) { $set('validationError', 'Item code must contain alpha-numeric values.'); return; } else if (strlen($iCode) < 6) { $set('validationError', 'Item code must be at least 6 digits.'); return; } else if (!ctype_alnum($sNumber)) { $set('validationError', 'Serial Number must contain alpha-numeric values.'); return; } else if (strlen($sNumber) < 9) { $set('validationError', 'Serial Number must be at least 9 digits.'); return; } } $set('validationError', 'Scan valid QR code. (Ex: Item_Code|Serial_Number )'); return; } else { $set('validationError', null); } $parts = explode('|', $state); $itemCode = trim($parts[0]); // Extract item code // 123456|123456789 $serialNumber = trim($parts[1]); // Store serial number before resetting fields $previousSerialNumber = $serialNumber; $previousItemCode = $itemCode; if (strlen($itemCode) < 6) { $set('validationError', 'Item code must be at least 6 digits.'); return; } else if (!ctype_alnum($itemCode)) { $set('validationError', 'Item Code should contain alpha-numeric values.'); $set('item_id', null); return; } else if ($serialNumber === '') { $set('validationError', 'Waiting for full QR scan...'); return; // Do not clear item_id, just wait for full input } else if (strlen($serialNumber) < 9) { $set('validationError', 'Serial Number must be at least 9 digits.'); return; } else if (!ctype_alnum($serialNumber)) { $set('validationError', 'Serial Number should contain alpha-numeric values.'); $set('item_id', null); return; } else { $set('validationError', null); } $plantId = $get('plant_id'); // Get selected plant if (!$plantId) { $set('validationError', 'Please select a plant first.'); $set('item_id', null); return; } // Check if the item exists for the selected plant $stickerMaster = \App\Models\StickerMaster::where('plant_id', $plantId) ->whereHas('item', function ($query) use ($itemCode) { $query->where('code', $itemCode); })->first(); if (!$stickerMaster) { $set('validationError', 'Item code does not exist in master data.'); $set('sticker_master_id', null); return; } else { $set('sticker_master_id', $stickerMaster->id); $set('item_id', $itemCode); } // Check if user input matches the database values foreach ($partValidationColumns as $field) { if ($get("{$field}_visible")) { // Only validate visible fields $userInput = $get($field); // Get user input $expectedValue = $stickerMaster->$field; // Get expected value from DB if ($userInput !== null && $userInput !== $expectedValue) { $set('validationError', "Invalid input for $field. Expected: $expectedValue"); return; // Stop execution if any validation fails } } } // $serialExists = QualityValidation::where('sticker_master_id', $stickerMaster->id) // ->where(function ($query) use ($serialNumber, $serialFields) { // foreach ($serialFields as $column) { // $query->orWhere($column, $serialNumber); // } // })->exists(); // if ($serialExists) { // $set('validationError', 'Already scanning process completed.'); // $set('item_id', "$previousItemCode|$previousSerialNumber"); // Restore original QR code // return; // } // Check if the serial number exists in any column of any row $serialExists = QualityValidation::where(function ($query) use ($serialNumber, $serialFields) { foreach ($serialFields as $column) { $query->orWhere($column, $serialNumber); } })->exists(); if ($serialExists) { $set('validationError', 'Serial number already exists in quality validation.'); // Restore the serial number before returning $set('item_id', "$itemCode|$previousSerialNumber"); // Reinsert full QR code return; } // Clear validation error if all inputs match $set('validationError', null); // Filter columns with value `1` $visibleColumns = []; foreach ($serialFields as $column) { if ($stickerMaster->$column === 1) { $visibleColumns[] = $column; } } // Filter part validation columns that are not `null` $visiblePartValidations = []; foreach ($partValidationColumns as $column) { if ($stickerMaster->$column !== null) { $visiblePartValidations[] = $column; } } foreach ($serialFields as $column) { if ($stickerMaster->$column == 1) { $set($column . '_visible', true); } else { $set($column . '_visible', false); } } foreach ($partValidationColumns as $column) { if ($stickerMaster->$column !== null) { $set($column . '_visible', true); // Separate key for visibility } else { $set($column . '_visible', false); } } // Assign serial number to only visible text inputs foreach ($serialFields as $field) { if ($get("{$field}_visible")) { $set($field, $serialNumber); } } }) ->extraAttributes(fn ($get) => [ 'class' => $get('validationError') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('validationError') ? $get('validationError') : null) ->hintColor('danger'), Forms\Components\TextInput::make('serial_number_motor') ->hidden(fn (callable $get) => !$get('serial_number_motor_visible')) // Controls visibility ->default(''), // Keeps input empty Forms\Components\TextInput::make('serial_number_pump') ->hidden(fn (callable $get) => !$get('serial_number_pump_visible')) ->default(''), Forms\Components\TextInput::make('serial_number_pumpset') ->hidden(fn (callable $get) => !$get('serial_number_pumpset_visible')) ->default(''), Forms\Components\TextInput::make('pack_slip_motor') ->hidden(fn (callable $get) => !$get('pack_slip_motor_visible')) ->default(''), Forms\Components\TextInput::make('pack_slip_pump') ->hidden(fn (callable $get) => !$get('pack_slip_pump_visible')) ->default(''), Forms\Components\TextInput::make('pack_slip_pumpset') ->hidden(fn (callable $get) => !$get('pack_slip_pumpset_visible')) ->default(''), Forms\Components\TextInput::make('name_plate_motor') ->hidden(fn (callable $get) => !$get('name_plate_motor_visible')) ->default(''), Forms\Components\TextInput::make('name_plate_pump') ->hidden(fn (callable $get) => !$get('name_plate_pump_visible')) ->default(''), Forms\Components\TextInput::make('name_plate_pumpset') ->hidden(fn (callable $get) => !$get('name_plate_pumpset_visible')) ->default(''), Forms\Components\TextInput::make('tube_sticker_motor') ->hidden(fn (callable $get) => !$get('tube_sticker_motor_visible')) ->default(''), Forms\Components\TextInput::make('tube_sticker_pump') ->hidden(fn (callable $get) => !$get('tube_sticker_pump_visible')) ->default(''), Forms\Components\TextInput::make('tube_sticker_pumpset') ->hidden(fn (callable $get) => !$get('tube_sticker_pumpset_visible')) ->default(''), Forms\Components\TextInput::make('warranty_card') ->hidden(fn (callable $get) => !$get('warranty_card_visible')) ->default(''), Forms\Components\TextInput::make('part_validation1') ->hidden(fn (callable $get) => !$get('part_validation1_visible')) ->default('') ->reactive() ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $stickerMasterId = $get('sticker_master_id'); if (!$stickerMasterId) { return; } $stickerMaster = \App\Models\StickerMaster::find($stickerMasterId); if (!$stickerMaster) { return; } $expectedValue = $stickerMaster->part_validation1; // If input is empty, reset the error if ($state === null || trim($state) === '') { $set('part_validation1_error', null); return; } if ($state === $expectedValue) { $set('part_validation1_error', null); } else { $set('part_validation1_error', "Invalid input for part validation 1."); // Expected: $expectedValue } }) ->extraAttributes(fn ($get) => [ 'class' => $get('part_validation1_error') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('part_validation1_error')) ->hintColor('danger'), Forms\Components\TextInput::make('part_validation2') ->hidden(fn (callable $get) => !$get('part_validation2_visible')) ->default('') ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $stickerMasterId = $get('sticker_master_id'); if (!$stickerMasterId) { return; } $stickerMaster = \App\Models\StickerMaster::find($stickerMasterId); if (!$stickerMaster) { return; } $expectedValue = $stickerMaster->part_validation2; // If input is empty, reset the error if ($state === null || trim($state) === '') { $set('part_validation2_error', null); return; } // If input is empty, do not show an error if ($state === $expectedValue) { $set('part_validation2_error', null); } else { $set('part_validation2_error', "Invalid input for part validation 2."); // Expected: $expectedValue } }) ->extraAttributes(fn ($get) => [ 'class' => $get('part_validation2_error') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('part_validation2_error')) ->hintColor('danger'), Forms\Components\TextInput::make('part_validation3') ->hidden(fn (callable $get) => !$get('part_validation3_visible')) ->default('') ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $stickerMasterId = $get('sticker_master_id'); if (!$stickerMasterId) { return; } $stickerMaster = \App\Models\StickerMaster::find($stickerMasterId); if (!$stickerMaster) { return; } $expectedValue = $stickerMaster->part_validation3; // If input is empty, reset the error if ($state === null || trim($state) === '') { $set('part_validation3_error', null); return; } // If input is empty, do not show an error if ($state === $expectedValue) { $set('part_validation3_error', null); } else { $set('part_validation3_error', "Invalid input for part validation 3."); // Expected: $expectedValue } }) ->extraAttributes(fn ($get) => [ 'class' => $get('part_validation3_error') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('part_validation3_error')) ->hintColor('danger'), Forms\Components\TextInput::make('part_validation4') ->hidden(fn (callable $get) => !$get('part_validation4_visible')) ->default('') ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $stickerMasterId = $get('sticker_master_id'); if (!$stickerMasterId) { return; } $stickerMaster = \App\Models\StickerMaster::find($stickerMasterId); if (!$stickerMaster) { return; } $expectedValue = $stickerMaster->part_validation4; // If input is empty, reset the error if ($state === null || trim($state) === '') { $set('part_validation4_error', null); return; } // If input is empty, do not show an error if ($state === $expectedValue) { $set('part_validation4_error', null); } else { $set('part_validation4_error', "Invalid input for part validation 4."); // Expected: $expectedValue } }) ->extraAttributes(fn ($get) => [ 'class' => $get('part_validation4_error') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('part_validation4_error')) ->hintColor('danger'), Forms\Components\TextInput::make('part_validation5') ->hidden(fn (callable $get) => !$get('part_validation5_visible')) ->default('') ->required() ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $stickerMasterId = $get('sticker_master_id'); if (!$stickerMasterId) { return; } $stickerMaster = \App\Models\StickerMaster::find($stickerMasterId); if (!$stickerMaster) { return; } $expectedValue = $stickerMaster->part_validation4; // If input is empty, reset the error if ($state === null || trim($state) === '') { $set('part_validation5_error', null); return; } // If input is empty, do not show an error if ($state === $expectedValue) { $set('part_validation5_error', null); } else { $set('part_validation5_error', "Invalid input for part validation 5."); // Expected: $expectedValue } }) ->extraAttributes(fn ($get) => [ 'class' => $get('part_validation5_error') ? 'border-red-500' : '', ]) ->hint(fn ($get) => $get('part_validation5_error')) ->hintColor('danger'), ]); } public static function table(Table $table): Table { return $table ->searchable() ->columns([ Tables\Columns\TextColumn::make('id') ->label('ID') ->numeric() ->sortable(), Tables\Columns\TextColumn::make('plant.name') ->sortable(), Tables\Columns\TextColumn::make('stickerMaster.item.code') ->label('Item Code') ->sortable(), Tables\Columns\TextColumn::make('production_order') ->label('Production Order') ->sortable(), Tables\Columns\TextColumn::make('serial_number_motor') ->sortable(), Tables\Columns\TextColumn::make('serial_number_pump') ->sortable(), Tables\Columns\TextColumn::make('serial_number_pumpset') ->sortable(), Tables\Columns\TextColumn::make('pack_slip_motor') ->sortable(), Tables\Columns\TextColumn::make('pack_slip_pump') ->sortable(), Tables\Columns\TextColumn::make('pack_slip_pumpset') ->sortable(), Tables\Columns\TextColumn::make('name_plate_motor') ->sortable(), Tables\Columns\TextColumn::make('name_plate_pump') ->sortable(), Tables\Columns\TextColumn::make('name_plate_pumpset') ->sortable(), Tables\Columns\TextColumn::make('tube_sticker_motor') ->sortable(), Tables\Columns\TextColumn::make('tube_sticker_pump') ->sortable(), Tables\Columns\TextColumn::make('tube_sticker_pumpset') ->sortable(), Tables\Columns\TextColumn::make('warranty_card') ->sortable(), Tables\Columns\TextColumn::make('part_validation1') ->sortable(), Tables\Columns\TextColumn::make('part_validation2') ->sortable(), Tables\Columns\TextColumn::make('part_validation3') ->sortable(), Tables\Columns\TextColumn::make('part_validation4') ->sortable(), Tables\Columns\TextColumn::make('part_validation5') ->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(), SelectFilter::make('item_code') ->relationship('stickerMaster.item', 'code') ->label('Filter by item code') ->searchable(), Filter::make('production_order') ->label('Filter by Production Order') ->form([ TextInput::make('production_order') ->placeholder('Enter Production Order'), ]) ->query(function ($query, array $data) { return $query ->when( $data['production_order'] ?? null, fn ($q) => $q->where('production_order', 'like', '%' . $data['production_order'] . '%') ); }) // This function adds indicators to show applied filters in the UI. // It helps users see what filters are currently active. ->indicateUsing(function (array $data) { return empty($data['production_order']) ? [] : ['Production Order: ' . $data['production_order']]; }), // Created Date Range Filter Filter::make('created_at') ->form([ DateTimePicker::make('created_from') ->label('Created From') ->native(false), // Optional: Use a nice date picker UI DateTimePicker::make('created_to') ->label('Created To') ->native(false), ]) ->query(function ($query, array $data) { return $query ->when( $data['created_from'] ?? null, fn ($q) => $q->where('created_at', '>=', $data['created_from']) ) ->when( $data['created_to'] ?? null, fn ($q) => $q->where('created_at', '<=', $data['created_to']) ); }) ->indicateUsing(function (array $data) { $indicators = []; if (!empty($data['created_from'])) { $indicators[] = 'From: ' . $data['created_from']; } if (!empty($data['created_to'])) { $indicators[] = 'To: ' . $data['created_to']; } return $indicators; }), ]) ->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\ListQualityValidations::route('/'), 'create' => Pages\CreateQualityValidation::route('/create'), 'view' => Pages\ViewQualityValidation::route('/{record}'), 'edit' => Pages\EditQualityValidation::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery() ->withoutGlobalScopes([ SoftDeletingScope::class, ]); } }