schema([ Section::make('Ingreso a Inventario') ->schema([ Select::make('orden_produccion_id') ->label('Orden de Producción') ->options(function () { // Obtener todas las OPs con procesos terminados $ops = \App\Models\OrdenProduccion::whereHas('procesosAcabado', function ($q) { $q->where('terminada', true); })->get(); // Filtrar solo las que tienen saldo disponible > 0 $opsConSaldo = []; foreach ($ops as $op) { $total = \App\Models\ProcesoAcabado::where('orden_produccion_id', $op->id) ->where('terminada', true) ->sum('cantidad_enviada'); $usado = \App\Models\InventarioPrenda::where('orden_produccion_id', $op->id) ->sum('cantidad_terminada'); $disponible = max(0, (int) $total - (int) $usado); if ($disponible > 0) { $opsConSaldo[$op->id] = $op->numero_orden . ' (Disponible: ' . $disponible . ')'; } } return $opsConSaldo; }) ->searchable() ->reactive() ->required() ->afterStateUpdated(function ($state, $set) { $remaining = 0; if ($state) { // Total de cantidad enviada desde procesos de acabados terminados $total = \App\Models\ProcesoAcabado::where('orden_produccion_id', $state) ->where('terminada', true) ->sum('cantidad_enviada'); // Ya asignado en otros inventarios $used = \App\Models\InventarioPrenda::where('orden_produccion_id', $state)->sum('cantidad_terminada'); $remaining = max(0, (int) $total - (int) $used); // Colocar valores en formulario $set('cantidad_terminada', $remaining); $set('cantidad_disponible', $remaining); // Si la OP tiene producto predeterminado, asignarlo como sugerencia $op = \App\Models\OrdenProduccion::find($state); if ($op && $op->producto_id) { $set('producto_id', $op->producto_id); } } })->helperText('Solo se muestran órdenes con procesos terminados y saldo disponible mayor a cero.'), TextInput::make('cantidad_terminada') ->numeric() ->required() ->disabled() ->dehydrated() ->helperText('Se calcula automáticamente desde los procesos de acabados completados asociados a la Orden de Producción.'), Select::make('producto_id') ->label('Producto (opcional)') ->relationship('producto', 'nombre') ->searchable() ->preload() ->nullable() ->helperText('Opcional. Si la Orden de Producción tiene un producto asociado, éste será la fuente de verdad. Si el producto seleccionado difiere, se mostrará un error y no se permitirá guardar.'), TextInput::make('cantidad_disponible') ->disabled() ->dehydrated(false), DatePicker::make('fecha_ingreso') ->required() ->default(now()), Select::make('estado') ->options([ 'en_bodega' => 'En bodega', ]) ->default('en_bodega') ->required(), ]) ->columns(2), Section::make('Distribuciones') ->schema([ \Filament\Forms\Components\Placeholder::make('distribuciones_notice') ->label('Distribuciones por bodega / color / talla') ->content('Gestiona las distribuciones desde la sección "Distribuciones" más abajo en la página. Usar el botón "Crear" para añadir nuevas distribuciones.'), ]) ->columns(1), ]); } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('ordenProduccion.numero_orden') ->label('OP') ->searchable(), TextColumn::make('cantidad_terminada'), TextColumn::make('cantidad_disponible'), TextColumn::make('fecha_ingreso') ->date(), BadgeColumn::make('estado') ->formatStateUsing(fn($state) => match ($state) { 'en_bodega' => 'En bodega', default => $state, }) ->colors([ 'primary' => 'en_bodega', ]), ]) ->defaultSort('created_at', 'desc') ->filters([ Tables\Filters\SelectFilter::make('orden_produccion_id') ->label('Orden de Producción') ->relationship('ordenProduccion', 'numero_orden') ->searchable() ->preload(), ]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ RelationManagers\DistribucionesRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListInventarioPrendas::route('/'), 'create' => Pages\CreateInventarioPrenda::route('/create'), 'edit' => Pages\EditInventarioPrenda::route('/{record}/edit'), ]; } }