diff --git a/app/Filament/Exports/BeforeTestReadingExporter.php b/app/Filament/Exports/BeforeTestReadingExporter.php new file mode 100644 index 0000000..0e51805 --- /dev/null +++ b/app/Filament/Exports/BeforeTestReadingExporter.php @@ -0,0 +1,83 @@ +label('ID'), + ExportColumn::make('no') + ->label('NO') + ->state(function ($record) use (&$rowNumber) { + // Increment and return the row number + return ++$rowNumber; + }), + ExportColumn::make('plant.code') + ->label('PLANT CODE'), + ExportColumn::make('line.name') + ->label('LINE NAME'), + ExportColumn::make('machine.name') + ->label('MACHINE NAME'), + ExportColumn::make('motorTestingMaster.item.code') + ->label('ITEM CODE'), + ExportColumn::make('motorTestingMaster.item.description') + ->label('MODEL DESCRIPTION'), + ExportColumn::make('serial_number') + ->label('SERIAL NUMBER'), + ExportColumn::make('motorTestingMaster.kw') + ->label('KW'), + ExportColumn::make('motorTestingMaster.hp') + ->label('HP'), + ExportColumn::make('motorTestingMaster.phase') + ->label('PHASE'), + ExportColumn::make('motorTestingMaster.connection') + ->label('CONNECTION'), + ExportColumn::make('motorTestingMaster.isi_model') + ->label('ISI MODEL'), + ExportColumn::make('before_fr_res_ry') + ->label('BEFORE FR RESISTANCE RY'), + ExportColumn::make('before_fr_res_yb') + ->label('BEFORE FR RESISTANCE YB'), + ExportColumn::make('before_fr_res_br') + ->label('BEFORE FR RESISTANCE BR'), + ExportColumn::make('before_fr_ir') + ->label('BEFORE FR IR'), + ExportColumn::make('tested_by') + ->label('TESTED BY'), + ExportColumn::make('updated_by') + ->label('UPDATED BY'), + ExportColumn::make('created_at') + ->label('CREATED AT'), + ExportColumn::make('updated_at') + ->label('UPDATED AT'), + ExportColumn::make('scanned_at') + ->label('SCANNED AT'), + ExportColumn::make('deleted_at') + ->enabledByDefault(false) + ->label('DELETED AT'), + ]; + } + + public static function getCompletedNotificationBody(Export $export): string + { + $body = 'Your before test reading export has completed and '.number_format($export->successful_rows).' '.str('row')->plural($export->successful_rows).' exported.'; + + if ($failedRowsCount = $export->getFailedRowsCount()) { + $body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to export.'; + } + + return $body; + } +} diff --git a/app/Filament/Resources/BeforeTestReadingResource.php b/app/Filament/Resources/BeforeTestReadingResource.php new file mode 100644 index 0000000..3bbeaec --- /dev/null +++ b/app/Filament/Resources/BeforeTestReadingResource.php @@ -0,0 +1,736 @@ +schema([ + Section::make('') + ->schema([ + Forms\Components\Select::make('plant_id') + ->label('Plant Name') + ->relationship('plant', 'name') + ->columnSpan(1) // (['default' => 1, 'sm' => 2]) + ->searchable() + ->required() + ->reactive() + ->options(function (callable $get) { + $userHas = Filament::auth()->user()->plant_id; + + return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray(); + }) + ->default(function () { + return optional(BeforeTestReading::latest()->first())->plant_id ?? null; + }) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $plantId = $get('plant_id'); + if (! $plantId) { + $set('line_id', null); + $set('motor_testing_master_id', null); + $set('machine_id', null); + $set('tPrError', 'Please select a plant first.'); + + return; + } else { + $set('line_id', null); + $set('motor_testing_master_id', null); + $set('machine_id', null); + $set('tPrError', null); + } + + $set('updated_by', Filament::auth()->user()?->name); + }) + ->extraAttributes(fn ($get) => [ + 'class' => $get('tPrError') ? 'border-red-500' : '', + ]) + ->hint(fn ($get) => $get('tPrError') ? $get('tPrError') : null) + ->hintColor('danger'), + Forms\Components\Select::make('line_id') + ->label('Line Name') + // ->relationship('line', 'name') + ->searchable() + ->options(function (callable $get) { + $plantId = $get('plant_id'); + if (! $plantId) { + return []; + } + + return Line::where('plant_id', $plantId) + ->pluck('name', 'id') + ->toArray(); + }) + ->default(function () { + return optional(BeforeTestReading::latest()->first())->line_id ?? null; + }) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->required() + ->reactive() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('motor_testing_master_id', null); + $set('machine_id', null); + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\Select::make('machine_id') + ->label('Work Center') + // ->relationship('machine', 'work_center') + ->searchable() + ->options(function (callable $get) { + $lineId = $get('line_id'); + if (! $lineId) { + return []; + } + + // Only show machines for the selected line + return Machine::where('line_id', $lineId) + ->pluck('work_center', 'id') + ->toArray(); + }) + ->default(function () { + return optional(BeforeTestReading::latest()->first())->machine_id ?? null; + }) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->required() + ->reactive() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\Select::make('motor_testing_master_id') + ->label('Item Code') + // ->relationship('motorTestingMaster', 'item.code') + // ->options(function (callable $get) { + // $plantId = $get('plant_id'); + // if (!$plantId) { + // return []; + // } + // return MotorTestingMaster::with('item') + // ->where('plant_id', $plantId) + // ->get() + // //->filter(fn ($mtm) => $mtm->item) + // ->pluck('item.code', 'id') + // ->toArray(); + // }) + ->options(function (callable $get) { + $plantId = $get('plant_id'); + if (! $plantId) { + return []; + } + + return MotorTestingMaster::query() + ->join('items', 'motor_testing_masters.item_id', '=', 'items.id') + ->where('motor_testing_masters.plant_id', $plantId) + ->select('motor_testing_masters.id', 'items.code') + ->pluck('items.code', 'motor_testing_masters.id') + ->toArray(); + }) + // ->getOptionLabelUsing(fn ($value) => + // MotorTestingMaster::with('item')->find($value)?->item?->code + // ) + ->required() + ->searchable() + ->reactive() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('serial_number') + ->label('Serial Number') + ->required() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('before_fr_res_ry') + ->label('Before FR Resistance RY') + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('before_fr_res_yb') + ->label('Before FR Resistance YB') + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('before_fr_res_br') + ->label('Before FR Resistance BR') + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('before_fr_ir') + ->label('Before FR IR') + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\TextInput::make('tested_by') + ->default(fn () => Filament::auth()->user()?->name) + ->readOnly() + ->required(), + Forms\Components\Hidden::make('updated_by') + ->default(fn () => Filament::auth()->user()?->name) + ->required(), + Forms\Components\TextInput::make('id') + ->hidden() + ->readOnly(), + ]) + ->columns(['default' => 1, 'sm' => 2]), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + // Tables\Columns\TextColumn::make('id') + // ->label('ID') + // ->numeric() + // ->sortable(), + 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.name') + ->label('Plant Name') + ->alignCenter(), + Tables\Columns\TextColumn::make('line.name') + ->label('Line Name') + ->alignCenter(), + Tables\Columns\TextColumn::make('machine.work_center') + ->label('Work Center') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.item.code') + ->label('Item Code') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.subassembly_code') + ->label('Subassembly Code') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.item.description') + ->label('Model') + ->alignCenter(), + Tables\Columns\TextColumn::make('serial_number') + ->label('Serial Number') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('motorTestingMaster.kw') + ->label('KW') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.hp') + ->label('HP') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.phase') + ->label('Phase') + ->alignCenter(), + Tables\Columns\TextColumn::make('motorTestingMaster.connection') + ->label('Connection') + ->alignCenter(), + Tables\Columns\IconColumn::make('motorTestingMaster.isi_model') + ->label('ISI Model') + ->alignCenter() + ->boolean(), + Tables\Columns\TextColumn::make('before_fr_res_ry') + ->label('Before FR Resistance RY') + ->alignCenter(), + Tables\Columns\TextColumn::make('before_fr_res_yb') + ->label('Before FR Resistance YB') + ->alignCenter(), + Tables\Columns\TextColumn::make('before_fr_res_br') + ->label('Before FR Resistance BR') + ->alignCenter(), + Tables\Columns\TextColumn::make('before_fr_ir') + ->label('Before FR IR') + ->alignCenter(), + Tables\Columns\TextColumn::make('scanned_at') + ->label('Scanned At') + ->alignCenter() + ->sortable() + ->dateTime(), + Tables\Columns\TextColumn::make('created_at') + ->label('Created At') + ->alignCenter() + ->dateTime() + ->sortable(), + Tables\Columns\TextColumn::make('tested_by') + ->label('Tested By') + ->alignCenter() + ->numeric(), + Tables\Columns\TextColumn::make('updated_at') + ->label('Updated At') + ->alignCenter() + ->sortable() + ->dateTime(), + Tables\Columns\TextColumn::make('updated_by') + ->label('Updated By') + ->alignCenter() + ->numeric(), + Tables\Columns\TextColumn::make('deleted_at') + ->label('Deleted At') + ->alignCenter() + ->sortable() + ->dateTime() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + Tables\Filters\TrashedFilter::make(), + Filter::make('advanced_filters') + ->label('Advanced Filters') + ->form([ + Select::make('Plant') + ->label('Search by Plant Name') + ->searchable() + ->nullable() + ->options(function () { + // return Plant::pluck('name', 'id'); + $userHas = Filament::auth()->user()->plant_id; + + if ($userHas && strlen($userHas) > 0) { + return Plant::where('id', $userHas)->pluck('name', 'id')->toArray(); + } else { + return Plant::whereHas('beforeTestReadings', function ($query) { + $query->whereNotNull('id'); + })->orderBy('code')->pluck('name', 'id'); + } + + // return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray(); + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('Line', null); + $set('item_code', null); + + }), + Select::make('Line') + ->label('Search by Line Name') + ->searchable() + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if (! $plantId) { + return []; + } + + return Line::where('plant_id', $plantId) + ->pluck('name', 'id') + ->toArray(); + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('item_code', null); + }), + Select::make('machine_name') + ->label('Search by Work Center') + ->searchable() + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + $lineId = $get('Line'); + + if (! $plantId || ! $lineId) { + return []; + } + + return Machine::where('plant_id', $plantId) + ->where('line_id', $lineId) + ->pluck('work_center', 'id') + ->toArray(); + }) + ->reactive(), + Select::make('item_code') + ->label('Search by Item Code') + ->searchable() + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if ($plantId) { + return Item::where('plant_id', $plantId) + ->whereHas('motorTestingMasters') + ->pluck('code', 'id') + ->toArray(); + } else { + return []; + // return Item::whereHas('motorTestingMasters') + // ->pluck('code', 'id') + // ->toArray(); + } + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('item_description', null); + }), + TextInput::make('serial_number') + ->label('Serial Number') + ->reactive() + ->placeholder('Enter Serial Number'), + Select::make('subassembly_code') + ->label('Search by Subassembly Code') + ->searchable() + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if ($plantId) { + return MotorTestingMaster::whereHas('beforeTestReadings', function ($query) { + $query->whereNotNull('id'); + })->whereNotNull('subassembly_code')->orderBy('subassembly_code')->pluck('subassembly_code', 'id'); + } else { + return []; + // return Item::whereHas('motorTestingMasters') + // ->pluck('code', 'id') + // ->toArray(); + } + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('item_description', null); + }), + Select::make('item_description') + ->label('Search by Model') + ->searchable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + + // $query = Item::query(); + // if ($plantId) { + // $query->where('plant_id', $plantId); + // } + + $plantId = $get('Plant'); + if ($plantId) { + return Item::where('plant_id', $plantId) + ->whereHas('motorTestingMasters') + ->pluck('description', 'id') + ->toArray(); + } else { + return []; + // return Item::whereHas('motorTestingMasters') + // ->pluck('description', 'id') + // ->toArray(); + } + // return $query->pluck('description', 'description')->toArray(); + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('item_code', null); + }), + Select::make('connection') + ->label('Connection') + ->required() + ->default('Star') + ->options(function (callable $get) { + $plantId = $get('Plant'); + if ($plantId) { + return Configuration::where('plant_id', $plantId) + ->where('c_name', 'MOTOR_CONNECTION') + ->orderBy('created_at') + ->pluck('c_value', 'c_value') + ->toArray(); + } else { + return Configuration::where('c_name', 'MOTOR_CONNECTION') + ->orderBy('created_at') + ->pluck('c_value', 'c_value') + ->toArray(); + } + }) + ->selectablePlaceholder(false) + ->reactive(), + Select::make('tested_by') + ->label('Tested By') + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if (! $plantId) { + return BeforeTestReading::whereNotNull('tested_by')->select('tested_by')->distinct()->pluck('tested_by', 'tested_by'); + } else { + return BeforeTestReading::where('plant_id', $plantId)->whereNotNull('tested_by')->select('tested_by')->distinct()->pluck('tested_by', 'tested_by'); + } + }) + ->searchable() + ->reactive(), + DateTimePicker::make(name: 'created_from') + ->label('Created From') + ->placeholder(placeholder: 'Select From DateTime') + ->reactive() + ->native(false), + DateTimePicker::make('created_to') + ->label('Created To') + ->placeholder(placeholder: 'Select To DateTime') + ->reactive() + ->native(false), + Select::make('updated_by') + ->label('Updated By') + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if (! $plantId) { + return BeforeTestReading::whereNotNull('updated_by')->select('updated_by')->distinct()->pluck('updated_by', 'updated_by'); + } else { + return BeforeTestReading::where('plant_id', $plantId)->whereNotNull('updated_by')->select('updated_by')->distinct()->pluck('updated_by', 'updated_by'); + } + }) + ->searchable() + ->reactive(), + DateTimePicker::make(name: 'updated_from') + ->label('Updated From') + ->placeholder(placeholder: 'Select From DateTime') + ->reactive() + ->native(false), + DateTimePicker::make('updated_to') + ->label('Updated To') + ->placeholder(placeholder: 'Select To DateTime') + ->reactive() + ->native(false), + ]) + ->query(function ($query, array $data) { + + // 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['connection']) && 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'); + } + + // && empty($data['phase']) + + if (! empty($data['Plant'])) { + $query->where('plant_id', $data['Plant']); + } else { + $userHas = Filament::auth()->user()->plant_id; + + if ($userHas && strlen($userHas) > 0) { + return $query->whereRaw('1 = 0'); + } + } + + if (! empty($data['Line'])) { + $query->where('line_id', $data['Line']); + } + + if (! empty($data['item_code'])) { + // $query->where('item_id', $data['item_code']); + $query->whereHas('motorTestingMaster', function ($subQuery) use ($data) { + $subQuery->where('item_id', $data['item_code']); + }); + } + + if (! empty($data['subassembly_code'])) { + $query->where('motor_testing_master_id', $data['subassembly_code']); + } + + if (! empty($data['machine_name'])) { + $query->where('machine_id', $data['machine_name']); + } + + if (! empty($data['serial_number'])) { + $query->where('serial_number', 'like', '%'.$data['serial_number'].'%'); + } + + if (! empty($data['item_description'])) { + $itemId = $data['item_description']; // Item::where('description', $data['item_description'])->first()?->id ?? null; + + if ($itemId) { // $item + $mastId = MotorTestingMaster::where('item_id', $itemId)->first()?->id ?? null; + if ($mastId) { // $item + $motId = BeforeTestReading::where('motor_testing_master_id', $mastId)->first()?->id ?? null; + if ($motId) { // $item + $query->where('motor_testing_master_id', $mastId); + // $query->whereHas('motorTestingMaster', function ($subQuery) use ($itemId) { + // $subQuery->where('item_id', $itemId); //$item->id + // }); + } else { + $query->whereRaw('1 = 0'); + } + } else { + $query->whereRaw('1 = 0'); + } + } else { + $query->whereRaw('1 = 0'); + } + } + + // if (!empty($data['phase'])) + // { + // //$query->where('phase',$data['phase']); + // $query->whereHas('motorTestingMaster', function ($subQuery) use ($data) { + // $subQuery->where('phase', $data['phase']); + // }); + // } + + if (! empty($data['connection'])) { + // $query->where('connection',$data['connection']); + $query->whereHas('motorTestingMaster', function ($subQuery) use ($data) { + $subQuery->where('connection', $data['connection']); + }); + } + + if (! empty($data['created_from'])) { + $query->where('created_at', '>=', $data['created_from']); + } + + if (! empty($data['created_to'])) { + $query->where('created_at', '<=', $data['created_to']); + } + + if (! empty($data['tested_by'])) { + $query->where('tested_by', $data['tested_by']); + } + + if (! empty($data['updated_from'])) { + $query->where('updated_at', '>=', $data['updated_from']); + } + + if (! empty($data['updated_to'])) { + $query->where('updated_at', '<=', $data['updated_to']); + } + + if (! empty($data['updated_by'])) { + $query->where('updated_by', $data['updated_by']); + } + }) + ->indicateUsing(function (array $data) { + $indicators = []; + + if (! empty($data['Plant'])) { + $indicators[] = 'Plant Name: '.Plant::where('id', $data['Plant'])->value('name'); + } else { + $userHas = Filament::auth()->user()->plant_id; + + if ($userHas && strlen($userHas) > 0) { + 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['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['serial_number'])) { + $indicators[] = 'Serial Number: '.$data['serial_number']; + } + + if (! empty($data['tested_by'])) { + $indicators[] = 'Tested By: '.$data['tested_by']; + } + + if (! empty($data['created_from'])) { + $indicators[] = 'Created From: '.$data['created_from']; + } + + if (! empty($data['created_to'])) { + $indicators[] = 'Created To: '.$data['created_to']; + } + + if (! empty($data['updated_by'])) { + $indicators[] = 'Updated By: '.$data['updated_by']; + } + + if (! empty($data['updated_from'])) { + $indicators[] = 'Updated From: '.$data['updated_from']; + } + + if (! empty($data['updated_to'])) { + $indicators[] = 'Updated To: '.$data['updated_to']; + } + + return $indicators; + }), + ]) + ->filtersFormMaxHeight('280px') + ->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([ + ExportAction::make() + ->label('Export Before Test Readings') + ->color('warning') + ->exporter(BeforeTestReadingExporter::class) + ->visible(function () { + return Filament::auth()->user()->can('view export before test reading'); + }), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListBeforeTestReadings::route('/'), + 'create' => Pages\CreateBeforeTestReading::route('/create'), + 'view' => Pages\ViewBeforeTestReading::route('/{record}'), + 'edit' => Pages\EditBeforeTestReading::route('/{record}/edit'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } +} diff --git a/app/Filament/Resources/BeforeTestReadingResource/Pages/CreateBeforeTestReading.php b/app/Filament/Resources/BeforeTestReadingResource/Pages/CreateBeforeTestReading.php new file mode 100644 index 0000000..857e9d3 --- /dev/null +++ b/app/Filament/Resources/BeforeTestReadingResource/Pages/CreateBeforeTestReading.php @@ -0,0 +1,12 @@ +id; + $plantName = $plant->name; if ($data['line_name'] == null || $data['line_name'] == '') { return response()->json([ @@ -203,12 +205,12 @@ class TestingPanelController extends Controller if (! empty($uniqueInvalidCodes)) { - // return response("Item codes : ". implode(', ', $uniqueInvalidCodes)." not found in motor testing master for the specified plant {$plant->name}", 400) + // return response("Item codes : ". implode(', ', $uniqueInvalidCodes)." not found in motor testing master for the specified plant {$plantName}", 400) // ->header('Content-Type', 'text/plain'); return response()->json([ 'status_code' => 'ERROR', - 'status_description' => 'Item codes : '.implode(', ', $uniqueInvalidCodes)." not found in master for the specified plant : '{$plant->name}'!", + 'status_description' => 'Item codes : '.implode(', ', $uniqueInvalidCodes)." not found in master for the specified plant : '{$plantName}'!", ], 404); } @@ -660,6 +662,257 @@ class TestingPanelController extends Controller } } + /** + * Store a newly created before test status in storage. + */ + public function storeBeforeTestStatus(Request $request) + { + $expectedUser = env('API_AUTH_USER'); + $expectedPw = env('API_AUTH_PW'); + + $header_auth = $request->header('Authorization'); + $expectedToken = $expectedUser.':'.$expectedPw; + + if ('Bearer '.$expectedToken != $header_auth) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid authorization token!', + ], 403); + } + + $data = $request->all(); + + if ($data['plant_code'] == null || $data['plant_code'] == '') { + // return response("ERROR: Please provide a valid plant code.", 400) + // ->header('Content-Type', 'text/plain'); + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Plant code can't be empty!", + ], 404); + } elseif (Str::length($data['plant_code']) < 4 || ! is_numeric($data['plant_code']) || ! preg_match('/^[1-9]\d{3,}$/', $data['plant_code'])) {// !ctype_digit($data['plant_code']) + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid plant code found!', + ], 404); + } + + $plant = Plant::where('code', $data['plant_code'])->first(); + if (! $plant) { + // return response("Plant not found.", 400)->header('Content-Type', 'text/plain'); + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Plant not found!', + ], 404); + } + + $plantId = $plant->id; + $plantName = $plant->name; + + if ($data['line_name'] == null || $data['line_name'] == '') { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Group work center can't be empty!", + ], 404); + } elseif (Str::length($data['line_name']) < 0) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid group work center found!', + ], 404); + } + + $gWorkCenter = WorkGroupMaster::where('name', $data['line_name'])->first(); + if (! $gWorkCenter) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Group work center not found!', + ], 404); + } + + $gWorkCenter = WorkGroupMaster::where('name', $data['line_name'])->where('plant_id', $plantId)->first(); + if (! $gWorkCenter) { + // return response( "Line not found for the specified plant : {$data['plant_code']}",400)->header('Content-Type', 'text/plain'); + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Group work center not found for the specified plant : '{$data['plant_code']}'!", + ], 404); + } + + $gWorkCenterId = $gWorkCenter->id; + + if ($data['machine_name'] == null || $data['machine_name'] == '') { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Work center can't be empty!", + ], 404); + } elseif (Str::length($data['machine_name']) < 0) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid work center found!', + ], 404); + } + + $machine = Machine::where('work_center', $data['machine_name'])->first(); + if (! $machine) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Work center not found!', + ], 404); + } + + $machine = Machine::where('work_center', $data['machine_name'])->where('plant_id', $plantId)->first(); + if (! $machine) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Work center not found for the specified plant : '{$data['plant_code']}'!", + ], 404); + } + + $machine = Machine::where('work_center', $data['machine_name'])->where('work_group_master_id', $gWorkCenterId)->first(); + if (! $machine) { + // return response("Machine not found for the specified line : {$data['line_name']}", 400)->header('Content-Type', 'text/plain'); + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Work center not found for the specified Group work center : '{$data['line_name']}'!", + ], 404); + + } + + $machine = Machine::where('work_center', $data['machine_name'])->where('plant_id', $plantId)->where('work_group_master_id', $gWorkCenterId)->first(); + if (! $machine) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Work center not found for the specified Plant : '{$data['plant_code']}' and Group work center : '{$data['line_name']}'!", + ], 404); + } + + $lineId = $machine->line_id; + $machineId = $machine->id; + + try { + $insertedSerials = []; + $missedItemCodes = []; + $duplicateItemCodes = []; + $existSnoCount = []; + + if (! empty($data['item_codes']) && is_array($data['item_codes'])) { + foreach ($data['item_codes'] as $item) { + $code = $item['item_code'] ?? null; + + // Check if item_code is present + if ($code == '' || $code == null) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Item code can't be empty!", + ], 404); + } + + // Collect duplicates + if (isset($itemCodeCounts[$code])) { + $itemCodeCounts[$code]++; + // Only add to duplicates array once + if ($itemCodeCounts[$code] == 2) { + $duplicateItemCodes[] = $code; + } + } else { + $itemCodeCounts[$code] = 1; + } + + $motorTestingMaster = MotorTestingMaster::whereHas('item', function ($query) use ($item) { + $query->where('code', $item['item_code']); + })->where('plant_id', $plantId)->first(); + + if (! $motorTestingMaster) { + $missedItemCodes[] = $item['item_code']; + } + + if (! empty($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + $existSnoCount[] = $serial['serial_number']; + } + } + } + + // If any duplicates found, return error + if (! empty($duplicateItemCodes)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Duplicate item codes found in request: '.implode(', ', $duplicateItemCodes), + ], 404); + } + + $uniqueInvalidCodes = array_unique($missedItemCodes); + + if (! empty($uniqueInvalidCodes)) { + + // return response("Item codes : ". implode(', ', $uniqueInvalidCodes)." not found in motor testing master for the specified plant {$plantName}", 400) + // ->header('Content-Type', 'text/plain'); + + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Item codes : '.implode(', ', $uniqueInvalidCodes)." not found in master for the specified plant : '{$plantName}'!", + ], 404); + } + + $insertedSnoCount = []; + + foreach ($data['item_codes'] as $item) { + + $motorTestingMaster = MotorTestingMaster::whereHas('item', callback: function ($query) use ($item) { + $query->where('code', $item['item_code']); + })->where('plant_id', $plantId)->first(); + + $motorTestingMasterId = $motorTestingMaster->id; + + if (! empty($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + + $row = [ + 'plant_id' => $plantId, + 'line_id' => $lineId, + 'machine_id' => $machineId, + 'motor_testing_master_id' => $motorTestingMasterId, + 'serial_number' => $serial['serial_number'] ?? null, + 'before_fr_res_ry' => $serial['before_fr_res_ry'] ?? null, + 'before_fr_res_yb' => $serial['before_fr_res_yb'] ?? null, + 'before_fr_res_br' => $serial['before_fr_res_br'] ?? null, + 'before_fr_ir' => $serial['before_fr_ir'] ?? null, + 'tested_by' => (($serial['tested_by'] == 'jothi') ? 'Admin' : $serial['tested_by']) ?? null, + 'scanned_at' => $serial['scanned_at'] ?? now(), + ]; + + // Insert the new record + BeforeTestReading::create($row); + $insertedSerials[] = $serial['serial_number'] ?? '[unknown]'; + $insertedSnoCount[] = $serial['serial_number']; + } + } + } + } + + if (! empty($insertedSerials)) { + if (count($existSnoCount) == count($insertedSnoCount)) { + return response()->json([ + 'status_code' => 'SUCCESS', + 'status_description' => 'Inserted before test serial numbers are: '.implode(', ', $insertedSerials), + ], 200); + } else { + $missingSno = array_diff($existSnoCount, $insertedSnoCount); + + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Missed before test serial numbers are: '.implode(', ', $missingSno), + ], 404); + } + } + } catch (\Exception $e) { + // return response($e->getMessage(), 500)->header('Content-Type', 'text/plain'); + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Store testing panel before test readings internal server error : '.$e?->getCode(), + ], 500); + } + } + /** * Display the specified resource. */ @@ -726,6 +979,7 @@ class TestingPanelController extends Controller } $plantId = $plant->id; + $plantName = $plant->name; $item = Item::where('code', $itemCode)->first(); @@ -741,7 +995,7 @@ class TestingPanelController extends Controller if (! $item) { return response()->json([ 'status_code' => 'ERROR', - 'status_description' => "Item code not found in item table for the plant : '$plant->name'!", + 'status_description' => "Item code not found in item table for the plant : '$plantName'!", ], 404); } @@ -765,7 +1019,7 @@ class TestingPanelController extends Controller if (! $motorTestingMaster) { return response()->json([ 'status_code' => 'ERROR', - 'status_description' => "Item code not found in motor testing master table for the plant : '$plant->name'!", + 'status_description' => "Item code not found in motor testing master table for the plant : '$plantName'!", ], 404); } diff --git a/app/Models/BeforeTestReading.php b/app/Models/BeforeTestReading.php new file mode 100644 index 0000000..c040319 --- /dev/null +++ b/app/Models/BeforeTestReading.php @@ -0,0 +1,54 @@ +belongsTo(Plant::class); + } + + public function line(): BelongsTo + { + return $this->belongsTo(Line::class); + } + + public function machine(): BelongsTo + { + return $this->belongsTo(Machine::class); + } + + public function item(): BelongsTo + { + return $this->belongsTo(Item::class); + } + + public function motorTestingMaster() + { + return $this->belongsTo(MotorTestingMaster::class); + } +} diff --git a/app/Models/Item.php b/app/Models/Item.php index 378e3aa..bed95e2 100644 --- a/app/Models/Item.php +++ b/app/Models/Item.php @@ -108,5 +108,4 @@ class Item extends Model { return $this->hasMany(PanelGrMaster::class, 'item_id', 'id'); } - } diff --git a/app/Models/Line.php b/app/Models/Line.php index 79a81a4..105dc60 100644 --- a/app/Models/Line.php +++ b/app/Models/Line.php @@ -51,6 +51,11 @@ class Line extends Model return $this->hasMany(TestingPanelReading::class); } + public function beforeTestReadings() + { + return $this->hasMany(BeforeTestReading::class); + } + public function workGroupMasters(): BelongsTo { return $this->belongsTo(WorkGroupMaster::class); diff --git a/app/Models/Machine.php b/app/Models/Machine.php index bcd2209..7263328 100644 --- a/app/Models/Machine.php +++ b/app/Models/Machine.php @@ -35,12 +35,12 @@ class Machine extends Model public function productCharacteristicsMasters() { - return $this->hasMany(ProductCharacteristicsMaster::class); + return $this->hasMany(ProductCharacteristicsMaster::class, 'machine_id', 'id'); } public function characteristicValues() { - return $this->hasMany(CharacteristicValue::class); + return $this->hasMany(CharacteristicValue::class, 'machine_id', 'id'); } public function ClassCharacteristics() @@ -65,12 +65,17 @@ class Machine extends Model public function testingPanelReadings() { - return $this->hasMany(TestingPanelReading::class); + return $this->hasMany(TestingPanelReading::class, 'machine_id', 'id'); + } + + public function beforeTestReadings() + { + return $this->hasMany(BeforeTestReading::class, 'machine_id', 'id'); } public function tempClassCharacteristics() { - return $this->hasMany(TempClassCharacteristic::class, 'plant_id', 'id'); + return $this->hasMany(TempClassCharacteristic::class, 'machine_id', 'id'); } public function equipmentMasters() diff --git a/app/Models/MotorTestingMaster.php b/app/Models/MotorTestingMaster.php index 49c4fb0..01b9a26 100644 --- a/app/Models/MotorTestingMaster.php +++ b/app/Models/MotorTestingMaster.php @@ -12,39 +12,39 @@ class MotorTestingMaster extends Model protected $fillable = [ 'plant_id', - 'item_id', + 'item_id', 'subassembly_code', - 'isi_model', - 'phase', - 'kw', - 'hp', - 'volt', - 'current', - 'rpm', - 'torque', - 'frequency', - 'connection', - 'ins_res_limit', - 'ins_res_type', + 'isi_model', + 'phase', + 'kw', + 'hp', + 'volt', + 'current', + 'rpm', + 'torque', + 'frequency', + 'connection', + 'ins_res_limit', + 'ins_res_type', 'routine_test_time', - 'res_ry_ll', - 'res_ry_ul', - 'res_yb_ll', - 'res_yb_ul', - 'res_br_ll', - 'res_br_ul', - 'lock_volt_limit', - 'leak_cur_limit', - 'lock_cur_ll', - 'lock_cur_ul', - 'noload_cur_ll', - 'noload_cur_ul', - 'noload_pow_ll', - 'noload_pow_ul', - 'noload_spd_ll', - 'noload_spd_ul', - 'created_by', - 'updated_by', + 'res_ry_ll', + 'res_ry_ul', + 'res_yb_ll', + 'res_yb_ul', + 'res_br_ll', + 'res_br_ul', + 'lock_volt_limit', + 'leak_cur_limit', + 'lock_cur_ll', + 'lock_cur_ul', + 'noload_cur_ll', + 'noload_cur_ul', + 'noload_pow_ll', + 'noload_pow_ul', + 'noload_spd_ll', + 'noload_spd_ul', + 'created_by', + 'updated_by', ]; public function plant(): BelongsTo @@ -52,14 +52,18 @@ class MotorTestingMaster extends Model return $this->belongsTo(Plant::class); } - public function item(): BelongsTo + public function item(): BelongsTo { return $this->belongsTo(Item::class, 'item_id', 'id'); - // return $this->belongsTo(Item::class); } public function testingPanelReadings() { - return $this->hasMany(TestingPanelReading::class, 'motor_testing_master_id'); + return $this->hasMany(TestingPanelReading::class, 'motor_testing_master_id', 'id'); + } + + public function beforeTestReadings() + { + return $this->hasMany(BeforeTestReading::class, 'motor_testing_master_id', 'id'); } } diff --git a/app/Models/Plant.php b/app/Models/Plant.php index 82dbf0f..cdc6593 100644 --- a/app/Models/Plant.php +++ b/app/Models/Plant.php @@ -164,9 +164,9 @@ class Plant extends Model // return $this->hasMany(ModelMaster::class, 'plant_id', 'id'); // } - // public function rejectReasons() + // public function windedSerialValidationErrors() // { - // return $this->hasMany(RejectReason::class, 'plant_id', 'id'); + // return $this->hasMany(WindedSerialValidationError::class, 'plant_id', 'id'); // } public function requestCharacteristics() @@ -199,6 +199,11 @@ class Plant extends Model return $this->hasMany(LeakTestReading::class, 'plant_id', 'id'); } + public function beforeTestReadings() + { + return $this->hasMany(BeforeTestReading::class, 'plant_id', 'id'); + } + public function asrsItemValidations() { return $this->hasMany(AsrsItemValidation::class, 'plant_id', 'id'); @@ -218,6 +223,4 @@ class Plant extends Model { return $this->hasMany(PanelBoxValidation::class, 'plant_id', 'id'); } - - } diff --git a/app/Policies/BeforeTestReadingPolicy.php b/app/Policies/BeforeTestReadingPolicy.php new file mode 100644 index 0000000..7464470 --- /dev/null +++ b/app/Policies/BeforeTestReadingPolicy.php @@ -0,0 +1,105 @@ +checkPermissionTo('view-any BeforeTestReading'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('view BeforeTestReading'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->checkPermissionTo('create BeforeTestReading'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('update BeforeTestReading'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('delete BeforeTestReading'); + } + + /** + * Determine whether the user can delete any models. + */ + public function deleteAny(User $user): bool + { + return $user->checkPermissionTo('delete-any BeforeTestReading'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('restore BeforeTestReading'); + } + + /** + * Determine whether the user can restore any models. + */ + public function restoreAny(User $user): bool + { + return $user->checkPermissionTo('restore-any BeforeTestReading'); + } + + /** + * Determine whether the user can replicate the model. + */ + public function replicate(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('replicate BeforeTestReading'); + } + + /** + * Determine whether the user can reorder the models. + */ + public function reorder(User $user): bool + { + return $user->checkPermissionTo('reorder BeforeTestReading'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, BeforeTestReading $beforetestreading): bool + { + return $user->checkPermissionTo('force-delete BeforeTestReading'); + } + + /** + * Determine whether the user can permanently delete any models. + */ + public function forceDeleteAny(User $user): bool + { + return $user->checkPermissionTo('force-delete-any BeforeTestReading'); + } +} diff --git a/database/migrations/2026_08_20_173056_create_before_test_readings_table.php b/database/migrations/2026_08_20_173056_create_before_test_readings_table.php new file mode 100644 index 0000000..576958a --- /dev/null +++ b/database/migrations/2026_08_20_173056_create_before_test_readings_table.php @@ -0,0 +1,53 @@ +