Submit Expense Reports With One Message: Use Twilio MMS and Concur API To Make Expense Reports A Breeze

November 20, 2014
Written by

expense

When you’re traveling on business, you’re focusing on being ready for that customer meeting, and doing work from the road. Stashing receipts for expense reports is at the bottom of the to-do list. When you get back to HQ, the last thing you want to do is spend a few hours going through your credit history and manually importing expenses. The easiest way to get all your time (and money) back from expenses is using Concur + Twilio MMS.

concurmms
Senior Developer Evangelist Chris Ismael, wrote a tutorial using Concur’s ReceiptImages API and the Twilio MMS API that lets you submit expense reports with one simple MMS. Concur (an SAP company) has a network of over 25 million users, spanning 20,000 businesses.

 

Just take a picture of your receipt, enter in the amount you want to be reimbursed for, and press send. Blam, expense report done.

Check out the code, and video of the app in action on Chris’ blog here. We’ve syndicated the rest of the post below.

 

The flow is explained in the diagram below. To get started, you would need a Twilio account and setup your MMS. You can follow this excellent blog post by Kevin Whinnery to set up your Twilio MMS. You also have the option signing up for a Concur developer sandbox account if you intend to run the same example in this post. The Concur node.js client library can be downloaded here

The code example walkthrough is split into four parts:

  1. Capturing data sent by Twilio MMS to our node.js app
  2. POSTing the image to Concur’s ReceiptImages API
  3. POSTing the amount text to Concur’s QuickExpense API
  4. Use TwiML to send confirmation SMS to user

Let’s Get Started!

1. Capture data sent by Twilio MMS to our Node.js app.

// After setting up Twilio to call our node.js app 
// ('/receiveMMS') when an SMS/MMS is received,
// the snippet below will get the Twilio-hosted
// MMS image URL and the message body, which
// represent the image receipt and expense amt

app.post('/receiveMMS', function (req, res) {

   fromTwilio.mediaUrl = req.body.MediaUrl0;
   fromTwilio.msgBody = +req.body.Body;  

   ....

});

2. POSTing the image to Concur’s ReceiptImages API

// *Post image to Concur using Concur module*
// The snippet below takes the Twilio-hosted MMS image URL
// and passes it to be uploaded to Concur

function(callback) {

   options = {
   oauthToken:concurToken,
   imageURL: fromTwilio.mediaUrl
};

concur.receipt.send(options)
   .then(function(imageId) {
      console.log(imageId);
      callback(null, imageId);
   })
  .fail(function(error) {
      console.log(error);
      ///TODO: handle error
  });
},

3. POSTing the expense amount to Concur’s QuickExpense API

// *Create expense entry and link image to it*

function(imageId, callback) {

    // Check if text message was included in MMS
    if (isNaN(fromTwilio.msgBody)) callback(null, "Receipt uploaded, expense entry skipped!");

    var now = new Date();
    var year = now.getFullYear();
    var month = now.getMonth();
    var date = now.getDate();

    var fullDate = year + '-' + (month +1) + '-' + date;

    // Populate QuickExpense JSON payload with
    // expense amount text sent through Twilio MMS
    var concurBody = {
        CurrencyCode: "USD",
        TransactionAmount: fromTwilio.msgBody,
        TransactionDate: fullDate,
        ReceiptImageID: imageId
    }

    var postData = JSON.stringify(concurBody);

    // Authorization parameters for Concur API
    var headers = {
        'Content-Type': 'application/json',
        'Content-Length': postData.length,
        'Authorization': 'OAuth ' + concurToken,
        'Accept' : 'application/json'
    };

    // Point call to QuickExpense Concur API
    var options = {
        host: 'www.concursolutions.com',
        port: 443,
        path: '/api/v3.0/expense/quickexpenses',
        method: 'POST',
        headers: headers
    };

    // Setup the request.
    var req = https.request(options, function (res) {
        res.setEncoding('utf-8');

        var responseString = '';

        res.on('data', function (data) {
            responseString += data;
        });

        res.on('end', function () {
            //console.log("Response: " + responseString);
            callback(null, "Receipt uploaded, expense entry created!");
        });
    });

    req.on('error', function (e) {
        // TODO: handle error.
    });

    req.write(postData);
    req.end();
}

4. Using TwiML to send confirmation to user

// *Builds the TwiML (XML) request that this app sends back to Twilio, to be relayed back as SMS to user*
// Sample usage: sendTwiml(res, "Receipt uploaded, expense entry created!")

function sendTwiml(res, message) {
    var twiml = '<!--?xml version="1.0" encoding="UTF-8" ?-->' + message + '';
    res.send(twiml, {
        'Content-Type': 'text/xml'
    }, 200);
}

You can check out the entire source code here.