Wednesday, January 14, 2015

Set Free-Shipping on certain products through observer in Magento 1.9

Scenario: We want to set Free Shipping if any Buyer purchases Product X and Product Y along with 0 or more other products from our Magento store.

Solution : We may create shopping cart rules to achieve this, but when I tried to do it, it did not work out. So, it is better to create a new Module and write an observer. That observer will apply the 'Free Shipping' to the cart when Product X and Product Y are found within the cart. But for this, the 'Free Shipping' shipping method must be enabled from Admin Panel.

For this, let's create the new module called 'Chandan_Freeshipping'. The required files to be created are as follows :

1. app/etc/modules/Chandan_Freeshipping.xml
2. app/code/local/Chandan/Freeshipping/etc/config.xml
3. app/code/local/Chandan/Freeshipping/Model/Observer.php

"Chandan" is the Namespace/Company name and module name is 'Freeshipping'

So, let's start with the first file Chandan_Freeshipping.xml. Here is its contents :

<?xml version="1.0"?>
<config>
    <modules>
        <Chandan_Freeshipping>
            <active>true</active>
            <codePool>local</codePool>
        </Chandan_Freeshipping>
    </modules>
</config>

Here we just mentioned that the corresponding module's files are stored in "local" codepool.

Now, the content of "config.xml" ...

<?xml version="1.0"?>
  <config>

   <modules>
    <Chandan_Freeshipping>
     <version>0.1.0</version>
    </Chandan_Freeshipping>
   </modules>

   <frontend>
    <events>
     <checkout_cart_product_add_after>
      <observers>
       <Chandan_Freeshipping_Model_Observer>
         <type>singleton</type>
        <class>
           Chandan_Freeshipping_Model_Observer
         </class>
         <method>checkfreeshipping</method>
      </Chandan_Freeshipping_Model_Observer>
      </observers>
     </checkout_cart_product_add_after>
     
     <checkout_controller_onepage_save_shipping_method>
      <observers>
       <Chandan_Freeshipping_Model_Observers>
        <type>singleton</type>
<class>
        Chandan_Freeshipping_Model_Observer
        </class>
        <method>applyfreeshipping</method>
       </Chandan_Freeshipping_Model_Observers>
      </observers>

      </checkout_controller_onepage_save_shipping_method>
       <paypal_prepare_line_items>
<observers>
        <Chandan_Freeshipping_Model_Observer_Paypal>
         <type>singleton</type>
          <class>
            Chandan_Freeshipping_Model_Observer
          </class>
          <method>applyfreeshipping</method>
        </Chandan_Freeshipping_Model_Observer_Paypal>
        </observers>
       </paypal_prepare_line_items>
    </events>
  </frontend>
 </config>

In the above XML, couple of points should be noticed : 

1. We are capturing 3 events 
   i. checkout_cart_product_add_after : The event is fired when a product is added to the cart. At this point, if we see product X and Y are within the cart, we just show a message like "You'll get the FreeShipping at the final Checkout". Check the screenshot below.
   
   

   

   ii. checkout_controller_onepage_save_shipping_method : This event is fired when Shipping method is saved in Final Checkout. Check the screenshot below.
   


   
   
Even though any other shipping method can be selected, but ONLY "Freeshipping" method will be finally applied as our observer is in work. Check the screenshot below.

  


   
   iii. paypal_prepare_line_items : This event is fired when user selects Paypal payment method and comes back to Order Review page. At that point of time, only one shipping method "FreeShipping" will be available to the purchaser as our observer captures this event and forces this method.

2. Check the construct of the event and observer mentioned in the above XML file.

<checkout_cart_product_add_after>
<observers>
  <Chandan_Freeshipping_Model_Observer>
 <type>singleton</type>
 <class>Chandan_Freeshipping_Model_Observer</class>
 <method>checkfreeshipping</method>
  </Chandan_Freeshipping_Model_Observer>
  </observers>
</checkout_cart_product_add_after>

The whole block is wrapped by tag having event name ('checkout_cart_product_add_after') being captured. Now the observer name is 'Chandan_Freeshipping_Model_Observer' having class name 'Chandan_Freeshipping_Model_Observer' and method name 'checkfreeshipping'. So, this 'checkfreeshipping' method of class 'Chandan_Freeshipping_Model_Observer' will handle the event.
     
3 different observers mentioned above have different names. It is better if these names are different from each other. For 3 events, we will create a new class 'Chandan_Freeshipping_Model_Observer' and the methods 'checkfreeshipping', 'applyfreeshipping' as mentioned in above XML. 

Next, let's check the content of Observer.php where, as said above, we need to define the observer class and its methods. 

<?php
class Chandan_Freeshipping_Model_Observer 

  
   // SKUs of Product X and Product Y
   private $fsprod1 = "acj0006s";
   private $fsprod2 = "acj003";  
   
   // A method which searches for Product X
   // and Product Y within the CART
   private function ifFreeShippingApplicable()
   {
    // Define an SKU array
     $sku_list = array();
    
    // GET CART Items
    $quote = Mage::getSingleton('checkout/session')->getQuote();
    $cartItems = $quote->getAllVisibleItems();
 
    // LOOP Thru Cart Items
    foreach ($cartItems as $item)
     {
        $productId = $item->getProductId();
        $product = Mage::getModel('catalog/product')->load($productId);
      
        // Insert the Product SKU into that array
      $sku_list[] = $product->getSku() ;
    }
 
    // Check if Products X, Y are in the Cart
    if(in_array($this->fsprod1,$sku_list) && in_array($this->fsprod2,$sku_list))
    {
     return true;
    }
    else
    { 
     return false;
    }
    
   }
   
   // Show message that FreeShipping will
   // be applied on Cart
   public function checkfreeshipping(Varien_Event_Observer $observer) 
   { 
      if( $this->ifFreeShippingApplicable() )  
     {  
       // Product X and Y Found, 
      // Hence show Message
      Mage::getSingleton('checkout/session')->addSuccess("You will get Free Shipping at final checkout");
     }
   }
   
   // Method for applying the 'Freeshipping' method
   public function applyfreeshipping(Varien_Event_Observer $observer) 
   {
    // Check for Product X & Y
    if( $this->ifFreeShippingApplicable() )
    {
        // GEt Quote
$quote = Mage::getSingleton('checkout/session')->getQuote();

// Apply the Free Shipping
$address = $quote->getShippingAddress();
$address->setShippingMethod('freeshipping_freeshipping');
    }
   }  
}
?>

The code above is quite self-explanatory, it contains the class 'Chandan_Freeshipping_Model_Observer' and its methods which are executed when certain events are fired. 

Hope this helps.

Tuesday, January 06, 2015

How to do CURL by POSTing JSON data

This is already documented on PHP Manual, however very recently I had to do a CURL with some data JSON encoded and POSTed to a WebService to get some results. The corresponding PHP coding is not very difficult, I am showing it below.  

I am testing this in localhost and it is going to run perfectly. I have a file called test.php and I will be calling the same file ( other file is okay too ) with a parameter "curl=1" during the curl process. 

<?php

// The CURL handler
if( isset($_REQUEST['curl']) && $_REQUEST['curl'] == 1)
{
  // The below echo will be the CURL result
  echo print_r
         json_decode
           file_get_contents( "php://input" )
         ),1);
  exit;

}

// CURL URL
$curl_url = "http://127.0.0.1/test.php?curl=1";

// Data we are going to Submit/POST
$base_data = array( 
             "page" => 5,
             "showList" => "customer",
            "sortBy" => "salary",
            "orderBy" => "desc",
            "includePriceGroups" => true,
          "countryCode" => "US",
            "languageCode" =>"EN" );

// JSON Encoding the POST data
$post_data = json_encode( $base_data );

// CURL Process Init
$ch = curl_init( $curl_url );

// SET CURL Options
// Set the method to 'POST'
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
// Set the DATA
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);   

// GET The result as a string                                     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      
// SET the HEADER
curl_setopt($ch, CURLOPT_HTTPHEADER, array(                         
    "Content-Type: application/json",                               
    "Content-Length: " . strlen($post_data))                         );                                                                                                                 
// GET the Result 
$result = curl_exec($ch);

// Show Result
echo "This Result:: " . $result;
?>

Though I have entered the "Content-type" header to be "application/json", but it can be "text/plain" also.


In the above scenario, this is what we get as output : 


stdClass Object
(
    [page] => 5
    [showList] => customer
    [sortBy] => salary
    [orderBy] => desc
    [includePriceGroups] => 1
    [countryCode] => US
    [languageCode] => EN
)


Now, let's find out, why the output is like that.  We are posting a data like this :


{ "page":5,"showList":"customer","sortBy":"salary", 
  "orderBy":"desc", "includePriceGroups":true, 
  "countryCode":"US", "languageCode":"EN"
}

It is in JS Object Notation format. We are getting the above data in CURL handler written at the top of the script : 

if( isset($_REQUEST['curl']) && $_REQUEST['curl'] == 1)
{
    echo print_r
         json_decode
           file_get_contents( "php://input" )
         ),1);
    exit;
}

We won't get this data in $_POST or $_REQUEST variables. To receive the post data, we need to call file_get_contents("php://input") i.e we are receiving it as an input stream. After that we convert it to a Object (of stdClass) by calling json_decode() function. Print_r() function finally print the object.

Hope this helps.