简体   繁体   中英

Programmatically created configurable item doesn't show options until I manually save it in the admin panel

I am creating aa configurable product in code (am doing an import module) and everything looks Ok. The attributes are added, the simple stock items are added to the configurable product with no problems however, when I view the item on the font end it shows as a simple product would (without options) but when I save open and save the product in the admin panel it then shows the options on the front end correctly.

I am using the following code before and after the re-save of the item to check if any attributes don't match (assuming I have missed something)

foreach ($product->getTypeInstance(true)->getEditableAttributes($product) as $code=>$attribute)    
{
    $val = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), $code, $storeId);
    Mage::log($code . '=>' . $val);
}

All the values match between a fresh imported product (that doesn't display the options) and a manually saved one (which does).

Here is the code I am using to create the product (I have omitted the bit that adds the attributes / simple items to the configurable product but let me know if this is required):

$productData = array(
    'name'              => $name,
    'websites'          => array(1, 2), 
    'short_description' => $shortDescription,
    'description'       => $longDesc,
    'status'            => 1,
    'weight'            => $weight,
    'tax_class_id'      => 2, //0:None;2:Taxable Goods;4:Shipping
    'categories'        => $categoryIds,
    'price'             => $sellPrice,
);

if ($parentStockItem == null) // != null is child item, == false is simple item,  == null is config item
{
    $productData['has_options'] = 1;
    $productData['required_options'] = 1;
    $productData['msrp_enabled'] = 2; //added to test as this was missing in my comparison check
    $productData['msrp_display_actual_price_type'] = 4;  //added to test as this was missing in my comparison check
}

return $mc->create($type, $setId, $stockCode, $productData);

Is there something I need to be doing to set an item to show the options on the front end?

Ok, I have managed to find the issue by comparing the data between database snapshots before and after saving the item.

The reason this is happening is because of the stock_status flag in cataloginventory_stock_status . This value default's to 0 but when you save the product it sets it to 1 . You also need to make sure you are setting the other stock inventory options so adding the following to my routine fixed the issue:

$stockItem = Mage::getModel('cataloginventory/stock_item');
$stockItem->assignProduct($product);
$stockItem->setData('stock_id', 1);
$stockItem->setData('qty', 0);
$stockItem->setData('use_config_min_qty', 1);
$stockItem->setData('use_config_backorders', 1);
$stockItem->setData('min_sale_qty', 1);
$stockItem->setData('use_config_min_sale_qty', 1);
$stockItem->setData('use_config_max_sale_qty', 1);
$stockItem->setData('is_in_stock', 1);
$stockItem->setData('use_config_notify_stock_qty', 1);
$stockItem->setData('manage_stock', 1);
$stockItem->save();

//This section is what was required.
$stockStatus = Mage::getModel('cataloginventory/stock_status');
$stockStatus->assignProduct($product);
$stockStatus->saveProductStatus($product->getId(), 1);

The item now appears with the options correctly straight after import.

I ran into this same problem. Its a tough nut to crack. My solution may not be elegant, but it has worked for a year now without problems. Its a little ugly, but it works.

Yes, you need to do many specific things. Instead of explaining each thing, I'll just post the source code I wrote that accepts a master product and its associated products. It boils down to the fact that you have to create a simple product first, use it as a 'template' for your configurable product.

You have to create the master and associated products first, then use the code below to create the configurable product. If you don't want the master product to exist after creating the configurable, simply add code to delete it then change the sku on the new configurable product's entity_id to the sku of the master product.

Make sure you change YOUR_MAGENTO_DBNAME to your database's name

public function createConfigurableProduct($master_sku, $sku_list) {
    // Recreate the array from the serialized string

    try {
        $sku = array();
        $sku = explode(",", $sku_list);

        if (empty($sku)) {
            die ("You have to pass a valid SKU list");
        }

        // Set an object up for the master sku passed by soap
        $masterProduct = Mage::getModel('catalog/product')->loadByAttribute('sku', $master_sku);
        $attrib = $this->getAttribFromProdId($masterProduct->entity_id);

        if ($attrib->attribute_set_id == "") {
            die ("Could not get master product attribute set id from master product");
        }

        $categories = $masterProduct->getResource()->getCategoryIds($masterProduct); 

        if (empty($categories)) {
            die ("could not get the categories that the master product is in. This code requires it is in at least one category");
        }

        // Create the configurable product based on the master product sku passed through SOAP
        $newProductObj = Mage::getResourceModel('catalog/product_collection')->getData();

        $attributes = $masterProduct->getAttributes();

        // Set attributes
        $product = Mage::getModel('catalog/product');

        // Create master copy
        foreach ($attributes as $attr) {
            $attrCode = $attr['attribute_code'];
            // Don't duplicate these values
            if (
                $attrCode != "type_id" 
                && $attrCode != "sku" 
                && $attrCode != "entity_id"
                && $attrCode != "visibility"
                && $attrCode != "url_key"
                && $attrCode != "url_path")
            {
                $product[$attrCode] = $masterProduct[$attrCode];
            }
        }

        // Add all of the stuff 
        $product->setTypeId('configurable');

        // It will create a configurable product with the master product's sku and append -C to the end. cannot duplicate skus
        $product->setSku(str_replace("-C", "", $masterProduct->sku));
        $product->setPrice($masterProduct->price);
        $product->setVisibilty(4); //catalog and search
        $product->setWebsiteIds(array(1));
        $product->setAttributeSetId($attrib->attribute_set_id); 
        $product->setCategoryIds($categories);
        $product->setName($masterProduct->name);
        $product->setDescription($masterProduct->description);
        $product->setShortDescription($masterProduct->short_description);
        $product->setStatus(1); 
        $product->setTaxClassId('2');
        $product->setFeaturedProduct('0');
        $product->setIsImported(0);
        $product->setWeight($masterProduct->weight);                
        $product->setCreatedAt(strtotime('now'));
        $product->product_type=$masterProduct->product_type;
        $product->vendor_code=$masterProduct->vendor_code;

        /* This is the configurable product attribute array
        We do a foreach loop and gather data from each sku's attrib array
        and create a new array for the new product based on what is to be 
        */

        // First, get the information about the master product from the database
        $db = Mage::getSingleton('core/resource')->getConnection('core_read');
        $sql="select * from 
                `nki_magentoV1.11.1.0`.catalog_eav_attribute AS A 
                INNER JOIN `YOUR_MAGENTO_DBNAME`.eav_attribute AS B ON A.attribute_id = B.attribute_id AND B.is_user_defined = 1 
                INNER JOIN `YOUR_MAGENTO_DBNAME`.eav_entity_attribute as EEA ON B.attribute_id = EEA.attribute_id
                WHERE EEA.attribute_set_id = " . $attrib->attribute_set_id . " AND A.is_configurable = 1 AND attribute_code != 'cost' AND B.source_model IS NOT null";
            //echo $sql;

        // Result Set

        $masterResult = $db->fetchAll($sql);
        $data = array();
        $retSku = array();

        foreach ($masterResult as $master) {
            $dataInner = array();

            // This section handles configurable product parameters based on the simple product's attributes
            $values = array();
            foreach ($sku as $prodsku) {

                $innerVals = array();
                // This gets the attribute of the current product
                try {
                    $productBySku = Mage::getModel('catalog/product')->loadByAttribute('sku',$prodsku);
                } catch (Exception $e)
                {
                    // Product cannot be loaded, so continue to next iteration of the loop
                    continue;
                }

                $attribVal = $productBySku[$master['attribute_code']];

                // Load up the attribute set and compare
                $attribute = $productBySku->getResource()->getAttribute($master['attribute_code']);

                $attributeInfo = Mage::getResourceModel('eav/entity_attribute_collection')
                    ->setCodeFilter($master['attribute_code'])
                    ->getFirstItem();

                // There is a possible chance that there is a null error occur here, however it is VERY
                // unlikely that attributeInfo will not be having a valid attribute loaded
                $attributeOptions = $attributeInfo->getSource()->getAllOptions(false);

                foreach ($attributeOptions as $option) {
                    if ($attribVal == $option['value']) {
                        $innerVals['value_index']=$option['value'];
                        $innerVals['label']=$option['label'];
                        $retSku[] = $prodsku;
                    } 
                }

                $innerVals['attribute_id']=$master['attribute_id'];

                if ($masterProduct['price'] != $productBySku['price']) {

                    $calcPrice = $masterProduct['price'] - $productBySku['price'];
                    $innerVals['pricing_value']=$calcPrice * -1;
                }
                else 
                {
                    $innerVals['pricing_value']= 0;
                }


                //$innerVals['pricing_value'] = '100';
                $innerVals['is_percent'] = '0';

                // Only add to the array if there was a value
                // return only the sku's added to the configurable product

                if ($innerVals['value_index'] <> NULL) {
                    $values[] = $innerVals;
                }


            }

            // Set the sata array for the configurable item
            $dataInner['id'] = NULL;
            $dataInner['label'] = $master['attribute_code'];
            $dataInner['position'] = NULL;
            $dataInner['attribute_id'] = $master['attribute_id'];
            $dataInner['frontend_label'] = $master['frontend_label'];
            $dataInner['html_id'] = 'config_super_product__attribute_0';
            $dataInner['values'] = $values;


            $data[] = $dataInner;   
        }

        $product->setConfigurableAttributesData($data);
        $product->setCanSaveConfigurableAttributes(1);

        // Set the stock data so it will appear on the site
        $stockData = $product->getStockData();
        $stockData['is_in_stock'] = 1;
        $stockData['use_config_manage_stockSpecified'] = true;
        $stockData['use_config_manage_stock'] = 0;
        $stockData['manage_stock'] = 1;
        $product->setStockData($stockData);

        // Finally save the product
        try{
            $product->save();
            $productId = $product->getId();

            //echo $product->getId() . ", $price, $itemNum added\n";
        }
        catch (Exception $e){ 
            // Saving the product failed
            $result = array (
                array(
                    'master_sku' => $master_sku,
                    'sku_list' => $sku_list,
                    'retval' => $e
                    )
            );

            error_log($e);
            return $result;
        } 

        // Add the associated products
        if ($productId > 0) {

            foreach($sku as $productSku) { 
                $productIdBySku = Mage::getModel('catalog/product')->loadByAttribute('sku',$productSku)->getId();

                // Add handler to not die on adding products that don't exist
                if ($producIdBySku > 0)
                {
                    $res = $this->addToConfigurable($productId, $productIdBySku);

                    /*                                              
                    if ($res == -5) 
                    {
                        $result = array (
                            array(
                                'master_sku' => $master_sku,
                                'sku_list' => $sku_list,
                                'retval' => ERR_ADD_ASSOCIATED_PROD_FAIL
                                )
                        );
                        return $result;
                    }
                    */

                }
            }

            $product->save();

            $stockItem = Mage::getModel('cataloginventory/stock_item');
            $stockItem->assignProduct($product);
            $stockItem->setData('is_in_stock', 1);
            $stockItem->setData('stock_id', 1);
            $stockItem->setData('store_id', 1);
            $stockItem->setData('manage_stock', 0);
            $stockItem->setData('use_config_manage_stock', 0);
            $stockItem->setData('min_sale_qty', 0);
            $stockItem->setData('use_config_min_sale_qty', 0);
            $stockItem->setData('max_sale_qty', 1000);
            $stockItem->setData('use_config_max_sale_qty', 0);

            $stockItem->save();


            //echo $productArray['product_id'];
        } else {
            // Something baaaaad happened
        }

    } catch (Exception $e) {
        // FATAL ERROR
        // Return php's fatal error that cannot be handled above (which should not happen, but might)
        die ( $e->getMessage() );
    }   

    echo "Configurable Product Created Successfully";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM