schema([ Section::make('Información del Proceso') ->schema([ Select::make('orden_produccion_id') ->label('Orden de Producción') ->options(fn () => \App\Models\OrdenProduccion::all()->pluck('numero_orden', 'id')->toArray()) ->searchable() ->reactive() ->required() ->afterStateUpdated(function ($state, $set) { if ($state) { // Calcular cantidad disponible desde Tintorería (neto: recepciones - reprocesos - cobros) $tintoreriaRecords = \App\Models\Tintoreria::where('orden_produccion_id', $state)->get(); $disponible = 0; foreach ($tintoreriaRecords as $tintoreria) { $recepciones = (int) $tintoreria->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); $reprocesos = (int) $tintoreria->ajustes()->where('tipo', 'reproceso')->sum('cantidad'); $cobros = (int) $tintoreria->cobros()->sum('cantidad'); $disponible += ($recepciones - $reprocesos - $cobros); } // Restar lo que ya se envió a otros acabados $yaEnAcabados = \App\Models\ProcesoAcabado::where('orden_produccion_id', $state) ->sum('cantidad_enviada'); $disponible = max(0, $disponible - $yaEnAcabados); $set('cantidad_enviada', $disponible); $orden = \App\Models\OrdenProduccion::find($state); $set('referencia_info', $orden->referencia ?? 'Sin referencia'); } else { $set('referencia_info', null); } }), 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_proceso') ->label('Tipo de proceso') ->placeholder('Ej: Planchado, Empacado, etc.') ->required(), TextInput::make('cantidad_enviada') ->label('Cantidad a enviar') ->numeric() ->required() ->minValue(1) ->reactive() ->helperText(function ($get) { $op_id = $get('orden_produccion_id'); if (!$op_id) return 'Selecciona una orden de producción primero'; // Calcular disponible neto desde Tintorería $tintoreriaRecords = \App\Models\Tintoreria::where('orden_produccion_id', $op_id)->get(); $disponible = 0; foreach ($tintoreriaRecords as $tintoreria) { $recepciones = (int) $tintoreria->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); $reprocesos = (int) $tintoreria->ajustes()->where('tipo', 'reproceso')->sum('cantidad'); $cobros = (int) $tintoreria->cobros()->sum('cantidad'); $disponible += ($recepciones - $reprocesos - $cobros); } // Restar lo que ya se envió a otros acabados $yaEnAcabados = \App\Models\ProcesoAcabado::where('orden_produccion_id', $op_id) ->sum('cantidad_enviada'); $disponible = max(0, $disponible - $yaEnAcabados); return 'Disponible desde Tintorería: ' . $disponible; }), DatePicker::make('fecha_envio') ->label('Fecha de envío') ->required() ->default(now()), ]) ->columns(2), Section::make('Distribución de Proveedores') ->description('Asigna la cantidad a enviar a cada proveedor') ->schema([ Forms\Components\Repeater::make('distribucion_proveedores') ->label('') ->schema([ Select::make('proveedor_id') ->label('Proveedor') ->options(\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 disponible $total = (int) ($get('../../cantidad_enviada') ?? 0); $distribuciones = $get('../../distribucion_proveedores') ?? []; $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})." ]); } }), ]) ->columns(2) ->defaultItems(1) ->addActionLabel('Agregar otro proveedor') ->collapsible() ->cloneable() ->live() ->helperText(function ($get) { $total = (int) ($get('cantidad_enviada') ?? 0); $distribuciones = $get('distribucion_proveedores') ?? []; $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"; } }), ]) ->collapsed(fn ($get) => !$get('distribucion_proveedores')), Section::make('Estado') ->schema([ Forms\Components\Checkbox::make('terminada') ->label('Marcar como terminada') ->helperText('Marca esta casilla cuando el proceso haya finalizado'), Textarea::make('observaciones') ->label('Observaciones') ->rows(3) ->nullable(), ]) ->columns(1), ]); } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('ordenProduccion.numero_orden') ->label('OP') ->searchable() ->sortable(), TextColumn::make('tipo_proceso') ->label('Tipo de proceso') ->searchable(), TextColumn::make('cantidad_enviada') ->label('Cantidad') ->sortable(), TextColumn::make('proveedores_asignados') ->label('Proveedores') ->getStateUsing(function ($record) { if (!$record->distribucion_proveedores) return 'Sin asignar'; $distribuciones = collect($record->distribucion_proveedores); return $distribuciones->map(function ($dist) { $proveedor = \App\Models\Proveedor::find($dist['proveedor_id'] ?? null); $nombre = $proveedor ? $proveedor->nombre : 'Desconocido'; return "{$nombre} ({$dist['cantidad']})"; })->join(', '); }) ->wrap() ->limit(50), BadgeColumn::make('terminada') ->label('Estado') ->formatStateUsing(fn($state) => $state ? 'Terminada' : 'En proceso') ->colors([ 'warning' => false, 'success' => true, ]), TextColumn::make('fecha_envio') ->label('Fecha envío') ->date() ->sortable(), TextColumn::make('created_at') ->label('Creado') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->defaultSort('created_at', 'desc') ->filters([ Tables\Filters\SelectFilter::make('orden_produccion_id') ->label('Orden de Producción') ->relationship('ordenProduccion', 'numero_orden') ->searchable() ->preload(), Tables\Filters\TernaryFilter::make('terminada') ->label('Estado') ->placeholder('Todos') ->trueLabel('Terminadas') ->falseLabel('En proceso'), ]) ->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\ListProcesoAcabados::route('/'), 'create' => Pages\CreateProcesoAcabado::route('/create'), 'edit' => Pages\EditProcesoAcabado::route('/{record}/edit'), ]; } }