Question

I have made a script which copies one customer group to another for products. However after running this script, I found out that it a) clears the URL key of the product and b) sets the visibility to Catalog, Search for all products. Also the script takes a verrrry long time (it reinitialised connection after 40 min, there are only some 300 products). Can anyone help me out? This is the code:

function productCallback($args)
{
$product = Mage::getModel('catalog/product');
$product->setData($args['row']);
$product->getGroupPrice();
$groupPrices = $product->getData('group_price');
$price = 0;
$from = $_POST['from_group'];
$to = $_POST['to_group'];

foreach($groupPrices as $key=>$value)
{
    foreach($value as $subkey => $subvalue)
    {
        if ($subkey == "cust_group" && $subvalue == $from) 
        {
            $price = $value['price'];
            $newGroupPrice = array(array ('website_id'=>0,
            'cust_group'=>$to,
            'price'=>$price,
            'website_price'=>$price,
            'all_groups'=>0));
            echo "price: ".$price . "<br/>";

            $newGroupPrices = array_merge($groupPrices,$newGroupPrice);

            $product->setData('group_price',$newGroupPrices);
            $product->save();
            break;
        }
    }
}
}

$products = Mage::getModel('catalog/product')->getCollection()
                ->addAttributeToSelect('sku')
                ->addAttributeToSelect(array('group_price'));

if($from > -1)  
   Mage::getSingleton('core/resource_iterator')->walk($products->getSelect(), array('productCallback'), array('arg1' => '===='));
Was it helpful?

Solution

you are calling $product->save() without calling $product->load(). This results in loss of data (or wrong data). You should never call save on an item from a collection. You should call load before doing that.
Also, calling save in a loop results in huge performance issues. save is very resource consuming.
If this is a "one time only script" I recommend you the fast (but a bit risky) method of reading and writing directly from/to the database.
The only table that contains the group prices is catalog_product_entity_group_price.
You can read the values for a product from a customer group on a specific website. If there is a record for that, then update it, otherwise insert a new line.
You can even do this from a single insert statement:

INSERT INTO
    catalog_product_entity_group_price
SET 
    `entity_id` = the product id here,
    `all_groups`  = 1 or 0...depending if applies to all groups or not
    `customer_group_id`  = the customer group here
    `value`  = the actual price in the base currency
    `website_id` the website id here
ON DUPLICATE KEY UPDATE
    `value` = the actual price in base currency

This should solve your problems fast, just make sure you backup your db before starting and you rebuild the indexes when finishing.

OTHER TIPS

This one seems to do the trick pretty well:

$from = $_POST['from_group'];
$to = $_POST['to_group'];

$collection = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToSelect('*')
;

foreach($collection as $product) {
    $groupPrices = $product->getData('group_price');

    if (is_null($groupPrices)) {
        $attribute = $product->getResource()->getAttribute('group_price');
        if ($attribute) {
            $attribute->getBackend()->afterLoad($product);
            $groupPrices = $product->getData('group_price');
        }
    }

    if(empty($groupPrices) || !is_array($groupPrices)){
        continue;
    }

    $newGroupPrices = array();
    $hasChanges = false;
    foreach($groupPrices as $value)
    {

        //skip the current price for the to group
        if($value['cust_group'] == $to){
            continue;
        }

        //add the current price item
        $newGroupPrices[] = $value;

        //add new price for the to group by copying from the from group
        if($value['cust_group'] == $from){
            $newValue = $value;
            $newValue['cust_group'] = $to;
            $hasChanges = true;
            $newGroupPrices[] = $newValue;
        }

    }

    if(!$hasChanges){
        continue;
    }


    //delete old price data
    $resource = Mage::getResourceModel('catalog/product_attribute_backend_groupprice');
    $resource->deletePriceData($product->getId());

    //save new price data
    $product->setData('group_price',$newGroupPrices)->save();
}

Saving in a collection loop shouldn't be an issue. However, the way you did it by using the iterator might have been the cause of the attribute overwrite issue you were experiencing.

Does this work for you?

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top