phpmagentomagento-1.9configurable-product

Updating configurable product throws Integrity constraint violation error about UNQ_CATALOG_PRODUCT_SUPER_ATTRIBUTE_PRODUCT_ID_ATTRIBUTE_ID


I have the following script which uses Magento models to create or update a configurable product.

// Method to create or update configurable product with configurable options
function createOrUpdateConfigurableProduct($product_data, $configurable_products_data)
{
    // Init product
    $product = Mage::getModel('catalog/product');

    // Load product id by sky
    $product_id = Mage::getModel('catalog/product')
        ->getIdBySku($product_data['sku']);

    // If product already exists
    if ($product_id)
    {
        // Load product
        $product->load($product_id);
    }

    // Set product data
    $product
        ->setTypeId('configurable')
        ->setAttributeSetId(4)
        ->setSku($product_data['sku'])
        ->setName($product_data['name'])
        ->setDescription($product_data['description'])
        ->setShortDescription($product_data['description'])
        ->setMetaTitle($product_data['name'])
        ->setMetaDescription($product_data['description'])
        ->setPrice($product_data['price'])
        ->setTaxClassId(2)
        ->setWebsiteIDs(array(1))
        ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
        ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
        ->setStockData(array(
            'use_config_manage_stock' => 0,
            'manage_stock'            => 1,
            'is_in_stock'             => ($product_data['qty'] >= 1 ? 1 : 0)
        ));

    // Workout all the attribute ids used
    $used_attribute_ids = array();
    foreach ($configurable_products_data as $product_id => $options) {
        foreach ($options as $option) {
            if (!in_array($option['attribute_id'], $used_attribute_ids)) {
                $used_attribute_ids[] = $option['attribute_id'];
            }
        }
    }

    // Set configurable attributes data
    $product->getTypeInstance()->setUsedProductAttributeIds($used_attribute_ids);
    $configurableAttributesData = $product->getTypeInstance()->getConfigurableAttributesAsArray();
    $product->setCanSaveConfigurableAttributes(true);
    $product->setConfigurableAttributesData($configurableAttributesData);

    // Set configurable products data & save
    $product->setConfigurableProductsData($configurable_products_data);
    $product->save();
}

Where $configurable_products_data looks something like this:

Array
(
    [49] => Array
        (
            [0] => Array
                (
                    [label] => 27 in.
                    [attribute_id] => 155
                    [value_index] => 47
                    [is_percent] => 0
                    [pricing_value] => 210
                )

            [1] => Array
                (
                    [label] => 32L
                    [attribute_id] => 156
                    [value_index] => 50
                    [is_percent] => 0
                    [pricing_value] => 210
                )

        )

    [50] => Array
        (
            [0] => Array
                (
                    [label] => 28 in.
                    [attribute_id] => 155
                    [value_index] => 48
                    [is_percent] => 0
                    [pricing_value] => 210
                )

            [1] => Array
                (
                    [label] => 32L
                    [attribute_id] => 156
                    [value_index] => 50
                    [is_percent] => 0
                    [pricing_value] => 210
                )

        )

    [51] => Array
        (
            [0] => Array
                (
                    [label] => 28 in.
                    [attribute_id] => 155
                    [value_index] => 48
                    [is_percent] => 0
                    [pricing_value] => 210
                )

            [1] => Array
                (
                    [label] => 34L
                    [attribute_id] => 156
                    [value_index] => 51
                    [is_percent] => 0
                    [pricing_value] => 210
                )

        )

)

When this code runs, on first run - it work's fine and create the configurable product. However, on the second run, it doesn't seem to be able to update existing configurable product, it's throwing the following cryptic error message:

Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '52-155' for key 'UNQ_CATALOG_PRODUCT_SUPER_ATTRIBUTE_PRODUCT_ID_ATTRIBUTE_ID''

Any ideas?


Solution

  • +----------------------------+----------------------+------+-----+---------+----------------+
    | Field                      | Type                 | Null | Key | Default | Extra          |
    +----------------------------+----------------------+------+-----+---------+----------------+
    | product_super_attribute_id | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |
    | product_id                 | int(10) unsigned     | NO   | MUL | 0       |                |
    | attribute_id               | smallint(5) unsigned | NO   |     | 0       |                |
    | position                   | smallint(5) unsigned | NO   |     | 0       |                |
    +----------------------------+----------------------+------+-----+---------+----------------+
    

    Above is the description of the table catalog_product_super_attribute table. This table hold the relation between configurable and simple products. You are getting this error because its trying to add same simple items which are already mapped. If you want to update without specifying new simple sku, possible workaround can be deleting entry from this table for the corresponding configurable product table. In your code error is coming from the line -

    $product->setConfigurableAttributesData($configurableAttributesData);
    

    Before updating you can add one line of check whether your configurable product is new.

    if ( $product_is_new ) {
        $product->setConfigurableAttributesData($configurableAttributesData);
    }