From f2a249bf35ff2d4ff4ea3ab901d9e66121d8ca45 Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Wed, 7 Oct 2026 09:15:36 +0530 Subject: [PATCH] Added migration and Updated model, resource, importer, exporter to add test_sequence_flag, test_started_at columns and Refactored validations and design in resource page for testing_panel_readings table and Added these columns to Motor Testing Panel Post API in TestingPanelController --- .../Exports/TestingPanelReadingExporter.php | 4 + .../Imports/TestingPanelReadingImporter.php | 11 ++ .../Resources/TestingPanelReadingResource.php | 148 +++++++++++++++++- .../Controllers/TestingPanelController.php | 2 + app/Models/TestingPanelReading.php | 2 + ...olumns_in_testing_panel_readings_table.php | 38 +++++ 6 files changed, 197 insertions(+), 8 deletions(-) create mode 100644 database/migrations/2026_10_06_125604_add_test_sequence_flag_and_test_started_at_columns_in_testing_panel_readings_table.php diff --git a/app/Filament/Exports/TestingPanelReadingExporter.php b/app/Filament/Exports/TestingPanelReadingExporter.php index 94a85f9e..eebdbb32 100644 --- a/app/Filament/Exports/TestingPanelReadingExporter.php +++ b/app/Filament/Exports/TestingPanelReadingExporter.php @@ -124,6 +124,10 @@ class TestingPanelReadingExporter extends Exporter ->label('RESULT'), ExportColumn::make('remark') ->label('REMARK'), + ExportColumn::make('test_sequence_flag') + ->label('TEST SEQUENCE FLAG'), + ExportColumn::make('test_started_at') + ->label('TEST STARTED AT'), ExportColumn::make('rework_count') ->label('REWORK COUNT'), ExportColumn::make('rework_winded') diff --git a/app/Filament/Imports/TestingPanelReadingImporter.php b/app/Filament/Imports/TestingPanelReadingImporter.php index e16f021c..9a29a345 100644 --- a/app/Filament/Imports/TestingPanelReadingImporter.php +++ b/app/Filament/Imports/TestingPanelReadingImporter.php @@ -251,6 +251,17 @@ class TestingPanelReadingImporter extends Importer ->label('REMARK') ->exampleHeader('REMARK') ->example('Testing Remark'), + ImportColumn::make('test_sequence_flag') + ->requiredMapping() + ->label('TEST SEQUENCE FLAG') + ->exampleHeader('TEST SEQUENCE FLAG') + ->example('0') + ->rules(['required']), + ImportColumn::make('test_started_at') + ->requiredMapping() + ->label('TEST STARTED AT') + ->exampleHeader('TEST STARTED AT') + ->example('01-01-2026 00:08:00'), ImportColumn::make('rework_count') ->requiredMapping() ->label('REWORK COUNT') diff --git a/app/Filament/Resources/TestingPanelReadingResource.php b/app/Filament/Resources/TestingPanelReadingResource.php index 4d5cca61..79c75252 100644 --- a/app/Filament/Resources/TestingPanelReadingResource.php +++ b/app/Filament/Resources/TestingPanelReadingResource.php @@ -193,6 +193,7 @@ class TestingPanelReadingResource extends Resource ->required(), Forms\Components\TextInput::make('output') ->label('Output ID') + ->placeholder('Enter Output ID') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -228,7 +229,8 @@ class TestingPanelReadingResource extends Resource }) ->required(), Forms\Components\TextInput::make('serial_number') - ->label('Serial Number') + ->label('Motor Serial Number') + ->placeholder('Enter Motor Serial Number') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -263,6 +265,7 @@ class TestingPanelReadingResource extends Resource ->required(), Forms\Components\TextInput::make('winded_serial_number') ->label('Winded Serial Number') + ->placeholder('Enter Winded Serial Number') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -293,7 +296,8 @@ class TestingPanelReadingResource extends Resource }; }), Forms\Components\TextInput::make('before_fr_volt') - ->label('Before FR Volt') + ->label('Before FR Voltage') + ->placeholder('Enter Before FR Voltage') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -302,6 +306,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_cur') ->label('Before FR Current') + ->placeholder('Enter Before FR Current') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -310,6 +315,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_pow') ->label('Before FR Power') + ->placeholder('Enter Before FR Power') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -318,6 +324,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_res_ry') ->label('Before FR Resistance RY') + ->placeholder('Enter Before FR Resistance RY') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -326,6 +333,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_res_yb') ->label('Before FR Resistance YB') + ->placeholder('Enter Before FR Resistance YB') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -334,6 +342,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_res_br') ->label('Before FR Resistance BR') + ->placeholder('Enter Before FR Resistance BR') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -342,6 +351,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_ir') ->label('Before FR IR') + ->placeholder('Enter Before FR IR') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -350,6 +360,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_ir_r') ->label('Before FR IR R') + ->placeholder('Enter Before FR IR R') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -358,6 +369,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_ir_y') ->label('Before FR IR Y') + ->placeholder('Enter Before FR IR Y') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -366,6 +378,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_ir_b') ->label('Before FR IR B') + ->placeholder('Enter Before FR IR B') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -374,6 +387,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_freq') ->label('Before FR Frequency') + ->placeholder('Enter Before FR Frequency') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -382,6 +396,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('before_fr_speed') ->label('Before FR Speed') + ->placeholder('Enter Before FR Speed') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -389,7 +404,8 @@ class TestingPanelReadingResource extends Resource $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('after_fr_vol') - ->label('After FR Volt') + ->label('After FR Voltage') + ->placeholder('Enter After FR Voltage') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -398,6 +414,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_cur') ->label('After FR Current') + ->placeholder('Enter After FR Current') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -406,6 +423,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_pow') ->label('After FR Power') + ->placeholder('Enter After FR Power') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -414,6 +432,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_hot') ->label('After FR IR Hot') + ->placeholder('Enter After FR IR Hot') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -422,6 +441,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_hot_r') ->label('After FR IR Hot R') + ->placeholder('Enter After FR IR Hot R') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -430,6 +450,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_hot_y') ->label('After FR IR Hot Y') + ->placeholder('Enter After FR IR Hot Y') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -438,6 +459,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_hot_b') ->label('After FR IR Hot B') + ->placeholder('Enter After FR IR Hot B') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -446,6 +468,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_cool') ->label('After FR IR Cool') + ->placeholder('Enter After FR IR Cool') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -454,6 +477,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_cool_r') ->label('After FR IR Cool R') + ->placeholder('Enter After FR IR Cool R') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -462,6 +486,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_cool_y') ->label('After FR IR Cool Y') + ->placeholder('Enter After FR IR Cool Y') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -470,6 +495,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_ir_cool_b') ->label('After FR IR Cool B') + ->placeholder('Enter After FR IR Cool B') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -478,6 +504,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_freq') ->label('After FR Frequency') + ->placeholder('Enter After FR Frequency') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -486,6 +513,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_speed') ->label('After FR Speed') + ->placeholder('Enter After FR Speed') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -494,6 +522,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('after_fr_leak_cur') ->label('After FR Leak Current') + ->placeholder('Enter After FR Leak Current') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -501,7 +530,8 @@ class TestingPanelReadingResource extends Resource $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('locked_rt_volt') - ->label('Locked RT Volt') + ->label('Locked RT Voltage') + ->placeholder('Enter Locked RT Voltage') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -510,6 +540,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('locked_rt_cur') ->label('Locked RT Current') + ->placeholder('Enter Locked RT Current') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -518,6 +549,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('locked_rt_pow') ->label('Locked RT Power') + ->placeholder('Enter Locked RT Power') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -525,7 +557,8 @@ class TestingPanelReadingResource extends Resource $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('no_load_pickup_volt') - ->label('No Load Pickup Volt') + ->label('No Load Pickup Voltage') + ->placeholder('Enter No Load Pickup Voltage') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -534,6 +567,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('room_temperature') ->label('Room Temperature') + ->placeholder('Enter Room Temperature') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -557,6 +591,7 @@ class TestingPanelReadingResource extends Resource ->required(), Forms\Components\TextInput::make('batch_number') ->label('Batch Number') + ->placeholder('Enter Batch Number') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) @@ -565,6 +600,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('batch_count') ->label('Batch Count') + ->placeholder('Enter Batch Count') ->columnSpan(1) ->reactive() ->integer() @@ -591,14 +627,39 @@ class TestingPanelReadingResource extends Resource ->required(), Forms\Components\TextInput::make('remark') ->label('Remark') + ->placeholder('Enter Remark') ->columnSpan(1) ->reactive() ->readOnly(fn (Get $get) => $get('id')) ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { $set('updated_by', Filament::auth()->user()?->name); }), + Forms\Components\TextInput::make('test_sequence_flag') + ->label('Test Sequence Flag') + ->placeholder('Enter Test Sequence Flag') + ->columnSpan(1) + ->reactive() + ->integer() + ->minValue(0) + ->maxValue(4) + ->default(4) + ->readOnly(fn (Get $get) => $get('id')) + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\DateTimePicker::make('test_started_at') + ->label('FR Started At') + ->reactive() + // ->live() + // ->format('d-m-Y H:i:s') + ->readOnly(fn (Get $get) => $get('id')) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('updated_by', Filament::auth()->user()?->name); + }), Forms\Components\TextInput::make('rework_count') ->label('Rework Count') + ->placeholder('Enter Rework Count') ->columnSpan(1) ->reactive() ->integer() @@ -610,6 +671,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\Select::make('rework_winded') ->label('Rework Winded Status') + ->placeholder('Enter Rework Winded Status') ->columnSpan(1) // ->nullable() ->reactive() @@ -628,6 +690,7 @@ class TestingPanelReadingResource extends Resource ->required(), Forms\Components\TextInput::make('update_count') ->label('Update Count') + ->placeholder('Enter Update Count') ->columnSpan(1) ->reactive() ->integer() @@ -639,6 +702,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('output_flag') ->label('Output Flag') + ->placeholder('Enter Output Flag') ->columnSpan(1) ->reactive() ->integer() @@ -651,6 +715,7 @@ class TestingPanelReadingResource extends Resource }), Forms\Components\TextInput::make('tested_by') ->label('Tested By') + ->placeholder('Enter Tested By') ->columnSpan(1) ->default(fn () => Filament::auth()->user()?->name) ->readOnly() @@ -866,6 +931,14 @@ class TestingPanelReadingResource extends Resource Tables\Columns\TextColumn::make('remark') ->label('Remark') ->alignCenter(), + Tables\Columns\TextColumn::make('test_sequence_flag') + ->label('Test Sequence Flag') + ->alignCenter(), + Tables\Columns\TextColumn::make('test_started_at') + ->label('FR Started At') + ->alignCenter() + ->sortable() + ->dateTime(), Tables\Columns\TextColumn::make('rework_count') ->label('Rework Count') ->alignCenter(), @@ -1116,11 +1189,11 @@ class TestingPanelReadingResource extends Resource TextInput::make('remark') ->label('Remark') ->reactive() - ->placeholder(placeholder: 'Enter Remark'), + ->placeholder('Enter Remark'), TextInput::make('batch_number') ->label('Batch Number') ->reactive() - ->placeholder(placeholder: 'Enter Batch Number'), + ->placeholder('Enter Batch Number'), Select::make('result') ->label('Search by Result') ->nullable() @@ -1135,6 +1208,30 @@ class TestingPanelReadingResource extends Resource ->mapWithKeys(fn ($value) => [$value => $value]) ->toArray(); }), + Select::make('test_sequence_flag') + ->label('Search by Test Sequence Flag') + ->nullable() + ->searchable() + ->reactive() + ->options(function (callable $get) { + $plantId = $get('Plant'); + + if (empty($plantId)) { + return []; + } + + return TestingPanelReading::where('plant_id', $plantId)->whereNotNull('test_sequence_flag')->distinct()->orderBy('test_sequence_flag')->pluck('test_sequence_flag', 'test_sequence_flag')->toArray(); // ->select('test_sequence_flag') + }), + DateTimePicker::make('test_started_from') + ->label('FR Started From') + ->placeholder('Select From DateTime') + ->reactive() + ->native(false), + DateTimePicker::make('test_started_to') + ->label('FR Started To') + ->placeholder('Select To DateTime') + ->reactive() + ->native(false), Select::make('tested_by') ->label('Tested By') ->nullable() @@ -1186,7 +1283,7 @@ class TestingPanelReadingResource extends Resource // dd($data); // Hide all records initially if no filters are applied - if (empty($data['Plant']) && empty($data['Line']) && empty($data['item_code']) && empty($data['subassembly_code']) && empty($data['machine_name']) && empty($data['item_description']) && empty($data['serial_number']) && empty($data['winded_serial_number']) && empty($data['output']) && empty($data['connection']) && empty($data['remark']) && empty($data['batch_no']) && empty($data['result']) && empty($data['tested_by']) && empty($data['created_from']) && empty($data['created_to']) && empty($data['updated_by']) && empty($data['updated_from']) && empty($data['updated_to'])) { + if (empty($data['Plant']) && empty($data['Line']) && empty($data['item_code']) && empty($data['subassembly_code']) && empty($data['machine_name']) && empty($data['item_description']) && empty($data['serial_number']) && empty($data['winded_serial_number']) && empty($data['output']) && empty($data['connection']) && empty($data['remark']) && empty($data['batch_number']) && empty($data['result']) && empty($data['test_sequence_flag']) && empty($data['test_started_from']) && empty($data['test_started_to']) && empty($data['tested_by']) && empty($data['created_from']) && empty($data['created_to']) && empty($data['updated_by']) && empty($data['updated_from']) && empty($data['updated_to'])) { return $query->whereRaw('1 = 0'); } @@ -1283,6 +1380,18 @@ class TestingPanelReadingResource extends Resource $query->where('result', $data['result']); } + if (! empty($data['test_sequence_flag'])) { + $query->where('test_sequence_flag', $data['test_sequence_flag']); + } + + if (! empty($data['test_started_from'])) { + $query->where('test_started_at', '>=', $data['test_started_from']); + } + + if (! empty($data['test_started_to'])) { + $query->where('test_started_at', '<=', $data['test_started_to']); + } + if (! empty($data['created_from'])) { $query->where('created_at', '>=', $data['created_from']); } @@ -1319,41 +1428,64 @@ class TestingPanelReadingResource extends Resource return 'Plant: Choose plant to filter records.'; } } + if (! empty($data['Line'])) { $indicators[] = 'Line Name: '.Line::where('id', $data['Line'])->value('name'); } + if (! empty($data['machine_name'])) { $indicators[] = 'Work Center: '.Machine::where('id', $data['machine_name'])->value('work_center'); } + if (! empty($data['item_code'])) { $indicators[] = 'Item Code: '.Item::where('id', $data['item_code'])->value('code'); } + if (! empty($data['subassembly_code'])) { $indicators[] = 'Subassembly Code: '.MotorTestingMaster::where('id', $data['subassembly_code'])->value('subassembly_code'); } + if (! empty($data['output'])) { $indicators[] = 'Output ID: '.$data['output']; } + if (! empty($data['item_description'])) { $item = Item::where('id', $data['item_description'])->first()?->description ?? null; $indicators[] = 'Model: '.$item; } + // if (!empty($data['phase'])) { // $indicators[] = 'Phase: ' . $data['phase']; // } + if (! empty($data['connection'])) { $indicators[] = 'Connection: '.$data['connection']; } + if (! empty($data['remark'])) { $indicators[] = 'Remark: '.$data['remark']; } + if (! empty($data['batch_number'])) { $indicators[] = 'Batch Number: '.$data['batch_number']; } + if (! empty($data['result'])) { $indicators[] = 'Result: '.$data['result']; } + if (! empty($data['test_sequence_flag'])) { + $indicators[] = 'Test Sequence Flag: '.$data['test_sequence_flag']; + } + + if (! empty($data['test_started_from'])) { + $indicators[] = 'Test Started From: '.$data['test_started_from']; + } + + if (! empty($data['test_started_to'])) { + $indicators[] = 'Test Started To: '.$data['test_started_to']; + } + if (! empty($data['serial_number'])) { $indicators[] = 'Serial Number: '.$data['serial_number']; } diff --git a/app/Http/Controllers/TestingPanelController.php b/app/Http/Controllers/TestingPanelController.php index cef11017..eade5bbd 100644 --- a/app/Http/Controllers/TestingPanelController.php +++ b/app/Http/Controllers/TestingPanelController.php @@ -325,6 +325,8 @@ class TestingPanelController extends Controller 'remark' => $serial['remark'] ?? null, 'rework_count' => $serial['rework_count'] ?? 0, 'rework_winded' => $serial['rework_winded'] ?? 0, + 'test_sequence_flag' => $serial['test_sequence_flag'] ?? '4', + 'test_started_at' => $serial['test_started_at'] ?? null, 'output_flag' => $serial['output_flag'] ?? 0, 'tested_by' => (($serial['tested_by'] == 'jothi') ? 'Admin' : $serial['tested_by']) ?? null, 'updated_by' => (($serial['updated_by'] == 'jothi') ? 'Admin' : $serial['updated_by']) ?? null, diff --git a/app/Models/TestingPanelReading.php b/app/Models/TestingPanelReading.php index 9450d85c..17891b1a 100644 --- a/app/Models/TestingPanelReading.php +++ b/app/Models/TestingPanelReading.php @@ -57,6 +57,8 @@ class TestingPanelReading extends Model 'batch_count', 'result', 'remark', + 'test_sequence_flag', + 'test_started_at', 'rework_count', 'rework_winded', 'update_count', diff --git a/database/migrations/2026_10_06_125604_add_test_sequence_flag_and_test_started_at_columns_in_testing_panel_readings_table.php b/database/migrations/2026_10_06_125604_add_test_sequence_flag_and_test_started_at_columns_in_testing_panel_readings_table.php new file mode 100644 index 00000000..0100f492 --- /dev/null +++ b/database/migrations/2026_10_06_125604_add_test_sequence_flag_and_test_started_at_columns_in_testing_panel_readings_table.php @@ -0,0 +1,38 @@ +