¿De dónde viene is_salable?

27

Nota: Si ha estado editando productos por código PHP, vuelva a indexarlos en el administrador después, ahorre sus horas tratando de averiguar por qué no se muestran como yo a continuación ...

Estoy dando vueltas en círculos tratando de averiguar cómo is_salablese configura un producto, y así averiguar por qué mis productos ahora se muestran.

Solo hay un lugar en el código que puedo encontrar que lo establece:

$salable = $this->isAvailable();

pero no puedo entender cómo o de dónde viene esto, ya que cuando lo sigo isAvailableparece dar vueltas ...

/app/code/core/Mage/Catalog/Model/Product.php

    public function isSalable()
    {
        Mage::dispatchEvent('catalog_product_is_salable_before', array(
            'product'   => $this
        ));

        $salable = $this->isAvailable();

    $object = new Varien_Object(array(
        'product'    => $this,
        'is_salable' => $salable
    ));
    Mage::dispatchEvent('catalog_product_is_salable_after', array(
        'product'   => $this,
        'salable'   => $object
    ));
    return $object->getIsSalable();
}

siguiendo $ this-> isAvailable () desde aquí van unas pocas líneas:

**public function isAvailable()
{ 
    return $this->getTypeInstance(true)->isSalable($this);
}**

Esto luego llama a app / code / core / Mage / Catalog / Model / Product / Type / Configurable.php's isSalable

public function isSalable($product = null)
{
    $salable = parent::isSalable($product);

    if ($salable !== false) {
        $salable = false;
        if (!is_null($product)) {
            $this->setStoreFilter($product->getStoreId(), $product);
        }
        foreach ($this->getUsedProducts(null, $product) as $child) {
            if ($child->isSalable()) {
                $salable = true;
                break;
            }
        }
    }

    return $salable;
}

que llama al padre: /app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php's isSalable:

public function isSalable($product = null)
{
    $salable = $this->getProduct($product)->getStatus() == Mage_Catalog_Model_Product_Status::STATUS_ENABLED;
    if ($salable && $this->getProduct($product)->hasData('is_salable')) {
        $salable = $this->getProduct($product)->getData('is_salable');
    }
    elseif ($salable && $this->isComposite()) {
        $salable = null;
    }

    return (boolean) (int) $salable;
}

que solo hace una llamada de datos has / get en el valor is_saleable ¿Lo rastreé bien? ¿De dónde viene este valor?

Emití un grep recursivo en mi instalación para is_salable, seguramente esto debería mostrar las líneas donde está configurado, pero no veo ninguna de inmediato:

grep -r is_salable *
app/code/core/Mage/CatalogInventory/Model/Stock/Status.php:            $object = new Varien_Object(array('is_in_stock' => $product->getData('is_salable')));
app/code/core/Mage/XmlConnect/Block/Wishlist.php:                $itemXmlObj->addChild('is_salable', (int)$item->getProduct()->isSalable());
app/code/core/Mage/XmlConnect/Block/Catalog/Product.php:            $item->addChild('is_salable', (int)$product->isSalable());
app/code/core/Mage/XmlConnect/Block/Cart/Crosssell.php:                $itemXmlObj->addChild('is_salable', 0);
app/code/core/Mage/XmlConnect/Block/Cart/Crosssell.php:                $itemXmlObj->addChild('is_salable', (int)$product->isSalable());
app/code/core/Mage/Catalog/Model/Product.php:        Mage::dispatchEvent('catalog_product_is_salable_before', array(
app/code/core/Mage/Catalog/Model/Product.php:            'is_salable' => $salable
app/code/core/Mage/Catalog/Model/Product.php:        Mage::dispatchEvent('catalog_product_is_salable_after', array(
app/code/core/Mage/Catalog/Model/Product.php:        if ($this->hasData('is_salable')) {
app/code/core/Mage/Catalog/Model/Product.php:            return $this->getData('is_salable');
app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php:        if ($salable && $this->getProduct($product)->hasData('is_salable')) {
app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php:            $salable = $this->getProduct($product)->getData('is_salable');

ENCONTRÓ:

grep -r setIsSalable *
app/code/core/Mage/CatalogInventory/Model/Stock/Status.php:        $product->setIsSalable($stockStatus);
app/code/core/Mage/CatalogInventory/Model/Stock/Status.php:                    $product->setIsSalable($status);

Era setIsSalable que no pensé / sabía buscar en lugar de simplemente setIsSalable .

Hayden Thring
fuente

Respuestas:

18

isAvailable() Se ve como esto:

public function isAvailable()
{
    return $this->getTypeInstance(true)->isSalable($this)
        || Mage::helper('catalog/product')->getSkipSaleableCheck();
}

Esto significa que el resultado del método depende del tipo de producto.
Cada tipo de producto tiene un isSalable()método:

  • Mage_Catalog_Model_Product_Type_Grouped::isSalable() - para productos agrupados
  • Mage_Catalog_Model_Product_Type_Configurable::isSalable() - para productos configurables
  • Mage_Catalog_Model_Product_Type_Abstract::isSalable()- para el resto de tipos de productos, ya que todos los tipos de productos se extienden Mage_Catalog_Model_Product_Type_Abstract.
    Creo que la llamada $this->getTypeInstance(true)te confunde. El método getTypeInstance()no devuelve una instancia del modelo de producto, sino una instancia de un tipo de producto.

[EDITAR]
Para un producto simple, esto se llama Mage_Catalog_Model_Product_Type_Grouped::isSalable(). Este método verifica si el producto está habilitado. Si no, entonces falsese devuelve. Si está habilitado, comprueba si tiene una propiedad is_salableque pueda establecer uno de sus observadores.
Si no tiene dicha propiedad, comprueba si la instancia del tipo de producto $this->isComposite(). Si es así, no es vendible.
Para los productos configurables, verifica si se cumplen las condiciones anteriores y si hay un producto simple asociado al configurable que sea vendible (nuevamente con las condiciones anteriores)
Lo mismo se hace para el producto agrupado pero de una manera diferente.

En conclusión is_salable, no tiene que existir. Pero en caso de que tenga un observador que establezca esa propiedad, se tendrá en cuenta al verificar si el producto se puede vender.
Aquí hay un ejemplo del núcleo: El método Mage_CatalogInventory_Model_Stock_Status::assignProduct()cals $product->setIsSalable()
Same va para Mage_CatalogInventory_Model_Stock_Status::addStockStatusToProducts.
El último es llamado por el evento catalog_product_collection_load_after.

Marius
fuente
muchas gracias por su ayuda nuevamente, había rastreado isAvailable to isSalable y Configurable.php's isSalable que solo llama a Abstract.php's isSalable pero todo lo que hace es verificar 'is_salable' pero no encuentro ninguna configuración. Agregaré mi rastro de código arriba.
Hayden Thring
añadido a mi pregunta
Hayden Thring
2
Sí hay. Lo mencioné en mi respuesta catalog_product_collection_load_after. Pero esto es solo un ejemplo. También existe cataloginventory/observer::addInventoryDataesa llamada assignProductque establece is_salable. Podría haber otros, pero no busqué todos.
Marius
1
No tengo un método confiable para hacer esto. Quizás obtenga todos los eventos que comiencen catalog_product_y depure los métodos llamados por los observadores en esos eventos. y ver si uno llama setIsSalableosetData('is_salable')
Marius
1
XmlConnect le permite conectar su aplicación móvil a su sitio web. Ignoralo.
Marius
2

si es vendible devuelve falso, Reindexing también puede tener problemas reindexar los datos

Hassan Ali Shahzad
fuente
0

Si después de reindexar y depurar no se puede cerrar y su producto configurable todavía se muestra como agotado, asegúrese de que todos los simples tengan el estado establecido en Habilitado, en TODAS las vistas de la tienda. Solo perdí dos horas preguntándome por qué un configurable estaba agotado sin importar lo que hiciera, hasta que revisé todas las vistas de la tienda y descubrí que algún cuerpo había desactivado el estado.

David Tay
fuente