Shared Expenses 2 is a web-based expense manager. It's based on the idea of a group of people living in one house, needing to have common items purchased for the house and/or select members. For example: a house has three members living in it, Ray, Sarah and Albert. Albert goes to the grocery store, buys milk and orange juice for himself and Ray. Ray makes an expensive dinner for everyone and wishes to be reimbursed. Sarah goes to the hardware store and buys Albert a bag of screws. Sarah also pays the utility bills, while Ray pays the rent that they all share.
All these monetary exchanges can be tracked through a simple web interface.
This is a complete rewrite of the original SharedExpenses that I wrote for my college house. Having learned a few things about writing financial software and more robust software in general, this should be much better designed and even looks a bit slicker. It's still got its rough edges, but is quite usable for the most basic needs.
This version also features the most-requested feature of the previous version: circular debt resolution. It was so commonly requested that I decided to make it not only a feature, but the default action. If the system detects that two or more people have a circular debt (example below), it will automatically remove it, update their balances and put an entry in the log.
Circular debt is as follows:
Because everyone owes each other $5 and as we're not collecting interest, you can simply 'erase' the debt of $5 from every balance. The net result in the above example is that Bob owes Carol $1 and Carol owes Alice $2.
The development trunk is available from anonymous SVN at:
svn co https://staticfree.info/svn/sharedexpenses2/trunk/ sharedexpenses2
Please submit any bugs to the SharedExpenses2 development site.
Create a SQL database for storing all the information. Load it up with expenses.sql. Make a copy of expenses.cfg.example and rename it expenses.cfg, then put all your DB configuration settings there.
A quick example with MySQL:
$ mysqladmin create expenses
$ echo "GRANT ALL PRIVILEGES ON expenses.* TO 'expenses'@'localhost' IDENTIFIED BY 'password';"|mysql -u root -p
$ cp expenses.cfg.example expenses.cfg
$ vim expenses.cfg # add in your settings
$ mysql -u expenses -p expenses < expenses.sql
$ ./expenses.py
As a web.py app, you can either run it from the command line to test it (it tells you what URL it fires up on, usually http://localhost:8080/ by default) or you can run it with lighttpd or apache using fastcgi or mod_perl. I personally use Apache2 + FastCGI so there's a handy helper configuration parameter container = apache-fcgi in the [run] section of the config that gets around the annoyance of it not working out-of-the-box.
The system is fairly straight-forward and is lightly documented with tooltips. The main bit that may be confusing is the circular debt removal. The system will post an entry when it finds such a condition, so you can check its calculations.
Unlike the previous version, this version has a more distinct notion of a 'user'. The main page requires you to be logged in in order to interact with it. If you use the built-in accounts, you can create a user account by going to /user/. Additionally, the system will pick up on any REMOTE_USER environment variables you have set, so you can use your favorite webserver authentication system instead.
This software is licensed under the GNU GPL license version 2 and above.
SharedExpenses 2
Copyright © 2008-2010 Steve Pomeroy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
When writing software that deals with money, even if it's just money between friends, it's best to make things as bullet proof as possible. One pitfall to avoid is actually very insidious: rounding.
It turns out most floating point implementations end up causing trouble if you aren't extremely careful and it's generally just best to avoid them. Instead of storing internal values in dollars (or whatever major currency you use), it's best to store them in cents. This keeps everything as integers, which computers are much better at dealing with. The only quirk here is that you need to be extra careful to turn the user-input "0.10" into a stored "10" at every possible bit where user input comes in.
A long time ago I was writing some financial software in Perl that did
some calculations on dollar value numbers. It turned out that there was a
nasty bug in the way Perl's floating point worked if it was a string: the
numeric value would be different than the string value. So you could print
out your value for debugging and it would be proper, but when doing a
comparison: $a == 0.10 it would fail. This is because,
internally, $a was set to 0.099999999999. If you did
a string comparison, $a eq "0.10", it actually evaluated to true!
The interim solution to this problem was to do a string formatting of all
the input values to force the system to re-round them properly.
If you can't take a look at your software's output and manually compute the same values that are on the screen, you're doing something wrong. SharedExpenses tries to do this by keeping a public log of all the transactions that occur, with the time and individual that posted them and any system actions that occur (such as circular debt removal). Given enough patience, you should be able to reconstruct the balances from the list of items shown.
One of the quirks with the SharedExpenses system is that you're splitting amounts between people that can result in fractions between people.
For example, two people are splitting an expense of $1.05. To do things properly, each person would need to have 52.5¢ stored in their account balances. As it is absurd to store half pennies, I instead need to shaft a person of a penny. To shaft people evenly, the best way is to randomly pick a person. And to make sure that a list of people greater than two (say, 10) get shafted fairly, you can line them, pick a random starting point and start dividing the remainder up amongst them in sequence.
Credit Pool is another take on the same use case which adds the notion of a common pool that you pay into / get paid out of. This is useful if you have a large number of people who buy into a common thing (group lunches seems a common example), but where you don't necessarily want to keep track of specific people who should be paid back.