up
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\TransferenciaBodegaResource\Pages;
|
||||
use App\Models\TransferenciaBodega;
|
||||
use App\Models\Producto;
|
||||
use App\Models\ProductVariant;
|
||||
use App\Models\Bodega;
|
||||
use App\Services\TransferenciaBodegaService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class TransferenciaBodegaResource extends Resource
|
||||
{
|
||||
protected static ?string $model = TransferenciaBodega::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-arrows-right-left';
|
||||
|
||||
protected static ?string $navigationGroup = 'Inventario';
|
||||
|
||||
protected static ?string $navigationLabel = 'Transferencias de Stock';
|
||||
|
||||
protected static ?string $modelLabel = 'Transferencia';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Transferencias';
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('Información del Producto')
|
||||
->schema([
|
||||
Forms\Components\Select::make('producto_id')
|
||||
->label('Producto')
|
||||
->relationship('producto', 'nombre')
|
||||
->searchable()
|
||||
->preload()
|
||||
->required()
|
||||
->reactive()
|
||||
->afterStateUpdated(function ($set, $get, $state) {
|
||||
if ($state) {
|
||||
$producto = Producto::find($state);
|
||||
if ($producto && $producto->variants()->exists()) {
|
||||
$set('tiene_variantes', true);
|
||||
$set('variante_id', null); // Limpiar selección anterior
|
||||
$set('stock_disponible_info', null);
|
||||
// Mostrar información sobre las variantes
|
||||
$cantidadVariantes = $producto->variants()->count();
|
||||
$set('info_variantes', "Este producto tiene {$cantidadVariantes} variante(s). Debe seleccionar una variante específica para la transferencia.");
|
||||
} else {
|
||||
$set('tiene_variantes', false);
|
||||
$set('variante_id', null);
|
||||
$set('info_variantes', null);
|
||||
// Mostrar stock disponible del producto
|
||||
$stockTotal = $producto->getStockEfectivo();
|
||||
$set('stock_disponible_info', "Stock total del producto: {$stockTotal} unidades");
|
||||
}
|
||||
} else {
|
||||
$set('tiene_variantes', false);
|
||||
$set('variante_id', null);
|
||||
$set('info_variantes', null);
|
||||
$set('stock_disponible_info', null);
|
||||
}
|
||||
}),
|
||||
|
||||
Forms\Components\Placeholder::make('info_variantes')
|
||||
->label('Información del Producto')
|
||||
->content(fn ($get) => $get('info_variantes') ?? '')
|
||||
->visible(fn ($get) => $get('tiene_variantes')),
|
||||
|
||||
Forms\Components\Placeholder::make('stock_disponible_info')
|
||||
->label('Stock Disponible')
|
||||
->content(fn ($get) => $get('stock_disponible_info') ?? '')
|
||||
->visible(fn ($get) => !$get('tiene_variantes') && $get('stock_disponible_info')),
|
||||
|
||||
Forms\Components\Select::make('variante_id')
|
||||
->label('Seleccionar Variante')
|
||||
->options(function ($get) {
|
||||
$productoId = $get('producto_id');
|
||||
if ($productoId) {
|
||||
return ProductVariant::where('producto_id', $productoId)
|
||||
->with(['color', 'size'])
|
||||
->get()
|
||||
->mapWithKeys(function ($variante) {
|
||||
$colorName = $variante->color->name ?? '';
|
||||
$sizeName = $variante->size->name ?? '';
|
||||
$stockEfectivo = $variante->getStockEfectivo();
|
||||
$displayName = "{$variante->sku} - {$colorName} {$sizeName} (Stock: {$stockEfectivo})";
|
||||
return [$variante->id => $displayName];
|
||||
});
|
||||
}
|
||||
return [];
|
||||
})
|
||||
->searchable()
|
||||
->required(fn ($get) => $get('tiene_variantes'))
|
||||
->visible(fn ($get) => $get('tiene_variantes'))
|
||||
->reactive()
|
||||
->afterStateUpdated(function ($set, $get, $state) {
|
||||
if ($state) {
|
||||
$variante = ProductVariant::find($state);
|
||||
if ($variante) {
|
||||
$stockTotal = $variante->getStockEfectivo();
|
||||
$set('stock_variante_info', "Stock total de esta variante: {$stockTotal} unidades");
|
||||
}
|
||||
} else {
|
||||
$set('stock_variante_info', null);
|
||||
}
|
||||
})
|
||||
->helperText('Seleccione la variante específica que desea transferir'),
|
||||
|
||||
Forms\Components\Placeholder::make('stock_variante_info')
|
||||
->label('Stock de la Variante')
|
||||
->content(fn ($get) => $get('stock_variante_info') ?? '')
|
||||
->visible(fn ($get) => $get('tiene_variantes') && $get('variante_id') && $get('stock_variante_info')),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Forms\Components\Section::make('Detalles de la Transferencia')
|
||||
->schema([
|
||||
Forms\Components\Select::make('bodega_origen_id')
|
||||
->label('Bodega Origen')
|
||||
->options(function ($get) {
|
||||
$productoId = $get('producto_id');
|
||||
$varianteId = $get('variante_id');
|
||||
|
||||
if ($varianteId) {
|
||||
// Si hay variante seleccionada, mostrar solo bodegas con stock de esa variante
|
||||
$variante = ProductVariant::find($varianteId);
|
||||
if ($variante) {
|
||||
return $variante->bodegas()
|
||||
->where('variante_bodega.stock', '>', 0)
|
||||
->get()
|
||||
->mapWithKeys(function ($bodega) {
|
||||
return [$bodega->id => "{$bodega->nombre} (Stock: {$bodega->pivot->stock})"];
|
||||
});
|
||||
}
|
||||
} elseif ($productoId) {
|
||||
// Si hay producto sin variantes, mostrar bodegas con stock del producto
|
||||
$producto = Producto::find($productoId);
|
||||
if ($producto && !$producto->variants()->exists()) {
|
||||
return $producto->bodegas()
|
||||
->where('producto_bodega.stock', '>', 0)
|
||||
->get()
|
||||
->mapWithKeys(function ($bodega) {
|
||||
return [$bodega->id => "{$bodega->nombre} (Stock: {$bodega->pivot->stock})"];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: mostrar todas las bodegas
|
||||
return Bodega::pluck('nombre', 'id');
|
||||
})
|
||||
->searchable()
|
||||
->required()
|
||||
->reactive()
|
||||
->afterStateUpdated(function ($set, $get, $state) {
|
||||
$set('stock_origen_disponible', null);
|
||||
if ($state) {
|
||||
$productoId = $get('producto_id');
|
||||
$varianteId = $get('variante_id');
|
||||
|
||||
if ($varianteId) {
|
||||
$variante = ProductVariant::find($varianteId);
|
||||
$stock = $variante->bodegas()
|
||||
->where('bodega_id', $state)
|
||||
->first()?->pivot?->stock ?? 0;
|
||||
} elseif ($productoId) {
|
||||
$producto = Producto::find($productoId);
|
||||
$stock = $producto->bodegas()
|
||||
->where('bodega_id', $state)
|
||||
->first()?->pivot?->stock ?? 0;
|
||||
} else {
|
||||
$stock = 0;
|
||||
}
|
||||
|
||||
$bodegaNombre = Bodega::find($state)?->nombre ?? '';
|
||||
$set('stock_origen_disponible', "Stock disponible en {$bodegaNombre}: {$stock} unidades");
|
||||
$set('max_cantidad', $stock);
|
||||
}
|
||||
})
|
||||
->helperText('Solo se muestran bodegas con stock disponible'),
|
||||
|
||||
Forms\Components\Placeholder::make('stock_origen_disponible')
|
||||
->label('Stock en Bodega Origen')
|
||||
->content(fn ($get) => $get('stock_origen_disponible') ?? '')
|
||||
->visible(fn ($get) => $get('stock_origen_disponible')),
|
||||
|
||||
Forms\Components\Select::make('bodega_destino_id')
|
||||
->label('Bodega Destino')
|
||||
->relationship('bodegaDestino', 'nombre')
|
||||
->searchable()
|
||||
->required()
|
||||
->different('bodega_origen_id'),
|
||||
|
||||
Forms\Components\TextInput::make('cantidad')
|
||||
->label('Cantidad a Transferir')
|
||||
->numeric()
|
||||
->required()
|
||||
->minValue(1)
|
||||
->maxValue(fn ($get) => $get('max_cantidad') ?? 999999)
|
||||
->helperText(fn ($get) =>
|
||||
$get('max_cantidad') ? "Máximo disponible: {$get('max_cantidad')} unidades" : ''
|
||||
),
|
||||
|
||||
Forms\Components\Textarea::make('motivo')
|
||||
->label('Motivo de la Transferencia')
|
||||
->placeholder('Ej: Reposición de sucursal, reorganización de inventario...')
|
||||
->rows(3)
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Forms\Components\Hidden::make('usuario_id')
|
||||
->default(Auth::id()),
|
||||
|
||||
Forms\Components\Hidden::make('fecha_transferencia')
|
||||
->default(now()),
|
||||
|
||||
Forms\Components\Hidden::make('tiene_variantes')
|
||||
->default(false),
|
||||
|
||||
Forms\Components\Hidden::make('max_cantidad')
|
||||
->default(0),
|
||||
|
||||
Forms\Components\Hidden::make('info_variantes'),
|
||||
Forms\Components\Hidden::make('stock_disponible_info'),
|
||||
Forms\Components\Hidden::make('stock_variante_info'),
|
||||
Forms\Components\Hidden::make('stock_origen_disponible'),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('producto.nombre')
|
||||
->label('Producto')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->wrap(),
|
||||
|
||||
Tables\Columns\TextColumn::make('variante_info')
|
||||
->label('Variante')
|
||||
->getStateUsing(function ($record) {
|
||||
if ($record->variante_id) {
|
||||
$variante = ProductVariant::find($record->variante_id);
|
||||
if ($variante) {
|
||||
$colorName = $variante->color->name ?? '';
|
||||
$sizeName = $variante->size->name ?? '';
|
||||
return "{$variante->sku} - {$colorName} {$sizeName}";
|
||||
}
|
||||
}
|
||||
return 'Producto general';
|
||||
})
|
||||
->badge()
|
||||
->color(fn ($state) => $state === 'Producto general' ? 'info' : 'warning')
|
||||
->searchable(query: function (Builder $query, string $search): Builder {
|
||||
return $query->whereHas('producto.variants', function ($q) use ($search) {
|
||||
$q->where('sku', 'like', "%{$search}%");
|
||||
});
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('bodegaOrigen.nombre')
|
||||
->label('Bodega Origen')
|
||||
->badge()
|
||||
->color('danger')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('bodegaDestino.nombre')
|
||||
->label('Bodega Destino')
|
||||
->badge()
|
||||
->color('success')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('cantidad')
|
||||
->label('Cantidad')
|
||||
->numeric()
|
||||
->sortable()
|
||||
->badge()
|
||||
->color('primary'),
|
||||
|
||||
Tables\Columns\TextColumn::make('motivo')
|
||||
->label('Motivo')
|
||||
->limit(30)
|
||||
->tooltip(function ($record) {
|
||||
return $record->motivo;
|
||||
})
|
||||
->wrap(),
|
||||
|
||||
Tables\Columns\TextColumn::make('usuario.name')
|
||||
->label('Usuario')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
Tables\Columns\TextColumn::make('fecha_transferencia')
|
||||
->label('Fecha')
|
||||
->dateTime('d/m/Y H:i')
|
||||
->sortable()
|
||||
->badge()
|
||||
->color('gray'),
|
||||
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('Creado')
|
||||
->dateTime('d/m/Y H:i')
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('bodega_origen_id')
|
||||
->label('Bodega Origen')
|
||||
->relationship('bodegaOrigen', 'nombre'),
|
||||
|
||||
SelectFilter::make('bodega_destino_id')
|
||||
->label('Bodega Destino')
|
||||
->relationship('bodegaDestino', 'nombre'),
|
||||
|
||||
SelectFilter::make('producto_id')
|
||||
->label('Producto')
|
||||
->relationship('producto', 'nombre')
|
||||
->searchable(),
|
||||
|
||||
Tables\Filters\Filter::make('con_variantes')
|
||||
->label('Solo Variantes')
|
||||
->query(fn (Builder $query): Builder => $query->whereNotNull('variante_id')),
|
||||
|
||||
Tables\Filters\Filter::make('sin_variantes')
|
||||
->label('Solo Productos Generales')
|
||||
->query(fn (Builder $query): Builder => $query->whereNull('variante_id')),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListTransferenciaBodegas::route('/'),
|
||||
'create' => Pages\CreateTransferenciaBodega::route('/create'),
|
||||
'edit' => Pages\EditTransferenciaBodega::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user