diff --git a/app/Models/InventarioPrendaDistribucion.php b/app/Models/InventarioPrendaDistribucion.php index 13b3377..2ea42e7 100644 --- a/app/Models/InventarioPrendaDistribucion.php +++ b/app/Models/InventarioPrendaDistribucion.php @@ -166,10 +166,7 @@ class InventarioPrendaDistribucion extends Model \DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]); } - $prod = \App\Models\Producto::find($productoId); - if ($prod && ! $prod->variants()->exists()) { - $prod->increment('stock', $cantidad); - } + // Nota: No incrementamos el stock global del producto aquí — el stock global ya se incrementó cuando se creó el InventarioPrenda. // Reducir disponibilidad en inventario_prenda $parent = $dist->inventarioPrenda; diff --git a/app/Models/OrdenProduccion.php b/app/Models/OrdenProduccion.php index 4d7f41e..1513ff5 100644 --- a/app/Models/OrdenProduccion.php +++ b/app/Models/OrdenProduccion.php @@ -79,9 +79,8 @@ class OrdenProduccion extends Model $orden->referencia = ''; } - // Reserva de tela al crear cuando la OP ya nace en 'en_corte' - $estadoInicial = $orden->estado ?? 'en_corte'; - if ($estadoInicial === 'en_corte' && $orden->tela_id && ($orden->metros_requeridos ?? 0) > 0) { + // Reserva de tela al crear cuando la OP usa una tela: restar metros_disponibles inmediatamente + if ($orden->tela_id && ($orden->metros_requeridos ?? 0) > 0) { $tela = \App\Models\Tela::find($orden->tela_id); if (! $tela) { throw \Illuminate\Validation\ValidationException::withMessages([ @@ -119,6 +118,60 @@ class OrdenProduccion extends Model } } + // Ajustes automáticos de reserva cuando cambia la tela o los metros requeridos + $originalTelaId = $orden->getOriginal('tela_id'); + $originalMetros = $orden->getOriginal('metros_requeridos') ?? 0; + $newTelaId = $orden->tela_id; + $newMetros = $orden->metros_requeridos ?? 0; + + // Si cambió la tela en la OP, devolver los metros reservados en la tela anterior (si aplica) + if ($originalTelaId && $originalTelaId != $newTelaId && $originalMetros > 0) { + $oldTela = \App\Models\Tela::find($originalTelaId); + if ($oldTela) { + $oldTela->metros_disponibles = $oldTela->metros_disponibles + $originalMetros; + $oldTela->save(); + } + } + + // Reservar metros en la nueva tela si se cambió + if ($newTelaId && $originalTelaId != $newTelaId && $newMetros > 0) { + $newTela = \App\Models\Tela::find($newTelaId); + if (! $newTela) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'tela_id' => 'No se encontró la tela asociada.', + ]); + } + + if ($newTela->metros_disponibles < $newMetros) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'metros_requeridos' => 'No hay suficientes metros disponibles para reservar (' . $newTela->metros_disponibles . ').', + ]); + } + + $newTela->metros_disponibles = $newTela->metros_disponibles - $newMetros; + $newTela->save(); + $orden->tela_reservada = true; + } + + // Si la misma tela y cambiaron los metros, ajustar la diferencia + if ($originalTelaId == $newTelaId && $originalMetros != $newMetros && $newTelaId) { + $delta = $newMetros - $originalMetros; + $tela = \App\Models\Tela::find($newTelaId); + if ($tela) { + if ($delta > 0) { + if ($tela->metros_disponibles < $delta) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'metros_requeridos' => 'No hay suficientes metros disponibles para aumentar la reserva.', + ]); + } + $tela->metros_disponibles = $tela->metros_disponibles - $delta; + } elseif ($delta < 0) { + $tela->metros_disponibles = $tela->metros_disponibles + abs($delta); + } + $tela->save(); + } + } + $originalEstado = $orden->getOriginal('estado'); $nuevoEstado = $orden->estado; diff --git a/tests/Feature/InventarioDistribucionTest.php b/tests/Feature/InventarioDistribucionTest.php index ffc767e..50eee79 100644 --- a/tests/Feature/InventarioDistribucionTest.php +++ b/tests/Feature/InventarioDistribucionTest.php @@ -85,6 +85,36 @@ class InventarioDistribucionTest extends TestCase $this->assertEquals(2, $pivot->stock); } + public function test_distribution_does_not_double_increment_product_stock() + { + $categoria = \App\Models\Categoria::create(['nombre' => 'Ropa']); + $producto = Producto::create(['nombre' => 'Doblez', 'descripcion' => '', 'stock' => 0, 'estado' => true, 'precio_compra' => 0, 'precio_venta' => 0, 'unidad_medida' => 'unidad', 'codigo_barras' => '', 'categoria_id' => $categoria->id, 'imagen' => '']); + + $op = OrdenProduccion::create(['numero_orden' => 'OP-0200', 'prenda_modelo' => 'Doblez', 'referencia' => 'D-01', 'cantidad_total' => 10, 'metros_requeridos' => 0, 'fecha_inicio' => now(), 'fecha_entrega_estimada' => now()->addDays(7)]); + + // Crear inventario: esto incrementa el stock global del producto en +5 + $inv = InventarioPrenda::create(['orden_produccion_id' => $op->id, 'cantidad_terminada' => 5, 'cantidad_disponible' => 5, 'fecha_ingreso' => now(), 'estado' => 'en_bodega', 'producto_id' => $producto->id]); + + $producto->refresh(); + $this->assertEquals(5, $producto->stock, 'Stock should be increased by inventario creation'); + + // Crear distribución: no debe aumentar nuevamente el stock global del producto + InventarioPrendaDistribucion::create([ + 'inventario_prenda_id' => $inv->id, + 'bodega_id' => 1, + 'color_id' => null, + 'size_id' => null, + 'cantidad' => 2, + ]); + + $producto->refresh(); + $this->assertEquals(5, $producto->stock, 'Stock should NOT be increased by distribution creator (no double count)'); + + $pivot = \DB::table('producto_bodega')->where('producto_id', $producto->id)->where('bodega_id', 1)->first(); + $this->assertNotNull($pivot); + $this->assertEquals(2, $pivot->stock); + } + public function test_creating_inventario_with_excessive_distributions_throws_validation_exception() { $categoria = \App\Models\Categoria::create(['nombre' => 'Ropa']);