I need to send SMS (By using any SMS API) to customers when products are back in stock.
I have rewrite Mage_ProductAlert_Model_Observer class and added SMS API in my Custom Module's Observer.php file but its not sending SMS to customers. Why?
Also, its only showing two customers details instead of all customers subscribed to product stock alert. Here is my code
Observer.php
<?php
class My_Alert_Model_ProductAlert_Observer
{
public function process()
{
$customer_stock_alerts = Mage::getModel('productalert/stock')
->getCollection()
->addStatusFilter(0)
->setCustomerOrder();
foreach ($customer_stock_alerts as $alert){
$stock_back_product = $alert->getProductId();
$current_product=Mage::getModel('catalog/product')->load($stock_back_product);
$current_product_name = $current_product->getName();
$customer_info = Mage::getModel('customer/customer')->load($alert->getCustomerId());
$customer_name = $customer_info->getPrimaryBillingAddress()->getFirstname();
$customer_mobile = $customer_info->getPrimaryBillingAddress()->getTelephone();
$message = 0;
$message = "Dear $customer_name, Product $current_product_name is back in Stock";
$message=urlencode($message);
$sendsms = "http://api.msg91.com/api/sendhttp.php?sender=MSGIND&route=4&mobiles=$customer_mobile&authkey=xxxxxxxxxxxxxxxxxxx&country=91&message=$message";
file_get_contents($sendsms);
}
}
}
?>
config.xml
<?xml version="1.0"?>
<config>
<modules>
<My_Alert>
<version>0.0.1</version>
</My_Alert>
</modules>
<global>
<models>
<my_alert>
<class>My_Alert_Model</class>
</my_alert>
</models>
</global>
<crontab>
<jobs>
<my_alert>
<schedule>
<cron_expr>*/5 * * * *</cron_expr>
</schedule>
<run>
<model>my_alert_productalert/observer::process</model>
</run>
</my_alert>
</jobs>
</crontab>
<frontend>
<routers>
<My_Alert_First>
<use>standard</use>
<args>
<module>My_Alert</module>
<frontName>my-alert</frontName>
</args>
</My_Alert_First>
</routers>
</frontend>
</config>
Can anyone share what's the issue this & why SMS is not sending?
I'm using Magento 1.9.
In Magento approach to handling Product Stock Alert collection. Our client has more than 40.000 subscribers and more than 30.000 are waiting for status to be changed from “Out of Stock” to “In Stock”. So when Magento tries to load 40.000 records from table product_alert_stock to collection to foreach them because of memory limitation php fails.
I Think you have not change core files you can over ride using your extension this link help you.
Related
The Issue:
If your magento enterprise store has multiple currencies enabled and you are using Cart Sidebar to give a quick overview of items in the cart: Full Page Cache will be a villain when the customer try to switch between currencies. The Cart Sidebar won't get updated based on the currency switched.
I have published the answer at
http://www.eglobeits.com/blog/magento/magento-enterprise-edition-full-page-cache-mutli-currencies-mini-cart-sidebar-issue-when-switching-currencies/,
but Adding the same below for your quick reference.
The Fix:
Redefine the Cart Side Place holder container and define a new cache Id generator rather than Using fpc's original one.
Follow below Steps:
1. Create app/code/local/Egits/PageCache/etc/config.xml with following content
<?xml version="1.0"?>
<config>
<modules>
<Egits_PageCache>
<version>0.0.1</version>
</Egits_PageCache>
</modules>
</config>
2. Create app/code/etc/modules/Egits_PageCache.xml wih following content
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Egits_PageCache>
<active>true</active>
<codePool>local</codePool>
<depends>
<Enterprise_PageCache />
</depends>
</Egits_PageCache>
</modules>
</config>
3. Create app/code/local/Egits/PageCache/etc/cache.xml wih following content
<?xml version="1.0" encoding="UTF-8"?>
<config>
<placeholders>
<cart_sidebar>
<block>checkout/cart_sidebar</block>
<placeholder>CART_SIDEBAR</placeholder>
<container>Egits_PageCache_Model_Container_Sidebar_Cart</container>
<cache_lifetime>86400</cache_lifetime>
</cart_sidebar>
</placeholders>
</config>
4. Create app/code/local/Egits/PageCache/Model/Container/Sidebar/Cart.php with following content
<?php
class Egits_PageCache_Model_Container_Sidebar_Cart extends Enterprise_PageCache_Model_Container_Sidebar_Cart
{
const CURRENCY_COOKIE = 'currency';
/**
* Get cache id for the block
* #return string
*/
protected function _getCacheId()
{
$cookieCart = Enterprise_PageCache_Model_Cookie::COOKIE_CART;
$cookieCustomer = Enterprise_PageCache_Model_Cookie::COOKIE_CUSTOMER;
$curreny = array_key_exists(self::CURRENCY_COOKIE, $_COOKIE) ? $_COOKIE[self::CURRENCY_COOKIE] : '';
return md5(
Enterprise_PageCache_Model_Container_Advanced_Quote::CACHE_TAG_PREFIX
. (array_key_exists($cookieCart, $_COOKIE) ? $_COOKIE[$cookieCart] : '')
. (array_key_exists($cookieCustomer, $_COOKIE) ? $_COOKIE[$cookieCustomer] : '')
. $curreny
);
}
}
4. Flush All your caches and you are done! :).. Pretty Simple... ehhh??
I'm trying to create new product type in magento and it is showing up in admin panel create new product page's product type options, but when I select it and continue, i get fatal error:
Fatal error: Call to a member function setConfig() on a non-object in
/home/shop/public_html/shop/app/code/core/Mage/Catalog/Model/Product/Type.php
on line 82
Line 82 is:
$typeModel->setConfig($types[$typeId]);
Module config file (app/code/local/Pood/Toodep6hi/etc/config.xml):
<?xml version="1.0"?>
<config>
<modules>
<Pood_Toodep6hi>
<version>0.1.0</version>
</Pood_Toodep6hi>
</modules>
<adminhtml>
<translate>
<modules>
<Pood_Toodep6hi>
<files>
<default>Pood_Toodep6hi.csv</default>
</files>
</Pood_Toodep6hi>
</modules>
</translate>
</adminhtml>
<global>
<models>
<Toodep6hi>
<class>Pood_Toodep6hi_Model</class>
</Toodep6hi>
</models>
<catalog>
<product>
<type>
<p6hitoode translate="label" module="Toodep6hi">
<label>Pohitoode</label>
<model>Toodep6hi/Product_Type_P6hitoode</model>
<price_model>Toodep6hi/Product_Price</price_model>
<index_data_retreiver>Toodep6hi/catalogIndex_Data_P6hitoode</index_data_retreiver>
<is_qty>1</is_qty>
</p6hitoode>
</type>
</product>
</catalog>
<helpers>
<Toodep6hi>
<class>Pood_Toodep6hi_Helper</class>
</Toodep6hi>
</helpers>
</global>
</config>
app/code/local/Pood/Model/Product/Type/P6hitoode.php:
<?php
class Pood_Toodep6hi_Model_Product_Type_P6hitoode extends Mage_Catalog_Model_Toodep6hi_Type_Abstract
{
const TYPE_P6HITOODE = "p6hitoode";
public function isVirtual()
{
return true;
}
}
I found a sililar problem: http://www.magentocommerce.com/boards/viewthread/196886/#t248371, but it did not help.
Every bit of help would be very appreciated.
Thank you!
the problem is case sensititve
<model>Toodep6hi/product_type_p6hitoode</model>
it should be
<model>toodep6hi/product_type_p6hitoode</model>
Try to extend Mage_Catalog_Model_Toodep6hi_Type_Abstract from Mage_Catalog_Model_Product_Type_Virtual
Use lower case here:
<model>Toodep6hi/Product_Type_P6hitoode</model>
so it will be:
<model>Toodep6hi/product_type_p6hitoode</model>
If will not help, try to use lower case for model:
<models>
<toodep6hi>
<class>Pood_Toodep6hi_Model</class>
</toodep6hi>
</models>
and lower case here then
<model>toodep6hi/product_type_p6hitoode</model>
Try this
<type>
<p6hitoode translate="label" module="Toodep6hi">
<label>Pohitoode</label>
<model>Toodep6hi/product_type_p6hitoode</model>
<price_model>Toodep6hi/product_price</price_model>
<index_data_retreiver>Toodep6hi/catalogIndex_data_p6hitoode</index_data_retreiver>
<is_qty>1</is_qty>
</p6hitoode>
</type>
Following this post I've finally managed to capture an event by extending the Magento_Adminhtml_Controller_Action and carry out some actions before it. But now I'm trying to improve it so I can capture another event triggered on the admin panel and from there pass an array through the request variable to another event on the frontend. I've these SO questions/answers, here and here but no way I can achieve what I need. I've tested the observer code using die() to be sure that the execution thread goes into the correct call and it is ok. I'm using the CommerceBug from AlanStorm, in case it can be used to get some light on this issue.
This is my Observer.php code.
<?php
class Dts_Videotestimonials_Model_Observer {
public function hookToAdminhtmlControllerActionPreDispatch($observer)
{
if($observer->getEvent()->getControllerAction()->getFullActionName() == 'videotestimonials_adminhtml_videotestimonialsbackend_post')
{
// dispatching our own event before action upload video is run and sending parameters we need
Mage::dispatchEvent("upload_video_before", array('request' => $observer->getControllerAction()->getRequest()));
}
}
public function hookToUploadVideoBefore($observer)
{
//Hooking to our own event
$request = $observer->getEvent()->getRequest()->getParams();
// do something with product
$user = Mage::getSingleton('admin/session');
$userName = $user->getUser()->getFirstname();
$userEmail = $user->getUser()->getEmail();
$request['product_id'] = "16"; #$_product->getId(),
$request['author_email'] = $userEmail;
$request['author_name'] = $userName;
$request['video_link'] = "http://www.youtube.com/watch?v=y435u6kfExA&feature=youtube_gdata_player";
$request['video_type'] = "link";
$request['title'] = "AT&T Phone Nokia 2610";
$request['comment'] = "this is a comment";
Mage::dispatchEvent("vidtest_youtube_post", $request);
}
}
EDITED:
Here is the full config.xml
<?xml version="1.0"?>
<config>
<modules>
<Dts_Videotestimonials>
<version>0.1.0</version>
</Dts_Videotestimonials>
</modules>
<global>
<models>
<videotestimonials>
<class>Dts_Videotestimonials_Model</class>
<resourceModel>videotestimonials_mysql4</resourceModel>
</videotestimonials>
</models>
<events>
<controller_action_predispatch>
<observers>
<controller_action_before>
<type>singleton</type>
<class>videotestimonials/observer</class>
<method>hookToAdminhtmlControllerActionPreDispatch</method>
</controller_action_before>
</observers>
</controller_action_predispatch>
<upload_video_before>
<observers>
<upload_video_before>
<type>singleton</type>
<class>videotestimonials/observer</class>
<method>hookToUploadVideoBefore</method>
</upload_video_before>
</observers>
</upload_video_before>
</events>
<helpers>
<videotestimonials>
<class>Dts_Videotestimonials_Helper</class>
</videotestimonials>
</helpers>
<blocks>
<videotestimonials>
<class>Dts_Videotestimonials_Block</class>
</videotestimonials>
</blocks>
</global>
<admin>
<routers>
<videotestimonials>
<use>admin</use>
<args>
<module>Dts_Videotestimonials</module>
<frontName>videotestimonials</frontName>
</args>
</videotestimonials>
</routers>
</admin>
<adminhtml>
<menu>
<videotestimonials module="videotestimonials">
<title>Videotestimonials</title>
<sort_order>100</sort_order>
<children>
<videotestimonialsbackend module="videotestimonials">
<title>VideoTestimonials_Admin</title>
<sort_order>0</sort_order>
<action>videotestimonials/adminhtml_videotestimonialsbackend</action>
</videotestimonialsbackend>
<pending_video translate="title">
<title>Videos pendientes</title>
<sort_order>20</sort_order>
<action>videotestimonials/adminhtml_pendingvideos/pending</action>
</pending_video>
</children>
</videotestimonials>
</menu>
<acl>
<resources>
<all>
<title>Allow Everything</title>
</all>
<admin>
<children>
<videotestimonials translate="title" module="videotestimonials">
<title>Videotestimonials</title>
<sort_order>1000</sort_order>
<children>
<videotestimonialsbackend translate="title">
<title>VideoTestimonials_Admin</title>
</videotestimonialsbackend>
<pending_video translate="title">
<title>Videos pendientes</title>
<sort_order>20</sort_order>
</pending_video>
</children>
</videotestimonials>
</children>
</admin>
</resources>
</acl>
<layout>
<updates>
<videotestimonials>
<file>videotestimonials.xml</file>
</videotestimonials>
</updates>
</layout>
</adminhtml>
<crontab>
<jobs>
<videotestimonials_videotestimonialscron>
<schedule><cron_expr>59 0 * */1 0</cron_expr></schedule>
<run><model>videotestimonials/cron::VideoTestimonialscron</model></run>
</videotestimonials_videotestimonialscron>
</jobs>
</crontab>
</config>
Here is what is happening. Your configuration of the admin controller is wrong. The proper way to include your controller in the admin section is this (you'll need to change out the module name, to match yours):
<?xml version="1.0" ?>
<config>
<modules>
<Video_Awesome>
<version>0.0.1</version>
</Video_Awesome>
</modules>
<global>
<models>
<Video_Awesome>
<class>Video_Awesome_Model</class>
<!-- No resource model used currently -->
</Video_Awesome>
</models>
<events>
<controller_action_predispatch>
<observers>
<controller_action_before>
<type>singleton</type>
<class>Video_Awesome/Observer</class>
<method>controllerActionPredispatch</method>
</controller_action_before>
</observers>
</controller_action_predispatch>
<upload_video_before>
<observers>
<Video_Awesome>
<type>singleton</type>
<class>Video_Awesome/Observer</class>
<method>uploadVideoBefore</method>
</Video_Awesome>
</observers>
</upload_video_before>
</events>
</global>
<admin>
<routers>
<adminhtml>
<!-- we are not creating our own router, but tapping into the adminhtml router -->
<args>
<modules>
<!-- Your module name, and then
the path to the controller (minus
the controllers folder name). So,
in this instance, I put the router
in a "Adminhtml" folder inside of
the controllers folder, like thus:
Video/Awesome/controllers/Adminhtml/videotestimonialsController.php -->
<Video_Awesome before="Mage_Adminhtml">Video_Awesome_Adminhtml</Video_Awesome>
</modules>
</args>
</adminhtml>
</routers>
</admin>
</config>
And, then, in your router (you don't need to call getEvent before getting the controller action):
public function controllerActionPredispatch ($observer)
{
if($observer->getControllerAction()->getFullActionName() == 'adminhtml_videotestimonials_post') {
// dispatching our own event before action upload video is run and sending parameters we need
Mage::dispatchEvent("upload_video_before", array('request' => $observer->getControllerAction()->getRequest()));
}
}
And finally, it doesn't sound as if you have a debugging setup for your Magento development. I would highly recommend one. I use PHPStorm (I don't have any stake in the company - this is not an advertisement :), and it works awesome. Set a breakpoint there to see if what the variables are.
I would also recommend using adminhtml_controller_action_predispatch_start, instead of the global controller_action_predispatch, as it will only trigger in the backend (a very, very small performance difference).
Also, as a small sidenote, I saw in your config.xml, that you were specifying menu items/acl there. You probably didn't know, but that is deprecated functionality, and those items should be put it adminhtml.xml.
Trying to add a group_id radio button set in Magento Pro v1.11
Following along with
http://phpmagento.blogspot.com/2012/01/how-to-show-customer-group-selecter-in.html and
http://developersindia.info/magento/magento-override-frontend-controller.html, which is working to a point, but the group_id is not getting written to the db.
my module, thus far:
Directory Structure
app/code/local
- WACI
-- Customer
--- controllers
---- AccountController.php
--- etc
---- config.xml
config.xml
<config>
<modules>
<WACI_Customer>
<version>0.1.0</version>
</WACI_Customer>
</modules>
<global>
<fieldsets>
<customer_account>
<group_id><create>1</create></group_id>
</customer_account>
</fieldsets>
</global>
<frontend>
<routers>
<customer>
<args>
<modules>
<WACI_Customer before="Mage_Customer_AccountController">
WACI_Customer
</WACI_Customer>
</modules>
</args>
</customer>
</routers>
</frontend>
</config>
AccountController.php
<?php
/**
*Customer account controller
*
* #package WACI_Customer
*/
require_once Mage::getModuleDir('controllers', 'Mage_Customer').DS.'AccountController.php';
class WACI_Customer_AccountController extends Mage_Customer_AccountController
{
/**
* Create customer account action
*/
public function createPostAction()
{
// contents of createPostAction(), with some extra logic
/**
* Initialize customer group id
*/
/* catch groupid at account creation */
if($this->getRequest()->getPost('group_id')){
$customer->setGroupId($this->getRequest()->getPost('group_id'));
} else {
$customer->getGroupId();
}
// rest of method
}
}
theme../persistent/customer/form/register.phtml
<div class="input-box">
<label for="group_id"><?php echo $this->__('Select your customer group') ?></label><br />
<?php
$groups = Mage::helper('customer')->getGroups()->toOptionArray();
foreach ($groups as $group){
echo '<input type="radio" name="group_id" value="'.$group['value'].'" class="validate-radio" >'.$group['label'].'</input><br/>';
}
?>
</div>
So, the radio buttons with the groups show up fine at registration, but the data isn't being written to the db, as group still shows as general in the admin/manage customers
I don't really want to modify core files, as the article describes,
I'm not certain that I'm properly overwriting the mage
accountController class (maybe theres a better way to do this?)
What am I mucking up?
See below URL I think it is very help full to you.
How to let customer choose customer group at registration
http://www.magentocommerce.com/boards/viewthread/24208/
selecting customer group during registration in magento
http://sabujcse.wordpress.com/2010/03/09/selecting-customer-group-during-registration-in-magento/
How to Add Customer Group field while register in magento
http://xhtmlandcsshelp.blogspot.in/2010/12/add-customer-group-while-register-in.html
How to add group in register form
http://sapnandu-magento.blogspot.in/2011/07/how-to-add-group-in-register-form.html
Check your config.xml:
<frontend>
<routers>
<customer>
<args>
<modules>
<WACI_Customer before="Mage_Customer_AccountController">
WACI_Customer
</WACI_Customer>
</modules>
</args>
</customer>
</routers>
</frontend>
Should be:
<frontend>
<routers>
<customer>
<args>
<modules>
<WACI_Customer before="Mage_Customer">WACI_Customer</WACI_Customer>
</modules>
</args>
</customer>
</routers>
</frontend>
You also need to pay attention with:
<WACI_Customer before="Mage_Customer">WACI_Customer</WACI_Customer>
and
<WACI_Customer before="Mage_Customer">
WACI_Customer
</WACI_Customer>
You have to make sure no empty spaces between <tag> and content and </tag>
I have a situation where the customer wants the special price to be rounded to the nearest whole number (Example: 1922.25 => 1922.00, 1256.85 => 1257.00)
This should be only for Special prices says the customer which means, if there's no special price for the product, the price should come as it is.
Note this is not only for display. This rule applies everywhere, even invoices. So is there a way to do this easily or we should only modify the core files?
EDIT
If we modify the core framework files like Product.php or Price.php, they will get overwritten with an update right? So this should be a safe way too preferably.
This is pretty easy.
Just observe catalog_product_load_after event, and overwrite special_price with a rounded value.
Create a bootstrap file for your module:
app/etc/modules/Danslo_RoundSpecialPrice.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Danslo_RoundSpecialPrice>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Catalog />
</depends>
</Danslo_RoundSpecialPrice>
</modules>
</config>
Specify that we want to observe the product load event:
app/code/local/Danslo/RoundSpecialPrice/etc/config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<global>
<models>
<roundspecialprice>
<class>Danslo_RoundSpecialPrice_Model</class>
</roundspecialprice>
</models>
<events>
<catalog_product_load_after>
<observers>
<round_special_price>
<class>roundspecialprice/observer</class>
<type>singleton</type>
<method>roundSpecialPrice</method>
</round_special_price>
</observers>
</catalog_product_load_after>
<catalog_product_collection_load_after>
<observers>
<round_special_price>
<class>roundspecialprice/observer</class>
<type>singleton</type>
<method>roundSpecialPriceInCollection</method>
</round_special_price>
</observers>
</catalog_product_collection_load_after>
</events>
</global>
</config>
Then just write your observer implementation:
app/code/local/Danslo/RoundSpecialPrice/Model/Observer.php:
class Danslo_RoundSpecialPrice_Model_Observer
{
public function roundSpecialPrice($observer)
{
$product = $observer->getProduct();
if ($product->getSpecialPrice()) {
$product->setSpecialPrice(round($product->getSpecialPrice()));
}
}
public function roundSpecialPriceInCollection($observer)
{
foreach ($observer->getCollection() as $product) {
if ($product->getSpecialPrice()) {
$product->setSpecialPrice(round($product->getSpecialPrice()));
}
}
}
}
In PHP:
if (special price)
price = round(price);
Which database are you using? Maybe you could do this at database level and leave application intact. For example, if you use Firebird, you can use a computed field defined like this:
alter table prices
add customer_price
computed by (
case when special_price
then round(price,0)
else price
end)