Friday, December 4, 2015

Android Check If App is in Foreground on Receiving GCM message

Recently in one of my project we got a requirement to do some tasks when there is a GCM message in the app. Basically the requirement was to forcefully show some screens when there is a PUSH message. So if app is in Foreground we shall directly go to screen and if app is not running and GCM is received, app should go to particular screen on start. In this blog I am going to explain how to do this.

Basically I have used ordered broadcast to achieve this. Here is step by step process.

First let's capture this when application is in foreground. First add a broadcast receiver in your activity.


BroadcastReceiver mBroadcastReceiver

Now initialize it in onCreate method of your activity.

mBroadcastReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            //Right here do what you want in your activity
        Log.v("message","got push on foreground");
            abortBroadcast();
        }
    };

Now register it in onResume method of your activity.

@Override
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter("com.your_package.GOT_PUSH");
        filter.setPriority(2);
        registerReceiver(mBroadcastReceiver, filter);
}

As you can see above we register intent with action. Now go to onMessage method of your GCMIntentService and add following code.

Intent responseIntent = new Intent("com.your_package.GOT_PUSH");
sendOrderedBroadcast(responseIntent, null);

As you can see above we are sending ordered broadcast in onMessage method. So whenever there is a PUSH message app onReceive method on receiver will be called in your activity and then you can do rest of the stuff.

Now let's see what to do when app is not running or is in background. We will define a receiver for that in our manifest file.

<receiver android:name=".BackgroundGCMBroadCastReceiver">
    <ntent-filter
        android:priority="1">
        <action
            android:name="com.your_package.GOT_PUSH" />
    </intent-filter>
</receiver>

Now add a class in your Project with name BackgroundGCMBroadCastReceiver which extends BroadcastReceiver.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import android.util.Log;

public class BackgroundGCMBroadCastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //In this receiver just send your notification
    Log.v("message","got push on background");
    }
}

That's it now you can do your logic in onReceive method. Do not forget to unRegister receiver in your onPause method of activity.

@Override
protected void onPause() {

super.onPause();
try {
unregisterReceiver(mBroadcastReceiver);
} catch (IllegalArgumentException ex) {

}
}

That's it. Hope this helps you.

Thursday, December 3, 2015

Magento - Multiple Actions for Single Coupon Code

Hello,

Recently in one of my project we had a requirements to supports multiple actions for single coupon code. For example if my my cart total is between 500 to 1000, the coupon should give flat 50 off discount and if total is more than 1000, coupon should give flat 100 off discount. But coupon code should be same.

We all know that magento only allows unique coupon code and each coupon will have only once action. So how to do this? I have explained it in this blog.  Please note that this solution needs changes in magento database. So only use it if you database very well.

So while looking to solve this issue. I found out that, in magento database there is a unique key defined for coupon code. So to solve this problem we have to remove that unique key.

So open your Magento database and run following SQL command.

ALTER TABLE salesrule_coupon DROP INDEX UNQ_SALESRULE_COUPON_CODE;

This will drop unique key index.

Now go back to magento admin panel and clear the cache and create two different shopping cart rules with different discounts and keep the coupon code same and it will work.

Hope this helps you.




Thursday, September 24, 2015

Laravel Global Variable for All Controller and Views

Hello,

Recently in one of my project we have an admin panel crated with Laravel. There was a requirement to setup global object that can be accessed in all controllers, views, models etc.  Basically it was logged in user object with additional information so we can access details of user in anywhere. Here in this blog I am going to explain how to do this.

First open app -> config -> filters.php file and add following code to it.

App::before(function($request)
{
    // Singleton (global) object
    App::singleton('app', function(){
        $app = new stdClass;
        if (Auth::check()) {
            // Put your User object in $app->user
            $app->user = Auth::User();
            $app->user_access = UserAccess::getAccess($app->user);
        }
        return $app;
    });
    $app = App::make('app');
    View::share('app', $app);
});


As you can see here we are setting filter to setup singleton object and checking if user is logged in or not. If he is logged in we are create global object with name app and setting user information there. Now you can access this in controller with following code. 

$app = App::make('app');
$user = $app->user;
$userAccess = $app->user_access;

And in view you can access in following way.

<div>Welcome {{$app->user->name}}</div>

Or you can use in if condition.

@if($app->user->access_level == "Admin")
@endif

Same way you can access it in model functions.

$app = App::make('app');
$user = $app->user;
$userAccess = $app->user_access;

Hope this helps you.

Wednesday, September 23, 2015

Upload File From Local Machine to Remote Server with SSH

Hello,

Recently while working on SSL on my Amazon EC 2 server I had to upload few certificates files from my local machine to EC 2 server. I had to spent some time to figure out this so thought of publishing blog on it so this may help others

First lets see how to upload file to remote server with permission on directory. We will use scp command for it. Following is the syntax.

$ scp /path/to/local/file sshuser@host:/path/to/remote/server

Once you run command it will prompt you for password. When you enter password it will upload file.

Now lets see what if you don't have password and have public or private key. Following is the command.

$ scp -i "yourkey" /path/to/local/file sshuser@host:/path/to/remote/server

If you have specified correct key it will upload your file.

Now here comes the real problem with EC 2. I was trying to upload crt file to system directory which was not allowed. So what you have to do is upload that file default ssh directory with following command

$ scp -i "yourkey" /path/to/local/file sshuser@host:filename

And then go to that directory. Usually in amazon EC 2. It's /home/ubntu directory. Then you can copy files from here using cp command with sudo.

I hope this helps you and dave your time.




Friday, September 18, 2015

Android Download and Save Image to Internal Memory

Hello,

Recently in one of my project. We have a requirement to download image from remote URL and save it to internal memory so every time image won't be downloaded but it will be displayed from internal memory.

First let's create a utility class and add static function to load and save image. Following is the UTIL class I used.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class Utils {
    public static void saveFile(Context context, Bitmap b, String picName){ 
    FileOutputStream fos; 
    try
        fos = context.openFileOutput(picName, Context.MODE_PRIVATE); 
        b.compress(Bitmap.CompressFormat.PNG, 100, fos); 
        fos.close(); 
    }  
    catch (FileNotFoundException e) { 
        Log.d("file", "file not found"); 
        e.printStackTrace(); 
    }  
    catch (IOException e) { 
        Log.d("file", "io exception"); 
        e.printStackTrace(); 
    } 

}
    
    public static Bitmap loadBitmap(Context context, String picName){ 
    Bitmap b = null
    FileInputStream fis; 
    try
        fis = context.openFileInput(picName); 
        b = BitmapFactory.decodeStream(fis); 
        fis.close(); 

    }  
    catch (FileNotFoundException e) { 
        Log.d("file", "file not found"); 
        e.printStackTrace(); 
    }  
    catch (IOException e) { 
        Log.d("file", "io exception"); 
        e.printStackTrace(); 
    }  
    return b; 
}

}

As you can see above it has two functions one is to save image and one is to load saved image. Now first we will check if if image is already saved or not.

ImageView imgView = new Image(getActivity());
Bitmap b = Utils.loadBitmap(getActivity(),"myImage.png");
if(b == null){
       new DownloadImageTask(imgView,"myImage.png").execute("http://remoteimagepath");
}else{
      imgView.setImageBitmap(b);
}

Now we have to add DownloadImageTask class as follow.

private class DownloadImageTask extends AsyncTask {
ImageView imageView = null;
        String name = "";
public DownloadImageTask(ImageView img, String name) {
this.imageView = img;
                this.name = name;
}

protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}

protected void onPostExecute(Bitmap result) {
Utils.saveFile(getActivity(),result, this.name);
this.imageView.setImageBitmap(result);
}
}

As you can see above in this class we are passing reference of imageView and when image is downloaded we setup bitmap to imageview and save image to local memory with name which we passed in parameter. 

Hope this helps you.

Monday, September 14, 2015

Amazon EC2 File Upload Permission

Hello,

Recently in one of my project we hosted our PHP website on Amazon EC 2 which was running Apache on ubuntu. In our project we have file upload functionality which was not working. First I tired to set permission to 777 for the upload directory but still it was not working, so I went into details and found out this was the user permission issue. In this blog I am going to explain how to solve this.

Your website is running in Apache on Ubuntu. So there is a apache user, which is actually handling file operations. By default apache user does not have write permission and it does not own your website folder. So there are three basic steps to resolve this issue.

1) Find out your apache user.

Fist we have to find out name of apache user. Run following command in terminal.


ps -ef | grep apache

Check the left most column of the output. See the image below. That is name of your apache user.

In my case it was www-data user. 

2) Change directory owner to Apache user.

Change owner of your upload directory.

sudo chown www-data /var/www/html/uploads

3) Setup permission on your directory.

sudo chmod 755 /var/www/html/uploads

That's it. Now you can upload file from your web application. Hope this helps you and save your time.





Saturday, September 12, 2015

How to Create a Horizontal Carousel View in Android (Using ViewPager)

Hello,

Recently in one of my project we have to create  Horizontal Carousel View for banner images. User can swipe left or right to view other banners and there will be bottom page indicators. See the below image of final output.


In this blog I am going to explain how to create horizontal carousel view. We are going to use Android ViewPager for this. First add following to layout XML.

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/viewpager"
    android:layout_width="fill_parent"
    android:layout_height="120dp" />
     
     <LinearLayout
     android:layout_width="fill_parent"
     android:id="@+id/pagination"
     android:layout_height="15dp"
     android:background="#443915"
     android:orientation="horizontal" 
     android:gravity="center">
    </LinearLayout>

In android view page we will have different fragments for each page so we will need layout XML for fragment. Add new XML file myfragment_layout.xml in your layout and add following code to it.

<?xml version="1.0" encoding="utf-8"?>
      <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY"

        android:id="@+id/imageView" />

Now let's create fragments for each images.

List fList = new ArrayList();
List bannerList = getAllBanners(); 
LinearLayout pagination = (LinearLayout)rootView.findViewById(R.id.pagination);

getAllBanners () is the function I used my code, you can replace it with your logic.
pagination is the linear layout we added in XML above.

Now first create a linear layout to hold all the indicators.

LinearLayout layout = new LinearLayout(getActivity());
layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));
layout.setOrientation(LinearLayout.HORIZONTAL);

for(int i=0;i
          fList.add(new MyFragment().newInstance(bannerList.get(i).getPicName()));
          ImageView imageView = new ImageView(getActivity());
          if(i == 0){
              imageView.setImageResource(R.drawable.activeindicators);
          }else{
              imageView.setImageResource(R.drawable.inactiveindicators);
          }
          imageView.setId(i);
          LayoutParams params =new LayoutParams(LayoutParams.WRAP_CONTENT,     LayoutParams.WRAP_CONTENT);
          imageView.setLayoutParams(params);
          layout.addView(imageView);
}

pagination.addView(layout);

As you can in above code we are adding indicators in pagination and adding fragments to fragment list. By default we are setting first indicator as active.

Now to create Fragment we have to add MyFragment class.

public class MyFragment extends Fragment {
    public static final String EXTRA_MESSAGE = "PICTURE";
    public final MyFragment newInstance(String picName){
      MyFragment f = new MyFragment();
      Bundle bdl = new Bundle(1);
      bdl.putString(EXTRA_MESSAGE, picName);
      f.setArguments(bdl);
      return f;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
      String picName = getArguments().getString(EXTRA_MESSAGE);
      View v = inflater.inflate(R.layout.myfragment_layout, container, false);
      ImageView messageTextView = (ImageView)v.findViewById(R.id.imageView);
      int id = getResources().getIdentifier("yourpackagename:drawable/" + picName, null, null);
      v.setImageResource(id);
      return v;
    }
}

Now lets's create Adapter for ViewPager. 

MyPageAdapter  pageAdapter = new MyPageAdapter(getActivity().getSupportFragmentManager(), fList);
ViewPager pager =(ViewPager)rootView.findViewById(R.id.viewpager);
pager.setAdapter(pageAdapter);

For that we have to create MyPageAdapter

class MyPageAdapter extends FragmentPagerAdapter {
      private List fragments;
      public MyPageAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
      }
      @Override 
      public Fragment getItem(int position) {
        return this.fragments.get(position);
      }
      @Override
      public int getCount() {
        return this.fragments.size();
      }
 }

This will create number of fragments as per your number. Now we have to add logic to change page indicators when user swipe left or right.

pager.setOnPageChangeListener(new OnPageChangeListener() {
  @Override
   public void onPageSelected(int position) {
   // TODO Auto-generated method stub
        for(int i=0 ;i<totalBannerCount;i++){
        ImageView img = (ImageView)rootView.findViewById(i);
        if(i== position){
            img.setImageResource(R.drawable.activeindicators);
        }else{
            img.setImageResource(R.drawable.inactiveindicators);
        }
    }
}
  @Override
   public void onPageScrolled(int arg0, float arg1, int arg2) {
      // TODO Auto-generated method stub
   }
   @Override
    public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub
    }
});

That's it and you have Horizontal Carousel View in Android. Hope this helps you.

Wednesday, September 9, 2015

Android How to Work With AutoCompleteTextView

Hello,

Recently in one of my project I have to create auto complete text view in android. In this blog I am going to explain how to work with it.

First you have to add AutoCompleteTextView in your layout XML file.

<AutoCompleteTextView  
        android:id="@+id/autoCompleteLocationTextView"  
        android:layout_width="fill_parent"  
        android:layout_height="60dp"  
        android:ems="10"  

        android:hint="Type to Search">

Then in your activity get reference of it.

AutoCompleteTextView  locationText = (AutoCompleteTextView)findViewById(R.id.autoCompleteLocationTextView);

Then set threshold for it.

locationText.setThreshold(1); 

Here we set threshold to 1 that means after typing first character it will show you matched suggestions. You can change it as per your requirement.

Then we have to set an adapter. Adapter is nothing but it's a collections of your suggestions.


String[] locationListArray = {
    "Ahmedabad",
    "Ahmednagar",
    "Agartala",
    "Mumbai",
    "Noida",
    "Kolkata"
}

ArrayAdapter adapter1 = new ArrayAdapter  
            (this,android.R.layout.select_dialog_item,locationListArray);

locationText.setAdapter(adapter1);

As you can see above we have loaded our collections in array and created adapter from it and assigned adapter to locationList. That's it now it will show you suggestions as soon as you start typing it.

If you want to get value of it on change. You can do following.

locationText.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView arg0, View arg1, int position,
                    long arg3) {
            String item = (String)arg0.getItemAtPosition(position);
});

Hope this helps you.

Introducing Tagsum - GPS Location Tagging

Hello,

This blog is about my company's product. After we introduced following two products.

Adsum
Tracksum

Here is our next product Tagsum - GPS Location Tagging. This app is helpful in tagging the required location with exact latitude and longitude.

This app is helpful in tagging the required location with exact latitude and longitude of the desired location. Very useful app for field survey in remote locations. You don't need special GPS devices to locate locations now. If you have smart phone just install this app and use it. It uses standard GPS services so you get very accurate locations. Locations added with this app can be downloaded in excel files later from admin panel.

Also in admin panel you can create routes with tagged location and can plot path on Google map with standard markings.

Also you can preload your locations in app and tag it with latitude and longitude from the application. So you can update your locations or add new locations.  This application can be used in various domains and fields like.

Field Survey
Geological Survey
Map building.
City Paths Creation etc..

Major benefit of our app is that you will get admin panel where you can maintain your app users, you can add/update/delete users, can see tagged locations, can create add new locations for tagging, can create paths. When you create path it will also calculate total kms for the path. This gives you much more flexibility. Your data will be confidential and only you can see that in admin panel.

So if you need this app please install app from Google Play Store. App is available from following link.

https://play.google.com/store/apps/details?id=com.tagsum.app&hl=en

And get back to us for admin panel access.


Monday, August 31, 2015

Install and Configure PHP/Apache on Amazon EC 2 with Ubuntu (With SFTP)

Hello,

Recently for one of my project we moved our web application to Amazon EC 2. So we had to configure Aapche and setup SFTP there. I faced some difficulties in setting this up so here in blog I am going to explain you the process so it will help you.

First of all login to SSH on your Amazon EC 2 instance. For that first you have to download public key from your amazon EC 2 instance.  You can use public IP of your EC 2 instance to login to SSH.

Open your terminal and type following command.

ssh -i "YourKey.pem" ubuntu@your_ip_address

once you are logged in first of we have to install apache. For that run following command.

First we will install apache with PHP 7 and configure it.

sudo apt-get install apache2 php7.0 libapache2-mod-php7.0
Now verify it


a2query -m php7.0
Load PHP module.


sudo a2enmod php7.0

Restart apache.


sudo service apache2 restart

New version of ubuntu comes with PHP 7 but to access it you have to install php command lines. Run following command.


sudo apt-get install php7.0-cli

Now test it with

php -v

This will install apache, php with single command. Once installation is done type public ip in browser and it should show apache startup page. If you see this page that means apache installed. Now lets test PHP.

Go to your apache root directory with following command

cd /var/www/html

There will be one index.html file. We have to remove this and create new file for testing.

sudo rm index.html

sudo vim index.php

This will open vim editor, press i and now you can type in file. Let's create simple php file

<?php
     echo "Hello AWS";
?>


press esc and : and type wq this will save file. Now again type public IP in browser and it should show Hello AWS on browser.

Now let's create new SFTP user. But for that first we have to allow password authentication for SSH. Type following command.

cd /etc/ssh
sudo vim sshd_config

Find allowPasswordAuthetnciation. It will be set as no, make it yes and save the file and restart SSH service.


sudo service ssh restart

Now we can add user with password.

sudo adduser --home /var/www/html username

It will ask for password. Now user is created with same group name. Now we have to make this user, owner of /var/www/html so we can edit files via FileZilla. Now lets fist change ownership of folders and files.

sudo chown -R root:username /var/www/html
sudo find /var/www/html -type f -exec chmod 664 {} \;
sudo find /var/www/html -type d -exec chmod 775 {} \;
sudo find /var/www/html -type d -exec chmod g+s {} \;

That's it now you can use this username and password with SFTP in FileZilla. Hope this helps you.


Thursday, August 27, 2015

Android Cordova 4.0.2 Webview Intercept Requests

Recently I was working on Android cordova app where I was using cordova 4.0.2 version. In this project I have to intercept urls loaded in webview and do some stuff.

In earlier cordova version we can do following.

myWebView.setWebViewClient(new WebViewClient() {
         public boolean shouldOverrideUrlLoading(WebView view, String url)  {
         }
});

But in newer version of cordova this will not work. So what to do? Here is this blog I am going to explain it.

First of all lets get webView


myWebView = (WebView) this.appView.getView();

Then add WebViewClient to webView.

myWebView.setWebViewClient(new SystemWebViewClient((SystemWebViewEngine) this.appView.getEngine()){
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
          }
          public void onPageFinished(WebView view, String url) {
                   super.onPageFinished(view, url);
          }
});

As you can see in cordova newer version they have added new class SystemWebViewClient in cordova lib that we have to use for accessing functions like shouldOverrideUrlLoading and onPageFinished.

Hope this helps you. 

Monday, August 24, 2015

PHP Parse SOAP XML Response

Recently in one of my project we were using SOAP service which was having XML response that we have to parse with PHP. For some reason PHP SOAP client was giving some because it XML response was using name namespaces and that was not parsed correctly with SOAP client. Here in this blog I am going to explain how to call XML web service without using SOAP client and parse response with PHP.

We will use PHP cURL. First lets create XML post data.

$postString = '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
<GetProducts xmlns="http://ws.sourcingcity.co.uk/">
  <query>pen</query>
  <username>username</username>
  <password>password</password>
  <pageindex>1</pageindex>
  <pagesize>20</pagesize>
</GetProducts>
  </soap:Body>
</soap:Envelope>';

So that's our post data. Now lets create cURL request.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://ws.sourcingcity.co.uk/ws3dpromo.asmx?op=GetProducts');
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                                            'Content-Type: text/xml; charset=utf-8',
                                            'Connection: Keep-Alive',
                                            'SOAPAction: http://ws.sourcingcity.co.uk/GetProducts'
                                            ));    
$result = curl_exec($ch);
curl_close($ch);

Now you will get XML response in $result which is in string format. We will use SimpleXML class of PHP.

$soap = simplexml_load_string($result);

That will load SimpleXML object. Now we will register namespace.

$soap->registerXPathNamespace('ns1', 'http://ws.sourcingcity.co.uk/');

Now you can use XPATH to go to specific nodes.

$productsResult = $soap->xpath('//ns1:GetProductsResponse/ns1:GetProductsResult')[0]->Products;

for($i=0;$iProduct);$i++){
$product = $productsResult->Product[$i];
echo "Product ".$i;
echo "Name : ".$product->Name;
echo "SCRef : ".$product->SCRef;
echo "Description : ".$product->Description;
echo "PriceRange : ".$product->PriceRange;
echo "ProductType : ".$product->ProductType;
echo "ProductGroups : ".$product->ProductGroups;
echo "Colours : ".$product->Colours;
echo "ThumbImageURL : ".$product->ThumbImageURL;
echo "LargeImageURL : ".$product->LargeImageURL;
}

That's it. In the same way you can parse any other XML response.

Wednesday, July 15, 2015

MAMP - Install MSSQL Extension

Recently in one of my project I was trying to connect to MS SQL server from PHP and it was showing error  "Call to undefined function mssql_connect()". That means you are missing MSSQL extension and you have to install it. In this blog I am going to explain how to do this.

First of all you will need FreeTds. FreeTds is the library for linux and unix to communicate with MS SQL server. You can download latest stable release from this link

ftp://ftp.freetds.org/pub/freetds/stable/freetds-patched.tar.gz

After downloading it, extract it and go to that directory in terminal and run following command.

$ sudo ./configure --prefix=/private/etc/freetds --with-tdsver=8.0 --sysconfdir=/private/etc/freetds/conf
$ sudo make
$ sudo make install

This will install FreeTds on your system. Now we have to compile MSSQL extension for your PHP version. For that first check which PHP version are you using in MAMP. That you can check in Server -> PHP tab


Check your version and download source code of that PHP version.


Extract it and go to this directory in terminal.

Now run following commands in terminal

$ ./configure --with-php-config=/usr/bin/php-config
$ make

Now go to MSSQL extension directory in PHP source code.

$ cd ext/mssql/
$ /usr/bin/phpize
$ ./configure --with-php-config=/usr/bin/php-config --with-mssql=/private/etc/freetds
$ make

Above command will generate MSSQL module so now go to module directory.

$ cd modules/

Now we have to copy this generated module to MAMP's current PHP extension directory. For that open the ini file of your PHP version. In my case I was using PHP 5.5.3 so my ini file was located at.

/Applications/MAMP/bin/php/php5.5.3/conf/php.ini

Open this file and search for "extension_dir" and you will find following line.

extension_dir = "/Applications/MAMP/bin/php/php5.5.3/lib/php/extensions/no-debug-non-zts-20121212/"

so this is your extension directory. We have to copy module here. So now go to terminal and run following command.

$ cp mssql.so /Applications/MAMP/bin/php/php5.5.3/lib/php/extensions/no-debug-non-zts-20121212/

This will copy mssql.so in your extensions directory. Now we have to add this extension in php.ini file.

Now in php.ini file find for the word "; Extensions" below that there are list of extensions. Add following line to the end of the list.

extension=mssql.so

Save the file. Restart your MAMP and run the phpinfo(). You must see following section there.


But wait it won't be there. That means there is something wrong. After wasting almost an hour I figure out that MAMP is actually using different ini file.  So we have to update that. For that go to 

/Applications/

Right click on your MAMP or MAMP Pro icon (if you are using MAMP Pro) and select "Show Package Contents" Now go to Contents/Resources  and open ini file of your PHP version. Now in that file find for the word "; Extensions" below that there are list of extensions. Add following line to the end of the list.

extension=mssql.so

Save the file. Restart your MAMP and run the phpinfo(). You must see following section there.


That's it and now you can connect to MSSQL server with following code.

$con = mssql_connect('MYSQLSERVER', 'username', 'password')
or die('could not connect to server.");

I hope this helps you and saves your time.

Saturday, July 4, 2015

Android ClassNotFound Exception

Today when I was working on my Android project, I ran into strange issue. When I start my app, it crashes with ClassNotFound exception. It was unable to found Main activity class.

I tried so many things like clean - rebuild, removing all the references and add them again, changing target APIs. But it was not working. App never started.

After doing failed attempt for almost half an hour, it came to my attention that src folder in project was a simple folder. There was no package sign on it and when I explore it, all my packages where turned into folders and sub folders and that was the issue. My src folder was not a sources folder and because of that it was unable to found a class.

So to solve this issue.  Right click on src folder Select Java Build Path - > Use as a source folder.

And that's it all the folders and sub folders in the src folder turned into packages and application was working fine. Hope this helps you and save your time.

Saturday, June 20, 2015

Magento Get All Products With Special Prices

Hello,

Recently in one of my projects we were working with Magento APIs. Where we have to fetch a list of all products with special prices to display hot deals on site. There are no APIs for this in Magento so I decided to write custom logic for that.

Here is how you can fetch it.

First get product collections.

$productCollection = Mage::getModel('catalog/product')->getCollection();
$productCollection->addAttributeToSelect(array(
        'image',
        'name',
        'price',
        'short_description'
 ))
 ->addFieldToFilter('visibility', array(
        Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
        Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG
 ));

Then apply filter on product collection to get products with only special prices.

$productCollection->addAttributeToFilter('special_from_date', array('date' => true, 'to' => $todayDate))
                        ->addAttributeToFilter('special_to_date', array('or'=> array(
                        0 => array('date' => true, 'from' => $tomorrowDate),
                        1 => array('is' => new Zend_Db_Expr('null')))
                        ), 'left');

That's it and now it will give you collections of only those products for which there is a special price set.

Now just loop through it and add to array.

$hotDeals = array();
foreach ($productCollection as $product){
        $product = Mage::getModel('catalog/product')->load($product->getId());
$name = $product->getName();
$productPrice = number_format($product->getPrice(), 2, '.', ',');
$specialPrice = number_format($product->getSpecialPrice(), 2, '.', ',');

        $hotDeals[] = array(
"product_id" => $product->getId(),
"product_name" => $name,
"product_image" =>  ($product['image'] == 'no_selection') ? $skinUrl.'frontend/default/default/images/catalog/product/placeholder/thumbnail.jpg' : (string)Mage::helper('catalog/image')->init($product, 'image')->resize(60),
"product_price" => $productPrice,
"special_price" => $specialPrice
);
}

And return it as JSON array.

$resultArray['success'] = true;
$resultArray['hot_deals'] = $hotDeals;

echo json_encode($resultArray);

Hope this helps you.

Friday, June 19, 2015

Magento Load Quote Generated By API on Frontend

Hello,

Recently in one of my project we were using magento to implement checkout process for third party website. Basically we were using Magento APIs to create quote. Now for the paypal payment we were redirecting users to magento url and start checkout process by redirecting them to paypal and on successful payment redirect back to magento site, place and order and redirect them back to their site. Now the problem is when we redirect user to magento site to start checkout process there is no customer or checkout session hence checkout can not be started as shopping cart was empty. In this blog I am going to explain how to load quote generated by API on frontend and start checkout process.

First of all let me explain why we have to this changes. Magento has its own session management on front end. It will not load cart of there is no checkout session found on front end. So we have to store everything in frontend session so magento can remember it.

First of all you have to pass three params when user is redirecting to magento site. Following are three params required.

customer_id
quote_id
store_id

As on front end we have to set specific store and create customer session with customer_id and load shopping cart. I was using following URL for redirection.

http://yourmagento/paypal/express/start/button/1/?customer_id=1&store_id=3&quote_id=146

As you can see above we are directly starting checkout process and redirecting user to paypal. But before that we have to set store and generate customer session and load quote. So lets go step by step. First of all open following file.


app/code/core/Mage/Core/Controller/Varien/Front.php

and find following function.

/**
     * Init Front Controller
     *
     * @return Mage_Core_Controller_Varien_Front
     */
    public function init()
    {
    }

This function is called first for any magento URL request. So here are going to do some initialization steps.

First let's set up the store for which quote id was generated. Add following code to start of init function.

$storeId = '';
//////////////////////////////////////Setting up store id///////////////////////////
if(isset($_REQUEST['store_id'])){
        $storeId = $_REQUEST['store_id'];
    Mage::getSingleton('core/session')->setStoreId($_REQUEST['store_id']); 
}

if( Mage::getSingleton('core/session')->getStoreId()){
$storeId = Mage::getSingleton('core/session')->getStoreId();
}
switch($storeId){
case "1" : Mage::app()->setCurrentStore('store1');break;
case "2" : Mage::app()->setCurrentStore('store2');break;
default: Mage::app()->setCurrentStore('store1');break;
}
//////////////////////////////////////////////////////////////////////////////////////


First we are checking if there is store id in request then first we are storing it to magento core session. Later we are getting it from session and storing respective store. Please note this is required if you have multiple stores, else you can avoid this. In my case there were multiple stores. 

Now next step is to create customer session. Add following code after above code.

////////////////////////////////////////Setting up customer id////////////////////////
if(isset($_REQUEST['customer_id'])){
Mage::getSingleton('core/session')->setCustomerId($_REQUEST['customer_id']); 
}
        
if( Mage::getSingleton('core/session')->getCustomerId()){
Mage::getSingleton('customer/session')->loginById(Mage::getSingleton('core/session')->getCustomerId());
}
//////////////////////////////////////////////////////////////////////////////////////

Now next step is to store quote id in session so it can be used later.

/////////////////////////////////////////Saving Quote Id//////////////////////////////
if(isset($_REQUEST['quote_id'])){
Mage::getSingleton('core/session')->setQuoteId($_REQUEST['quote_id']); 
}
//////////////////////////////////////////////////////////////////////////////////////

Now open following file.

/app/code/core/Mage/Checkout/Model/Session.php

And check following function.

/**
     * Get checkout quote instance by current session
     *
     * @return Mage_Sales_Model_Quote
     */
    public function getQuote()
    {
    }

Add below code to the function after following line.

Mage::dispatchEvent('custom_quote_process', array('checkout_session' => $this));

//////////////////////////////////////////Returning quote stored in session////////////////////////
if(Mage::getSingleton('core/session')->getQuoteId()){
    $this->_quote = Mage::getModel('sales/quote')->setStore(Mage::app()->getStore())->load(Mage::getSingleton('core/session')->getQuoteId());
return $this->_quote;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

That's it and now you can start checkout process with this quote. Hope this helps you. 

Thursday, June 18, 2015

Magento Cart Payment List API, Paypal Not Available

Hello,

Recently we were working on Magento API. Where we were implementing checkout process for a website using Magento platforms. Since we were integrating in third party website which was built on ASP.NET, we were using Magento API. Here we have faced an issue on Select Payment Method step, that Paypal was not coming in list. In this blog I am going to explain how to solve this issue.

Magento API cart_payment.list is the API we were using for this and Paypal was enabled but still were not getting it. The reason was because we were using Paypal Standard Checkout where user is redirected to Paypal website for Payment. Since API is called on backend and there is no UI for that, so there is no point of redirecting to site. Hence this Payment method was ignored in API. Check the following function in app/code/core/Mage/Checkout/Model/Cart/Payment/Api.php file.

/**
     * @param  $method
     * @param  $quote
     * @return bool
     */
    protected function _canUsePaymentMethod($method, $quote)
    {
        if (!($method->isGateway() || $method->canUseInternal())) {
            return false;
        }

        if (!$method->canUseForCountry($quote->getBillingAddress()->getCountry())) {
            return false;
        }

        if (!$method->canUseForCurrency(Mage::app()->getStore($quote->getStoreId())->getBaseCurrencyCode())) {
            return false;
        }

        /**
         * Checking for min/max order total for assigned payment method
         */
        $total = $quote->getBaseGrandTotal();
        $minTotal = $method->getConfigData('min_order_total');
        $maxTotal = $method->getConfigData('max_order_total');

        if ((!empty($minTotal) && ($total < $minTotal)) || (!empty($maxTotal) && ($total > $maxTotal))) {
            return false;
        }

        return true;
    }


Here as you can see It's checking if Payment method is Gateway or can be used internally. Since Paypal standard checkout can not be used in internally as user is redirected to Paypal site. So to solve this issue just comment following code in _canUsePaymentMethod function.

/*if (!($method->isGateway() || $method->canUseInternal())) {
            return false;
}*/

That's it and now cart_payment.list will return you Paypal in list. Please note ideally you have to override this code and should not change in core code.

Sunday, June 7, 2015

Android BroadCast Receiver vs Service

Hello,

Recently in one of my project we had a requirement to perform certain background task and I Was confused what to use for this. I was confused between BroadCast Receiver or Service. So I thought of digging more into it and here I am sharing my thoughts on this. After long time I am writing a blog without any code.

First lets understand what is BroadCast Receiver

BroadCast Receiver is meant to respond to certain events and intent. For example phone restart, or GCM message or certain other system events. So when this event occurs an intent is created and broadcast receiver are notified through this intent. Broadcast receiver will get this in onReceive method and then we can perform certain tasks.

Now let's understand what is service.

Service is meant to perform certain tasks in background without affecting user's activities in foreground. So for example a downloader. User started downloading and that can be handled in service so user don't have to wait for it to be finished. While the background service is running user can do his other activities.

So we can see both BroadCast Receiver and service do the same thing. They perform certain task in background so what shall we use for background task? The answer depends on how much time do you need to perform background tasks.

Broadcast receiver has time limit of 10 seconds. If the tasks is not completed in 10 seconds then this process is eligible to be killed or terminated by systems. So it could be chance that it gets terminated before process is finished.

While service has no time limits it can perform as long as possible and would be terminated only in extreme conditions. Android system will kill services at last only.

So the concept is clear for the time consuming tasks you have to use Service and for less time consuming tasks you shall use BroadCast Receiver. So for tasks like connecting to internet or downloading something so synching data to server a Service is recommended. While for the tasks like adding to local database or storing something to shared preferences or updating UI on certain events a BroadCast Receiver is recommended.

I hope my blog clears your doubt and helps you in choosing right thing for you. Do share your opinion in comments. 

Tuesday, May 26, 2015

Create Buy 1 Get 1 Free Promotion in Magento

Recently I was working on Magento admin where we have to create promotions like Buy 1 Get 1 Free. Initially I had a trouble setting it as I don't know much about Magento admin. So In this blog I am going to explain how to do it in 10 simple steps so it can save your time.

Step 1:
First of login to Magento Admin and Go to Promotions -> Shopping Cart Price Rules

Step 2:
Click on Add New Rule. (Button on top right corner)

Step 3:
Add a rule name and descriptions. Select customer groups.

Step 4:
Go to conditions tab.

Step 5:
Click on green + button and select option "Product Attribute Combination"

Step 6:
Now it should show you "If an item is FOUND  in the cart with ALL  of these conditions true:" Now click again on new + button at bottom of this text and select SKU from the drop down.

Step : 7
Now it should show you "SKU  is  ... " Click on three dots and Search the SKU of the product for which you want to set offer.

Step: 8
Now go to actions tab and select option "Percent of product price discount" from the Apply drop down.

Step: 9
Set 50 as value in Discount Amount Textbox.

Step 10:
Set two as value in Maximum Qty Discount is Applied To Textbox and save the rule.

That's it basically we gave 50% discount on total if there are product with 2 quantity in cart. This is how user has to pay for only one item and they get other item as free. Hope this helps you.