From 35f56cbbe0efbc8c2b13f0c99657f3f780218077 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:14:05 -0500 Subject: [PATCH] up --- .../Pages/EditConfeccion.php | 10 +- .../RecepcionesRelationManager.php | 11 +- app/Models/Confeccion.php | 110 ++++++++---------- app/Models/Recepcion.php | 36 +++++- scripts/debug_confeccion_9.php | 67 +++++++++++ scripts/debug_op_9.php | 72 ++++++++++++ scripts/sync_inventarios.php | 75 ++++++++++++ 7 files changed, 299 insertions(+), 82 deletions(-) create mode 100644 scripts/debug_confeccion_9.php create mode 100644 scripts/debug_op_9.php create mode 100644 scripts/sync_inventarios.php diff --git a/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php b/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php index c7f0467..014b504 100644 --- a/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php +++ b/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php @@ -30,12 +30,8 @@ class EditConfeccion extends EditRecord ->helperText(fn () => 'Máximo: ' . ($this->getRecord()->faltantes ?? 0)) ->default(fn () => $this->getRecord()->faltantes ?? 0), - Forms\Components\TextInput::make('prendas_defectuosas') - ->numeric() - ->minValue(0) - ->maxValue(fn ($get) => (int) ($get('cantidad') ?? 0)) - ->helperText('Opcional. Se restará del total recibido.'), - Forms\Components\Textarea::make('notas'), + Forms\Components\Textarea::make('notas') + ->helperText('Si hay prendas defectuosas, regístralas después en "Arreglos".'), ]) ->action(function (array $data): void { $record = $this->getRecord(); @@ -46,7 +42,7 @@ class EditConfeccion extends EditRecord 'referencia_id' => $record->id, 'cantidad' => (int) $data['cantidad'], 'fecha_recepcion' => $data['fecha_recepcion'], - 'prendas_defectuosas' => isset($data['prendas_defectuosas']) ? (int) $data['prendas_defectuosas'] : 0, + 'prendas_defectuosas' => 0, 'notas' => $data['notas'] ?? null, ]); diff --git a/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php b/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php index fff31a9..28cd9b0 100644 --- a/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php +++ b/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php @@ -30,14 +30,8 @@ class RecepcionesRelationManager extends RelationManager ->maxValue(fn () => $this->getOwnerRecord()?->faltantes ?? 0) ->helperText(fn () => 'Máximo: ' . ($this->getOwnerRecord()?->faltantes ?? 0)), - TextInput::make('prendas_defectuosas') - ->label('Faltantes') - ->numeric() - ->minValue(0) - ->maxValue(fn ($get) => (int) ($get('cantidad') ?? 0)) - ->helperText('Opcional. Se restará del total recibido.'), - - Textarea::make('notas'), + Textarea::make('notas') + ->helperText('Si hay prendas defectuosas, regístralas en "Arreglos" después de crear la recepción.'), ]); } @@ -48,7 +42,6 @@ class RecepcionesRelationManager extends RelationManager TextColumn::make('id')->label('#'), TextColumn::make('fecha_recepcion')->dateTime()->label('Fecha'), TextColumn::make('cantidad')->label('Cantidad'), - TextColumn::make('prendas_defectuosas')->label('Faltantes'), TextColumn::make('usuario.name')->label('Usuario'), TextColumn::make('notas')->limit(50)->wrap(), TextColumn::make('created_at')->dateTime()->label('Creado'), diff --git a/app/Models/Confeccion.php b/app/Models/Confeccion.php index 2feb646..ac93534 100644 --- a/app/Models/Confeccion.php +++ b/app/Models/Confeccion.php @@ -118,7 +118,8 @@ class Confeccion extends Model } /** - * Registrar un arreglo como ajuste histórico y crear traslado de reparaciones + * Registrar un arreglo: prendas que llegaron mal y salen a reparación + * Permiten re-recepción cuando regresen arregladas */ public function registerArreglo(int $cantidad, ?string $notas = null, ?int $userId = null) { @@ -126,9 +127,25 @@ class Confeccion extends Model throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); } - $recibido = $this->recibido_total; - if ($cantidad > $recibido) { - throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad supera lo recibido.']); + // Validar que no exceda las recepciones efectivas (solo puedes marcar como arreglo lo que YA recibiste) + $recepcionesEfectivas = (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $arreglosActuales = (int) $this->ajustes()->where('tipo', 'arreglo')->sum('cantidad'); + + $disponibleParaArreglos = $recepcionesEfectivas - $arreglosActuales; + + if ($cantidad > $disponibleParaArreglos) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'cantidad' => "No puedes registrar {$cantidad} prendas como arreglo. + + 📊 Resumen: + • Recepciones efectivas: {$recepcionesEfectivas} + • Arreglos ya registrados: {$arreglosActuales} + • Disponible para marcar como arreglo: {$disponibleParaArreglos} + + ➡️ Solo puedes registrar máximo {$disponibleParaArreglos} prendas como arreglo. + + 💡 Los arreglos deben ser de prendas YA recibidas que necesitan reparación." + ]); } // Crear ajuste @@ -141,31 +158,12 @@ class Confeccion extends Model 'notas' => $notas, ]); - // Crear traslado de reparaciones para reflejar la salida - \App\Models\TrasladoPrenda::create([ - 'orden_produccion_id' => $this->orden_produccion_id, - 'referencia_type' => self::class, - 'referencia_id' => $this->id, - 'origen' => 'confeccion', - 'destino' => 'reparaciones', - 'cantidad_enviada' => $cantidad, - 'cantidad_recibida' => 0, - 'prendas_defectuosas' => 0, - 'reparaciones' => $cantidad, - 'fecha_envio' => now(), - 'fecha_recepcion' => now(), - 'estado' => 'recibido', - ]); - - // Recalcular cantidad_recibida almacenada para compatibilidad con UI - $this->cantidad_recibida = $this->recibido_total; - $this->save(); - return $aj; } /** - * Registrar un cobro: descontar inventario y crear registro de cobro + * Registrar un cobro: solo registra el cobro sin descontar inventario + * Los cobros son prendas que NO llegaron - se cobran al confeccionista */ public function registerCobro(int $cantidad, float $valor, ?string $notas = null, ?int $userId = null) { @@ -173,46 +171,36 @@ class Confeccion extends Model throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); } - if (!$this->orden_produccion_id) { - throw \Illuminate\Validation\ValidationException::withMessages(['orden_produccion_id' => 'La confección debe tener una orden de producción asociada.']); + // Validar que no se exceda lo enviado + $enviada = (int) ($this->cantidad_enviada ?? 0); + if ($enviada <= 0) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La confección no tiene cantidad_enviada registrada.']); } - // Buscar inventarios disponibles de esta orden de producción - $inventarios = \App\Models\InventarioPrenda::where('orden_produccion_id', $this->orden_produccion_id) - ->where('cantidad_disponible', '>', 0) - ->orderBy('cantidad_disponible', 'desc') - ->get(); - - if ($inventarios->isEmpty()) { - throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'No hay inventario disponible para la orden de producción #' . $this->orden_produccion_id . '. Asegúrate de que exista inventario con cantidad_disponible > 0.']); - } - - $totalDisponible = $inventarios->sum('cantidad_disponible'); + // Calcular lo que ya se ha contabilizado + $recepcionesEfectivas = (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $arreglos = (int) $this->ajustes()->where('tipo', 'arreglo')->sum('cantidad'); + $recibidoNeto = $recepcionesEfectivas - $arreglos; // Los arreglos permiten re-recepción - if ($totalDisponible < $cantidad) { - throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => "Solo hay {$totalDisponible} unidades disponibles en inventario. No se puede descontar {$cantidad}."]); - } + $cobrosActuales = (int) $this->cobros()->sum('cantidad'); + + $totalContabilizado = $recibidoNeto + $cobrosActuales; + $disponible = $enviada - $totalContabilizado; - // Descontar del inventario de forma distribuida si es necesario - $cantidadRestante = $cantidad; - foreach ($inventarios as $inventario) { - if ($cantidadRestante <= 0) { - break; - } - - $aDescontar = min($cantidadRestante, $inventario->cantidad_disponible); - $inventario->cantidad_disponible -= $aDescontar; - $inventario->save(); - - // Si está asociado a producto, decrementar stock - if ($inventario->producto_id) { - $producto = \App\Models\Producto::find($inventario->producto_id); - if ($producto) { - $producto->decrement('stock', $aDescontar); - } - } - - $cantidadRestante -= $aDescontar; + if ($cantidad > $disponible) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'cantidad' => "No puedes registrar {$cantidad} prendas como cobro. + + 📊 Resumen: + • Enviadas: {$enviada} + • Recepciones efectivas: {$recepcionesEfectivas} + • Arreglos (permiten re-recepción): {$arreglos} + • Recibido neto: {$recibidoNeto} + • Cobros registrados: {$cobrosActuales} + • Disponible para cobros: {$disponible} + + ➡️ Solo puedes registrar máximo {$disponible} prendas más como cobros." + ]); } // Crear registro de cobro diff --git a/app/Models/Recepcion.php b/app/Models/Recepcion.php index a3acd93..81f1fcf 100644 --- a/app/Models/Recepcion.php +++ b/app/Models/Recepcion.php @@ -60,20 +60,46 @@ class Recepcion extends Model $rec->fecha_recepcion = now(); } - // Validación: no permitir sobrepasar la cantidad enviada en la referencia (considerando defectuosos) + // Validación: no permitir sobrepasar la cantidad enviada en la referencia (considerando cobros) if ($rec->referencia) { $referencia = $rec->referencia; $enviada = (int) ($referencia->cantidad_enviada ?? 0); - // ya recibido efectivo (cantidad - defectuosos) + // Ya recibido efectivo (cantidad - defectuosos) - arreglos permiten re-recepción $yaRecibido = (int) \App\Models\Recepcion::where('referencia_type', get_class($referencia)) ->where('referencia_id', $referencia->id) ->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + + // Los arreglos se restan porque permiten re-recepción cuando regresen + $arreglos = 0; + if (method_exists($referencia, 'ajustes')) { + $arreglos = (int) $referencia->ajustes()->where('tipo', 'arreglo')->sum('cantidad'); + } + + // Los cobros NO permiten más recepciones (son prendas que no llegaron) + $cobros = 0; + if (method_exists($referencia, 'cobros')) { + $cobros = (int) $referencia->cobros()->sum('cantidad'); + } $efectivo = $rec->cantidad - $rec->prendas_defectuosas; - - if (($yaRecibido + $efectivo) > $enviada) { - throw ValidationException::withMessages(['cantidad' => "La recepción excede la cantidad pendiente (faltan: " . max(0, $enviada - $yaRecibido) . ")."]); + $yaRecibidoNeto = $yaRecibido - $arreglos; + $maxPermitido = $enviada - $cobros; + + if (($yaRecibidoNeto + $efectivo) > $maxPermitido) { + $disponible = max(0, $maxPermitido - $yaRecibidoNeto); + throw ValidationException::withMessages([ + 'cantidad' => "La recepción excede lo permitido. + + 📊 Resumen: + • Enviadas: {$enviada} + • Ya recibidas (neto): {$yaRecibidoNeto} + • Cobros registrados: {$cobros} + • Arreglos (permiten re-recepción): {$arreglos} + • Disponible para recibir: {$disponible} + + ➡️ Solo puedes recibir {$disponible} prendas más." + ]); } } diff --git a/scripts/debug_confeccion_9.php b/scripts/debug_confeccion_9.php new file mode 100644 index 0000000..695490a --- /dev/null +++ b/scripts/debug_confeccion_9.php @@ -0,0 +1,67 @@ +make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +echo "=== Diagnóstico de Confección #9 ===\n\n"; + +$confeccion = \App\Models\Confeccion::find(9); + +if (!$confeccion) { + echo "❌ No se encontró la confección con ID 9\n"; + exit(1); +} + +echo "✅ Confección encontrada:\n"; +echo " ID: {$confeccion->id}\n"; +echo " Orden Producción ID: {$confeccion->orden_produccion_id}\n"; +echo " Cliente: {$confeccion->cliente->nombre}\n\n"; + +if (!$confeccion->orden_produccion_id) { + echo "❌ La confección NO tiene orden_produccion_id asociada\n"; + exit(1); +} + +echo "=== Buscando inventarios para orden_produccion_id = {$confeccion->orden_produccion_id} ===\n\n"; + +$inventarios = \App\Models\InventarioPrenda::where('orden_produccion_id', $confeccion->orden_produccion_id)->get(); + +echo "Total inventarios encontrados: {$inventarios->count()}\n\n"; + +if ($inventarios->isEmpty()) { + echo "❌ NO HAY INVENTARIOS para esta orden de producción\n"; + echo " Esto explica el error\n\n"; + + // Verificar si existe la orden de producción + $op = \App\Models\OrdenProduccion::find($confeccion->orden_produccion_id); + if ($op) { + echo "✅ La orden de producción #{$op->id} existe:\n"; + echo " Producto: " . ($op->producto->nombre ?? 'N/A') . "\n"; + echo " Cantidad: {$op->cantidad}\n"; + echo " Estado: {$op->estado}\n\n"; + echo "⚠️ Necesitas crear registros de inventario para esta orden\n"; + } else { + echo "❌ La orden de producción no existe\n"; + } +} else { + echo "Detalles de inventarios:\n"; + foreach ($inventarios as $inv) { + echo "---\n"; + echo "ID: {$inv->id}\n"; + echo "Cantidad terminada: {$inv->cantidad_terminada}\n"; + echo "Cantidad disponible: {$inv->cantidad_disponible}\n"; + echo "Estado: {$inv->estado}\n"; + echo "Producto ID: {$inv->producto_id}\n"; + } + + $totalDisponible = $inventarios->sum('cantidad_disponible'); + echo "\n✅ Total disponible: {$totalDisponible} unidades\n"; + + if ($totalDisponible > 0) { + echo "✅ Hay inventario suficiente para registrar cobros\n"; + } else { + echo "❌ No hay inventario con cantidad_disponible > 0\n"; + } +} diff --git a/scripts/debug_op_9.php b/scripts/debug_op_9.php new file mode 100644 index 0000000..0215b72 --- /dev/null +++ b/scripts/debug_op_9.php @@ -0,0 +1,72 @@ +make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +echo "=== Diagnóstico de Orden de Producción #9 ===\n\n"; + +$op = \App\Models\OrdenProduccion::find(9); + +if (!$op) { + echo "❌ No se encontró la orden de producción con ID 9\n"; + exit(1); +} + +echo "✅ Orden de Producción encontrada:\n"; +echo " ID: {$op->id}\n"; +echo " Producto: " . ($op->producto->nombre ?? 'N/A') . " (ID: {$op->producto_id})\n"; +echo " Cantidad: {$op->cantidad}\n"; +echo " Estado: {$op->estado}\n\n"; + +// Buscar confecciones asociadas +$confecciones = \App\Models\Confeccion::where('orden_produccion_id', 9)->get(); +echo "Confecciones asociadas a esta OP: {$confecciones->count()}\n"; +foreach ($confecciones as $conf) { + $clienteNombre = $conf->cliente ? $conf->cliente->nombre : 'Sin cliente'; + echo " - Confección #{$conf->id} - Cliente: {$clienteNombre}\n"; +} +echo "\n"; + +echo "=== Buscando inventarios para orden_produccion_id = 9 ===\n\n"; + +$inventarios = \App\Models\InventarioPrenda::where('orden_produccion_id', 9)->get(); + +echo "Total inventarios encontrados: {$inventarios->count()}\n\n"; + +if ($inventarios->isEmpty()) { + echo "❌ NO HAY INVENTARIOS para esta orden de producción\n"; + echo " Esto explica el error al intentar registrar cobros\n\n"; + echo "⚠️ Necesitas crear registros de InventarioPrenda para esta orden\n"; + echo " Deberías ir a la sección de recepciones/inventario y registrar\n"; + echo " las {$op->cantidad} prendas producidas\n"; +} else { + echo "Detalles de inventarios:\n"; + $totalTerminada = 0; + $totalDisponible = 0; + + foreach ($inventarios as $inv) { + echo "---\n"; + echo "ID: {$inv->id}\n"; + echo "Cantidad terminada: {$inv->cantidad_terminada}\n"; + echo "Cantidad disponible: {$inv->cantidad_disponible}\n"; + echo "Estado: {$inv->estado}\n"; + echo "Producto ID: {$inv->producto_id}\n"; + echo "Fecha ingreso: {$inv->fecha_ingreso}\n"; + + $totalTerminada += $inv->cantidad_terminada; + $totalDisponible += $inv->cantidad_disponible; + } + + echo "\n📊 Resumen:\n"; + echo " Total terminada: {$totalTerminada} unidades\n"; + echo " Total disponible: {$totalDisponible} unidades\n"; + + if ($totalDisponible > 0) { + echo "\n✅ Hay inventario suficiente para registrar cobros\n"; + } else { + echo "\n❌ No hay inventario con cantidad_disponible > 0\n"; + echo " Todas las prendas ya han sido cobradas/distribuidas\n"; + } +} diff --git a/scripts/sync_inventarios.php b/scripts/sync_inventarios.php new file mode 100644 index 0000000..9d9f8db --- /dev/null +++ b/scripts/sync_inventarios.php @@ -0,0 +1,75 @@ +make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +echo "=== Sincronización de Inventarios desde Recepciones ===\n\n"; + +// Buscar todas las confecciones que tienen recepciones pero cuya OP no tiene inventario +$confecciones = \App\Models\Confeccion::whereNotNull('orden_produccion_id') + ->whereHas('recepciones') + ->with(['ordenProduccion', 'recepciones']) + ->get(); + +echo "Total confecciones con recepciones: {$confecciones->count()}\n\n"; + +$creados = 0; +$actualizados = 0; +$sinCambios = 0; + +foreach ($confecciones as $confeccion) { + $op_id = $confeccion->orden_produccion_id; + $op = $confeccion->ordenProduccion; + + if (!$op) { + echo "⚠️ Confección #{$confeccion->id} tiene orden_produccion_id={$op_id} pero la OP no existe\n"; + continue; + } + + // Sumar recepciones efectivas (cantidad - defectuosas) + $totalRecibido = $confeccion->recepciones->sum(function($rec) { + return $rec->cantidad - ($rec->prendas_defectuosas ?? 0); + }); + + if ($totalRecibido <= 0) { + continue; + } + + // Buscar o crear inventario + $inventario = \App\Models\InventarioPrenda::where('orden_produccion_id', $op_id)->first(); + + if (!$inventario) { + // Crear inventario nuevo + $inventario = \App\Models\InventarioPrenda::create([ + 'orden_produccion_id' => $op_id, + 'cantidad_terminada' => $totalRecibido, + 'cantidad_disponible' => $totalRecibido, + 'fecha_ingreso' => $confeccion->recepciones->first()->fecha_recepcion ?? now(), + 'estado' => 'en_bodega', + ]); + + echo "✅ Creado inventario para OP #{$op_id} con {$totalRecibido} prendas\n"; + echo " → Confección #{$confeccion->id}\n"; + $creados++; + } else { + // Verificar si necesita actualización + if ($inventario->cantidad_terminada < $totalRecibido) { + $diferencia = $totalRecibido - $inventario->cantidad_terminada; + $inventario->cantidad_terminada = $totalRecibido; + $inventario->cantidad_disponible += $diferencia; + $inventario->save(); + + echo "✅ Actualizado inventario para OP #{$op_id}: +{$diferencia} prendas (total: {$totalRecibido})\n"; + $actualizados++; + } else { + $sinCambios++; + } + } +} + +echo "\n📊 Resumen:\n"; +echo " Inventarios creados: {$creados}\n"; +echo " Inventarios actualizados: {$actualizados}\n"; +echo " Sin cambios: {$sinCambios}\n";