diff --git a/app/Filament/Exports/TestApprovalMappingExporter.php b/app/Filament/Exports/TestApprovalMappingExporter.php new file mode 100644 index 0000000..44d754a --- /dev/null +++ b/app/Filament/Exports/TestApprovalMappingExporter.php @@ -0,0 +1,62 @@ +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('workGroupMaster.name') + ->label('WORK GROUP CENTER'), + ExportColumn::make('machine.work_center') + ->label('WORK CENTER'), + ExportColumn::make('tested_by') + ->label('TESTED BY'), + ExportColumn::make('verified_by') + ->label('VERIFIED BY'), + ExportColumn::make('approved_by') + ->label('APPROVED BY'), + ExportColumn::make('created_at') + ->label('CREATED AT'), + ExportColumn::make('updated_at') + ->label('UPDATED AT'), + ExportColumn::make('created_by') + ->label('CREATED BY'), + ExportColumn::make('updated_by') + ->label('UPDATED BY'), + ExportColumn::make('deleted_at') + ->label('DELETED AT') + ->enabledByDefault(false), + ]; + } + + public static function getCompletedNotificationBody(Export $export): string + { + $body = 'Your test approval mapping 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/Imports/TestApprovalMappingImporter.php b/app/Filament/Imports/TestApprovalMappingImporter.php new file mode 100644 index 0000000..728f2e2 --- /dev/null +++ b/app/Filament/Imports/TestApprovalMappingImporter.php @@ -0,0 +1,61 @@ +requiredMapping() + ->relationship() + ->rules(['required']), + ImportColumn::make('line') + ->requiredMapping() + ->relationship() + ->rules(['required']), + ImportColumn::make('workGroupMaster') + ->requiredMapping() + ->relationship() + ->rules(['required']), + ImportColumn::make('machine') + ->requiredMapping() + ->relationship() + ->rules(['required']), + ImportColumn::make('tested_by'), + ImportColumn::make('verified_by'), + ImportColumn::make('approved_by'), + ImportColumn::make('created_by'), + ImportColumn::make('updated_by'), + ]; + } + + public function resolveRecord(): ?TestApprovalMapping + { + // return TestApprovalMapping::firstOrNew([ + // // Update existing records, matching them by `$this->data['column_name']` + // 'email' => $this->data['email'], + // ]); + + return new TestApprovalMapping(); + } + + public static function getCompletedNotificationBody(Import $import): string + { + $body = 'Your test approval mapping import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.'; + + if ($failedRowsCount = $import->getFailedRowsCount()) { + $body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.'; + } + + return $body; + } +} diff --git a/app/Filament/Resources/TestApprovalMappingResource.php b/app/Filament/Resources/TestApprovalMappingResource.php new file mode 100644 index 0000000..83e3785 --- /dev/null +++ b/app/Filament/Resources/TestApprovalMappingResource.php @@ -0,0 +1,293 @@ +schema([ + Forms\Components\Select::make('plant_id') + ->label('Plant Name') + ->relationship('plant', 'name') + ->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(TestApprovalMapping::latest()->first())->plant_id; + }) + ->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('work_group_master_id', null); + $set('machine_id', null); + $set('tPrError', 'Please select a plant first.'); + + return; + } else { + $set('line_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') + ->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(TestApprovalMapping::latest()->first())->line_id; + }) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->required() + ->reactive() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $set('work_group_master_id', null); + $set('machine_id', null); + $set('updated_by', Filament::auth()->user()?->name); + }), + Forms\Components\Select::make('work_group_master_id') + ->label('Work Group Center') + ->searchable() + ->options(function (callable $get) { + $plantId = $get('plant_id'); + if (! $plantId) { + return []; + } + + return WorkGroupMaster::where('plant_id', $plantId) + ->pluck('name', 'id') + ->toArray(); + }) + ->default(function () { + return optional(TestApprovalMapping::latest()->first())->work_group_master_id; + }) + ->disabled(fn (Get $get) => ! empty($get('id'))) + ->required() + ->reactive() + ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { + $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) { + $plantId = $get('plant_id'); + $lineId = $get('line_id'); + if (! $plantId || ! $lineId) { + return []; + } + + // Only show machines for the selected line + return Machine::where('plant_id', $plantId) + ->where('line_id', $lineId) + ->pluck('work_center', 'id') + ->toArray(); + }) + ->default(function () { + return optional(TestApprovalMapping::latest()->first())->machine_id; + }) + ->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\TextInput::make('tested_by') + ->label('Tested By'), + Forms\Components\TextInput::make('verified_by') + ->label('Verified By'), + Forms\Components\TextInput::make('approved_by') + ->label('Approved By'), + Forms\Components\Hidden::make('created_by') + ->label('Created By') + ->default(fn () => Filament::auth()->user()?->name), + Forms\Components\Hidden::make('updated_by') + ->label('Updated By') + ->default(fn () => Filament::auth()->user()?->name), + Forms\Components\TextInput::make('id') + ->hidden() + ->readOnly(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('No.') + ->label('No.') + ->alignCenter() + ->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') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('line.name') + ->label('Line') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('workGroupMaster.name') + ->label('Work Group Center') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('machine.work_center') + ->label('Machine') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('tested_by') + ->label('Tested By') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('verified_by') + ->label('Verified By') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('approved_by') + ->label('Approved By') + ->alignCenter() + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->label('Created At') + ->dateTime() + ->sortable() + ->alignCenter(), + Tables\Columns\TextColumn::make('created_by') + ->label('Created By') + ->sortable() + ->alignCenter(), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_by') + ->label('Updated By') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('deleted_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + Tables\Filters\TrashedFilter::make(), + ]) + ->actions([ + Tables\Actions\ViewAction::make(), + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + Tables\Actions\ForceDeleteBulkAction::make(), + Tables\Actions\RestoreBulkAction::make(), + ]), + ]) + ->headerActions([ + ImportAction::make() + ->label('Import Test Approval Mapping') + ->color('warning') + ->importer(TestApprovalMappingImporter::class) + ->visible(function () { + return Filament::auth()->user()->can('view import test approval mapping'); + }), + ExportAction::make() + ->label('Export Test Approval Mapping') + ->color('warning') + ->exporter(TestApprovalMappingExporter::class) + ->visible(function () { + return Filament::auth()->user()->can('view export test approval mapping'); + }), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListTestApprovalMappings::route('/'), + 'create' => Pages\CreateTestApprovalMapping::route('/create'), + 'view' => Pages\ViewTestApprovalMapping::route('/{record}'), + 'edit' => Pages\EditTestApprovalMapping::route('/{record}/edit'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } +} diff --git a/app/Filament/Resources/TestApprovalMappingResource/Pages/CreateTestApprovalMapping.php b/app/Filament/Resources/TestApprovalMappingResource/Pages/CreateTestApprovalMapping.php new file mode 100644 index 0000000..10aed38 --- /dev/null +++ b/app/Filament/Resources/TestApprovalMappingResource/Pages/CreateTestApprovalMapping.php @@ -0,0 +1,12 @@ +belongsTo(Plant::class); + } + + public function line(): BelongsTo + { + return $this->belongsTo(Line::class); + } + + public function workGroupMaster(): BelongsTo + { + return $this->belongsTo(WorkGroupMaster::class); + } + + public function machine(): BelongsTo + { + return $this->belongsTo(Machine::class); + } +} diff --git a/app/Policies/TestApprovalMappingPolicy.php b/app/Policies/TestApprovalMappingPolicy.php new file mode 100644 index 0000000..a2a812e --- /dev/null +++ b/app/Policies/TestApprovalMappingPolicy.php @@ -0,0 +1,106 @@ +checkPermissionTo('view-any TestApprovalMapping'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('view TestApprovalMapping'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->checkPermissionTo('create TestApprovalMapping'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('update TestApprovalMapping'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('delete TestApprovalMapping'); + } + + /** + * Determine whether the user can delete any models. + */ + public function deleteAny(User $user): bool + { + return $user->checkPermissionTo('delete-any TestApprovalMapping'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('restore TestApprovalMapping'); + } + + /** + * Determine whether the user can restore any models. + */ + public function restoreAny(User $user): bool + { + return $user->checkPermissionTo('restore-any TestApprovalMapping'); + } + + /** + * Determine whether the user can replicate the model. + */ + public function replicate(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('replicate TestApprovalMapping'); + } + + /** + * Determine whether the user can reorder the models. + */ + public function reorder(User $user): bool + { + return $user->checkPermissionTo('reorder TestApprovalMapping'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, TestApprovalMapping $testapprovalmapping): bool + { + return $user->checkPermissionTo('force-delete TestApprovalMapping'); + } + + /** + * Determine whether the user can permanently delete any models. + */ + public function forceDeleteAny(User $user): bool + { + return $user->checkPermissionTo('force-delete-any TestApprovalMapping'); + } +} diff --git a/database/migrations/2026_09_17_095052_create_test_approval_mappings_table.php b/database/migrations/2026_09_17_095052_create_test_approval_mappings_table.php new file mode 100644 index 0000000..4ee476a --- /dev/null +++ b/database/migrations/2026_09_17_095052_create_test_approval_mappings_table.php @@ -0,0 +1,48 @@ +