user()?->can('ver ojals') ?? false; } public static function form(Forms\Form $form): Forms\Form { return $form->schema([ Select::make('orden_produccion_id') ->label('Orden de Producción') ->options(function () { // Solo OPs que tienen confecciones recibidas return \App\Models\OrdenProduccion::whereHas('confecciones', function ($q) { $q->where('cantidad_recibida', '>', 0); })->get()->mapWithKeys(function ($op) { // Calcular cantidad disponible desde confecciones (recibidas - arreglos - cobros) $cantidadRecibida = $op->confecciones->sum('cantidad_recibida'); $arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class) ->whereHas('referencia', function($q) use ($op) { $q->where('orden_produccion_id', $op->id); })->where('tipo', 'arreglo')->sum('cantidad'); $cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class) ->whereHas('referencia', function($q) use ($op) { $q->where('orden_produccion_id', $op->id); })->sum('cantidad'); $cantidadConfecciones = $cantidadRecibida - $arreglos - $cobros; // Calcular cantidad ya enviada en ojales $cantidadEnOjales = \App\Models\Ojal::where('orden_produccion_id', $op->id) ->sum('cantidad_enviada'); // Calcular saldo disponible $saldoDisponible = $cantidadConfecciones - $cantidadEnOjales; // Solo incluir si hay saldo disponible if ($saldoDisponible > 0) { return [$op->id => "{$op->numero_orden} (Disponible: {$saldoDisponible})"]; } return []; })->filter(); // Eliminar valores vacíos }) ->searchable() ->required() ->live() ->afterStateUpdated(function ($state, $set) { if ($state) { $op = \App\Models\OrdenProduccion::find($state); if ($op) { // Calcular cantidad disponible (confecciones - arreglos - cobros - ojales ya enviados) $cantidadRecibida = $op->confecciones->sum('cantidad_recibida'); $arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class) ->whereHas('referencia', function($q) use ($state) { $q->where('orden_produccion_id', $state); })->where('tipo', 'arreglo')->sum('cantidad'); $cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class) ->whereHas('referencia', function($q) use ($state) { $q->where('orden_produccion_id', $state); })->sum('cantidad'); $cantidadConfecciones = $cantidadRecibida - $arreglos - $cobros; $cantidadEnOjales = \App\Models\Ojal::where('orden_produccion_id', $state) ->sum('cantidad_enviada'); $cantidadDisponible = $cantidadConfecciones - $cantidadEnOjales; $set('cantidad_enviada', $cantidadDisponible); $set('referencia_info', $op->referencia ?? 'Sin referencia'); } } else { $set('referencia_info', null); } }) ->helperText('Solo se muestran órdenes con prendas disponibles para enviar'), TextInput::make('referencia_info') ->label('Referencia de la Prenda') ->disabled() ->dehydrated(false) ->visible(fn ($get) => $get('orden_produccion_id') !== null) ->helperText('Esta es la referencia de la prenda de la orden de producción seleccionada'), TextInput::make('tipo') ->label('Tipo') ->placeholder('Ej: Ojal, Prensilla, Botón, etc.') ->required() ->helperText('Especifica el tipo de accesorio'), TextInput::make('cantidad_enviada') ->label('Cantidad total disponible') ->numeric() ->readOnly() ->helperText(function ($state) { if (!$state) return 'Selecciona una OP primero'; return "Máximo disponible: {$state} unidades"; }) ->live(), Repeater::make('distribuciones') ->label('Distribución entre proveedores') ->schema([ Select::make('proveedor_id') ->label('Proveedor') ->options(fn () => \App\Models\Proveedor::where('categoria', 'empleado')->pluck('nombre', 'id')) ->searchable() ->required(), TextInput::make('cantidad') ->label('Cantidad') ->numeric() ->required() ->minValue(1) ->live() ->afterStateUpdated(function ($state, $set, $get) { // Validar que la suma no exceda el total $total = (int) ($get('../../cantidad_enviada') ?? 0); $distribuciones = $get('../../distribuciones') ?? []; $suma = 0; foreach ($distribuciones as $dist) { $suma += (int) ($dist['cantidad'] ?? 0); } if ($suma > $total) { throw \Illuminate\Validation\ValidationException::withMessages([ 'cantidad' => "La suma de las distribuciones ({$suma}) excede el total disponible ({$total})." ]); } }), ]) ->defaultItems(1) ->addActionLabel('Agregar proveedor') ->helperText(function ($get) { $total = (int) ($get('cantidad_enviada') ?? 0); $distribuciones = $get('distribuciones') ?? []; $suma = 0; foreach ($distribuciones as $dist) { $suma += (int) ($dist['cantidad'] ?? 0); } $restante = $total - $suma; if ($restante < 0) { return "⚠️ Excede el total por " . abs($restante) . " unidades"; } elseif ($restante > 0) { return "Faltan {$restante} unidades por distribuir"; } else { return "✓ Total distribuido correctamente"; } }) ->live(), Checkbox::make('terminada') ->label('Marcar como terminada') ->helperText('Al marcar terminada, se enviará automáticamente a tintorería') ->live(), ]); } public static function table(Tables\Table $table): Tables\Table { return $table ->columns([ Tables\Columns\TextColumn::make('tipo') ->label('Tipo') ->searchable() ->sortable() ->badge() ->color('info'), Tables\Columns\TextColumn::make('ordenProduccion.numero_orden') ->label('OP') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('cantidad_enviada') ->label('Cantidad') ->sortable(), Tables\Columns\TextColumn::make('proveedor.nombre') ->label('Proveedor') ->searchable() ->default('Sin asignar'), Tables\Columns\IconColumn::make('terminada') ->boolean() ->label('Terminada') ->sortable(), Tables\Columns\TextColumn::make('fecha_envio') ->date() ->label('Fecha envío') ->sortable(), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->label('Creado') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ SelectFilter::make('tipo') ->label('Tipo'), SelectFilter::make('terminada') ->options([ '0' => 'Pendiente', '1' => 'Terminada', ]) ]) ->actions([ Tables\Actions\EditAction::make(), Tables\Actions\Action::make('marcar_terminada') ->label('Terminar') ->icon('heroicon-o-check-circle') ->color('success') ->visible(fn ($record) => !$record->terminada) ->requiresConfirmation() ->modalHeading('Marcar como terminado') ->modalDescription('¿Confirmas que este proceso ha terminado?') ->action(function ($record) { $record->terminada = true; $record->save(); \Filament\Notifications\Notification::make() ->success() ->title('Marcado como terminado') ->send(); }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]) ->defaultSort('created_at', 'desc'); } public static function getPages(): array { return [ 'index' => Pages\ListOjalPresillas::route('/'), 'create' => Pages\CreateOjalPresilla::route('/create'), 'edit' => Pages\EditOjalPresilla::route('/{record}/edit'), ]; } }