Given that I have multiple websites in my Magento instance, how do I identify the website where a particular event happened? For example, observing the checkout_cart_add_product_complete event lets me catch all Add to Cart events. Let's say I wanted to get the website Id of the website where this Add to Cart event happened, how do you I do that?
public function addToCart(Varien_Event_Observer $observer) {
$product = $observer->getEvent()->getProduct();
$websiteId = $observer->getEvent()->get ??? ();
}
I know that I can get the websiteIds of the product that was added to the cart, by doing the following
$websiteIds = $observer->getEvent()->getProduct()->getWebsiteIds();
But that is not what I want, because if the product belongs to more than one website, it will give me all the websites and not the one where the Add to Cart event happened.
Thanks
Have you tried:
Mage::app()->getStore()->getId()
within your observer? That should give you the current store id..
You can directly get the StoreId from Mage, not from the observer object.
StoreId:
Mage::app()->getStore()->getStoreId();
WebsiteId:
Mage::app()->getStore()->getWebsiteId();
Related
I'm building a website for a client, he wants to update his stock from his Presta website to his CRM. In order to achieve that it's very simple, I only have to call an URL like this :
http://crm.com/client1/bin/majstock.php?mode=stock&pdt=REF~-1;REF2~-1
Where REF is obviously the Ref of the product, and the number after ~ is the quantity to update, so in this example the customer bought 2 products, one is REF and the other one is REF2.
The problem is that I don't know where I should call this URL, and where I can get the parameters
Thanks for your help !
You can use the hook actionOrderStatusUpdates like that:
public function hookActionOrderStatusUpdate($params)
{
$OrderState = $params['newOrderStatus']; // an OrderState object
// $OrderState->id // order status ID
// $params['id_order'] // order ID
$Order = new Order((int)$params['id_order']);
$products = $Order->getProductsDetail();
// or
$products = $Order->getProducts();
}
You could create a new module with a hook on actionOrderStatusUpdate and call the CRM when the desired status is set on the order.
What I have done:
I have few custom calculations to be done after placing an order for the customer in magento admin panel. I have hooked on to sales_order_save_after event inside tab inside my module's config.xml .
The Problem:
I need to get the customer_id of the actual customer for whom the order is been placed on the backend. How can this be done?
$_customer = Mage::getSingleton('customer/session')->getCustomer();
$customer_id=$_customer->getId();
The above will give me the customer_id in case of front end, I need a way to get the customer's id when ordering from backend.
In case, the event "adminhtml_sales_order_create_process_data", is what I need to hook on, do let me know. because I am also kind of confused about which event to hook on.
Help me out.
Please use this event sales_order_place_after.
And in your code, you might get the customer id like this:
public function hookSalesOrderPlaceAfter(Varien_Event_Observer $observer) {
$order = $observer->getEvent()->getOrder();
$customer_email = $order->getCustomerEmail();
$website_id = Mage::app()->getStore()->getWebsiteId();
$customer = Mage::getModel('customer/customer')->setWebsiteId($website_id)->loadByEmail($customer_email);
...
}
Hope it will help you.
This code below works for me (Thanks to Makwana Ketan shared this code)
$sessionquoteId = Mage::getSingleton('adminhtml/session_quote')->getQuote()->getId();
$sessionCustomerId = Mage::getModel('sales/quote')->loadByIdWithoutStore($sessionquoteId)->getCustomerId();
I sell two services in my Magento store. I've disabled cart and multi-page checkout. I want to sell only one service at a time. Means I want to accomplish, if customer tries to add both services to cart so the previous service should be removed.
How can I accomplish this? I've been searching this from last 5 hours.
in the file
app/code/core/Mage/Sales/Model/Quote.php
there is a method public function addProduct($product, $request = null);
you should only add $this->removeAllItems(); to be the first line in the method, like:
public function addProduct(Mage_Catalog_Model_Product $product, $request = null)
{
$this->removeAllItems(); // new code
....
}
of course, it's better idea to be overridden in the local pool.
I am currently developing a module working with the product edit in the backend.
Its purpose is to retrieve categories the product belongs to and populate an attribute (the Brand attribute) with the list of selected categories.
It is mandatory for the admin to select at least one category.
My module works as expected except that I don't know how to stop the saving process if the admin hasn't selected any category while editing a product.
Here is the workflow
Administrator selects categories in the category tab in the product edit page
Admin clicks on "Save"
My module "observes" and gathers all categories
--> If there are selected categories
My module's observer does its stuff to update the Brand attribute
--> Else
My module's observer adds an error to the admin session
My module's observer should tell Magento to stop saving the product. But how do I do that ?
The generic question would maybe be : how to pass a "stop save" argument to an observer ?
Here are a sample of my config.xml file and the method that deals with the workflow I explained above.
Thanks a lot for your help and have fun Magentoing !
config.xml
<catalog_product_prepare_save>
<observers>
<brands_product_save_observer>
<type>singleton</type>
<class>brands/observer</class>
<method>saveProductBrand</method>
</brands_product_save_observer>
</observers>
</catalog_product_prepare_save>
Observer.php
public function saveProductBrand($observer) {
$product = $observer->getProduct();
$categoryIds = $product->getCategoryIds();
if (isset($categoryIds)) {
foreach ($categoryIds as $categoryId) {
$isBrandCategory = Mage::getModel('brands/navigation')->isBrandCategory($categoryId);
if ($isBrandCategory)
$brandCategories[] = $categoryId;
}
if (isset($brandCategories)) {
$brandId = Mage::getModel('brands/navigation')->getBrand($brandCategories[0]);
if ($brandId) {
$attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 140);
foreach ($attribute->getSource()->getAllOptions(true, true) as $option) {
$attributeArray[$option['label']] = $option['value'];
}
$categoryName = Mage::getModel('catalog/category')->load($brandId)->getName();
$product->setData('brand', $attributeArray[$categoryName]);
}
} else {
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('catalog')->__('Please add this product to a brand in the "Categories" tab.'));
HERE SOME CODE TO TELL MAGENTO TO STOP SAVING THE PRODUCT
return;
}
}
}
It's always a crap shoot as to which sections of Magento support this, but throwing an exception is often the prescribed way of telling Magento that something went wrong. The layers higher up the stack are set to catch these exceptions and use them to go back to the form and display an error message. Give this a try
Mage::throwException(Mage::helper('adminhtml')->__('You totally failed at that.'));
If you take a look at the Adminhtml module's Catalog/ProductController.php (1.5, but I'd assume a similar format in previous versions)
function saveAction()
{
...
$product = $this->_initProductSave();
try {
$product->save();
$productId = $product->getId();
...
}
The _initProductSave method is where the catalog_product_prepare_save event is fired. Since this is outside the saveAction's try/catch block, the exception won't be caught (as described in the comments below).
You'll need to move you validation code into the product model's before save event (catalog_product_save_before). Doing that should let you throw an exception and have the admin display the error message and represent the form for editing.
A couple of thoughts. Do you actually want to stop the save, or would "undoing" the changes be enough? If your observer detects that the required information is missing, then just iterate through the changed data and set it back to the original and allow the save to proceed. You should be able to do $product->getOrigData() to compare which has changed?
Alternatively, why not make the category attribute mandatory? You should be able to do that in your config xml (not exactly sure how off the top of my head)
Finally, you could bind to the controller_action_predispatch_catalog_product_save Event instead, and if you detect the error state, set a no-dispatch flag, add your error message to the session and redirectReferrer. Check out my earlier answer here for details.
=========EDIT=========
I found a new way. In your Observer, change the _dataSaveAllowed value on the object to false. Mage_Core_Model_Abstract::save() checks that value before proceeding with the save.
HTH,
JD
In case you need to prevent the save method to execute for a core model (i.e. Catalog/Product), you can use reflection to set "$_dataSaveAllowed" to false:
public function catalogProductSaveBefore($observer)
{
try {
$product = $observer->getProduct();
$reflectionClass = new ReflectionClass('Mage_Catalog_Model_Product');
$reflectionProperty = $reflectionClass->getProperty('_dataSaveAllowed');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($product, false);
} catch (Exception $e) {
Mage::log($e->getMessage());
}
return $this;
}
I don't think you can you stop execution the way you want via an observer, Magento doesn't pay attention to anything that you might return or set via your observer.
One idea would be too rewrite the save method of the product model. You could check for any error flag that you set in your observer and then prevent the save from that point. Something like this:
function save()
{
if( $error_detection )
{
return $this;
}
else
{
return parent::save();
}
}
One of the possible approaches can be this one as well - it's a hack though
Mage::app()->getRequest()->setPost("YOUR_KEY",false);
I have a two part question about customizing my Magento store.
When someone buys a downloadable product, I want to generate a licence code and include it in the invoice.
I have added a product attribute called ‘license_code’ to my product’s default attribute set and I want to set its value with php when a customer checks out.
What is the event to observe that will let me access the products in the cart just after they are purchased but before the invoice is created?
I also need to know what script to use to set a product’s attribute value during that event.
Thank you for your help!
Possible events are sales_order_place_before or sales_convert_quote_*.
You cannot save your 'license_code' attribute because that will affect all products, a product does not store it's values when ordered. Instead a better idea would be to manipulate the options of an order item.
function salesConvertQuoteItemToOrderItem(Varien_Event_Observer $observer)
{
$orderItem = $observer->getOrderItem();
$options = $orderItem->getProductOptions();
$options['licence_code'] = YOUR-DOWNLOADABLE-CODE-HERE;
$orderItem->setProductOptions($options);
}
Retrieving the code later is essentially the same process with getProductOptions(), the order item objects are already used on the order view pages so are easy to find and use in your theme.
Ok I think I got it figured out.
I set up my event observers as follows:
<events>
<sales_order_item_save_before>
<observers>
<downloadable_observer>
<class>Licensing_Catalog_Model_Observer</class>
<method>generate_licenses</method>
</downloadable_observer>
</observers>
</sales_order_item_save_before>
</events>
and then my observing function as:
public function generate_licenses($observer)
{
$orderItem = $observer->getEvent()->getItem();
$options = $orderItem->getProductOptions();
$options['licence_code'] = 'YOUR-DOWNLOADABLE-CODE-HERE';
$orderItem->setProductOptions($options);
return $this;
}
Thank you so much for the help, clockworkgeek!