0

I wrote a cron task that adds products to certain categories based on the news to date. The intention is that if a product has a news to date that is in the future it will be automatically added to the "New" category and then removed when the news to date is in the past. But for some reason whenever this cron is run, products that are saved with the updated categories are also enabled when they were set to be disabled. Below is the code for the cron that runs.

/**
* Observer class that adds products to categories based on news_to_date and search_type
*
* @author Thomas Wilson, Our Daily Bread Ministries
*/

class ThomasWilson_BatchCategory_Model_Observer
{

public function getNewProducts($store)
{
    $date = strftime("%Y-%m-%d %H:%M:%S", Mage::getModel('core/date')->timestamp());

    //Get products that have a news_to_date that is after today's date
    $newproducts = Mage::getModel('catalog/product')->getCollection()
            ->addAttributeToSelect(array(
                'news_to_date',
                'name',
                'search_type'
            ))
            ->addStoreFilter($store)
            ->addAttributeToFilter('news_to_date', array(
                'gt' => $date,
                'notnull' => true,
            ));

    return $newproducts;
}

public function getOldProducts($store)
{
    $date = strftime("%Y-%m-%d %H:%M:%S", Mage::getModel('core/date')->timestamp());

    //Get products that have a news_to_date that is before today's date
    $oldproducts = Mage::getModel('catalog/product')->getCollection()
            ->addAttributeToSelect(array(
                'news_to_date',
                'name',
                'search_type'
            ))
            ->addStoreFilter($store)
            ->addAttributeToFilter('news_to_date', array(
                'lt' => $date,
                'notnull' => true
            ));

    return $oldproducts;
}

/**
 * 
 * @param Catalog/Product $product
 * @param array $newCategories
 * @param bool $save
 */
public function addToCategory($product, $newCategories, $save=false) 
{

    $currentCategories = $product->getCategoryIds();

    $currentPlusNewCategories = array_merge($newCategories, $currentCategories);

    if ($currentPlusNewCategories === $currentCategories) {
        $message = $product->getName() . " Nothing to add";
        return mage::log($message, null, 'batchcategory.log');
    } else {
        if ($save) {
            $product->setCategoryIds($currentPlusNewCategories)->save();
            $message = $product->getName() 
                    . " " . $product->getAttributeText('search_type') 
                    . " " . $product->getData("news_to_date") . " added to new categories";
            return mage::log($message, null, 'batchcategory.log');
        } else {
            $message = $product->getName() 
                    . " " . $product->getAttributeText('search_type') 
                    . " " . $product->getData("news_to_date") . " added to "; 
            $message .= " Not Saved.";
            return mage::log($message, null, 'batchcategory.log');
        }
    } 
}

/**
 * 
 * @param Catalog/Product $product
 * @param array $deletecats
 * @param bool $save
 */
function removeFromCategory($product, $categoriesToDelete, $save=false) 
{
    $currentCategories = $product->getCategoryIds();

    if (array_intersect($categoriesToDelete, $currentCategories) === $categoriesToDelete) {
        foreach ($categoriesToDelete as $category) {
            if (in_array($category, $currentCategories)) {
                $categoryPosition = array_search($category, $currentCategories);
                unset($currentCategories[$categoryPosition]);
            }
        }
        if ($save) {
            $product->setCategoryIds($currentCategories)
                    ->setData("news_to_date", null)
                    ->save();
            $message = $product->getName() 
                    . " " . $product->getData("news_to_date") 
                    . " removed from new categories";
            mage::log($message, null, 'batchcategory.log');
            return true;
        } else {
            $message = $product->getName() 
                    . " " . $product->getData("news_to_date") 
                    . " would be removed from new categories";
            return mage::log($message, null, 'batchcategory.log');
        }
    } else {
        $product->setData("news_to_date", null)->save();
        $message = $product->getName() . " Nothing to delete";
        return mage::log($message, null, 'batchcategory.log');
    }
}

public function updateCategoriesUs()
{

    $newproducts = $this->getNewProducts(4);

    foreach($newproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->addToCategory($product, array('375', '474'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->addToCategory($product, array('375', '680'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->addToCategory($product, array('375', '763'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->addToCategory($product, array('375', '357'/*New Books*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->addToCategory($product, array('375', '464'/*New Stationery*/), true);
                break;
            default:
                $this->addToCategory($product, array('375'/*New!*/), true);
        }
    }

    $oldproducts = $this->getOldProducts(4);

    foreach($oldproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->removeFromCategory($product, array('375', '474'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->removeFromCategory($product, array('375', '680'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->removeFromCategory($product, array('375', '763'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->removeFromCategory($product, array('375', '357'/*New Books*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->removeFromCategory($product, array('375', '464'/*New Stationery*/), true);
                break;
            default:
                $this->removeFromCategory($product, array('375'/*New!*/), true);
        }
    }
}

public function updateCategoriesTrade()
{

    $newproducts = $this->getNewProducts(5);

    foreach($newproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->addToCategory($product, array('819', '712'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->addToCategory($product, array('819', '364'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->addToCategory($product, array('819', '383'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->addToCategory($product, array('819', '781'/*New Curriculum*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->addToCategory($product, array('819', '776'/*New Stationery*/), true);
                break;
            default:
                $this->addToCategory($product, array('819'/*New!*/), true);
        }
    }

    $oldproducts = $this->getOldProducts(5);

    foreach($oldproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->removeFromCategory($product, array('819', '712'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->removeFromCategory($product, array('819', '364'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->removeFromCategory($product, array('819', '383'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->removeFromCategory($product, array('819', '781'/*New Curriculum*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->removeFromCategory($product, array('819', '776'/*New Stationery*/), true);
                break;
            default:
                $this->removeFromCategory($product, array('819'/*New!*/), true);
        }
    }
}

public function updateCategoriesCa()
{

    $newproducts = $this->getNewProducts(2);

    foreach($newproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->addToCategory($product, array('116', '12'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->addToCategory($product, array('116', '40'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->addToCategory($product, array('116', '69'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->addToCategory($product, array('116', '284'/*New Curriculum*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->addToCategory($product, array('116', '148'/*New Stationery*/), true);
                break;
            default:
                $this->addToCategory($product, array('116'/*New!*/), true);
        }
    }

    $oldproducts = $this->getOldProducts(2);

    foreach($oldproducts as $product) {
        switch ($product->getAttributeText('search_type')) {
            case 'DVD' /*DVD*/:
                $this->removeFromCategory($product, array('116', '12'/*New on DVD*/), true);
                break;
            case 'Music CD' /*MUSIC*/:
                $this->removeFromCategory($product, array('116', '40'/*New Music*/), true);
                break;
            case 'Paperback Book':
            case 'Hardcover Book':
            case 'Large Print Book':
            case 'Gift Edition Book':
            case 'Journal':
                /*BOOK*/
                $this->removeFromCategory($product, array('116', '69'/*New Books*/), true);
                break;
            case 'Bible Study Guide':
            case 'Teaching DVD':
                /*New Curriculum*/
                $this->removeFromCategory($product, array('116', '284'/*New Curriculum*/), true);
                break;
            case 'Stationery':
                /*New Stationery*/
                $this->removeFromCategory($product, array('116', '148'/*New Stationery*/), true);
                break;
            default:
                $this->removeFromCategory($product, array('116'/*New!*/), true);
        }
    }
  }
}
0

I discovered that because I was not includding the status attribute in my collection the save method thought the status was set to null and set it to enabled by default.

$oldproducts = Mage::getModel('catalog/product')->getCollection()
        ->addAttributeToSelect(array(
            'news_to_date',
            'name',
            'search_type',
            'status',
            'url_key',
            'tier_price'
        ))
        ->addStoreFilter($store)
        ->addAttributeToFilter('news_to_date', array(
            'lt' => $date,
            'notnull' => true
        ));

return $oldproducts;

I had to add stats, url_key, and tier_price to my collection to make sure magento didn't reset these attributes to their default values.

0

The problem is that you are calling save on a product instance that comes from a collection object.
save should only be called on an instance you called load on prior.
Never call save on product instances that come from a collection.
You will lose data. You only noticed that for the status because this attribute has logic behind it, but you can lose other values. For example for attributes that have a default value.
You should try to create a function that is similar to the _saveCategories method in the product resource model and only touch the categories.
This will also improve the performance of the script since save is expensive.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.