Product won't save. Processing forever - php

I'm doing a module to Magento my module have the same functions of Crosssell native function from magento.
I have this product grid and the user select some checkboxes to associate this products to the main product.
All ok.
But, I've create a custom attribute to save the ID's of this products and make a Observer to 'catalog_product_save_after' event:
<events>
<catalog_product_save_after>
<observers>
<brindeproduto_save_product_data>
<type>singleton</type>
<class>brindeproduto/observer</class>
<method>saveProductTabData</method>
</brindeproduto_save_product_data>
</observers>
</catalog_product_save_after>
</events>
On my saveProductTabData I load the main product by the ID on Request, and put the IDS of the selecte products on my custom attribute like these "1,2,3,4,5,6".
Ok, but when I do $product->save(); I got infinite load on my browser, without any error or exeption.
The code on observer are simple.
$product = Mage::getModel('catalog/product')->load($product_id);
//some logical Specific information that is not in question now.
$product->save();
Nothing more.
I've tryed debug the save function and get some intriguing result.
On Mage_Core_Model_Abstract function save(), I put some die on parts of code, and get all of then. this code it's part of function save line 330 on Magento 1.5 Community.
if ($dataCommited) {
$this->_afterSaveCommit();
}
return $this;
It's the last line on function. I put die before return.
if ($dataCommited) {
$this->_afterSaveCommit();
}
die('test');
return $this;
I've got the die. But nothing more before return. Some body have ideia of what's happen?? Lost by 5 hours on that.
Any help will be mutch appreciated.

You should NOT be doing any save in your observer (*_save_after).
This will cause a never ending loop

Related

Magento: Adding custom field to Newsletter using Observers

First... I'm new to this so bear with me.
I'm trying to make a module which adds custom field to newsletter using observers.
I made a column in "newsletter_subscribers" table (mysql4-install-0.1.0.php)
$installer = $this;
$installer->startSetup();
$installer->run("
ALTER TABLE {$this->getTable('newsletter_subscriber')}
ADD (user_name VARCHAR(50) NOT NULL);
");
$installer->endSetup();
Then i modified config.xml for observer
<events>
<newsletter_subscriber_save_before>
<observers>
<My_Newsletter>
<type>model</type>
<class>Newsletter_Observer</class>
<method>newsletterSubscriberSaveBefore</method>
</My_Newsletter>
</observers>
</newsletter_subscriber_save_before>
</events>
Then made an observer.php
class My_Newsletter_Model_Observer
{
public function newsletterSubscriberSaveBefore(Varien_Event_Observer $observer)
{
$subscriber = $observer->getEvent()->getSubscriber();
$name = Mage::app()->getRequest()->getParam('subscriber_name');
$subscriber->setSubscriberName($name);
return $this;
}
}
So my questions is.
What did i miss?
It doesn't work. I know I'm missing something important.
You specify
ADD (user_name VARCHAR(50) NOT NULL);
That means your code should be:
$subscriber->setUserName($name);
well easiest solution to explain would be to put a
die("TEST");
at the beginning of the method itself.
If it dies with output TEST the observer is listening to the dispatched event.
Clear the cache, because Magento doesnt know due to ddl caching, even if caching is off in admin menu.
Have you taken a look at 'newsletter_subscriber' table? Did the sql script do its job?
According to #SeanBreeden you need to call your magic setter-method via setUserName($name);
Is your observer in the right section if saved from frontend (<global> or <frontend>)?
Thanks guys. It was my fault atfer all. I put "Newsletter_Observer" class in config.xml, but my Observer.php was in Newsletter/Model/ folder.

Magento Custom Pricing / Attributes on a Quote Item

I have created attributes that save directly to a quote item in my checkout_cart_product_add_after Observer method will not persist the value as it seems to be reverted after the Observer exits.
See code samples below:
config.xml (snippet):
<checkout_cart_product_add_after>
<observers>
<module>
<type>model</type>
<class>NativeRemedies_OrderGroove_Model_Observer</class>
<method>productAddAfter</method>
</module>
</observers>
</checkout_cart_product_add_after>
Observer.php (snippet):
public function handleOrderGroove()
{
foreach($this->og->products as $_product){
if($_product->every>0){
foreach($this->_quote->getAllVisibleItems() as $_item){
//if sku is in the active list of recurring products selected add quote item id to array
if($_item->getSku()==$_product->id){
Mage::helper('nrordergroove')->setRecurringItem($_item->getItemId());
$_item->setOrdergrooveActive(true)->save();
$_item->getProduct()->setPrice(2);
$_item->setCustomPrice(2);
$_item->setOriginalCustomPrice(2);
$_item->getProduct()->setIsSuperMode(true);
}
}
} // else, do nothing
}
The $_item object in this example isn't providing the facility to retain the attribute as set - even when calling ->save().
Thank in advance for your help. I have seen all of the tutorials about setting custom prices and attributes - nothing seems to remedy the situation!
Edit 1
I'm starting to feel like this is a bug in 1.6+. I have seen much discussion on various boards about this working in >=1.4.
Edit 2
Just to be absolutely clear, the issue here is that the Custom Pricing attribute is being overwritten effectively by the Product model or the collectTotals methods. I need a workaround.
As it happens my working code here did, in fact, work. An extension conflict with Amasty's Special Promotions was causing the custom pricing to be unset. This is tested as working with the following Magento versions:
1.5 Community
1.6.1 Community
1.11.1.1 Enterprise
Here is the answer to your question, yes this is in the newer version of Magento 1.5+:
When checking out items get converted from a quote to a order at which point your attribute are being lost.
You would need to add something similar to this observer in order for your attributes to retain at checkout:
<sales_convert_quote_item_to_order_item>
<observers>
<extra_options>
<type>model</type>
<class>extra_options/observer</class>
<method>salesConvertQuoteItemToOrderItem</method>
</extra_options>
</observers>
</sales_convert_quote_item_to_order_item>
Here we move the option from the quote item to the order item.
public function salesConvertQuoteItemToOrderItem(Varien_Event_Observer $observer)
{
$quoteItem = $observer->getItem();
if ($additionalOptions = $quoteItem->getOptionByCode('additional_options')) {
$orderItem = $observer->getOrderItem();
$options = $orderItem->getProductOptions();
$options['additional_options'] = unserialize($additionalOptions->getValue());
$orderItem->setProductOptions($options);
}
}
Take a look here for more details:
Magento - Quote/order product item attribute based on user input

Magento custom price rules for product

Hello i need to use magento to sell a product that will have custom price rules.
the rule will depend by the quantity of this product sold.
I know that magento can make special rule, if a customer by ++ quantity of this product, but me i need to apply different rule and i cant find the way.
For example, product bought from customers first 100 times, price is :100$
product bought 200-500 times, price is 400$
500-1000times, product is 800$
1000 - > product is fixed price 1000$
is it possible for magento to do this?
Thank you
You can do this by creating a module that uses the checkout_cart_product_add_after and checkout_cart_update_items_after observers.
Then inside your observer class you can put the following function in to set the price:
public function yourAddToCartFunction($observer) {
if ($p = $observer->getQuoteItem()->getParentItem()) {
$discount_amount = $your_discount_logic;
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #configs
} else {
$p = $observer->getQuoteItem();
$discount_amount = $your_discount_logic;
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #simple products
}
}
You will more than likely need a different function for the cart update observer call. The one above is for the cart_add_after event. The function for the cart update is nearly identical except you have to go through the cart object to get the logic.
public function yourCartUpdateFunction($observer) {
$cart = $observer->cart;
$quote = $cart->getQuote();
foreach($quote->getAllVisibleItems() as $item) {
if ($p = $item->getParentItem()) {
$discount_amount = $your_discount_logic;
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #configs
} else {
$discount_amount = $your_discount_logic;
$item->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #simple products
}
}
}
The reason you would want the second function is if the logic needs to happen again if the cart is updated. If the price is going to stick forever no matter what happens once it is in the cart, you can probably exclude the second function.
MASSIVE EDIT:
Ok this is how I would do this. I am assuming you are starting with a basic, functional module.
The first thing you want to do is setup your observers in your modules config.xml file. In this case you are going to use be using the checkout_cart_product_add_after and checkout_cart_update_items_after observers. You will set that up by adding the following to your config.xml file:
<config>
...
<global>
...
<events>
<checkout_cart_product_add_after>
<observers>
<call_this_something_unique>
<type>singleton</type>
<class>Ocaff_Custompricing_Model_Cart_Observer</class>
<method>calculateAddToCart</method>
</call_this_something_unique>
</observers>
</checkout_cart_product_add_after>
<checkout_cart_update_items_after>
<observers>
<call_this_something_unique_2>
<type>singleton</type>
<class>Ocaff_Custompricing_Model_Cart_Observer</class>
<method>calculateCartUpdate</method>
</call_this_something_unique_2>
</observers>
</checkout_cart_update_items_after>
</events>
...
</global>
...
</config>
Basically what this does is it tells Magento that when the checkout_cart_product_add_after event is triggered, run the calculateAddToCart method of the Ocaff_Custompricing_Model_Cart_Observer class and also to run the calculateCartUpdate when the checkout_cart_update_items_after event is triggered.
Ok now that you have your configuration put together you can create your model. In the case of this example the class would be located in the /app/code/local/Ocaff/Custompricing/Model/Cart/Observer.php file (however you will put the class that matches your module)
Ok now in your Observer.php file you are going to put the following code:
<?php
class Ocaff_Custompricing_Model_Cart_Observer {
public function calculateAddToCart($observer) {
if ($p = $observer->getQuoteItem()->getParentItem()) {
$discount_amount = Mage::helper('custompricing')->calculatePrice($p);
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #configs
} else {
$p = $observer->getQuoteItem();
$discount_amount = Mage::helper('custompricing')->calculatePrice($p);
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #simple products
}
}
public function calculateCartUpdate($observer) {
$cart = $observer->cart;
$quote = $cart->getQuote();
foreach($quote->getAllVisibleItems() as $item) {
if ($p = $item->getParentItem()) {
$discount_amount = Mage::helper('custompricing')->calculatePrice($prpoduct);
$p->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #configs
} else {
$discount_amount = Mage::helper('custompricing')->calculatePrice($p);
$item->setCustomPrice($discount_amount)->setOriginalCustomPrice($discount_amount); #simple products
}
}
}
}
Ok a few notes here. both functions take a single paramater that I have called observer (and pretty much everywhere else calls it that too). This is a single variable that holds all the information that Magento passes along to all the functions that handle the event. In the case of the calculateAddToCart function we are only grabbing the Quote Item (which is confusing since in checkout with Magento there are quite a few different objects that kind of all represent the same thing if you are looking at it from 50,000 feet). What this function does is takes the quote item and determines if the product that was added to cart is a simple or configurable product and takes that appropiate action.
The calculateCartUpdate function basically does the exact same thing, but it has to instead iterate through all the products in the cart since in Magento you update the entire cart all at once, not every line item.
In both functions you will notice that I am updating the Custom Price and the Original Custom Price field. I am not 100% sure why you have to update both (and really why ask questions if it works :))
Ok now you may or may not notice that I have done something a little less than conventional for figuring out the $discount_amount variable. I am calling a helper function to get the price that the product should be set to. I put this into a helper because you may want to access that logic elsewhere in the system and I generally prefer to put that kind of logic into a Helper (in fact I am pretty sure you are going to want to use this on the product and category pages since you are modifying the way pricing is working for some products and customers get mad when prices change up unexpectadly).
Ok now onto the helper function. Since I am not 100% sure what logic you really want in the end, we are just going to keep this function simple and have it return $2. This will make everything that goes into the cart $2 no matter what its price actually is. This is going to be where you figure out your logic for pricing.
<?php
class Ocaff_Custompricing_Helper_Data {
public function calculatePrice($product=null) {
// Your custom logic will go here. Whatever number you come up with and return will be the price that the item is set to
return 2;
}
}
For the most part this should get you about 90% of where you want to be. Try this out and post questions and I'll do my best to help you.
Another Edit: Activating Helpers in config.xml
Put this code inside your config.xml file right after your observers block detailed above. This will tell Magento the location of the helper files for your module.
<helpers>
<custompricing>
<class>Ocaff_Custompricing_Helper</class>
</custompricing>
</helpers>
This is a tier prices feature, you don't need to create a catalog price rule. Check in the product edit page when you manage your products in the backend, the tab Prices and see the option "Tier Prices"

How do I edit a product attribute using PHP during a cart checkout in Magento?

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!

Is there an event for customer account registration in Magento?

I would like to be able to run some functionality with a module that I am building whenever a customer registers an account, but I can't seem to find any event that is fired upon a new customer registration.
Does anybody know of an event that is dispatched for that?
Whenever I'm looking for an event, I'll temporarily edit the Mage.php file to output all the events for a particular request.
File: app/Mage.php
public static function dispatchEvent($name, array $data = array())
{
Mage::log('Event: ' . $name); //not using Mage::log, as
//file_put_contents('/tmp/test.log','Dispatching '. $name. "\n",FILE_APPEND); //poor man's log
Varien_Profiler::start('DISPATCH EVENT:'.$name);
$result = self::app()->dispatchEvent($name, $data);
#$result = self::registry('events')->dispatch($name, $data);
Varien_Profiler::stop('DISPATCH EVENT:'.$name);
return $result;
}
and then perform whatever action it is I'm trying to hook into. Magento events are logically named, so scanning/sorting through the resulting logs usually reveals what I'm after.
customer_register_success is what you are looking for:
<config>
<frontend>
<events>
<customer_register_success>
<observers>
<your_module>
<type>singleton</type>
<class>your_module/observer</class>
<method>yourMethod</method>
</your_module>
</observers>
</customer_register_success>
</events>
</frontend>
</config>
I discovered how to achieve this today. It involves using one of the generic controller events. This node in the config.xml will hook into the right event:
<events>
....
<controller_action_postdispatch_customer_account_createPost>
<observers>
<your_module_here>...etc
The controller_action_postdispatch_REQUESTPATH event is thrown for every controller that extends Mage_Core_Controller_Front_Action (which is basically all of them) which makes it very easy to target. Ditto for controller_action_predispatch_REQUESTPATH.
I'm a bit surprised that none of the answers if solving the case completely.
Customer create can happen
by url customer/account/create
by register in checkout
I solved it by tracking two events:
config.xml
<events>
<controller_action_postdispatch_customer_account_createpost>
<observers>
<myextensionkey_create_account>
<class>myextensionkey/observer</class>
<method>createAccount</method>
<type>singleton</type>
</myextensionkey_create_account>
</observers>
</controller_action_postdispatch_customer_account_createpost>
<checkout_submit_all_after>
<observers>
<myextensionkey_checkout_create_account>
<class>myextensionkey/observer</class>
<method>createAccountCheckout</method>
<type>singleton</type>
</myextensionkey_checkout_create_account>
</observers>
</checkout_submit_all_after>
</events>
and in Observer.php
public function createAccount($observer) { ... } //Nothing special here
public function createAccountCheckout($observer) {
if ($observer->getQuote()->getData('checkout_method') != Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER) {
return;
}
Edit: I changed
<controller_action_predispatch_customer_account_createpost>
into
<controller_action_postdispatch_customer_account_createpost>
because on predispatch the account is not created yet. There can be an error for example if the email already exists in the shop.
There isn't a direct event for this, but you could use the customer_save_commit_after event. This event also guarantees you that the customer is save in the shop's database. The problem with this event is that is triggered twice. Bellow is an hack that allows you to use this event - the observer function is listed:
public function customer_save_commit_after($p_oObserver) {
$l_oCustomer = $p_oObserver->getCustomer();
if ($l_oCustomer->isObjectNew() && !$l_oCustomer->getMyCustomKeyForIsAlreadyProcessed()) {
$l_oCustomer->setMyCustomKeyForIsAlreadyProcessed(true);
// new customer
}
else {
// existing customer
}
return false;
}
Hope this helps someone!
You have to consider also when the user register on-the-fly on checkout: a Register on chekout. Thinking on this case, you can catch the "checkout_type_onepage_save_order_after" event with your own Observer class, and then this code...
if($observer->getEvent()->getQuote()->getCheckoutMethod(true) == Mage_Sales_Model_Quote::CHECKOUT_METHOD_REGISTER){
(...)
}
Anybody may say: Mage_Sales_Model_Quote->getCheckoutMethod() is deprecated since 1.4!!,but:
If we call the ortodox method Mage_Checkout_Model_Type_Onepage->getCheckoutMethod(), waiting for something as "METHOD_REGISTER" this is executed:
if ($this->getCustomerSession()->isLoggedIn()) {
return self::METHOD_CUSTOMER;
}
... "METHOD_CUSTOMER" is the name for a checkout with an already registrated user, not our case.... but yes!, because....
...the registration operation is perfomed before "checkout_type_onepage_save_order_after" event. Then we a have a METHOD_CUSTOMER now. Ups, something inconsistent?
Fortunatly, the Quote remains with the original value: CHECKOUT_METHOD_REGISTER
Any other idea for the registration on checkout?
You can try customer_save_after, the only thing that the registration sends this event twice
Actually there are customer_save_after and customer_save_before (magento 1.5)
If you want to modify on-the-fly some data after form post, pick customer_save_before, change the data you want and that's all (the save action come after, so your change will be taken into account).
$customer->save() just doesn't work in customer_save_after. (fatal error) Use this observer to run a code after customer creation which are NOT related to customer data.
Hope that helps!
customer_register_success
adminhtml_customer_save_after
these two are the default events when a customer is inserted into the database....
first event fires in frontend when a user registers and second event fires in the backend when a customer is created through admin panel...i hope you know how to register an observer for an event...hope this will help you...
I was looking of the same thing. I believe the event is customer_register_success.
You can find a link for all events at:
http://www.nicksays.co.uk/magento_events_cheat_sheet/
I found the event checkout_submit_all_after.
<checkout_submit_all_after>
<observers>
<my_example>
<class>my_example/observer</class>
<method>customerRegistered</method>
</my_example>
</observers>
</checkout_submit_all_after>
In my Observer.php I get the quote object that is passed in.
public function customerRegistered (Varien_Event_Observer $observer) {
$quote = $observer->getQuote();
$checkout_method = $quote->getData();
$checkout_method = $checkout_method['checkout_method'];
if ($checkout_method == Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER) {
}
Do not use $quote->getCheckoutMethod() it gives you login_in instead. Not sure why. Hope this helps.
I've discovered that the customer_login and customer_session_init events are both thrown on account create. You could register a listener for either and then check to see the create date on the account?
The answer to this question is that there isn't an event for that.
You can use the customer_register_success event. It is triggered after the customer is succesfully created. Here is the link of event cheat sheets. Hope it also helps you.
http://www.nicksays.co.uk/magento-events-cheat-sheet-1-7/
customer_register_success is the event dispatched after successful customer registration.
Here's from the code from Mage/Customer/controllers/AccountController.php::454 in magento 1.8:
protected function _dispatchRegisterSuccess($customer)
{
Mage::dispatchEvent('customer_register_success',
array('account_controller' => $this, 'customer' => $customer)
);
}
customer_save_after is the event which gets called after a new customer registration.
Read about all the events here:
http://www.magentocommerce.com/wiki/5_-_modules_and_development/reference/events
event name:customer_registration_is_allowed
I'm not sure if this is you want,you can write a observer to test

Categories