Skip to content

Getting (and setting) a custom product price (per customer) in Magento

The current project I’m working on has something special: each client has its own price, but this price is not in Magento but in an Oracle DB. Every client on the website has a client id related to the Oracle DB, and in the Oracle DB there is a discount that is different for each client.

The possibility of adding all these price rules for each client in Magento is discarded. Then, the solution is getting that discount and applying it to the product price. This means that the final product price is different for each client (OK, that was our goal).

At this point, we have to find out how to apply that discount to the product price and set the new price in Magento. This is what I’m going to explain in the following lines.

Creating a module

First of all, we need to create a custom module for this. I’m not going to explain how to do so. Go to the Alan Storm (what a cool name!) website and learn!

Once you have created your module, your etc/config.xml file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<config>
 <modules>
  <COMPANY_CustomPrice>
   <version>0.1.0</version>
  </COMPANY_CustomPrice>
 </modules>
 <global>
  <events>
   <catalog_product_get_final_price>
    <observers>
     <COMPANY_CustomPrice_price_observer>
      <type>singleton</type>
      <class>COMPANY_CustomPrice_Model_Observer</class>
      <method>get_final_price</method>
     </COMPANY_CustomPrice_price_observer>
    </observers>
   </catalog_product_get_final_price>
  </events>
 </global>
</config>

Here we are rewriting the method that gets the final price. Now its time to create the observer. Create a Model/Observer.php file and paste the following code:

<?php

class COMPANY_CustomPrice_Model_Observer
{

 public function __construct()
 {
 }

 public function get_final_price($observer)
 {
  /* Check if the customer is logged in, if so, then we proceed (this can be done on the xml using <customer_is_logged_in> (or something like that...)  */

  if(Mage::getSingleton('customer/session')->isLoggedIn())
  {
   $customer_id = Mage::getSingleton('customer/session')->getCustomerId();

   /*Do whatever you need to get the custom discount for this client
   ---
   */

   $discount = 0.3;

   $event = $observer->getEvent();
   $product = $event->getProduct();
   $product->original_price = $product->getPrice();

   $final_price = $product->original_price * (1 - $discount);

   $product->setFinalPrice($final_price);

   return $this;
  }
 }
}
?>

What now?

Now that we know how to set the a special price manually, there are going to be a lot of conditions to take into the account depending on our website. In my case, we only apply a special price for registered clients that have been assigned an special id (different than the magento client id).

Note that this change is being applied only on the product page, not on the product list. This is because, in my case, we have to get the price from an Oracle DB that takes its time to return the result. If it’s only a single product, then it’s OK, but if we need to get more results, it takes longer.

There are also other things to take into the account: is this the best way to change the price on the product price? How about changing the price directly and not setting a «special price»? I’ll find out and write about it (here or in a new post).

This works in Magento CE and EE

Advertisements

1025 MySQL error when upgrading magento

Upgrading Magento is a tricky task. Even though the process is somewhat easy, when you find errors that they are not always easy to solve. One of these errors is the 1025 mysql error. This error is related to foreign keys checks.

There is no easy way to solve it. You can try modifying the app/etc/config.xml file, look for the <initStatements> tag and modify it to look like this:

<initStatements>SET NAMES utf8; SET FOREIGN_KEY_CHECKS=0;SET UNIQUE_CHECKS=0;</initStatements>

We’re forcing magento to don’t check foreign keys when it works. This could work. It didn’t in my particular case.

The thing is that if I update from 1.8 to:

  • 1.9 » got 1025 mysql error
  • 1.10 » got 1025 mysql error
  • 1.11 » got 1025 mysql error

When I had almost lost hope I tried the 1.9.1.1 version… and it worked! Ok, this has no sense at all. But the lesson I learnt was: try everything before giving up when upgrading magento.

Clean way of deleting orders in Magento

If you prefer to use an extension to add a «Delete» option on the orders list, see the Seamless Delete Order extension.

But if you want to do it by your own using the Magento functions, it’s quite easy. Just use something like this (this function would delete all orders, so don’t apply it directly!):

foreach(Mage::getModel('sales/order')->getCollection() as $order)
{
    $order->delete();
}

Functions in Blocks and in Helpers: what’s the difference?

For me, it’s pretty clear when the difference between a Block and a Model. Basically, the Model defines and implements our «object» in the Magento system, so we can call it whenever we need it. Blocks let us run specific functions from a concrete part of the website (defined in the layout) and call them from the phtml files that have been loaded from the page layout using a block.

But imagine that you haven’t defined a specific block of your model in the layout of one concrete page, but you need to run a function that uses your model. The solution is using helpers. The functions defined in Helpers files can be loaded from anywhere on the phtml files, so you don’t need to create a specific block each time you need to use your model. Functions defined in Helpers can be accessed by:

Mage::helper('module/class')->your_function()

How to get and show customer reward points in Magento Enterprise

One of the cool features in Magento Enterprise Edition is the reward points system. It’s very simple to configure and a really good way to make the customer feel «rewarded» for each action that he/she performs on the web.

The reward points are shown by default in «My account» area and also in the checkout process. If we need to show the reward points in any other place on the web, we need to call the enterprise_reward/reward model giving the customer. This is very simple:

$customer_id = Mage::getSingleton('customer/session')->getCustomer()->getID();
$customer = Mage::getModel('customer/customer')->load($customer_id);
$rewardpoints = Mage::getModel('enterprise_reward/reward')
->setCustomer($customer)
->setWebsiteId(Mage::app()->getWebsite()->getId())
->loadByCustomer()
->getCurrencyAmount();

echo $rewardpoints;

The easiest way to use jQuery in Magento

There are many different ways to use jQuery in Magento. The point on this is that given that Magento uses Prototype as default javascript framework (arghhh!), if we try to use jQuery libraries directly, there is going to be a «conflict».

We can solve this activating the jQuery «no conflicts mode», but there are easier ways. The easiest I’ve found is to install the following extension:

After installing it, you can use jQuery functions without any problem. Just keep in mind that instead of the usual «$» at the beginning of each function, you have to use «jQuery». That is, for example:

jQuery('#show_video').click(function() {
jQuery('#video').show('slow', function() {
});
});

Get and show the collection SQL query on Magento

I’ve been “suffering” out of memory problems on one of our clients magento installations. The version is the 1.4.0.1, and it seems that the queries are not as efficient as they are on Magento 1.5 and above.

So I needed to find out what were exactly the SQL queries that produced that out of memory error. The most difficult thing is to find where the collection query is done. Maybe there is a base collection function where we can execute the query, but if not, the only way at this moment is to find the prepareCollection() function loaded:

1. Find where your collection is get. In my case, I needed to find the last 5 orders query that is shown on the Dashboard. I found it in app/code/core/Mage/Adminhtml/Block/Widget/Grid.php, in the _prepareCollection() function.

2. At the end of that function there is a «$this->getCollection()», this one is the variable that has the collection. Now, we only need to add ->getSelect()->__toString in order to show the query:

Zend_Debug::dump($this->getCollection()->getSelect()->__toString());

3. Now we only need to update the page where the query is done and we’ll see the SQL query

I usually use Zend_Debug::dump() function to show things on screen.