user()->can('ver compras'); } public static function form(Form $form): Form { return $form ->schema([ Forms\Components\Section::make('Información de la Compra') ->schema([ Forms\Components\Select::make('proveedor_id') ->relationship('proveedor', 'nombre') ->required() ->columnSpan(1) ->helperText('Selecciona el proveedor de esta compra'), Forms\Components\Select::make('estado') ->required() ->columnSpan(1) ->options(function (Get $get) { // Solo permite 'Pendiente' si no hay ID (creación) return request()->routeIs('filament.admin.resources.compras.create') ? ['Pendiente' => 'Pendiente'] : [ 'Pendiente' => 'Pendiente', 'Recibida' => 'Recibida', 'Anulada' => 'Anulada', ]; }) ->default('Pendiente') ->disabled(fn () => request()->routeIs('filament.admin.resources.compras.create')) ->helperText(function (Get $get) { return request()->routeIs('filament.admin.resources.compras.create') ? 'Las compras se crean en estado "Pendiente"' : 'Cambiar a "Recibida" actualizará automáticamente el stock en las bodegas'; }), Forms\Components\Placeholder::make('total_display') ->label('Total de la Compra') ->columnSpan(2) ->content(function (Get $get) { $detalles = $get('detalles') ?? []; $total = collect($detalles)->sum('subtotal'); return '$' . number_format($total, 2); }), ]) ->columns(2), Forms\Components\Section::make('Detalles de la Compra') ->description('Agrega los productos de esta compra de forma rápida') ->schema([ Forms\Components\Repeater::make('detalles') ->relationship('detalles') ->schema([ Forms\Components\TextInput::make('codigo_escaneado') ->label('Código de barras') ->placeholder('Escanea o escribe...') ->live(onBlur: true) ->columnSpan(2) ->afterStateUpdated(function (Set $set, $state) { if (!$state) return; // Buscar en ProductVariant $variant = ProductVariant::where('barcode', $state)->first(); if ($variant) { $set('producto_id', $variant->producto_id); $set('variante_id', $variant->id); $colorName = $variant->color ? $variant->color->name : 'Sin color'; $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; Notification::make() ->success() ->title('✓ Variante encontrada') ->body("{$variant->producto->nombre} - {$colorName}/{$sizeName}") ->send(); return; } // Buscar en Producto $producto = Producto::where('codigo_barras', $state)->first(); if ($producto) { $set('producto_id', $producto->id); $set('variante_id', null); if ($producto->variants()->exists()) { Notification::make() ->warning() ->title('⚠ Producto con variantes') ->body('Selecciona una variante específica.') ->send(); } else { Notification::make() ->success() ->title('✓ Producto encontrado') ->body($producto->nombre) ->send(); } } else { Notification::make() ->warning() ->title('Código no encontrado') ->body('No existe un producto con este código.') ->send(); } }), Forms\Components\Select::make('bodega_id') ->label('Bodega') ->relationship('bodega', 'nombre') ->searchable() ->required() ->columnSpan(1) ->default(function () { $bodegaPrincipal = Bodega::where('nombre', 'Principal')->first(); return $bodegaPrincipal ? $bodegaPrincipal->id : null; }), Forms\Components\Select::make('producto_id') ->label('Producto') ->relationship('producto', 'nombre') ->searchable() ->required() ->columnSpan(2) ->live() ->afterStateUpdated(function (Set $set, $state) { $set('variante_id', null); if ($state) { $producto = Producto::find($state); if ($producto && $producto->variants()->exists()) { Notification::make() ->info() ->title('Producto con variantes') ->body('Selecciona una variante.') ->send(); } } }), Forms\Components\Select::make('variante_id') ->label('Variante') ->columnSpan(2) ->options(function (Get $get) { $productoId = $get('producto_id'); if (!$productoId) return []; $producto = Producto::find($productoId); if (!$producto || !$producto->variants()->exists()) return []; return ProductVariant::where('producto_id', $productoId) ->with(['color', 'size']) ->get() ->mapWithKeys(function ($variant) { $colorName = $variant->color ? $variant->color->name : 'Sin color'; $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; return [$variant->id => "{$colorName} / {$sizeName}"]; }); }) ->searchable() ->live() ->visible(function (Get $get) { $productoId = $get('producto_id'); if (!$productoId) return false; $producto = Producto::find($productoId); return $producto && $producto->variants()->exists(); }) ->required(function (Get $get) { $productoId = $get('producto_id'); if (!$productoId) return false; $producto = Producto::find($productoId); return $producto && $producto->variants()->exists(); }), Forms\Components\TextInput::make('cantidad') ->label('Cant.') ->required() ->numeric() ->default(1) ->columnSpan(1) ->live(onBlur: true) ->afterStateUpdated(function (Set $set, Get $get) { $cantidad = (float) ($get('cantidad') ?? 0); $precio = (float) ($get('precio_unitario') ?? 0); $set('subtotal', $cantidad * $precio); }), Forms\Components\TextInput::make('precio_unitario') ->label('Precio Unit.') ->required() ->numeric() ->prefix('$') ->columnSpan(1) ->live(onBlur: true) ->afterStateUpdated(function (Set $set, Get $get) { $cantidad = (float) ($get('cantidad') ?? 0); $precio = (float) ($get('precio_unitario') ?? 0); $set('subtotal', $cantidad * $precio); }), Forms\Components\TextInput::make('subtotal') ->label('Subtotal') ->numeric() ->prefix('$') ->disabled() ->dehydrated(true) ->columnSpan(1), Forms\Components\TextInput::make('DetalleCompra') ->label('Observaciones') ->maxLength(255) ->columnSpan(3), ]) ->columns(6) ->defaultItems(1) ->reorderable(false) ->collapsible() ->itemLabel(fn (array $state): ?string => isset($state['producto_id']) ? Producto::find($state['producto_id'])?->nombre ?? 'Producto' : 'Nuevo producto' ) ->addActionLabel('+ Agregar producto') ->live() ->afterStateUpdated(function (Set $set, Get $get) { // Calcular el total cuando cambian los detalles $detalles = $get('detalles') ?? []; $total = collect($detalles)->sum('subtotal'); $set('total', $total); }), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('id') ->label('ID') ->sortable(), Tables\Columns\TextColumn::make('proveedor.nombre') ->label('Proveedor') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('total') ->label('Total') ->money('cop') ->sortable() ->alignEnd(), Tables\Columns\BadgeColumn::make('estado') ->label('Estado') ->colors([ 'warning' => 'Pendiente', 'success' => 'Recibida', 'danger' => 'Anulada', ]), Tables\Columns\TextColumn::make('detalles_count') ->label('Items') ->counts('detalles') ->badge() ->color('primary'), Tables\Columns\TextColumn::make('created_at') ->label('Fecha') ->dateTime('d/m/Y H:i') ->sortable(), Tables\Columns\TextColumn::make('updated_at') ->label('Actualizada') ->dateTime('d/m/Y H:i') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->paginated(true) //->paginationPageOptions([50]) ->defaultSort('created_at', 'desc') ->filters([ // ]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ DetallesRelationManagerRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListCompras::route('/'), 'create' => Pages\CreateCompra::route('/create'), 'edit' => Pages\EditCompra::route('/{record}/edit'), ]; } }