Magento Sale Notifications with Smart Lights

This past week at work I made an extension to let us visually see when a sale was made without having to check magento using LIFX smart lights. Every time an order is placed the LIFX lights flash colors to boost office moral. The extension is fairly simple, it gets triggered once an invoice is created in Magento via an observer. A function is then called which sends a CURL command to the LIFX API. I made this extension available on GitHub for anyone else interested. Here’s the link. If you’re interested in how it works then keep reading.

First, all of the necessary Magento 1x extension files and folder structure have to be created like so:

app/etc/modules/Company_Package.xml
app/code/local/{Company}/{Package}/etc/adminhtml.xml
app/code/local/{Company}/{Package}/etc/config.xml
app/code/local/{Company}/{Package}/etc/system.xml
app/code/local/{Company}/{Package}/Helper/Data.php
app/code/local/{Company}/{Package}/Model/Observer.php

It’s important to note the structure used for creating an extension. Where company and package are used, you would replace company with either your name or company and then package would be replaced with the name of your extension. In my case, I use a shortened version of my name with the extension name, Cmallory/Lifx and Cmallory_Lifx.

Once you have created the files and folders required you will need to create your declaration file so that magento knows to load your code and from where.

File: app/etc/modules/Cmallory_Lifx.xml

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

In the above file there are 3 main points to understand. In the  <module> tag you are declaring your extension as Company_Package. Using this tag tells magento how to call your package and also where it’s located after  app/code/local .  After that, you’re letting magento know the extension is enabled by setting the  <active> tag to true. Setting this to false would disable your extension. The last tag is telling magento which code pool the extension is in. This means either app/code/community/ or app/code/local/ depending on if you write community or local. In magento it’s considered best practice to NEVER modify or add files to  app/code/core/ .

Next we need to tell Magento when to trigger our extension. We do this using an observer based on an event in our config.xml file. In this case I wanted it to trigger after an invoice was paid so I used the event  sales_orders_invoice_pay .

File: app/code/local/Cmallory/Lifx/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Cmallory_Lifx>
            <version>0.1</version>
        </Cmallory_Lifx>
    </modules>
    <global>
        <models>
            <lifx>
                <class>Cmallory_Lifx_Model</class>
            </lifx>
        </models>
        <helpers>
            <cmallory_lifx>
                <class>Cmallory_Lifx_Helper</class>
            </cmallory_lifx>
        </helpers>
        <events>
            <sales_order_invoice_pay>
                <observers>
                    <auto_invoice_order>
                        <type>singleton</type>
                        <class>Cmallory_Lifx_Model_Observer</class>
                        <method>sendSalesLight</method>
                    </auto_invoice_order>
                </observers>
            </sales_order_invoice_pay>
        </events>
    </global>
    <adminhtml>
        <acl>
            <resources>
                <admin>
                    <children>
                        <system>
                            <children>
                                <config>
                                    <children>
                                        <cmallory_lifx>
                                            <title>LIFX Notifications</title>
                                        </cmallory_lifx>
                                    </children>
                                </config>
                            </children>
                        </system>
                    </children>
                </admin>
            </resources>
        </acl>
    </adminhtml>
</config>

First we declare which extension it is for after the <modules> tag. Next we declare our model with the  <model> tag. The model will be what actually sends the code to the LIFX api. After that you have the  <helper> tag declaring our helper file so that we have admin panel configurable options for the extension, we will get to that later. Once the Model and Helpers are declared we’ll declare the event we want to trigger our extension with the  <event> tag. Below that we declare the observer with the  <class> tag and then our function within our Observer.php file using the  <method>. The  <adminhtml> section is so that you can allow access based on roles.

Now we will create the  observer.php file.

File: app/code/local/Cmallory/Lifx/Model/Observer.php

<?php
class Cmallory_Lifx_Model_Observer
{
  public function sendSalesLight(Varien_Event_Observer $observer)
  {
      // Get Order Information
      $invoice = $observer->getEvent()->getInvoice();
      $order = $invoice->getOrder();
      $orderNo = $order->getIncrementID();
      $subtotal = $order->getSubtotal();
      $reqSubtotal = Mage::getStoreConfig('cmallory_lifx/general/subtotal',Mage::app()->getStore());
      if ($subtotal > $reqSubtotal) {
          // Send request to LIFX API
          $link = "https://api.lifx.com/v1/lights/all/effects/breathe";
          $authToken = Mage::getStoreConfig('cmallory_lifx/general/api_token',Mage::app()->getStore());
          $headers = array('Authorization: Bearer ' . $authToken);
          $data = 'period=' . Mage::getStoreConfig('cmallory_lifx/general/period',Mage::app()->getStore()) . '&cycles=' . Mage::getStoreConfig('cmallory_lifx/general/flash',Mage::app()->getStore()) . '&color=' . Mage::getStoreConfig('cmallory_lifx/general/color',Mage::app()->getStore());
          $ch = curl_init($link);
          curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
          curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
          curl_setopt($ch, CURLOPT_POST, true);
          $response = curl_exec($ch);
          $error = curl_error($ch);
          // Log responses
          if (empty($error)){
            Mage::log("Order ID: " . print_r($orderNo, true), null, 'cmallory_lifx.log');
            Mage::log("Subtotal Amount: " . print_r($subtotal, true), null, 'cmallory_lifx.log');
            Mage::log("Notification Sent Successfully", null, 'cmallory_lifx.log');
          } else {
            Mage::log("Order ID: " . print_r($orderNo, true), null, 'cmallory_lifx.log');
            Mage::log("Subtotal Amount: " . print_r($subtotal, true), null, 'cmallory_lifx.log');
            Mage::log("Error Sending Notification: " . print_r($error, true), null, 'cmallory_lifx.log');
          }
          curl_close($ch);
      } else {
        Mage::log("Order ID: " . print_r($orderNo, true), null, 'cmallory_lifx.log');
        Mage::log("Subtotal Amount: " . print_r($subtotal, true), null, 'cmallory_lifx.log');
        Mage::log("Notification Not Sent: Subtotal below required value", null, 'cmallory_lifx.log');
      }
    }
  }

This file looks a little more in depth than the last ones we made but it’s still simple. At the top we grab the order information then make sure the order is over the designated amount based on a setting in the admin panel. Next the request is sent to the LIFX API with settings configured in the admin panel. Lastly we log the responses to a log file for debugging.

The last three files are created so that we can have configurable options in the admin panel. Without these two files magento will not pull any options into your extension.

File: app/code/local/Cmallory/Lifx/Helper/Data.php

<?php
class Cmallory_Lifx_Helper_Data extends Mage_Core_Helper_Abstract
{

}

You will notice that in the helper there is no code running. We are simply creating this helper because Magento requires it in order for the extension to have an admin panel section.

File: app/code/local/Cmallory/Lifx/etc/adminhtml.xml

<acl>
    <resources>
        <admin>
            <children>
                <system>
                    <children>
                        <config>
                            <children>
                                <cmallory_lifx>
                                    <title>LIFX Notifications</title>
                                </cmallory_lifx>
                            </children>
                        </config>
                    </children>
                </system>
            </children>
        </admin>
    </resources>
</acl>

This file is exactly the same as what is shown in the config file under the  <adminhtml> tag. The main part is declaring which extension this is for after the last  <children> tag.

Lastly, we create system.xml which creates a tab in System > Configuration and allows us to use user configurable options.

File: app/code/local/Cmallory/Lifx/etc/system.xml

<?xml version="1.0"?>
<config>
    <tabs>
        <cmallory translate="label" module="cmallory_lifx">
            <label>LIFX</label>
            <sort_order>50</sort_order>
        </cmallory>
    </tabs>
    <sections>
        <cmallory_lifx translate="label" module="cmallory_lifx">
            <class>separator-top</class>
            <label>LIFX Notifications</label>
            <tab>cmallory</tab>
            <sort_order>10</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <general translate="label">
                    <label>General Options</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>10</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>0</show_in_website>
                    <show_in_store>0</show_in_store>
                    <fields>
                        <api_token translate="label">
                            <label>API Token</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>20</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </api_token>
                        <subtotal translate="label">
                            <label>Order Subtotal</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>30</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                            <comment>Enter the value you would like the order to be over for the notification to be activated</comment>
                        </subtotal>
                        <color translate="label">
                            <label>Light Color</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>40</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                            <comment>Enter the color you would like the light to flash</comment>
                        </color>
                        <flash translate="label">
                            <label>Number of Flashes</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>50</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                            <comment>Enter how many times you would like the light to flash</comment>
                        </flash>
                        <period translate="label">
                            <label>Length of Flashes</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>60</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                            <comment>Enter how long in seconds each flash should light up</comment>
                        </period>
                    </fields>
                </general>
            </groups>
        </cmallory_lifx>
    </sections>
</config>

In the file above you’ll notice we define the tab using the <tab> tag. Here you create a new tab or create your own. I created my own. Next are the sections within the tab using the <section> tab. Next we have the <group> tag which will contain the configurable <fields> after clicking the section in the admin panel. This file coincides with the functions in  Observer.php that look like  Mage::getStoreConfig('cmallory_lifx/general/api_token',Mage::app()->getStore()).  In this function, cmallory_lifx defines the  <tabs> tag, general defines the  <groups> tag and api_token defines which  <field> tag to pull the data from.

From the system.xml you can see that you can configure your API token which can be found in your LIFX account, change the light color, define the number of times the light flashes, the duration for the flash of lights, and the minimum subtotal an order has to have for the notification to go off.

That’s it! Everything you need to make a Magento LIFX Extension.