diff --git a/app/Filament/Resources/ProcesoAcabadoResource.php b/app/Filament/Resources/ProcesoAcabadoResource.php index 6b3da61..5366ef1 100644 --- a/app/Filament/Resources/ProcesoAcabadoResource.php +++ b/app/Filament/Resources/ProcesoAcabadoResource.php @@ -36,82 +36,87 @@ class ProcesoAcabadoResource extends Resource public static function form(Form $form): Form { return $form->schema([ - Section::make('Datos iniciales') + Section::make('Información del Proceso') ->schema([ Select::make('orden_produccion_id') ->label('Orden de Producción') - ->options(fn () => \App\Models\OrdenProduccion::whereRaw('( - (select coalesce(sum(cantidad_recibida),0) from tintorerias where tintorerias.orden_produccion_id = orden_produccions.id) - - ( - select coalesce(sum(cantidad_enviada),0) from proceso_acabados where proceso_acabados.orden_produccion_id = orden_produccions.id and proceso_acabados.fecha_recepcion is null - ) - ) > 0')->pluck('numero_orden', 'id')->toArray()) + ->options(fn () => \App\Models\OrdenProduccion::all()->pluck('numero_orden', 'id')->toArray()) ->searchable() ->reactive() ->required() ->afterStateUpdated(function ($state, $set) { if ($state) { - // Total recibido en Tintorería para esta OP - $sumTint = \App\Models\Tintoreria::where('orden_produccion_id', $state)->sum('cantidad_recibida'); - - // Restar todo lo ya enviado a procesos de acabados (de la misma OP) - $sentToAcabados = \App\Models\ProcesoAcabado::where('orden_produccion_id', $state) - ->sum('cantidad_enviada'); - - $pending = max(0, (int)$sumTint - (int)$sentToAcabados); - - $set('cantidad_enviada', $pending ?: 0); - $set('fecha_envio', now()->toDateString()); + // Calcular cantidad disponible desde Tintorería + $disponible = \App\Models\Tintoreria::where('orden_produccion_id', $state) + ->sum('cantidad_recibida'); + + $set('cantidad_enviada', $disponible ?: 0); } }), TextInput::make('tipo_proceso') ->label('Tipo de proceso') + ->placeholder('Ej: Planchado, Empacado, etc.') ->required(), - Select::make('proveedor_id') - ->label('Proveedor (opcional)') - ->relationship('proveedor', 'nombre') - ->searchable() - ->preload() - ->nullable(), - - TextInput::make('responsable_interno') - ->label('Responsable interno') - ->nullable(), - TextInput::make('cantidad_enviada') + ->label('Cantidad a enviar') ->numeric() ->required() + ->minValue(1) ->reactive() - ->helperText(fn ($get) => 'Sugerido: ' . (max(0, (int)\App\Models\Tintoreria::where('orden_produccion_id', $get('orden_produccion_id'))->sum('cantidad_recibida') - (int)\App\Models\ProcesoAcabado::where('orden_produccion_id', $get('orden_produccion_id'))->sum('cantidad_enviada')) ?: 0)), - + ->helperText(fn ($get) => { + $op_id = $get('orden_produccion_id'); + if (!$op_id) return 'Selecciona una orden de producción primero'; + $disponible = \App\Models\Tintoreria::where('orden_produccion_id', $op_id)->sum('cantidad_recibida'); + return 'Disponible desde Tintorería: ' . $disponible; + }), DatePicker::make('fecha_envio') + ->label('Fecha de envío') ->required() ->default(now()), ]) ->columns(2), - Section::make('Recepción') + Section::make('Distribución de Proveedores') + ->description('Asigna la cantidad a enviar a cada proveedor') ->schema([ - DatePicker::make('fecha_recepcion') - ->nullable(), - - TextInput::make('cantidad_recibida') - ->numeric() - ->reactive() - ->afterStateUpdated(function ($state, $set, $get) { - // Mantener residual o validaciones posteriores - $cantidad_enviada = $get('cantidad_enviada') ?? 0; - $cantidad_recibida = $state ?? 0; - $residual = $cantidad_enviada - $cantidad_recibida; - if ($residual < 0) $residual = 0; - $set('observaciones', $get('observaciones') ?? 'Residual: ' . $residual); - }), - + Forms\Components\Repeater::make('distribucion_proveedores') + ->label('') + ->schema([ + Select::make('proveedor_id') + ->label('Proveedor') + ->options(\App\Models\Proveedor::pluck('nombre', 'id')) + ->searchable() + ->required(), + + TextInput::make('cantidad') + ->label('Cantidad') + ->numeric() + ->required() + ->minValue(1), + ]) + ->columns(2) + ->defaultItems(1) + ->addActionLabel('Agregar otro proveedor') + ->collapsible() + ->cloneable(), ]) - ->columns(2), + ->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), ]); } @@ -121,28 +126,50 @@ class ProcesoAcabadoResource extends Resource ->columns([ TextColumn::make('ordenProduccion.numero_orden') ->label('OP') + ->searchable() + ->sortable(), + + TextColumn::make('tipo_proceso') + ->label('Tipo de proceso') ->searchable(), - TextColumn::make('tipo_proceso'), + TextColumn::make('cantidad_enviada') + ->label('Cantidad') + ->sortable(), - TextColumn::make('proveedor.nombre') - ->label('Proveedor') - ->toggleable(), + 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), - TextColumn::make('responsable_interno') - ->toggleable(), - - TextColumn::make('cantidad_enviada'), - - TextColumn::make('cantidad_recibida'), - - BadgeColumn::make('fecha_recepcion') + BadgeColumn::make('terminada') ->label('Estado') - ->formatStateUsing(fn($state) => $state ? 'Completado' : 'Pendiente') + ->formatStateUsing(fn($state) => $state ? 'Terminada' : 'En proceso') ->colors([ - 'warning' => null, - 'success' => fn($state) => $state !== null, + '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([ @@ -151,6 +178,12 @@ class ProcesoAcabadoResource extends Resource ->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(), diff --git a/app/Models/ProcesoAcabado.php b/app/Models/ProcesoAcabado.php index f249773..11ab493 100644 --- a/app/Models/ProcesoAcabado.php +++ b/app/Models/ProcesoAcabado.php @@ -10,14 +10,23 @@ class ProcesoAcabado extends Model 'orden_produccion_id', 'tipo_proceso', 'proveedor_id', + 'distribucion_proveedores', 'responsable_interno', 'cantidad_enviada', 'cantidad_recibida', 'fecha_envio', 'fecha_recepcion', + 'terminada', 'observaciones', ]; + protected $casts = [ + 'distribucion_proveedores' => 'array', + 'terminada' => 'boolean', + 'fecha_envio' => 'date', + 'fecha_recepcion' => 'date', + ]; + /* Relaciones */ public function ordenProduccion() { diff --git a/database/migrations/2026_01_30_030321_add_terminada_and_distribucion_to_proceso_acabados_table.php b/database/migrations/2026_01_30_030321_add_terminada_and_distribucion_to_proceso_acabados_table.php new file mode 100644 index 0000000..be57c63 --- /dev/null +++ b/database/migrations/2026_01_30_030321_add_terminada_and_distribucion_to_proceso_acabados_table.php @@ -0,0 +1,23 @@ +json('distribucion_proveedores')->nullable()->after('proveedor_id'); + $table->boolean('terminada')->default(false)->after('fecha_recepcion'); + }); + } + + public function down(): void + { + Schema::table('proceso_acabados', function (Blueprint $table) { + $table->dropColumn(['distribucion_proveedores', 'terminada']); + }); + } +};