magento target rule not applying to a specific product - magento

A simple product is in specific category other products have that rule applied.This is happening on magento enterprise 1.13.0.1 version.
A rule is applicable to that category but when I look in catalogrule_product table then there is no entry for that product. This means no rule applies to that product.
http://www.solvingmagento.com/quick-tip-magento-catalog-price-rules-dont-work/ is the link I refered.
I want to know if for some reason a product has no target rules applied then:
1. Is there no cron job that will handle this and populate catalogrule_product table.
If yes then which cron job does this.
Also when we saved product its expected that catalog_product_save_after event should get fired resulting in Mage_CatalogRule module’s observer method applyAllRulesOnProduct getting executed but still no luck.
When I click via admin apply rule then it works.
I want to know is has magento not provided any cron job/indexer to handle this.
Thanks in Advance.

If you are creating products outside of the magento backend (using php, or soap) you may have to use the following code after you have called the $product->save() method...
public function applyActiveRulesToProduct($productId)
{
try {
$product = Mage::getModel('catalog/product') -> load($productId);
$rules = Mage::getModel('catalogrule/rule')->getCollection()->addFieldToFilter('is_active', 1);
foreach ($rules as $rule) {
$rule->applyAllRulesToProduct($product);
}
return "Applied rules to " . $productId;
} catch (Exception $e) {
return $e->getMessage();
}
}
It is code that i wrote for my own soap api extension. I could not get the rules to apply using applyToProduct(product, websiteIds) but using applyAllRulesToProduct with filters on the rules array seems to do the trick.
FYI, this code is buried inside of the CatalogRule.Rule.php core code as well, but it cannot be called directly using the rule model or product model. Who knows why they did that.

Related

Magento: Navigation static page directly to specific product

I would like to add a static link at the navigation bar that can link directly to a specific product.
As I only have one product listing under category "pillow", I wish to set it to go into the product directly, skipping the catalog view.
I am aware of two methods, being URL rewrite management and static block, however I experience problem with both.
For "URL rewrite", it worked but once I update something at the category (e.g. moving the position), the system generate a new "URL rewrite" and delete the my custom one.
For "static block", I do not know what code to put in it. My guess was to add below code, but it doesn't work.
{{block type="catalog/product_view" product_id="896" template="catalog/category/view.phtml"}}
How do I get it done? Thanks in advance.
I have taken a different approach to the problem which may be helpful. It seems like your end goal is to skip the category view if a category only contains one product. So rather than fussing with hard coding templates or trying to clobber the category with URL rewrite, you can accomplish this using an event observer.
The approach will listen for the <catalog_controller_category_init_after> event to fire and check whether the category only has one product. If so it will send the request directly to the product. You will need to add a new extension or modify an existing one.
etc/config.xml
Create a new node under config/frontend/events:
<catalog_controller_category_init_after>
<observers>
<redirectSingleProduct>
<class>My_MyExtension_Model_Observer</class>
<method>redirectSingleProduct</method>
</redirectSingleProduct>
</observers>
</catalog_controller_category_init_after>
Model/Observer.php
Create the corresponding method to handle the event:
class My_MyExtension_Model_Observer
{
/**
* Check whether a category view only contains one product, if so send the request directly to it.
* #param Varien_Event_Observer $observer
* #return $this
*/
public function redirectSingleProduct(Varien_Event_Observer $observer)
{
$category = $observer->getCategory();
if ($category->getProductCount() == 1) {
$product = $category->getProductCollection()->addUrlRewrite()->getFirstItem();
$url = $product->getProductUrl();
$observer->getControllerAction()->getResponse()->setRedirect($url);
}
return $this;
}
}

Magento - catalog_product_save_after: Check if product has been saved

I am currently trying to save a product with attributes that I have built, and it's working fine. I have also set up my code to call the catalog_product_save_after function on my observer, as shown below:
class Package_MyModule_Model_Observer
{
public function catalog_product_save_after($observer)
{
$product = $observer->getProduct();
//Do stuff here
}
}
In this line of code here, is there a way to detect whether the product has already been saved (i.e. no error messages were shown)? Because I need to update some values in the database when the product is saved successfully.
Mostly this gets called after product is saved successfully, but to be sure you can hook into
catalog_product_save_commit_after

Can't able to set the product attribute programmatically in magento through observer

I want to update the products description attribute after the product save.so for this i am using the observer called catalog_product_save_after and depending on some condition i create the description for the product and i will save the description of the products by following code
product->setDescription();
product->save();
the problem is when i am calling the product->save(); the site is loading and loading later i found that product->save(); this function is again calling the catalog_product_save_after. that's why it is going into the infinite loop.
Please help me to set the description for the product.
Option 1:
You can use catalog_product_save_before and just use $product->setDescription('something') (without the save).
Option 2
Make your observer run only once.
function doSomething($observer) {
//some code here
$id = $product->getId();
if (!Mage::registry('observer_already_executed_'.$id)) {
//do your magic here
Mage::register('observer_already_executed_'.$id, 1);
}
}

Magento add product for different storeview in one step

currently when I add or edit products for magento via api I will do something like this for each storeview:
$product = Mage::getModel('catalog/product');
$product->setStoreId($default_store_id); // 0 = default/all store view.
// do something
try
{
$product->save();
}
catch (Exception $e)
{
echo $e->getMessage();
}
This will takes 1 second for each storeview. When I edit 1 product for 10 storeviews it will takes 10 seconds.
Is there any way to edit alle storeview data (different languages) in one step?
No is the simple answer. You can create optimised code though for editing and only save the attribute you are updating as opposed to the entire product object but this depends on the scenario you are catering for.
$product = Mage::getModel('catalog/product')->setStoreId($storeId)->load($product_id);
$product->setName('Product Name');
$product->getResource()->saveAttribute($product, 'name');
Other option is to work directly on the database for updates rather than use magento objects.

How do order statuses/states work in Magento 1.4.x

As far as I understand Magento have various order statuses under global/sales/order/statuses which can be altered by either copying app/code/core/Mage/Sales/etc/config.xml to local scope or overriding it with your custom module.
There are also global/sales/order/states defined in the same file and as far as I understand states are something like statuses groups. Only states (not statuses) can be set at the order status in magento and statuses are something like states subdivisions. So in administrator interface you can change statuses of a placed order but you can't change state from the order status drop-down (you can change it by either invoicing the client or canceling the order).
As far as I understand you can easily add a new status to your Magento but can't add new state as states are somehow hardcoded with the rest or Magento order processing logic. I really hope that I'm wrong.
Please correct me if I'm wrong in any point as these are just my thoughts and it might be quite far from real Magento 1.4.x flow.
I'm quite sure that 'state' is free data, it can be set to ANY value using the setData option on an order instance. So if you write a custom module that can load an order, set data to one of your new 'states' and test with what ever custom logic you require.
$order = Mage::getModel('sales/order')->load(1);
$order->setData('state','myCustomState');
$order->setData('status','onCustomState');
echo $order->getState()
// Returns myCustomState
its worth bearing in mine that CLOSED/CANCELLED are protected states, so trying to use $order->setState('my_state') will fail on those order, but shouldn't fail on setData so you can overwrite a closed or cancelled order with this method.
if you were to overwrite the order model with a custom one you could add your own logic such as isOnCustomState() and allow the order to be handled in any way just by loading by id.
To add 'custom logic' to your order you could do something copy app\code\core\Mage\Sales\Model\Order.php into your local folder, then you can add functions into that model,
public function isActive(){ if($this->getState() == 'active'){ return true; } else { return false; }
public function isInActive(){ if($this->getState() == 'deactivated'){ return true; } else { return false; }
public function activate(){
if(!$this->isActive()){
$this->setData('state','active');
$this->setData('status','Active Subscription');
// some custom code to start a recuring payment
return $this;
}
}
public function deactiveate(){
if(!$this->isInActive()){
$this->setData('state','deactivated');
$this->sendOrderUpdateEmail(true,'Your subscription has been deactivated.');
// some custom code to stop a recuring payment
return $this;
}
}
now you can load an order and set activate or deactivate on that order to fire your custom code,
$order = Mage::getModel('sales/order')->load(1)->activate();
this code is all untested and just an example of somethings you could try, please don't just dump this code in your model and expect it to work perfectly. in code\core\Mage\Sales\etc\config.xml in the nodes sales/order/states add
<activated translate="label">
<label>Active Subscription</label>
<statuses>
<pending default="1"/>
</statuses>
<visible_on_front/>
</activated>
Magento Order is a finite state machine.
Therefore when you define status it would automatically try to define its state. Altering state directly is not recommended.
When you define status it checks various flags for shipment and invoices and depending in all those it would get the right state. Once order is in approved state however you can easily change status regardless of if there is invoice or any flag etc.

Resources