Tuesday, December 27, 2011

Use existing Sqlite database in Android

Hello,

Since last few days, I have been working with android and I am very excited about it. This is my first blog on Android and many more is to come.

Normally Sqlite database is used with Android application. So this blog is about how you can use existing Sqlite database in Android application. First you need to add following table in your database. I recommend Sqlite  Expert Personal tool to make changes or create new Sqlite database. Open the database and run following query

"CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US')"

After that insert record in it.

"INSERT INTO "android_metadata" VALUES ('en_US')"

Once done add your database file in assets folder of your android application. You can do simple copy paste here.

Now we will create class which will have all database related functions and methods. We will use SQLiteOpenHelper class provided by Android framework to connect with Sqlite database. Following is the class definition.

public class DatabaseAdapter extends SQLiteOpenHelper {
         private static String dbPath= "data/data/com.YourPackageName/applicationDb/";
         private static String dbName = "YourDBName";
         private SQLiteDatabase applicationDatabase; 
         private final Context applicationContext;

       
         public VocabTesterDatabaseHelper(Context context) {
                 super(context,  dbName , null, 3);
                 this. applicationContext  = context;
         }


         private boolean checkDataBase(){
                 File dbFile = new File( dbPath +  dbName);
return dbFile.exists();
  }


          private void copyDataBase() throws IOException{
try {

                  InputStream input =  applicationContext .getAssets().open(dbName);
                           String outPutFileName=  dbPath  +  dbName ;
                     OutputStream output = new FileOutputStream( outPutFileName);
                      byte[] buffer = new byte[1024];
                  int length;
                  while ((length = input.read(buffer))>0){
                 output.write(buffer, 0, length);
                  }
                  output.flush();
                  output.close();
                  input.close();
       }
                       catch (IOException e) {
                    Log.v("error",e.toString());
                    }
   }


             public void openDataBase() throws SQLException{
                String fullDbPath= dbPath + dbName;
             applicationDatabase = SQLiteDatabase.openDatabase( fullDbPath,     null,SQLiteDatabase.OPEN_READONLY);
   }

                @Override
public synchronized void close() {
       if( applicationDatabase != null)
        applicationDatabase .close();
             super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}






}

That's it and your database helper class is ready. Initially we placed database in Assets folder and later on we moved it to particular folder in application. Still I am working on this class so I will add more functions to class and at the same time, I will upgrade this post. Stay tuned.

Thanks.




Tuesday, December 6, 2011

Case Study: Infusionsoft API Integration with Magento

Hello,

Here is another case study blog. My earlier case study blog was on ChannelAdvisor API  integration with Magento. You can read it here . Recently we were working on a Infusionsoft API integration with Magento.

What is Infusionsoft?

Infusionsoft helps small businesses in terms of marketing automationThey help small businesses to convert leads, grow sales and save time. They have CRMs which helps customer to centralize all their data at one location which can be easily accessible from anywhere. With their Email marketing customer can create emails which helps them in increasing sales and getting new clients. With their automation customer can create a system which can trigger behavior based communication, workflow  which helps them saving time and managing their sales and marking process.

Also they give nice set of REST APIs using which, it can be connected to ant third party applications and that was main requirement of our project.  Imagine the scenario that you have an Magento eCommerce site where you have thousands of customers registered and you are planning to use Infusionsoft as a primary service for your marketing.  In this case you need something between Magento and Infusionsoft  that can communicate user information.

We integrated Infusionsoft API with Magento registration. So that whenever a new user registers in Magento, their details automatically sent to Infusionsoft database using API. In case user updates information in Magento same  information is updated in Infusionsoft too. In case Admin deletes  user account, that particular user will be removed from Infustionsoft database  too.  This is the complete integration of Infusionsoft API with Magento.

This is very useful in case you have some user preferences in Magento database and based on that you want to send them marketing emails and in many other cases.

Friday, November 25, 2011

Get Google suggestions in Sencha Touch application

Recently I was working on a project where requirement was to bring Google suggestions to sencha touch app. Exact requirement was to build auto suggest search box with suggestions from Google search.

I tried to get it using Ajax Request but it was not working because it become cross domain request so I was getting error that "Access Denied".  After that I tried to get it using JsonStore using scriptTagProxy Check the code below.


var searchStore = new Ext.data.JsonStore({
                        fields: [],
                        root: 'items',
                        proxy:new Ext.data.ScriptTagProxy({
                           url: 'http://suggestqueries.google.com/complete/search?hl=en&ds=yt&client=youtube&hjson=t&cp=1&q='+search+'&key=&format=5&alt=json'
                         })
                    });

Here biggest issue is Google suggest returns JSON but not in key value pair. It just gives text of suggestions as follow. For example if we search for query we get following output.

["QUERY",["query","query in access 2007","query xl 2011","query gratis xl","query kartu tri 3","query optimization","query opmin 4 2 axis","query bolt browser simpati 2011","query telkomsel bolt handler","query in access 2010"],["","","","","","","","","",""]]

Now above data will not be loaded in store as we don't have any fields here. So how to access data. You have two options.

Override Ext.data.Connection method which is used in Ext.Ajax and add support for cross domain access.


Now above option seems bit difficult and time consuming.  I have another solution for it. Add load listeners to store.


searchStore.on({                     
                       load:function(store,records){                     
                          console.log(store.proxy.reader.jsonData);
                       }
                    });              
searchStore.load();


store.proxy.reader.jsonData, this will give you jsonData returned in response. You can use it to display suggestions the way you want.

Hope this helps you.

Important Note : I am not sure whether it's legal to use Google result in any application or not. But here the project mentioned was of the company, which is certified google application company. So please check the Google policy before using Google suggestions in your application.

Tuesday, November 15, 2011

Sencha touch 2 and MVC

Recently I switched to sencha touch 2 and I had to struggle little bit to implement MVC in it. So I am writing this blog post so that it will be useful for others.

Old way (sencha touch 1.0)


In sencha touch 1.0 we normally create object of viewport in application launch function as follow.


Ext.regApplication({
    name: "myApp",
    defaultTarget: "viewport",
    launch: function () {
        this.viewport = new myApp.Viewport({
            application: this
        });
    }
});

This will create an viewport object and render other items in viewport. So what is so different in sencha touch 2.0. It's totally different than it's older version. Following are the major changes.

1) Dynamic loading of scripts


Now you don't need to link all your JavaScript files in index file as it will be dynamically loaded from controllers. So you must set loader config in app.js file as follow.


Ext.Loader.setConfig({
enabled: true
});

2) Rendering viewport


Now you don't need to create viewport object explicitly in app launch function but it will be automatically created if you set autoCreateViewport to true in application definition. See the following code.


Ext.application({
    name: 'myApp',
    autoCreateViewport : true
});


If you set autoCreateViewport to true, app will try to load Viewport.js file from app/view/ folder. So you  must place a file there. This file will define your viewport. In this file you must specify a class which extends panel or container with fullscreen set to true.

Please remember you can extend Ext.viewport.Viewport or Ext.container.Viewport as it's singleton classes and can not extended. Whatever class you define here in Viewport.js file, it's object will be automatically instantiated and that control will be added to viewport. So here you only need to specify class with fullscreen set to true .Check the following code.

Ext.define('myApp.view.Viewport', {
    extend: 'Ext.Panel',

    requires: [
        'Ext.Panel'
    ],
    config: {
        fullscreen: true,
        layout: {
            type: 'card',
            align: 'stretch'
        },
        defaults: {
            flex: 1
        },
        items: [{
            xtype : 'panel',
            html : 'Welcome to Sencah Touch 2.0'
        }]
    }
}); 

Hope this will help you.




Tuesday, November 1, 2011

Synchronize ExtJs Grid vertical Scrollbar

Recently I was working on ExtJs project in which there were two grids side by side and requirement was to synchronize scrollbar of both grids. See the picture below.


If user moves vertical scrollbar of left grid right grid scrollbar should be moved automatically and vice versa.

So how to do that? Following is the trick. Suppose left grid object is leftGrid and right grid object is rightGrid variables.


var leftGridScroller = leftGrid.getVerticalScroller();
  leftGridScroller.on({
    'bodyscroll': function (event) {
       var rightGridScroller = rightGrid.getVerticalScroller();
       rightGridScroller.el.dom.scrollTop =  leftGridScroller.el.dom.scrollTop;
     }, scope: this
});

And Same way for right hand side grid.


var rightGridScroller = rightGrid.getVerticalScroller();
  rightGridScroller.on({
    'bodyscroll': function (event) {
       var leftGridScroller = leftGrid.getVerticalScroller();
       leftGridScroller.el.dom.scrollTop = rightGridScroller.el.dom.scrollTop;
     }, scope: this
});


This code will work only when you have scroller visible. Else getVerticalScroller will return undefined. So ypu must check for it if you are not sure about number of records in grid.

Same way one can synchronize horizontal scrollbar using above code. Only thing need to change is, you have to use getHorizontalScroller function instead of getVerticalScroller. For horizontal scroller property is scrollLeft.

Same trick can be applied to ExtJs panel scrollbar. Here you can get object of scrollbar using docekdItems if you are using ExtJs version 4.x.x. Please not that thise example is of ExtJs 4.0.2a.

Tuesday, October 18, 2011

Convert JavaScript object to Associative Array

Hello,

This is small post about converting JavaScript object to  associative array. Recently I was working on a project where I need to iterate through dynamic object. In short I have to create enumeration  for a dynamic object.  Object was dynamic so that all the properties of object were unknown. Following is the function to convert a JavaScript object to JavaScript associative array.

function toArray(_Object){
       var _Array = new Array();
       for(var name in _Object){
               _Array[name] = _Object[name];
       }
       return _Array;
}

So if you have any JavaScript object that can be converted to associative array using above function. New array will have all the object properties as keys and it's values as values and same way we can convert JavaScript associative array can be converted to JavaScript object.

function toObject(_Array){
       var _Object = new Object();
       for(var key in _Array){
              _Object[key] = _Array[key];
       }
       return _Object;
}

Above function will convert JavaScript associative array to Object. New object will have all keys in arrays as property and it's values as values of property.

Hope this will be helpful for you.

Saturday, October 1, 2011

Select Item in sencha touch list on load

Hello,

Recently I was working on Sencha Touch application. Requirement was to populate list and select a specific item which was selected by user earlier.

Following is the trick to do it.


myList.on('refresh', function(){
       var recordIndex = myList.store.find('field', 'value');
       myList.select(recordIndex,true,false);  
});


myList.store.find returns the index of record that matches the filters and it will be first match of record. So if you have multiple records with same value in field this will not be useful for you. You must need some unique value.

myList.select will select record in specific index. Second argument is to keep existing selection. In case of multiselect list this will preserve last selection and. Third argument is to suppress the slectionChange event. Sometimes you might have disclosure set on list. So might want to suppress the selection change.

Here select function also accept record or records instead of index. If you have record which were selected earlier, you can directly pass those records in select function as follow.

myList.select(records,true,false);

This is how you can select and item in sencha touch list.

Saturday, September 24, 2011

Case Study: Connect Magento with ChannelAdvisor

Hello,

This blog is again on different topic. It will not have single line of code. It's a case study on Synchronizing magento with leading eCommerce platforms.

Magento is very popular eCommerce platform widely used across the globe. eBay is acquiring magento and magento framework will be core part of eBay soon. eBay, Magento and Paypal are going to launch new eCommerce platform called xCommerce.

Sometimes it would be difficult to manage everything for those who sell their stuff online and using Magento and other sites like eBay and Amaozn. Because you have magento orders in magento admin. You can view eBay orders in eBay seller account and same way for Amazon orders. So seller have to process all the orders at different place. Same way it would be difficult to manage inventory.

To resolve this problems, magento should be synchronized with other platforms so that all the process like inventory management and order processing can be done at one place. Since last few months, I am working Magento synchronization with those platforms and I would like to share that experience here as a case study.

So this blog is about ChannelAdvisor

ChannelAdvisor provides you multiple channel for eBay and Amazon. ChannelAdvisor provides set of API to access ChhanelAdvisor account from outside. Those API can be used  synchronize it with Magento.

Inventory API

Inventory API is used to manage inventory. It gives various functions like

-Add item
-Delete item
-Update item
-Set quantity
-Set price and much more.

And it provides ability to send set of attributes for products so that all the magento attributes can be sent to CA. So basically on magento we need to set a cron job which runs every specified time interval and send updates in inventory to CA.

Order API


It gives an order api using which we can retrieve order details and using those details we can insert those orders in magento via code and process them in admin. You can retrieve orders based on specific date range. Also various filters can be applied like get all the pending orders, get all unshipped orders etc. We can control detail level of information. If you want all the information about order or only selected information, this can be controlled in API. Same way one can control number of orders returned by API. If you specify 100 orders, it will return information about 100 orders in one API call. It also gives you full details about customer, so that can be used in Magento to create customer and assign that order to him. Orders can be synchronized by setting a cron job in magento which runs on specified time interval and fetch those orders and create them in Magento.

Also after processing orders tracking information can be sent back to ChannelAdvisor using order API.

This makes complete integration of CA with Magento.

I hope this post helps you and if you are looking for such solution let me know.

Thanks,

Tuesday, September 6, 2011

Sencha touch charts remove decimal values on axes

Hello,

If you have used sencha touch charts, you might have faced this issue. If you set minimum and maximum to chart axes, you might have decimal values in numeric axes. See the image below.


This occurs if you specify maximum and minimum on axes. See the code below.



minimum: 0,
maximum: 100,
majorTickSteps :5,
minorTickSteps :5

Here minimum defines minimum allowed value and maximum defines maximum allowed value on axes. Axes will not have value more than maximum. majorTickSteps defines number of steps on axes for example if you specify minimum to 0 and maximum to 100, 0 to 100 are divided in equal five steps according to axes data.

So if you have data in store which can not be distributed equally on axes. It will display decimal values with 10 decimal points. This is annoying when you are crating an application like dashboard and you are displaying more than one charts at a time in panel.

To overcome this problem, override Ext.chart.axis.Axis class method drawAxis as follow.


Ext.override(Ext.chart.axis.Axis, {
    drawAxis: function (init) {
    }
});

Search code of this function in touch-charts-debug.js and paste the same code here and do the following modifications.

Search for the following line in code

me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(10));

Change parameter in toFixed function to 0

me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(0));

That's it and you will have integer values in charts.



Sunday, September 4, 2011

Sencha Touch Working with Models, Proxies, Stores

Data package is the important core part of sencha touch 1.x package. It enables application to persist data through application using models and proxies.

Model defines your business entity and proxy allows you to create CRUD (create, read, update, delete) functions for the models. Model is assigned to store. Here in this blog I am going to explain how to use models and proxy with store.

First define a proxy.


Ext.data.ProxyMgr.registerType("myProxy",
    Ext.extend(Ext.data.Proxy, {
        create: function (operation, callback, scope) {
             //Here goes your create logic
        },
        read: function (operation, callback, scope) {
             //Here goes your read logic
        },
        update: function (operation, callback, scope) {
             //Here goes your update logic
        },
        destroy: function (operation, callback, scope) {
             //Here goes your delete logic
        }
    })
);

This will create a new proxy with a name my proxy. Now create a model and assign proxy to it.


Ext.regModel('myModel', {
    fields: [
        {name : 'field1' , type : 'int'},
        {name : 'field2' , type : 'datetime'},
        {name : 'field3' , type : 'string'}    ],
    proxy: {
        type: "myProxy"
    }
});


Now assign model to a store.

var myStore= new Ext.data.Store({
    model: 'myModel'
});


Now to call the read function of proxy you can call store load method.

myStore.load()

To call create function of proxy you can add new item in store and call sync method.

var newModel = Ext.ModelMgr.create({ 'field1': value1,
            'field2': value2,
            'field3': value3
        }, 'myModel');

myStore.add(newModel);

myStore.sync();

To call update function of proxy you can update item in store as follow.

var updateModel = Ext.ModelMgr.create({ 'field1': value1,
            'field2': value2,
            'field3': value3
        }, 'myModel');

myStore.update(updateModel);

To call destroy method you have to explicitly call proxy destroy function since destroy method is not yet implemented for the store as follow.

var deleteModel= Ext.ModelMgr.create({ 'field1': value1,
            'field2': value2,
            'field3': value3
        }, 'myModel');

deleteModel.getProxy().destroy(new Ext.data.Operation({ action: 'destroy',records:deleteModel.data}));

Saturday, August 6, 2011

Sencha Touch offline store

Hello,

This is my first blog post on Sencha Touch. Recently I tried sencha touch and I built an application which can work offline once loaded in browser. Here I will explain how can you get your data offline in sencha touch.

First of all define an offline store with following configuration.


myApp.stores.offlineWordStore = new Ext.data.JsonStore({
    model: 'myModel',
    proxy: {
        type: 'localstorage',
        id: 'myStore'
    }
});

Here is important thing is proxy configuration. It's defined with the type localstorage. When you define proxy with local storage it will use HTML 5 local storage to store data.

Now define your online store as follow.


myApp.stores.onlineWordStore = new Ext.data.Store({
    model: 'myModel',
    proxy: {      
        url: 'http://www.example.com',
        reader: {
            type: 'json',
            root: 'wordset'
        }
    },
    listeners: {
        load: function () {
            Ext.dispatch({
                controller: myApp.controllers.general,
                action: 'setOfflineStore',
                data : this
            });
        }
    }
});

Carefully check load listener, I am calling a function of a controller where I will add all the data of online store to offline store. This is necessary because offline store can not load data directly with configuration like url. Following is the function in controller.


setOfflineStore: function (options) {
        var store = options.data;
        myApp.stores.offlineWordStore.proxy.clear();
       myApp.stores.offlineWordStore.removeAll();
        store.each(function (record) {
                var word = myApp.stores.offlineWordStore.add(record.data)[0];
        });

        myApp.stores.offlineWordStore.sync();
}

That's it and your offline store is ready to work. Now you have to load online store and it will populate data inside offline store.

myApp.stores.onlineWordStore.load();


Friday, July 29, 2011

ExtJs 4 MVC get reference of views

In old version of ExtJs how do we get reference of any component? Either we use control.getComponent() method or we use Ext.getCmp('controlID') method. This will give you an instance of particular component. So how do we get instance of views in ExtJs 4 MVC?

it has something called refs. You can add reference to any views in any controller.


refs: [
        {
            ref : 'myGrid',
            selector: 'myGrid'
        }
]


Here selector is the type of the component. This use can set with alias for views. For Example.


Ext.define('myApp.myGrid', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.myGrid',

    initComponent: function () {   
        this.callParent(arguments);
    }
});


ExtJs MVC has something called component query. This will be used to get reference of particular type of component.

ref  creates a function with name specified there and you can use that function to get reference of that particular component.

You will get reference of myGrid by following code inside controller.

var myGrid = this.getMyGrid();

Remember here that it will not create new instance of grid. It will give a reference to an existing instance. If no instance is available it will return null. To know how to create an instance of view check out my earlier blog here.


Tuesday, July 26, 2011

ExtJs 4.0.2 - Print Grid

Recently I tried ExtJs 4.0.2a. Here I am going to share a trick to print ExtJs grid. Concept is to open a new window. Render grid inside window and print grid.

Add a button in toolbar of grid panel. Call it a print button. Set handler for the button and add following code in handler. First of all open a new window.

var printDialog = window.open('', 'PrintPortfolioGrid');

Add some basic HTML to newly open a window. Most important thing is to add link to ExtJS core files and CSS so we can properly render grid.

var html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
            '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' +         
            '<html>' +
            '<head>' +
            '<title>Print Portfolio Grid</title>' +
            '<ink rel="stylesheet" type="text/css" href="ext-4.0.2a/resources/css/ext-all.css" />' +
            '<link rel="stylesheet" type="text/css" href="styles/Triskell.css" />' +
            '<script type="text/javascript" src="ext-4.0.2a/ext-debug.js"></script>' +
            '</head>' +
            '<body></body>' +
            '</html>';

printDialog.focus();
printDialog.document.write(html);
printDialog.document.close();

Now add some events to initialize document and Ext so that we can render grid.

printDialog.onload = function () {
            printDialog.Ext.onReady(function () {
                printDialog.Ext.create('Ext.grid.Panel', {
                    store: printDialog.Ext.create('Ext.data.Store', {
                        fields: ['Name','Cost'],
                        data: [
                                { Name: 'IT Portfolio, Cost: '1500$'},
                                { Name: 'Product Portfolio', Cost: '2500$'},
                                { Name: 'Asset Portfolio', Cost: '4500$'},
                                { Name: 'NPD Portfolio', Cost: '3500$'},
                            ]
                    }),
                    renderTo: printDialog.Ext.getBody(),
                    columns: [
                                   { header: 'Name', dataIndex: 'Name', flex: 1 },
                                   { header: 'Cost', dataIndex: 'Cost', flex: 1 }
                                  ],
                    width: 723,
                    height: 500
                });
                printDialog.print();                
            });
        }

That's it and it will open a print dialog.Select a required printer and it will print your grid.



Friday, July 22, 2011

ExtJs MVC- Dynamically Load Views

Hello,

Recently I tried ExtJs 4.0.2a and MVC application architecture and I must say that's an awesome improvement. Using MVC you have so much of flexibility. Now you can organize your whole application in proper structure that can be easily maintained and updated. It's really powerful feature available in ExtJs 4.0. You can get more details about this from this link. The MVC Architecture

They have explained a straight forward application with a grid with CRUD operations. What I will explain is dynamically loading views. Please read above article before further reading this post.

I was having requirement to dynamically load different views on all the the use actions. For example I have following four views for my content panel.

app/view/content/UsersGrid.js
app/view/content/ProjectsGrid.js
app/view/content/PremimumUsersGrid.js
app/view/content/PortfolioGrid.js

and let's say I have assigned following aliases to all of the above views.

UsersGrid => 'UsersGrid'
ProjectsGrid => 'ProjectsGrid'
PremimumUsersGrid => 'PremimumUsersGrid'
PortfolioGrid => 'PortfolioGrid'

I have a content panel in my view port and in which above views would be loaded dynamically. I can add reference of ContentPanel in my content controller to get the instance of it dynamically.


refs: [
        {
            ref :  'contentPanel',
            selector: 'ContentPanel'
        }
]

refs is the new way in MVC to get the reference of the the control. Above code will create a function getContentPanel() dynamically and I can use it to get reference of Content Panel. Here ref property specify name of function. Selector specify xtype of control. This xtype can be set using alias as follow.

alias : 'widget.ContentPanel'

Now consider I have a button. On click of button I want to load UsersGrid. Following will be code to load content panel and creating and adding view dynamically.

var contentPanel = this.getContentPanel();
contentPanel .removeAll(); //removing existing views.

var usersGrid = Ext.create('MyApp.view.Content.UsersGrid');

contentPanel.add(usersGrid);
contentPanel.doLayout();

Same way you can load other views as well.

Saturday, July 16, 2011

How to create and use templates in PHP

Hello,

This blog is for freshers in PHP.

First of all why Templates?


Templates are for reusable piece of code.  Consider an example. You have to send mail on some events and all the events are being invoked on different pages. However mail content is always same only some values are changed like sender name and sender signature etc. So instead of building message body every time you build a reusable templates that can be used by simply replacing some values in it. Another advantage of templates is you just need to change only templates and changes are visible at every place where template is used. Email template is just an example you can also build dynamic websites using templates. Here in this blog I will give example of email templates. So let's start our example.

First of all create an HTML file for your mail message with following syntax.

<div style="width: 800px;">

<span>Hello </span><span>%%client_full_name%%</span><br />
<span>%%email_introduction_text%%</span><br />

<b> Thank you for your query, we will get back to you soon</b>

<span>%%sales_rep_name%%</span><br />
<span>%%sale_rep_phone_num%%</span><br />
</div>

If you carefully check above HTML all the variables enclosed in %% %% are the variables which will be replaced by values dynamically when you use mail template. Following is the code for it.

First of all build an array with all the variable names as a key and with their values.


$variablesArray=array(
   '%%client_full_name%%'=>$clientName,
   '%%email_introduction_text%%'=>$emailIntroductionText,
   '%%sales_rep_name%%'=>$salesRepName,
   '%%sale_rep_phone_num%%'=>$sale_rep_phone
   );

Now read the mail template file and replace all the variables with respective values.

$myFile = "mail_template.html";

$fh = fopen($myFile, 'r');
$body = fread($fh, filesize($myFile));
fclose($fh);
       
foreach($variablesArray as $variable=>$value)
{
         $body=str_replace($variable,$value,$body);
}

That's it $body will have all the values replaced now and you can use this while sending mail. This way you can also build dynamic website also.

Hope this post helps you.

Tuesday, June 28, 2011

Replicate Category Tree from one Magento to Other Magento (Import category in Magento)

Recently I was working on Magento migration where I have to migrate magento shop from one server to other and create an identical shop on other server. Here time was the concern. So instead of creating categories manually I decided to create to replicate whole category tree with same category ids on other server. As next turn was to import product and keep in the same category. I used Magento API to get category tree from old Magento and traversed through it to create categories in new Magento. Check the following code.

I used recursive function to traverse the whole tree.


$flag = 1;
$client=new SoapClient('http://www.oldmagentodomain.com/api/soap/?wsdl');
$sessionId = $client->login('myAPIUserName','myApiKey');

$categoryTree= $client->call($sessionId, 'category.tree');

$currentCategory = $categoryTree['children'];


importCategory($currentCategory,$client); //This starts the import.



function importCategory($currentCategory,$client)
{

      $count= count($currentCategory);
      for($i=0; $i<$count; $i++)
      {
           $categoryId = $currentCategory[$i]['category_id'];
           $categoryInfo = $client->call($sessionId, 'category.info',$id);
   
           if($flag == 1)
           {
               $rootParentCategory = 1;
               $flag = 0;
           }
           else
           {
                $rootCategory = $categoryInfo ['parent_id'];
           }

                             
           $newCategory = new Mage_Catalog_Model_Category();                      
           $newCategory ->setName($categoryInfo ['name']);
           $newCategory ->setUrlKey($categoryInfo ['url_key']);
           $newCategory ->setLevel($categoryInfo ['level']);
           $newCategory ->setIsActive($categoryInfo ['is_active']);
           $newCategory ->setIsAnchor($categoryInfo ['is_anchor']);
           $newCategory ->setId($categoryInfo ['category_id']);

                               
           $parentCategory = Mage::getModel('catalog/category')->load($rootCategory);
           if($parentCategory)
           {
                $newCategory ->setPath($parentCategory->getPath()."/");                              
           }
            else
           {      
                 $newCategory ->setPath('');                                
            }

           $newCategory ->save(); 

           $childCategories = $currentCategory[$i]['children'];

           if($childCategories)
           {
               importCategory($childCategories,$client);
           }



     }
}

I hope this will help you. Now next post would be about importing products via Magento API. Stay tuned.

Thanks.

Saturday, June 25, 2011

Small Tips for ExtJs Programming

Hello,

Here I am sharing some tips that would be useful for you while working with ExtJs. These tips are about issues I faced while working on ExtJs projects.

1) Get-Set ExtJs Panel HTML

I don't know how many of you faced this issue. While working on one project, requirement was to set panel HTML dynamically. If you check Panel class there is not any method like getHtml() setHtml(). Following is the solution for it.

var dynamicHtml = '<div> This is dynamic HTML</div>';
myPanelObj.body.dom.innerHTML = dynamicHtml;

This will set panel HTML. Same way you can get panel HTML using myPanelObj.body.dom.innerHTML.

2) ExtJs Window me.Events are undefined error

If you are extending ExtJs window and on creating object of extended control, if you get above error then you forgot to call base class constructor. Call the base class constructor using following code.

ExtendedWindowObject.superclass.constructor.call(this, config);

3) Set padding while using ExtJs panel table layout.

When you use table layout in ExtJs panel layout. All the controls are arranged in a table. Sometimes it does not look good if you don't give padding to it. It looks very clumsy. So to give padding give id to panel and create a class in CSS with name of that id. See the example below.


#myPanelObj td{
    padding:5px;
},

4) Use renderer to format data in ExtJs grid cell.

If you want to format your data in grid cell use renderer. For example if you are displaying currency in ExtJs grid and you want to append $ sign to it. 

renderer: function(value, cell, record, rowIndex, colIndex, store)
{
          return value + '$';
}

5) Dynamically add event to ExtJs controls. 

Sometimes it may happen that you have to sue some ExtJs controls and you are not allowed to change the control and you need to add some listeners. Following is the code to add listeners dynamically.

myExtJsObj.on('hide',function(){ 
//function body.
});

6) Add Panel Click event

ExtJs panel does not support click event directly. However using following code you can make clickable panel.

listeners: {
                    render: function(p) {                                                                            
                                          p.getEl().on('click', handleProductPanelClick.createDelegate(null, p, true,this.id));
                     }
}

7) Another use of renderer to give style.

You can also use renderer  to give some styles to cells.

renderer: function(value, metaData, r) { 
                  metaData.attr = ' style="color:red;" ';
                  return value;
}

This will assign red color to cell.

That's it for now. I will update this post whenever I will have some more tips.

Monday, June 20, 2011

ExtJs Grid Paging - Go To Last Page After Inserting New Record

Hello,

Recently I was working on a ExtJs editor grid where user can enter new row by pressing button in the top toolbar. A row is inserted at bottom of grid and user can insert data in row. When user tab out or click on Save, the data goes to database and grid store reloaded. See the image below.


Now here is the issue. Consider grid page size as 25 and number of records are 35 and you are on page 1. That means you are viewing record 1 to 25. Now when you insert the row and when grid is refreshed, newly inserted record is in page 2 and you are still on page 1 so sometimes user feels that data is not inserted. So how to overcome this. I will describe solution that I have used. There may be other better solution. If you have any suggestion please add a comment.

First you need to add afteredit event in you grid. See the code below.


listeners:{
            afteredit:function(e){                       
                         Ext.Ajax.request({
                                    url : 'http://www.example.com/insertData.php',
                                    method:'GET',
                                    params:{                                 
                                        id : e.record.id,
                                        value : e.value
                                    },
                                    success:function(resp,opt){                                     
                                    },
                                    failure:function(resp,opt){
                                       
                                    }
                                });
             }
}


When you tab out of editor or Click on Save this event will be fired and it will send data to database using ajax request. Now we all know that for paging in MySql we have to use start and limit. For example.

select * from myTable limit 0,25

Above query will give first 25 records. to fetch next page use following query

select * from myTable limit 25,25

here first 25 indicates first row number of second page. So my trick was to return first row index of last page of table in which new record is inserted. Check the following code.


$start = 25;
$result = $start;


$output[ 'success' ] = true;
$output[ 'result' ] = $result; 
echo json_encode($output);

Above code will return JSON data back to browser. Now use that to reload the store. Following code will come in Success methods of Ajax Request mentioned in above code.


var returnValue= eval('(' + resp.responseText + ')');                                  
var start = returnValue.result;
if(start){
              myGrid.store.baseParams.start = start;                                      
}
myGrid.getView().refresh();
myGrid.store.reload();

ExtJs grid store uses start and limit parameter along with paging toolbar. So trick was to set start in base parameters of grid store and reload the grid. This will lead you to the last page in grid after inserting new record so user can see newly added record.


Saturday, June 11, 2011

ExtJs Dynamic Script Loading

Hello,

When we are working with ExtJs or other JavaScript framework, we regularly face problem of dynamic script loading. If you have may JavaScript files and you don't want to load all the files at the same time. Sometimes on particular user action we want to load JavaScript files.  When you are working in multilingual sites, you want to load only user selected language file. (How to build multilingual site using JavaScript? Refer to my earlier post for it click here )

So how to load JavaScript files as per  demand? We can use ScriptLoader for that. This is a component, which you can use in any of your web application. You just need to attach component JavaScript file to your app and then you can use it.

You can check this file on Google code. Download the ScriptLoader

Download this file and attach it to your web app.

<script type="text/javascript" src="ScriptLoader.js"/>

When this file is loaded it will create object of ScriptLoader.  Check the last line if JS file.

Ext.ux.ScriptMgr = new Ext.ux.ScriptLoaderMgr();

Now you can use above object to download any JavaScript file you want.

Ext.ux.ScriptMgr.ScriptMgr.load({
                             scripts : [
                                             'ExampleFile1.js',
                                             'ExampleFile2.js',
                                             'ExampleFile3.js'
                                         ],
                             callback : function() {
                                                     
                                            }
});

You can give any number of files you want in array. Callback function will be invloked when all the files are downloaded successfully. Remember that this is an asynchronous process, hence callback function is necessary if you want to trigger some events on successful download.

ScriptLoder can be used to dynamically load CSS files as well.

Saturday, June 4, 2011

Update Completed Order Details in Magento

Hello,

Recently I faced a very tough challenge because of stupid mistake made by one of my team member. We were importing orders in Magento through custom script. While importing orders, one supposed to add parent configurable product and a product option. Instead of that he added all the child products and because of that all the orders and its invoices were created with zero price. It was very frustrating situation for me as total number of such orders were around 1,35,0000. So I have to update all those orders. After spending almost a day I came up with a solution and created a PHP script to load that order and update it's details. Following it the code. I will explain all the code segments one by one.


$transaction = Mage::getModel('core/resource_transaction');
$order = Mage::getModel("sales/order")->loadByIncrementId(1000000);
$subTotal = 0.000;
$date=$order->created_at;
$order_id=$order->getId();
 
$arr_sku=array();
$arr_price=array();
$arr_par_sku=array();
$arr_qty=array();


Above code will load an order specified by increment id and get the order created date as we need that date to update some table entries to change data in invoice. Also above array variables are used to hold product prices and skus. Later we need that to change some table entries.


foreach ($order->getItemsCollection() as $orderItem) {    
       
        $sku = $orderItem->getSku();
        $qty = $orderItem->getQtyOrdered();
        $arr_qty[]=$qty;
        $original_sku = $sku;
        $arr_sku[]=$original_sku;
        $product = Mage::getModel('catalog/product');
        $newProd = Mage::getModel('catalog/product');
        $newProd = $newProd->load($newProd->getIdBySku($sku));
                           
        $parentIdArray = $newProd->loadParentProductIds()->getData('parent_product_ids');
       
        $parent_id=$parentIdArray[0];                                      
        $product = $product->load($parent_id);
     
        $attribute_value = "";
        $childProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null,$product);
        $par_sku=$product->getSku();
        $arr_par_sku[]=$par_sku;
        $price = $product->getPrice();
        $arr_price[]=$price;
        foreach($childProducts as $childProduct)
        {
            if($childProduct->sku == $original_sku){
                $attribute_value = $childProduct->color;                              
                $attribute_text=$childProduct->getAttributeText('color');
             
               $attribute_data=array('info_buyRequest'=>array(
                                                'product'=>$childProduct->getId(),
                                                'super_attribute'=>array(
                                                                          '80'=>$attribute_value,
                                                                            )
                                                ),
                                        'attributes_info'=>array(
                                                               '0'=>array(
                                                                        'label'=>'Color',
                                                                        'value'=>$attribute_text
                                                                            )                                                                    
                                                                ),
                                         'simple_name'=>  $childProduct->getName(),
                                         'simple_sku'=>$childProduct->getSku(),
                                         'product_calculations' =>1,
                                         'shipment_type'=>0
                        );  
                     
                $orderItem->setProductOptions($attribute_data);
                $orderItem->setProductId($product->getId());
                $orderItem->setProductType('configurable');
                $orderItem->setQtyOrdered($qty);
                $orderItem->setName($product->getName());
                $orderItem->setSku($product->getSku());
                $orderItem->setPrice($product->getPrice());
                $orderItem->setBasePrice($product->getPrice());
                $orderItem->setOriginalPrice($product->getPrice());
                $orderItem->setRowTotal($product->getPrice());
                $orderItem->setBaseRowTotal($product->getPrice());              
                $subTotal += $product->getPrice();
                break;
            }
        } 
    }


Above code will get each order item which is child product in my case and it replaces that order item with parent product and product option which was color in my case.


$price2=$subTotal+6.95;
    $order->setSubtotal($subTotal)
            ->setBaseSubtotal($subTotal)
            ->setGrandTotal($subTotal)
            ->setBaseGrandTotal($subTotal);
    $transaction->addObject($order);
    $transaction->addCommitCallback(array($order, 'place'));
    $transaction->addCommitCallback(array($order, 'save'));
    $transaction->save();

Above code will save the order. Now if you open order in Magento admin panel. You can see product is changed but if you check order sub total, total paid etc, it will be still zero. Because Magento did not update it automatically. You have to explicitly update it from database. That I will explain you in other post.

I hope this post helps you if you face same situation like me. Do post you suggesstions in comments. Thanks

Saturday, May 7, 2011

Programmatically create order in Magento

Hello,

This is the toughest work I ever did in Magento. Since last few days I am working on Magento and Channel Advisor(CA) Integration.  The requirement was to fetch order from CA and process them in Magento. We were using Channel Advisor PHP API to fetch orders from CA.

CA order service API needs order criteria to fetch orders. Following is the order criteria we were passing.


$OrderCriteria = array(
'OrderCreationFilterBeginTimeGMT'=> $date1,
'OrderCreationFilterEndTimeGMT'=> $date2,
'StatusUpdateFilterBeginTimeGMT' => $date1,
'StatusUpdateFilterEndTimeGMT' => $date2,
'JoinDateFiltersWithOr' => true,
'DetailLevel' => 'Complete',
'ExportState' => 'NotExported',
'OrderStateFilter' => 'Active',
'PaymentStatusFilter' => 'Cleared',
'CheckoutStatusFilter'  => 'Completed',
'ShippingStatusFilter'  =>'Unshipped',
'PageNumberFilter'=>1,
'PageSize'=>20
);



$arrData = array(
        'accountID'=>$accountID,
        'orderCriteria'=>$OrderCriteria
);
$result=$client->GetOrderList($arrData);               
$results=$result->GetOrderListResult->ResultData;
$orders=$results->OrderResponseItem ;

It will return first 20 orders that match above criteria.

Now here is the tough job. We have to fetch all the order data and have to create order in Magento. Following is the code for it.


foreach($orders as $order)
{

$quote = Mage::getModel('sales/quote')
->setStoreId(Mage::app()
->getStore('default')->getId());
$customer = Mage::getModel('customer/customer')
->setWebsiteId(1)
->loadByEmail($order->BuyerEmailAddress);                  
                   
if(empty($customer)){
$quote->assignCustomer($customer);
}
else{
$quote->setCustomerEmail($order->BuyerEmailAddress);
}

$orderitems = $order->ShoppingCart->LineItemSKUList->OrderLineItemItem;


foreach($orderitems as $orderItem){
        $product = $newProd
                               ->load($newProd->getIdBySku($orderItem->SKU));

        $buyInfo = array(
         'qty' => $orderItem->Quantity
         );

         $quote->addProduct($product, new Varien_Object($buyInfo));                    

}


$region=$order->ShippingInfo->Region;
$regionid = GetRegionId($region);


$firstName = ($order->BillingInfo->FirstName != "")
? ($order->BillingInfo->FirstName)
:($order->ShippingInfo->FirstName);
if(empty($firstName)){
$firstName = "FirstName";  
}

$firstName = ($order->BillingInfo->FirstName != "") 
? ($order->BillingInfo->FirstName) 
:($order->ShippingInfo->FirstName);
if(empty($firstName)){
$firstName = "FirstName";    
}

$lastName = ($order->BillingInfo->LastName != "") 
? ($order->BillingInfo->LastName) 
: ($order->ShippingInfo->LastName);
if(empty($lastName)){
$lastName = "LastName";    
}
                    
$street = (($order->BillingInfo->AddressLine1 != "")
? ($order->BillingInfo->AddressLine1) 
: ($order->ShippingInfo->AddressLine1)).
(($order->BillingInfo->AddressLine2 != "") 
? ($order->BillingInfo->AddressLine2) 
: ($order->ShippingInfo->AddressLine2));

if(empty($street)){
$street = "Street";    
}
                    
$city = ($order->BillingInfo->City != "") 
? ($order->BillingInfo->City) 
: ($order->ShippingInfo->City);
if(empty($city)){
$city = "City";    
}
                    
$postCode = ($order->BillingInfo->PostalCode != "") 
? ($order->BillingInfo->PostalCode) 
: ($order->ShippingInfo->PostalCode);
if(empty($postCode)){
$postCode = "00000";    
}
                    
$telephone = ($order->BillingInfo->PhoneNumberDay != "") 
? ($order->BillingInfo->PhoneNumberDay) 
: ($order->ShippingInfo->PhoneNumberDay);

if(empty($telephone)){
$telephone = "00000";    
}
                    
$addressData = array(
'firstname' => $firstName,
'lastname' => $lastName,
'street' => $street,
'city' => $city,
'postcode' => $postCode,
'telephone' => $telephone,
'country_id' => $order->ShippingInfo->CountryCode,
'region_id' => $regionid
);

$billingAddress = $quote
                             ->getBillingAddress()
                             ->addData($addressData);

$firstName = ($order->ShippingInfo->FirstName != "") 
? ($order->ShippingInfo->FirstName) 
: ($order->BillingInfo->FirstName);
if(empty($firstName)){
$firstName = "FirstName";    
}
                    
$lastName = ($order->ShippingInfo->LastName != "") 
? ($order->ShippingInfo->LastName) 
: ($order->BillingInfo->LastName);
if(empty($lastName)){
$lastName = "LastName";    
}
                    
$street = (($order->ShippingInfo->AddressLine1 != "") 
? ($order->ShippingInfo->AddressLine1) 
: ($order->BillingInfo->AddressLine1)).
(($order->ShippingInfo->AddressLine2 != "") 
? ($order->ShippingInfo->AddressLine2) 
: ($order->BillingInfo->AddressLine2));                    
if(empty($street)){
$street = "Street";    
}
                    
$city = ($order->ShippingInfo->City != "") 
? ($order->ShippingInfo->City) 
: ($order->BillingInfo->City);
if(empty($city)){
$city = "City";    
}
                    
$postCode = ($order->ShippingInfo->PostalCode != "") 
? ($order->ShippingInfo->PostalCode) 
: ($order->BillingInfo->PostalCode);
if(empty($postCode)){
$postCode = "00000";    
}
                    
$telephone = ($order->ShippingInfo->PhoneNumberDay != "") 
? ($order->ShippingInfo->PhoneNumberDay) 
: ($order->BillingInfo->PhoneNumberDay);
if(empty($telephone)){
$telephone = "00000";    
}
                    
$addressData = array(
'firstname' => $firstName,
'lastname' => $lastName,
'street' => $street,
'city' => $city,
'postcode' => $postCode,
'telephone' => $telephone,
'country_id' => $order->ShippingInfo->CountryCode,
'region_id' => $regionid
);

$shippingAddress = $quote->getShippingAddress()->addData($addressData);
                    
$shippingAddress->setCollectShippingRates(true)
->collectShippingRates()
                        ->setShippingMethod('perproductshipping_ground')
                        ->setPaymentMethod('purchaseorder');
                        
$quote->getPayment()->importData(array(
'method' => 'purchaseorder',
'po_number' => $order->ClientOrderIdentifier));
         
$quote->collectTotals()->save();
                    
Mage::app()->getStore()->setConfig(Mage_Sales_Model_Order::XML_PATH_EMAIL_ENABLED, "0"); 
                    
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();




}

That's it and it will create new purchase order in magento. Limitations of above code are as follow.

1) It will only create purchase order
2) It will only be useful for simple products.

I hope this post helps you.

Thanks,