We have been using a third party to pack and ship our packages. Therefore we don't see all orders that pass by anymore.
But there are several products that we have to supply manually ourselves, such as a digital gift card. Is there a possibility to have Magento send us an email when a specific SKU has been ordered by a customer? For instance to inform us that we need to create a gift card for a customer?
I don't want to see every order in our emailbox, just with some specific SKU's in it.
Thanks,
Menno
Yes this can be achieved with a custom module. Create your module and add an event observer to it's config.xml;
<events>
<checkout_onepage_controller_success_action>
<observers>
<copymein>
<type>singleton</type>
<class>dispatcher/observer</class>
<method>ccMyEmail</method>
</copymein>
</observers>
</checkout_onepage_controller_success_action>
</events>
Then in Model/Observer.php declare your function;
public function ccMyEmai($observer) {
$order_ids = $observer->getData('order_ids');
if(isset($order_ids)) {
foreach ($order_ids as $order_id) :
$sendToMe = false;
$order = Mage::getModel('sales/order')->load($order_id);
if (isset($order)) {
$orderItems = $order->getAllItems();
foreach ($orderItems as $_item) {
$product = Mage::getModel('catalog/product')->load($item->getData('product_id'));
if($product->getSku() == ('123' || '234' || '345')) { // Your SKUs
$sendToMe = true;
}
}
}
if($sendToMe) {
$mail = Mage::getModel('core/email');
$mail->setToName('Your name');
$mail->setToEmail('your#email.com');
$mail->setBody('Order number '.$order->getIncrementId().' has items that need action');
$mail->setSubject('Order '.$order->getIncrementId().' needs attention');
$mail->setFromName('Your from name');
$mail->setFromEmail('your#siteemail.com');
$mail->setType('text');
try {
$mail->send();
} catch (Exception $e) {
Mage::log($e);
}
}
endforeach;
}
}
Just a note that it would be more efficient to create a product attribute that isnt visible on the frontend that defines whether a product requires your attention - something along the lines of needs_attention Yes/No, then scan the ordered products for a yes value in that attribute. Much more manageable than hard coding the SKU's you are looking for ;)
You might create a custom module for this functionality. So in the new module, you have to hook Observer event: checkout_onepage_controller_success_action.
You can do like following as :
<checkout_onepage_controller_success_action>
<observers>
<xxx_checkout_success>
<type>singleton</type>
<class>[Your Module Name]/observer</class>
<method>sendEmailToCustomerForSales</method>
</xxx_checkout_success>
</observers>
</checkout_onepage_controller_success_action>
And, in this sendEmailToCustomerForSales() method, it can send an email to the customer according to a specific SKU.
Please refer this code:
public function sendEmailToCustomerForSales($observer) {
$orderId = (int)current($observer->getEvent()->getOrderIds());
$order = Mage::getModel('sales/order')->load($orderId);
$itemCollection = $order->getItemsCollection();
foreach($itemCollection as $item) {
$_product = Mage::getModel('catalog/product')->load($item->getProductId());
if($_product->getSku() == '[Your specific sku]') {
/*send an email to the customer*/
}
}
}
Related
I'm reposting this from magento.stackexchange because of practically no views/answers there.
We have an observer that modifies final price, that's triggered on the event catalog_product_get_final_price. Problem is, when you retrieve products via collection with addAttributeToSelect("*"), they come back with a final_price already set, and the product getFinalPrice function merely returns what's in the database instead of recalculating (and running the observers for) the final price.
Mage_Catalog_Model_Product
public function getFinalPrice($qty=null)
{
// *** Collection items already have a 'final_price' from flat tables
// but it's wrong because observers haven't run yet ***
$price = $this->_getData('final_price');
if ($price !== null) {
return $price;
}
return $this->getPriceModel()->getFinalPrice($qty, $this);
}
I've also noticed that all of our custom attributes are also not being interpreted (we save things as JSON but decode into objects them on product load before using them).
This behavior doesn't happen when you load the product directly -- all the observers and models are interpreted when the product is loaded.
Is there a way to ensure the data we're retrieving from a collection matches in format and value the data we would retrieve if we load the product directly?
I know I can just load the product individually to trigger all of the events that go along with it, but in the case of 3rd party software, that might not always be the case and the final price is wrong.
We're on version 1.7 if it helps.
Set up an event
<catalog_product_collection_load_after>
<observers>
<modulename>
<type>singleton</type>
<class>Seamus_Module_Model_Observer</class>
<method>changePrice</method>
</modulename>
</observers>
</catalog_product_collection_load_after>
On your observer do something like...
public function changePrice($observer)
{
$event = $observer->getEvent();
$products = $observer->getCollection();
foreach( $products as $product )
{
$product->setFinalPrice( $this->getPriceLogic($product) );
}
return $this;
}
Which controller in Magento do I need to override if I want to redirect a certain product view page to another url?
I'd like to use the following code for redirection. Is there any more Magento-like way of doing it?
if($this->getProductId() == 10) {
header("Location: /mymodule");
die();
}
Magento Admin has a feature for this under Catalog > URL Rewrite Management. Create a new product rewrite with these steps:
Click the Add URL Rewrite button at top right.
Select “Custom” from Create URL Rewrite.
Choose the appropriate Store.
Set Request Path to something like this catalog/product/view/id/10 (assuming 10 is the ID of your product).
Set Target Path to whatever route or URL you want to send the request to.
Set Redirect to probably “Temporary (302)”.
Found a solution. Might not be the best one but it works:
Observer.php:
class Namespace_Mymodule_Model_Observer {
public function redirect(){
//request object
$request = Mage::app()->getRequest();
//only redirect in the frontend/catalog
$storeId = Mage::app()->getStore()->getId();
if(in_array($request->getModuleName(), array("catalog")) && $storeId != 0) {
$response = Mage::app()->getResponse();
$params = Mage::app()->getRequest()->getParams();
//check the product id
if($params[id] == 10) {
return $response->setRedirect("/mymodule", 301)->sendHeaders();
}
}
}
}
And the config.xml in the global/events section:
<controller_action_predispatch>
<observers>
<namespace_mymodule_observer>
<type>singleton</type>
<class>namespace_mymodule/observer</class>
<method>redirect</method>
</namespace_mymodule_observer>
</observers>
</controller_action_predispatch>
I believe a better approach is to actually utilize the observer event since all you need is included here already. Also, the answer does not differentiate between products and categories since in_array($request->getModuleName(), array("catalog")) would be true for both.
class Namespace_Mymodule_Model_Observer {
public function redirect(Varien_Event_Observer $observer) {
$actionName = $observer->getEvent()->getControllerAction()->getFullActionName();
$productId = $observer->getEvent()->getControllerAction()->getRequest()->getParam('id');
if($actionName == 'catalog_product_view' && $productId == 10) {
$response = $observer->getEvent()->getControllerAction()->getResponse();
$response->setRedirect('/mymodule', 301)->sendHeaders();
}
}
}
I have catch an event catalog_product_save_commit_after and written an observer for it to get product stock.
In config.xml I have written the code below
<events>
<catalog_product_save_commit_after>
<observers>
<Arkix_Logs_observer>
<type>singleton</type>
<class>Arkix_Logs_Model_Observer</class>
<method>get_update_inventory</method>
</Arkix_Logs_observer>
</observers>
</catalog_product_save_commit_after>
</events>
In Observer.php I have written:
public function get_update_inventory( $observer){
$product = $observer->getEvent()->getItem();
$origStockData = $product->getOrigData('stock_item')->getOrigData();//to get original stock
echo '<pre>';print_r($origStockData);
$stockData = $product->getStockItem()->getData();//to get new stock
echo "product name id ".$product->getId();
die('haha');
}
But error is coming Call to a member function getOrigData() on non object in observer.php
I think you need to instantiate the model Mage::getModel('cataloginventory/stock_item') before using the getOridData() function. So
try,
public function get_update_inventory( $observer){
$productId = $observer->getProduct()->getId();
$model = Mage::getModel('catalog/product');
$_product = $model->load($productId);
$stocklevel = (int)Mage::getModel('cataloginventory/stock_item')
->loadByProduct($_product)->getQty();
print_r($stocklevel);
}
comment here if you have any doubt.
For anybody that comes across this, there are 2 things wrong here:
...
<catalog_product_save_commit_after>
...
</catalog_product_save_commit_after>
The event that you should be using is
...
<catalog_product_save_after>
...
</catalog_product_save_after>
Since the method getOridData() is only available before the transaction is commited.
The method to get the observer product is $observer->getEvent()->getProduct(); , not $observer->getEvent()->getItem();
May be you can try following code instead of using getOrigData()
$product->getStockItem()->getQty();
What magento method I can use to stop the checkout button to function until a certain condition its true?
basically is a user has deleted a product on basket while he must not checkout until two products are on the basket
public function deleteAction()
{
parent::deleteAction();
if($this->_getCart()->getQuote()->getItemsCount() == 1) {
$this->addErrorMessage('Please remove one voucher. Or add one More infant milk product');
}
}
This is quite easy to accomplish using the config flag checkout/options/onepage_checkout_enabled:
public function deleteAction()
{
parent::deleteAction();
if($this->_getCart()->getQuote()->getItemsCount() == 1) {
Mage::app()->getStore()->setConfig('checkout/options/onepage_checkout_enabled',0);
}
}
A side note:
It's not really necessary to rewrite the controller here, as you could handle it in a postdispatch controller observer action:
<events>
<controller_action_postdispatch_checkout_cart_delete>
<observers>
<yourmodule_postdispatch_delete>
<class>yourmodel/observer</class>
<method>deletePostdispatch</method>
</yourmodule_postdispatch_delete>
</observers>
</controller_action_postdispatch_checkout_cart_delete>
</events>
And the observer method would look like:
public function deletePostdispatch($observer)
{
if(Mage::getSingleton('checkout/session')->getQuote()->getItemsCount()==1){
Mage::app()->getStore()->setConfig('checkout/options/onepage_checkout_enabled',0);
}
}
HTH, Cheers!
Why are there no events dispatched on or around the newsletter subscription/un-subscription process either in the customer or newsletter modules.
The only alternative i am faced with at the moment is to use a rewrite for the subscriber model to fit some code in around here.
Does anyone else have a good alternative to this - or am I missing something
I encountered a situation where I needed to listen for subscription/unsubscription events. I encountered this question and thought I would leave this solution here for anyone that may need it:
By adding an observer to the event newsletter_subscriber_save_before in your config.xml:
<global>
....
<events>
....
<newsletter_subscriber_save_before>
<observers>
<your_unique_event_name>
<class>yourgroupname/observer</class>
<method>newsletterSubscriberChange</method>
</your_unique_event_name>
</observers>
</newsletter_subscriber_save_before>
</events>
</global>
You can then call getSubscriber() (in the context of $observer->getEvent(), see next code block) in your observer to get the Mage_Newsletter_Model_Subscriber model that allows you get data about the subscriber. This works for occurrences of subscription and unsubscriptions.
public function newsletterSubscriberChange(Varien_Event_Observer $observer) {
$subscriber = $observer->getEvent()->getSubscriber();
//now do whatever you want to do with the $subscriber
//for example
if($subscriber->isSubscribed()) {
//...
}
//or
if($subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED) {
//...
} elseif($subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED) {
//..
}
}
So it turns out this is really easy. These model events are super powerful and let you do things like this super easily. Can't turn down free functionality!
For quick reference, here is what data the Mage_Newsletter_Model_Subscriber model provides (1.7)
Here's what just worked for me on 1.7.0.2. I know this thread is old, but posting it here in case it can help anyone (since there's not a lot of info about this event out there):
*NOTE: Replace myco_myextension with your extension's unique name:*
In config.xml:
<newsletter_subscriber_save_commit_after>
<observers>
<myco_myextension_model_observer>
<class>Myco_Myextension_Model_Observer</class>
<method>subscribedToNewsletter</method>
</myco_myextension_model_observer>
</observers>
</newsletter_subscriber_save_commit_after>
In Observer.php:
public function subscribedToNewsletter(Varien_Event_Observer $observer)
{
$event = $observer->getEvent();
$subscriber = $event->getDataObject();
$data = $subscriber->getData();
$statusChange = $subscriber->getIsStatusChanged();
// Trigger if user is now subscribed and there has been a status change:
if ($data['subscriber_status'] == "1" && $statusChange == true) {
// Insert your code here
}
return $observer;
}
The newsletter/subscriber model is a normal Magento model from the looks of it, so it should still dispatch some events from the upstream classes. Take a look at something like newsletter_subscriber_create_after and newsletter_subscriber_delete_after for some possible event hooks to use.
the newsletter modul hooks to event: customer_save_after