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";
}