belongsTo(InventarioPrenda::class); } public function bodega() { return $this->belongsTo(Bodega::class); } public function proveedor() { return $this->belongsTo(Proveedor::class); } public function color() { return $this->belongsTo(Color::class); } public function size() { return $this->belongsTo(Size::class); } protected static function booted() { // Validaciones: impedir que la suma de distribuciones supere la cantidad terminada static::creating(function ($dist) { $parentId = $dist->inventario_prenda_id ?? null; if (! $parentId) return; $parent = \App\Models\InventarioPrenda::find($parentId); if (! $parent) return; $cantidad = intval($dist->cantidad ?? 0); $sumExistentes = (int) self::where('inventario_prenda_id', $parentId)->sum('cantidad'); // Validar contra la cantidad terminada total (no distribuir más del total entregado) if (($sumExistentes + $cantidad) > (int) $parent->cantidad_terminada) { throw \Illuminate\Validation\ValidationException::withMessages([ 'cantidad' => 'No se puede añadir más prendas que las disponibles.', ]); } }); static::updating(function ($dist) { $parentId = $dist->inventario_prenda_id ?? null; if (! $parentId) return; $parent = \App\Models\InventarioPrenda::find($parentId); if (! $parent) return; $newCantidad = intval($dist->cantidad ?? 0); $othersSum = (int) self::where('inventario_prenda_id', $parentId) ->where('id', '<>', $dist->id) ->sum('cantidad'); // Validar contra la cantidad terminada total (no distribuir más del total entregado) if (($othersSum + $newCantidad) > (int) $parent->cantidad_terminada) { throw \Illuminate\Validation\ValidationException::withMessages([ 'cantidad' => 'No se puede añadir más prendas que las disponibles.', ]); } }); // Al crear una distribución, incrementar stock static::created(function ($dist) { $cantidad = $dist->cantidad ?? 0; if ($cantidad <= 0) return; $bodegaId = $dist->bodega_id; // If a proveedor_id is present, treat as assignment to a provider/person (no warehouse stock changes) if ($dist->proveedor_id && ! $bodegaId) { // Just decrement disponibilidad on parent $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad); $parent->save(); } return; } if ($dist->color_id && $dist->size_id) { // Variante // Determinar producto: preferir inventario.prenda.producto_id -> op.producto_id $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null); // Si no existe producto, intentar crear/inferrir desde la Orden de Producción if (! $productoId && $dist->inventarioPrenda && $dist->inventarioPrenda->ordenProduccion) { $op = $dist->inventarioPrenda->ordenProduccion; $nombre = $op->prenda_modelo ?? $op->referencia ?? ('Producto OP #' . $op->id); $codigo = 'AUTOD-' . $op->id . '-' . time(); $codigo = substr($codigo, 0, 50); while (\App\Models\Producto::where('codigo_barras', $codigo)->exists()) { $codigo .= '-' . rand(0, 9); $codigo = substr($codigo, 0, 50); } $producto = \App\Models\Producto::firstOrCreate( ['nombre' => $nombre], [ 'descripcion' => 'Creado automáticamente desde distribución (OP #' . $op->id . ')', 'stock' => 0, 'estado' => true, 'precio_compra' => 0, 'precio_venta' => 0, 'unidad_medida' => 'unidad', 'codigo_barras' => $codigo, ] ); $productoId = $producto->id; // Guardar producto en el inventario padre para futuras referencias $parent = $dist->inventarioPrenda; if ($parent && ! $parent->producto_id) { $parent->producto_id = $productoId; $parent->save(); } } $variant = \App\Models\ProductVariant::firstOrCreate([ 'producto_id' => $productoId, 'color_id' => $dist->color_id, 'size_id' => $dist->size_id, ], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']); $existing = \DB::table('variante_bodega') ->where('variante_id', $variant->id) ->where('bodega_id', $bodegaId) ->first(); if ($existing) { \DB::table('variante_bodega') ->where('variante_id', $variant->id) ->where('bodega_id', $bodegaId) ->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]); } else { \DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]); } $variant->increment('stock', $cantidad); // Reducir disponibilidad en inventario_prenda $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad); $parent->save(); } } else { // Producto $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null); // Si no existe producto, intentar crear/inferrir desde la Orden de Producción if (! $productoId && $dist->inventarioPrenda && $dist->inventarioPrenda->ordenProduccion) { $op = $dist->inventarioPrenda->ordenProduccion; $nombre = $op->prenda_modelo ?? $op->referencia ?? ('Producto OP #' . $op->id); $codigo = 'AUTOP-' . $op->id . '-' . time(); $codigo = substr($codigo, 0, 50); while (\App\Models\Producto::where('codigo_barras', $codigo)->exists()) { $codigo .= '-' . rand(0, 9); $codigo = substr($codigo, 0, 50); } $producto = \App\Models\Producto::create([ 'nombre' => $nombre, 'descripcion' => 'Creado automáticamente desde distribución (OP #' . $op->id . ')', 'stock' => 0, 'estado' => true, 'precio_compra' => 0, 'precio_venta' => 0, 'unidad_medida' => 'unidad', 'codigo_barras' => $codigo, 'categoria_id' => \App\Models\Categoria::first()?->id ?? \App\Models\Categoria::create(['nombre' => 'Generica'])->id, ]); $productoId = $producto->id; // Guardar producto en el inventario padre para futuras referencias $parent = $dist->inventarioPrenda; if ($parent && ! $parent->producto_id) { $parent->producto_id = $productoId; $parent->save(); } } if ($productoId) { $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first(); if ($existing) { \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]); } else { \DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]); } // 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; if ($parent) { $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad); $parent->save(); } } } }); // Al actualizar, ajustar la diferencia static::updated(function ($dist) { $original = $dist->getOriginal(); $oldCantidad = intval($original['cantidad'] ?? 0); $newCantidad = intval($dist->cantidad ?? 0); $delta = $newCantidad - $oldCantidad; if ($delta == 0) return; $bodegaId = $dist->bodega_id; if ($dist->color_id && $dist->size_id) { $variant = \App\Models\ProductVariant::firstOrCreate([ 'producto_id' => $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null), 'color_id' => $dist->color_id, 'size_id' => $dist->size_id, ], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']); $existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first(); if ($existing) { \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]); } else { \DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]); } $variant->increment('stock', $delta); $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = max(0, min($parent->cantidad_terminada, $parent->cantidad_disponible - $delta)); $parent->save(); } } else { $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null); if ($productoId) { $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first(); if ($existing) { \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]); } else { \DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]); } $prod = \App\Models\Producto::find($productoId); if ($prod && ! $prod->variants()->exists()) { $prod->increment('stock', $delta); } $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = max(0, min($parent->cantidad_terminada, $parent->cantidad_disponible - $delta)); $parent->save(); } } } }); // Al eliminar, restar la cantidad static::deleted(function ($dist) { $cantidad = $dist->cantidad ?? 0; if ($cantidad <= 0) return; $bodegaId = $dist->bodega_id; if ($dist->color_id && $dist->size_id) { $variant = \App\Models\ProductVariant::where('color_id', $dist->color_id)->where('size_id', $dist->size_id)->first(); if ($variant) { $existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first(); if ($existing) { $newStock = max(0, ($existing->stock ?? 0) - $cantidad); \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]); } $variant->decrement('stock', $cantidad); // Restaurar disponibilidad en inventario_prenda $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = min($parent->cantidad_terminada, $parent->cantidad_disponible + $cantidad); $parent->save(); } } } else { $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null); if ($productoId) { $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first(); if ($existing) { $newStock = max(0, ($existing->stock ?? 0) - $cantidad); \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]); } $prod = \App\Models\Producto::find($productoId); if ($prod && ! $prod->variants()->exists()) { $prod->decrement('stock', $cantidad); } // Restaurar disponibilidad en inventario_prenda $parent = $dist->inventarioPrenda; if ($parent) { $parent->cantidad_disponible = min($parent->cantidad_terminada, $parent->cantidad_disponible + $cantidad); $parent->save(); } } } }); } }