diff --git a/app/Filament/Resources/StockDataMasterResource.php b/app/Filament/Resources/StockDataMasterResource.php index 5405a03..31a0f58 100644 --- a/app/Filament/Resources/StockDataMasterResource.php +++ b/app/Filament/Resources/StockDataMasterResource.php @@ -6,6 +6,9 @@ use App\Filament\Exports\StockDataMasterExporter; use App\Filament\Imports\StockDataMasterImporter; use App\Filament\Resources\StockDataMasterResource\Pages; use App\Filament\Resources\StockDataMasterResource\RelationManagers; +use App\Models\Item; +use App\Models\Plant; +use App\Models\SerialValidation; use App\Models\StickerMaster; use App\Models\StockDataMaster; use Filament\Facades\Filament; @@ -18,6 +21,12 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; use Filament\Tables\Actions\ExportAction; use Filament\Tables\Actions\ImportAction; +use Filament\Tables\Filters\Filter; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\DateTimePicker; +use Filament\Forms\Components\Radio; +use Filament\Notifications\Notification; class StockDataMasterResource extends Resource { @@ -164,37 +173,44 @@ class StockDataMasterResource extends Resource ->label('Motor Scanned Status') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('pump_scanned_status') ->label('Pump Scanned Status') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('capacitor_scanned_status') ->label('Capacitor Scanned Status') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('scanned_status_set') ->label('Scanned Status Set') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('panel_box_item_code') ->label('Panel Box Item Code') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('panel_box_supplier') ->label('Panel Box Supplier') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('panel_box_sno') ->label('Panel Box Serial Number') ->alignCenter() ->searchable() - ->sortable(), + ->sortable() + ->visible(fn ($livewire) => ($livewire->tableFilters['advanced_filters']['type'] ?? null) != '1'), Tables\Columns\TextColumn::make('scanned_status') ->label('Scanned Status') ->alignCenter() @@ -205,6 +221,64 @@ class StockDataMasterResource extends Resource ->alignCenter() ->searchable() ->sortable(), + Tables\Columns\TextColumn::make('system_stock') + ->label('System Stock') + ->alignCenter() + ->getStateUsing(fn ($record) => $record->quantity), + Tables\Columns\TextColumn::make('scanned_stock') + ->label('Scanned Stock') + ->alignCenter() + ->getStateUsing(fn ($record) => $record->scanned_quantity), + Tables\Columns\TextColumn::make('duplicate_stock') + ->label('Duplicate Stock') + ->alignCenter() + ->getStateUsing(function ($record) { + return \App\Models\DuplicateStock::where('stock_data_master_id', $record->id)->count(); + }), + Tables\Columns\TextColumn::make('not_in_stock') + ->label('Not In Stock') + ->alignCenter() + ->getStateUsing(function ($record) { + return \App\Models\NotInStock::where('serial_number', $record->serial_number) + ->where('plant_id', $record->plant_id) + ->count(); + }), + Tables\Columns\TextColumn::make('physical_stock') + ->label('Physical Stock') + ->alignCenter() + ->getStateUsing(function ($record) { + + $duplicate = \App\Models\DuplicateStock::where('stock_data_master_id', $record->id)->count(); + + $notInStock = \App\Models\NotInStock::where('serial_number', $record->serial_number) + ->where('plant_id', $record->plant_id) + ->count(); + + $scanned = $record->scanned_quantity ?? 0; + + return $scanned + $duplicate + $notInStock; + }), + Tables\Columns\TextColumn::make('stock_difference') + ->label('Stock Difference Count') + ->alignCenter() + ->getStateUsing(function ($record) { + + $duplicate = \App\Models\DuplicateStock::where('stock_data_master_id', $record->id)->count(); + + $notInStock = \App\Models\NotInStock::where('serial_number', $record->serial_number) + ->where('plant_id', $record->plant_id) + ->count(); + + $scanned = (int) $record->scanned_quantity; + + $physicalStock = $scanned + $duplicate + $notInStock; + + $systemStock = (int) $record->quantity; + + $difference = $physicalStock - $systemStock; + + return max($difference, 0); // prevents negative values + }), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->alignCenter() @@ -226,7 +300,230 @@ class StockDataMasterResource extends Resource ]) ->filters([ Tables\Filters\TrashedFilter::make(), + Filter::make('advanced_filters') + ->label('Advanced Filters') + ->form([ + Radio::make('type') + ->label('Type') + ->options([ + '0' => 'FG', + '1' => 'SFG', + ]) + ->inline() + ->nullable(), + Select::make('Plant') + ->label('Select Plant') + ->nullable() + ->options(function (callable $get) { + $userHas = Filament::auth()->user()->plant_id; + + if ($userHas && strlen($userHas) > 0) { + return Plant::where('id', $userHas)->pluck('name', 'id')->toArray(); + } else { + return Plant::whereHas('stockDataMasters', function ($query) { + $query->whereNotNull('id'); + })->orderBy('code')->pluck('name', 'id'); + } + }) + ->reactive() + ->afterStateUpdated(function ($state, callable $set, callable $get): void { + $set('sticker_master_id', null); + $set('operator_id', null); + }), + TextInput::make('location') + ->label('Location') + ->placeholder(placeholder: 'Enter Location'), + TextInput::make('serial_number') + ->label('Serial Number') + ->placeholder(placeholder: 'Enter Serial Number'), + Select::make('sticker_master_id') + ->label('Search by Item Code') + ->nullable() + ->options(function (callable $get) { + $pId = $get('Plant'); + + if (empty($pId)) { + return []; + } + return Item::whereHas('stickerMasters', function ($query) use ($pId) { + if ($pId) { + $query->where('plant_id', $pId); + } + // $query->whereHas('stockDataMasters'); + })->pluck('code', 'id'); + }) + ->searchable() + ->reactive(), + Select::make('scanned_status') + ->label('Scanned Status') + ->nullable() + ->options([ + 'Scanned' => 'Scanned', + 'Pending' => 'Pending', + ]) + ->searchable() + ->reactive(), + Select::make('updated_by') + ->label('Created By') + ->nullable() + ->options(function (callable $get) { + $plantId = $get('Plant'); + if (! $plantId) { + return StockDataMaster::whereNotNull('updated_by')->select('updated_by')->distinct()->pluck('updated_by', 'updated_by'); + } else { + return StockDataMaster::where('plant_id', $plantId)->whereNotNull('updated_by')->select('updated_by')->distinct()->pluck('updated_by', 'updated_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), + ]) + ->query(function ($query, array $data) { + if (!isset($data['type']) && (empty($data['Plant']) && empty($data['invoice_number']) && empty($data['serial_number']) && empty($data['created_from']) && empty($data['created_to']) && empty($data['operator_id']) && empty($data['scanned_status']) && empty($data['sticker_master_id']))) { + + if (empty($data['type'])) { + Notification::make() + ->title('Please, choose valid type to filter.') + ->danger() + ->send(); + } + return $query->whereRaw('1 = 0'); + } + + if ($data['type'] == '0') { + + $query->where('type', '0'); + + if (!empty($data['scanned_status'])) { + + if ($data['scanned_status'] == 'Scanned') { + $query->whereNotNull('scanned_status') + ->where('scanned_status', '!=', ''); + } elseif ($data['scanned_status'] == 'Pending') { + + $query->where(function ($query) { + $query->whereNull('scanned_status') + ->orWhere('scanned_status', '!=', 'Scanned'); + }); + + } + } + } elseif ($data['type'] == '1') { + $query->where('type', '1') + ->whereNotNull('quantity'); + + if ($data['scanned_status']) { + + if ($data['scanned_status'] == 'Scanned') { + + $query->whereNotNull('scanned_status') + ->where('scanned_status', '!=', ''); + + } elseif ($data['scanned_status'] == 'Pending') { + + $query->where(function ($q) { + $q->whereNull('scanned_status') + ->orWhere('scanned_status', '!=', 'Scanned'); + }); + } + } + } + + if (! empty($data['Plant'])) { // $plant = $data['Plant'] ?? null + $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['location'])) { + $query->where('location', 'like', '%'.$data['location'].'%'); + } + + if (! empty($data['serial_number'])) { + $query->where('serial_number', 'like', '%'.$data['serial_number'].'%'); + } + + 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['updated_by'])) { + $query->where('updated_by', $data['updated_by']); + } + + if (! empty($data['sticker_master_id'])) { + $stickerMasterIds = StickerMaster::where('item_id', $data['sticker_master_id']) + ->pluck('id') + ->toArray(); + + if (! empty($stickerMasterIds)) { + $query->whereIn('sticker_master_id', $stickerMasterIds); + } + } + }) + ->indicateUsing(function (array $data) { + $indicators = []; + + if (! empty($data['Plant'])) { + $indicators[] = 'Plant: '.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['location'])) { + $indicators[] = 'Location: '.$data['location']; + } + + if (! empty($data['serial_number'])) { + $indicators[] = 'Serial Number: '.$data['serial_number']; + } + + if (! empty($data['sticker_master_id'])) { + $itemCode = Item::find($data['sticker_master_id'])->code ?? 'Unknown'; + $indicators[] = 'Item Code: '.$itemCode; + } + + if (! empty($data['updated_by'])) { + $indicators[] = 'Created By: '.$data['updated_by']; + } + + if (! empty($data['created_from'])) { + $indicators[] = 'From: '.$data['created_from']; + } + + if (! empty($data['created_to'])) { + $indicators[] = 'To: '.$data['created_to']; + } + + if (! empty($data['scanned_status'])) { + $indicators[] = 'Scanned Status: '.$data['scanned_status']; + } + + return $indicators; + }), ]) + ->filtersFormMaxHeight('280px') ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\EditAction::make(),