up
This commit is contained in:
+269
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\ProductVariantResource\RelationManagers;
|
||||
|
||||
use App\Models\Bodega;
|
||||
use App\Models\ProductVariant;
|
||||
use App\Services\TransferenciaBodegaService;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Notifications\Notification;
|
||||
|
||||
class BodegasRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'bodegas';
|
||||
|
||||
protected static ?string $title = 'Stock por Bodega';
|
||||
|
||||
protected static ?string $modelLabel = 'Bodega';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Bodegas';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->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'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user