schema([ Forms\Components\Select::make('bodega_id') ->label('Bodega') ->options(\App\Models\Bodega::pluck('nombre', 'id')) ->required() ->searchable() ->preload(), Forms\Components\TextInput::make('stock') ->label('Stock en esta Bodega') ->numeric() ->required() ->default(0) ->minValue(0) ->helperText('Cantidad de esta variante en la bodega seleccionada'), ]); } public function table(Table $table): Table { return $table ->recordTitleAttribute('nombre') ->columns([ Tables\Columns\TextColumn::make('nombre') ->label('Bodega') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('pivot.stock') ->label('Stock') ->alignCenter() ->sortable() ->formatStateUsing(function ($state) { $estado = $state > 0 ? '✅' : '⚠️'; return "{$estado} {$state} unidades"; }) ->tooltip(function ($state) { return "Stock en unidades: {$state}"; }), Tables\Columns\TextColumn::make('pivot.updated_at') ->label('Última Actualización') ->dateTime('d/m/Y H:i') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\Filter::make('con_stock') ->label('Solo con Stock') ->query(fn($query) => $query->where('variante_bodega.stock', '>', 0)), ]) ->headerActions([ Tables\Actions\CreateAction::make() ->label('Asignar a Bodega') ->modalHeading('Asignar Variante a Bodega') ->action(function (array $data): void { $variante = $this->getOwnerRecord(); $bodegaId = $data['bodega_id']; $stock = $data['stock']; // Verificar si ya existe la relación if ($variante->bodegas()->where('bodega_id', $bodegaId)->exists()) { Notification::make() ->warning() ->title('Variante ya asignada') ->body('Esta variante ya está asignada a esa bodega. Use la opción de editar.') ->send(); return; } // Crear la relación $variante->bodegas()->attach($bodegaId, ['stock' => $stock]); Notification::make() ->success() ->title('Variante asignada') ->body('La variante ha sido asignada a la bodega correctamente.') ->send(); }), Tables\Actions\Action::make('transferir_stock') ->label('Transferir entre Bodegas') ->icon('heroicon-o-arrows-right-left') ->color('info') ->form([ Forms\Components\Placeholder::make('info') ->label('Información de la Variante') ->content(function () { $variante = $this->getOwnerRecord(); return "Variante: {$variante->sku} | Stock Total: {$variante->getStockEfectivo()} unidades"; }), Forms\Components\Select::make('bodega_origen_id') ->label('Bodega Origen') ->options(function () { $variante = $this->getOwnerRecord(); return $variante->bodegas() ->where('variante_bodega.stock', '>', 0) ->pluck('nombre', 'bodegas.id'); }) ->required() ->searchable() ->reactive() ->afterStateUpdated(function ($set, $get, $state) { if ($state) { $variante = $this->getOwnerRecord(); $stock = $variante->bodegas() ->where('bodegas.id', $state) ->first()?->pivot?->stock ?? 0; $set('stock_disponible', $stock); } }), Forms\Components\Placeholder::make('stock_disponible') ->label('Stock Disponible en Origen') ->content(fn($get) => ($get('stock_disponible') ?? 0) . ' unidades'), Forms\Components\Select::make('bodega_destino_id') ->label('Bodega Destino') ->options(Bodega::pluck('nombre', 'id')) ->required() ->searchable() ->different('bodega_origen_id'), Forms\Components\TextInput::make('cantidad') ->label('Cantidad a Transferir') ->numeric() ->required() ->minValue(1) ->maxValue(function ($get) { return $get('stock_disponible') ?? 0; }), Forms\Components\TextInput::make('motivo') ->label('Motivo de la Transferencia') ->placeholder('Ej: Reposición, reorganización de inventario...') ->maxLength(255), ]) ->action(function (array $data): void { $variante = $this->getOwnerRecord(); $service = new TransferenciaBodegaService(); try { $transferencia = $service->transferirVariante( $variante->id, $data['bodega_origen_id'], $data['bodega_destino_id'], $data['cantidad'], $data['motivo'] ?? null ); Notification::make() ->success() ->title('Transferencia Exitosa') ->body("Se transfirieron {$data['cantidad']} unidades entre bodegas.") ->send(); } catch (\Exception $e) { Notification::make() ->danger() ->title('Error en Transferencia') ->body($e->getMessage()) ->send(); } }), ]) ->actions([ Tables\Actions\EditAction::make() ->label('Editar Stock') ->form([ Forms\Components\TextInput::make('stock') ->label('Stock en esta Bodega') ->numeric() ->required() ->minValue(0) ->helperText('Cantidad de esta variante en la bodega'), ]) ->fillForm(function ($record): array { return [ 'stock' => $record->pivot?->stock ?? 0, ]; }) ->using(function (array $data, $record): void { // Actualizamos el pivot directamente $record->pivot->update(['stock' => (int)$data['stock']]); // Notificación Notification::make() ->success() ->title('Stock Actualizado') ->body("El stock se actualizó a {$data['stock']} unidades.") ->send(); }), Tables\Actions\Action::make('vaciar_stock') ->label('Vaciar Stock') ->icon('heroicon-o-minus-circle') ->color('warning') ->requiresConfirmation() ->modalHeading('Vaciar Stock de Bodega') ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para esta bodega? La bodega seguirá asignada a la variante.') ->modalSubmitActionLabel('Sí, vaciar stock') ->action(function ($record): void { $record->pivot->update(['stock' => 0]); Notification::make() ->success() ->title('Stock Vaciado') ->body('El stock de la bodega ha sido puesto en 0.') ->send(); }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkAction::make('vaciar_stock_multiple') ->label('Vaciar Stock de Seleccionadas') ->icon('heroicon-o-minus-circle') ->color('warning') ->requiresConfirmation() ->modalHeading('Vaciar Stock de Bodegas Seleccionadas') ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para todas las bodegas seleccionadas?') ->action(function ($records): void { foreach ($records as $record) { $record->pivot->update(['stock' => 0]); } Notification::make() ->success() ->title('Stock Vaciado') ->body('El stock de las bodegas seleccionadas ha sido puesto en 0.') ->send(); }), Tables\Actions\DeleteBulkAction::make() ->label('Quitar de Bodegas Seleccionadas') ->requiresConfirmation() ->modalHeading('Quitar Variante de Bodegas') ->modalDescription('¿Estás seguro de que quieres quitar completamente esta variante de las bodegas seleccionadas? Se perderá toda la información de stock.') ->modalSubmitActionLabel('Sí, quitar completamente'), ]), ]); } }