Friday, 24 July 2015

Developing USSD apps: Airtel Mobile money USSD app

NB: You can now read this post at my new site

I have just thought of this app right now because my MTN phone is out of battery otherwise we would have used the MTN mobile money app which is more popular in Uganda. Since I need to be navigating the menu as am developing the app, I will use my Airtel line.

If you are in Uganda, dial *185# on your Airtel line to follow along.



If you're not, no worries, these are just simple menus and you probably have something similar with your local MSP. All the same, your only hustle should be getting to grips with manipulating ussdmenu-server.jar libraries to your advantage.

From the last post, our servlet looked something like this, only that we have filled in some values to return, if left null, the system will default to its original values:

package com.egima.ussd;

import com.egima.ussdmenuserver.UssdReceiver;
import com.egima.ussdmenuserver.UssdTree;
/**
 *
 * @author Egima
 *
 */
public class MyUssdReceiver extends UssdReceiver {
       private static final long serialVersionUID = 1L;

       @Override
       public String getAppShortCode() {
             //can be any short code of your choice, we are just simulating
             return "*185#";
       }
       @Override
       public int getBufferLimit() {
             return 5;
       }

       @Override
       public String getUssdAppId() {
             return "appid";
       }

       @Override
       public String getUssdAppPassword() {
             return "password";
       }

       @Override
       public String getUssdClientUrl() {
             return "http://127.0.0.1:8000/ussd/";
       }

       @Override
       public UssdTree getUssdTree() {
             return null;
       }


}

}

From the above code, the only thing our servlet lacks is the UssdTree, and that is the most important part of our app. For clarity purposes, we shall move it to another class MyTree.java which subclasses UssdTree.

So create MyTree.java in the existing package and put the following code there. It's really self explanatory

package com.egima.ussd;

import java.util.HashMap;

import com.egima.ussdmenuserver.UssdNode;
import com.egima.ussdmenuserver.UssdPrompt;
import com.egima.ussdmenuserver.UssdTree;
/**
 *
 * @author Egima
 *
 */
public class MyTree extends UssdTree {

       public MyTree(String treeHeader) {
             super(treeHeader);
             initTree();
       }

       private void initTree() {
              /***********************************************************************
             add first level children falling directly under root menu, give them suitable
             id's which must be unique across the whole tree
              ************************************************************************/
       addNode(new UssdNode("Send Money", "sendmoney", "root"));
       addNode(new UssdNode("Airtime/Data", "airtimedata", "root"));
       addNode(new UssdNode("Widthdraw Cash", "withdrawcash", "root"));
       addNode(new UssdNode("Pay Bill", "paybill", "root"));
       addNode(new UssdNode("Buy Goods", "buygoods", "root"));
       addNode(new UssdNode("Check Balance", "checkbalance", "root"));
       addNode(new UssdNode("Financial Services", "financialservices", "root"));
       addNode(new UssdNode("My Account", "myaccount", "root"));
       addNode(new UssdNode("Messages", "messages", "root"));
      
       /***********************************************************************
        * add the children of each menu item in similar manner e.g for paybill item
        * ********************************************************************/
        addNode(new UssdNode("UMEME touchpay", "umeme", "paybill"));
        addNode(new UssdNode("NWSC eWater", "nwsc", "paybill"));
        addNode(new UssdNode("Pay TV", "paytv", "paybill"));
        /***********************************************************************
         * at this rate, you can pick on and supply menus to the rest, lets look at
         * a UssdPrompt
         * Assume on selecting UMEME touchpay option, you are asked for account number,
         * amount to pay and mobile money pin, each of which are prompts
         */
        addNode(new UssdPrompt("Enter UMEME account No","umemeaccno","umeme") {
            
             @Override
             public boolean validate(Object arg0) {
                    /*
                     * probably here you'd check if the input account number is in your DB
                     * but lets assume there is only 1 client and his account number is 1100
                     */
                    String input=(String) arg0;
                    return "1100".equals(input);
             }
            
             @Override
             public String getValidationError() {
                    /*
                     * Incase the account number is not valid
                     */
                    return "Unknown account number, please check your entry";
             }
       });
        /******************************************************************
         * after the first prompt passes, the next prompt is called, so a prompt
         * must have only 1 child i.e the next prompt
         */
        addNode(new UssdPrompt("How much do you want to pay","amount","umemeaccno") {
            
             @Override
             public boolean validate(Object arg0) {
                    /*
                     *since this is a cash amount, we shall just ensure it's a valid double
                     *figure greater than 0
                     */
                    double amount=0;
                    try{
                           amount=Double.parseDouble((String)arg0);
                           }catch(Exception e){
                                 return false;
                           }
                    return amount>0;
             }
            
             @Override
             public String getValidationError() {
                    return "Invalid cash amount";
             }
       });
        /******************************************************************
         * finally we add another child to amount prompt to ask for the pin,
         * since this is the last prompt(has no children), we shall override the
         * processNodeEndEvent method to perform our session end processing
         */
       addNode(new UssdPrompt("Enter Mobile money pin","pin","amount") {
            
             @Override
             public boolean validate(Object arg0) {
                    /*
                     * lets assume the pin is 4649, otherwise you'd check from the DB
                     */
                   
                    return "4649".equals(arg0);
             }
            
             @Override
             public String getValidationError() {
                    return "Invalid pin";
             }

             @Override
             public String processNodeEndEvent(HashMap userData) {
                    /*
                     * let's retrieve all the data we need now by node name
                     */
                    //umemeaccno
                    String accno=(String) userData.get("umemeaccno");
                    //amount
                    double amt=Double.parseDouble((String)userData.get("amount"));
                    //pin
                    String pin=(String) userData.get("pin");
                    /*
                     * assume the initial balance was 300,000/= and we are going to deduct th
                     * input amount
                     */
                    double balance=300000-amt;
                   
                    /*
                     * just for clarity and understanding purposes, we shall send this
                     * data to display
                     */
                    StringBuilder data=new StringBuilder();
                    data.append("Dear customer
"
);
                    data.append("ACC NO:"+accno+"
"
);
                    data.append("PIN:"+pin+"
"
);
                    data.append("AMT:"+amt+"
"
);
                    data.append("BAL:"+balance);
                    return data.toString();
             }
            
       });
       }

}

You can now return this new object in the servlet as our UssdTree like so:
@Override
       public UssdTree getUssdTree() {
             return new MyTree("Airtel Money");
       }


Now redeploy your app and test from the simulator.

  • use the short code you set in the system for the app, or you can use others to test validation mechanism
  • select the pay bill option since it is what we have tackled so far
  • select umeme option 1
  • follow the prompts to input data according to the validation you had defined in the code, else you can test the validation with different data.
You can try out completing the menus and supplying them children as seen in the real app just to sharpen your skills at using the ussdmenu-server.jar lib.

It's friday guys, PARTY TIME, don't be like this





No comments:

Post a Comment