diff --git a/app/Filament/Pages/Welcome.php b/app/Filament/Pages/Welcome.php index 39880c3..89b5118 100644 --- a/app/Filament/Pages/Welcome.php +++ b/app/Filament/Pages/Welcome.php @@ -7,13 +7,11 @@ use Illuminate\Support\Facades\Auth; class Welcome extends Page { - protected static ?string $navigationIcon = 'heroicon-o-document-text'; + protected static ?string $navigationIcon = 'heroicon-s-gift'; // 'heroicon-o-document-text'; protected static string $view = 'filament.pages.welcome'; - - -public function getHeading(): string + public function getHeading(): string { return ''; } diff --git a/app/Filament/Resources/CharacteristicApproverMasterResource.php b/app/Filament/Resources/CharacteristicApproverMasterResource.php index afd4d4b..5f7a4ac 100644 --- a/app/Filament/Resources/CharacteristicApproverMasterResource.php +++ b/app/Filament/Resources/CharacteristicApproverMasterResource.php @@ -65,41 +65,63 @@ class CharacteristicApproverMasterResource extends Resource ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), - Forms\Components\TextInput::make('characteristic_field') - ->label('Master Characteristic Field') - ->columnSpan(2) - ->required() - ->default('NIL') - ->afterStateUpdated(function ($state, callable $set) { - $set('updated_by', Filament::auth()->user()?->name); - }), Forms\Components\TextInput::make('machine_name') ->label('Machine') ->columnSpan(2) + ->reactive() ->required() + ->minLength(5) ->default(function () { return optional(CharacteristicApproverMaster::latest()->first())->machine_name ?? ''; }) ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), + Forms\Components\TextInput::make('characteristic_field') + ->label('Master Characteristic Field') + ->columnSpan(2) + ->reactive() + ->required() + ->minLength(1) + ->default('NIL') + ->afterStateUpdated(function ($state, callable $set) { + if (strtolower($state) == 'nil' || $state == '' || $state == null) { + $set('characteristic_field', 'NIL'); + } + $set('updated_by', Filament::auth()->user()?->name); + }), Section::make('Approver - 1') // ->description('Prevent abuse by limiting the number of requests per period') ->columnSpan(['default' => 2, 'sm' => 4]) ->schema([ Forms\Components\TextInput::make('name1') ->label('Name') + ->reactive() + ->required() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('mail1') - ->label('Mail') + ->label('E-Mail') ->columnSpan(['default' => 1, 'sm' => 2]) + ->reactive() + ->required() + ->email() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('duration1') ->label('Duration (HH.MM)') + ->reactive() + ->required() + ->minLength(4) + ->maxLength(5) + ->regex('/^([0-9]|0[0-9]|1[0-9]|2[0-3])\.(0[0-9]|[1-5][0-9])$/') + ->validationMessages([ + // 'regex' => 'Duration must be 4 digits in HH.MM format (e.g., 12.30, 23.59). Hours: 00-23, Minutes: 00-59.', + 'regex' => 'Duration must be HH.MM format (example: 00.00 - 23.59)', + // 'length' => 'Duration must be exactly 5 characters', + ]) ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), @@ -111,17 +133,26 @@ class CharacteristicApproverMasterResource extends Resource ->schema([ Forms\Components\TextInput::make('name2') ->label('Name') + ->reactive() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('mail2') - ->label('Mail') + ->label('E-Mail') ->columnSpan(['default' => 1, 'sm' => 2]) + ->reactive() + ->email() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('duration2') ->label('Duration (HH.MM)') + ->reactive() + ->length(4) + ->regex('/^([0-9]|0[0-9]|1[0-9]|2[0-3])\.(0[0-9]|[1-5][0-9])$/') + ->validationMessages([ + 'regex' => 'Duration must be HH.MM format (example: 00.00 - 23.59)', + ]) ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), @@ -133,17 +164,26 @@ class CharacteristicApproverMasterResource extends Resource ->schema([ Forms\Components\TextInput::make('name3') ->label('Name') + ->reactive() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('mail3') - ->label('Mail') + ->label('E-Mail') ->columnSpan(['default' => 1, 'sm' => 2]) + ->reactive() + ->email() ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), Forms\Components\TextInput::make('duration3') ->label('Duration (HH.MM)') + ->reactive() + ->length(4) + ->regex('/^([0-9]|0[0-9]|1[0-9]|2[0-3])\.(0[0-9]|[1-5][0-9])$/') + ->validationMessages([ + 'regex' => 'Duration must be HH.MM format (example: 00.00 - 23.59)', + ]) ->afterStateUpdated(function ($state, callable $set) { $set('updated_by', Filament::auth()->user()?->name); }), @@ -205,7 +245,7 @@ class CharacteristicApproverMasterResource extends Resource ->searchable() ->sortable(), Tables\Columns\TextColumn::make('mail1') - ->label('Mail 1') + ->label('E-Mail 1') ->alignCenter() ->searchable() ->sortable(), @@ -219,7 +259,7 @@ class CharacteristicApproverMasterResource extends Resource ->searchable() ->sortable(), Tables\Columns\TextColumn::make('mail2') - ->label('Mail 2') + ->label('E-Mail 2') ->alignCenter() ->searchable() ->sortable(), @@ -233,7 +273,7 @@ class CharacteristicApproverMasterResource extends Resource ->searchable() ->sortable(), Tables\Columns\TextColumn::make('mail3') - ->label('Mail 3') + ->label('E-Mail 3') ->alignCenter() ->searchable() ->sortable(), diff --git a/app/Filament/Resources/RequestCharacteristicResource.php b/app/Filament/Resources/RequestCharacteristicResource.php index b411bdc..a5d88d8 100644 --- a/app/Filament/Resources/RequestCharacteristicResource.php +++ b/app/Filament/Resources/RequestCharacteristicResource.php @@ -8,6 +8,7 @@ use App\Models\CharacteristicApproverMaster; use App\Models\Item; use App\Models\Machine; use App\Models\RequestCharacteristic; +use Closure; use Filament\Facades\Filament; use Filament\Forms; use Filament\Forms\Components\Section; @@ -21,6 +22,7 @@ use Filament\Tables\Actions\ImportAction; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; +use Illuminate\Support\Facades\Schema; use Illuminate\Validation\Rule; class RequestCharacteristicResource extends Resource @@ -236,7 +238,7 @@ class RequestCharacteristicResource extends Resource }) ->required(), // ->disabled(fn ($get) => self::isFieldDisabled($get)) - Section::make('Request Characteristic') + Section::make('Request Characteristic Field') // ->columnSpan(['default' => 2, 'sm' => 4]) ->reactive() ->schema([ @@ -244,24 +246,82 @@ class RequestCharacteristicResource extends Resource ->label('Characteristic Name') ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get) { + $set('characteristic_name', strtoupper($state)); $set('updated_by', Filament::auth()->user()?->name); }) ->required() - ->disabled(fn ($get) => self::isFieldDisabled($get)), + ->rules([ + // function (callable $get) { + // return Rule::unique('request_characteristics', 'characteristic_name') + // ->where('plant_id', $get('plant_id')) + // ->where('machine_id', $get('machine_id')) + // ->where('machine_name', $get('machine_name')) + // ->ignore($get('id')); + // }, + function (callable $get): Closure { + return function (string $attribute, $value, Closure $fail) use ($get) { + $charVal = strtolower($value); + $columns = Schema::getColumnListing('class_characteristics'); + + if (! in_array($charVal, $columns, true)) { + $fail('Unknown characteristic field found.'); // .implode(', ', $columns). + } else { + + $plantId = $get('plant_id'); + $jobNo = $get('aufnr'); + $updId = $get('id'); + $pendingExists = RequestCharacteristic::where('plant_id', $plantId)->where('aufnr', $jobNo)->where('characteristic_name', $value)->latest()->first(); + + if ($pendingExists) { + if ($updId && $pendingExists->id == $updId) { + return; + } + $app1 = $pendingExists->approver_status1 ?? null; + $app2 = $pendingExists->approver_status2 ?? null; + $app3 = $pendingExists->approver_status3 ?? null; + + if ($app1 != 'Rejected' && $app2 != 'Rejected' && $app3 != 'Rejected' && $app1 != 'Approved' && $app2 != 'Approved' && $app3 != 'Approved') { + $fail('Approval is already pending.'); + } + } + } + }; + }, + ]) + ->readOnly(fn ($get) => self::isFieldDisabled($get)), // disabled Forms\Components\TextInput::make('current_value') ->label('Current Value') ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get) { $set('updated_by', Filament::auth()->user()?->name); }) - ->disabled(fn ($get) => self::isFieldDisabled(get: $get)), + ->required(function (callable $get) { + $updateVal = $get('update_value'); + if ($updateVal == null || $updateVal == '') { + return true; + } + + return false; + }) + ->readOnly(fn ($get) => self::isFieldDisabled($get)), Forms\Components\TextInput::make('update_value') ->label('Update Value') ->reactive() ->afterStateUpdated(function ($state, callable $set, callable $get) { $set('updated_by', Filament::auth()->user()?->name); }) - ->disabled(fn ($get) => self::isFieldDisabled($get)), + ->rules([ + function (callable $get): Closure { + return function (string $attribute, $value, Closure $fail) use ($get) { + $currVal = $get('current_value'); + + if ($value == $currVal) { + $fail('Update value must be different from current value.'); + } + }; + }, + ]) + ->readOnly(fn ($get) => self::isFieldDisabled($get)), ]) ->collapsible() ->columns(['default' => 1, 'sm' => 3]), @@ -798,6 +858,19 @@ class RequestCharacteristicResource extends Resource ->dateTime() ->searchable() ->sortable(), + Tables\Columns\TextColumn::make('mail_status') + ->label('Mail Status') + ->alignCenter() + ->searchable() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('trigger_at') + ->label('Trigger At') + ->dateTime() + ->alignCenter() + ->searchable() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->dateTime() diff --git a/routes/api.php b/routes/api.php index a9441f3..5d16f73 100644 --- a/routes/api.php +++ b/routes/api.php @@ -210,6 +210,5 @@ Route::post('file/store', [SapFileController::class, 'store'])->name('file.store // Route::post('invoice-exit', [InvoiceValidationController::class, 'handle']); - // Route::post('/characteristic/hold-save', [CharacteristicApprovalController::class, 'holdSave']) // ->name('characteristic.hold.save');