Whenever one of our team member travels to another country we tell her to track expenses like food, transportation and accomodation so that later that money can be refunded. Each of us does it in a different way: we write it in a notes application in a cellphone, or in a text file in our computer, or maybe in a web application. The problem with the two first approaches is that the information might be lost: the machine might crash or be lost. The last approach is ok, but then you need to remember to connect to the internet to track the expense, and that can happen several hours after having paid, and our memory is not very good.

So I wanted to simply send an sms message to some number to track my expenses. I carry my cellphone all the time so I can send an sms immediately after paying something. Such an application seems very hard to do at first, specially because of the messaging component: receiving sms, configuring a number, etc. Doesn't it?

Well, we have GeoChat! GeoChat is an application that lets you create groups of people to stay in touch with them. When a message is sent to a group it will be broadcasted to every member. And not necessarily to their mobile phone: each user can decide to receive emails, twitter updates, an instant message to their jabber client, etc. The original use case is for people in the field to report emergency and disaster situations to recover from them as quickly as possible. But that doesn't mean we can't use it for other purposes.

For example, one thing that you can do is configure a group in GeoChat to forward some or all of the messages to an external service. You can also configure GeoChat not to broadcast its messages.

So here's the idea: we'll create a group and we'll configure it to send every message to an external service. This service will receive messages like "shopping $20" or "accomodation $300".

So I started coding it and in one hour I got it working! This new tool is called Xpenz.

That shows us how easy is to build some applications on top of GeoChat. In fact, here we are not using much of GeoChat's power, mainly the messaging component. For this you could instead use Nuntium, but I decided to use GeoChat since a lot of messaging is already configured for me and I also had the authentication problem solved.

The code is in Google Code, so it's open source. Let's review the main logic:

class TrackController < ApplicationController
  def expense
    name = params[:sender]
    if name.blank?
      head 'bad_request'
    else
      User.track :user => name, :message => request.raw_post
      head 'ok'
    end
  end
end

So basically we are getting the sender query parameter, which is the GeoChat login name, and if it is present we track the expense by using the request raw post body. And here's User#track:

def self.track(options)
    user = User.find_or_create_by_name options[:user]
    pieces = options[:message].split(' ')
    pieces.map!{|x| x.start_with?('$') ? x[1 .. -1] : x}

    numbers = pieces.select{|x| x.float?}
    texts = pieces.select{|x| !x.float?}
    text = texts.join(' ')

    if numbers.length == 0
      user.currency = text
      user.save!
    else
      if numbers.length == 1
        amount = numbers[0].to_f
      else
        amount = numbers.last
        numbers[0 .. -2].reverse.each{|n| text = "#{n} #{text}"}
      end
      Expense.create! :user => user, :amount => amount, :reason => text, :currency => user.currency
    end
  end

So the first line finds or create the user in xpenz for the GeoChat user. Then we split the message in spaces and do some logic do termine whether it's a currency change or an expense track.

The main point here is that I just had to write about 20 lines of code to make it work. Well, maybe 50 because I tested it. ;-)