Showing posts with label GnuCash. Show all posts
Showing posts with label GnuCash. Show all posts

Thursday, December 14, 2006

GnuCash 2.0.3 Bug Fixing

(gnucash:12739): GLib-CRITICAL **: g_date_set_month: assertion `g_date_valid_month (m)' failed

(gnucash:12739): GLib-CRITICAL **: g_date_strftime: assertion `g_date_valid (d)' failed
I had seen the error messages above so often that after 10 minutes, I decided to fix them.

I searched for the error messages and soon landed at the month_name function in src/gnome-utils/gnc-dense-cal.c

#define MONTH_NAME_BUFSIZE 5
/* Takes the number of months since January, in the range 0 to
* 11. Returns the abbreviated month name according to the current
* locale. (i18n'd version of the above static character array.) */
static const gchar *month_name(int mon)
{
static gchar buf[MONTH_NAME_BUFSIZE];
GDate *date;

memset(buf, 0, MONTH_NAME_BUFSIZE);
date = g_date_new();
g_date_set_month(date, mon);
g_date_strftime(buf, MONTH_NAME_BUFSIZE-1, "%b", date);
g_date_free(date);

return buf;
}
The comment above has it: the variable mon will be from 0 to 11 and the number 0 is what choked glib. This is done.

Next, the error message on strftime is cryptic. I went online and searched for what actually g_date_strftime expects and what g_date_new does. From a reliable source, it seems g_date_new creates a new date which is invalid, to make it valid we can use the function g_date_new_dmy.

With all these, let's whack the bugs:

#define MONTH_NAME_BUFSIZE 5
/* Takes the number of months since January, in the range 0 to
* 11. Returns the abbreviated month name according to the current
* locale. (i18n'd version of the above static character array.) */
static const gchar *month_name(int mon)
{
static gchar buf[MONTH_NAME_BUFSIZE];
GDate *date;

memset(buf, 0, MONTH_NAME_BUFSIZE);
/* date = g_date_new();*/
date = g_date_new_dmy(4, G_DATE_JULY, 2006); /* initialize to sane value */
/* printf("%s: setmonth is %d \n", __func__, mon); */ /* Debug statement */
g_date_set_month(date, mon+1);
g_date_strftime(buf, MONTH_NAME_BUFSIZE-1, "%b", date);
g_date_free(date);

return buf;
}
GnuCash developers have my permission to incorporate this fix into the project if they wish.

Upgrading GnuCash

Gnucash 2.0.3 is out. Since there are some weird stuff in 2.0.2, I did an upgrade to see if the bugs are fixed.

Compilation was really a breeze because the Gnome environment is already up (I am using garnome). All I have to do is to issue the following commands:

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:[path to gnome pkgconfig directories]

export PATH=$PATH:[path to gconftool-2 directory]

./configure --prefix=[path you want]

make;make install
My build was done without any errors after about 20 minutes. During execution there were some warnings from Glib on illegal parameters for the date functions.

I grep'ed the code and opened up a few C files which had the matching string.

The programming style is certainly not defensive: return values not checked, shabby handling of pointers, use of magic numbers, etc.

Some people argue on the ground that checking all these will slow the program down and add overhead. Well, this argument is only valid in very few corner cases where timing is very critical and computing resource is extremely tight. I don't see these conditions exist for most projects, including this one.

Given these folks are working on this project for free, and the fact that some salaried programmers are writing even crappier codes. I can't complain.

Saturday, December 02, 2006

FD Formula on GnuCash

In my previous post on GnuCash, I showed the steps to install GnuCash on Slackware 11.

It is not trivial, but doable.

These few days I have been busy setting up GnuCash with intention to dump MS Excel. As usual, the journey wasn't smooth-sailing.

The first problem I encountered was there doesn't seem to be any way to automatically manage FDs (Fixed Deposits, it is called Certificate of Deposit, CD in other countries).

Scenario: I have a amount p of money as FD. The FD will mature every n month and interests generated will be reinvested at the prevalent rate.

What I want: GnuCash to automatically renew the entry at the maturity date. As long as the FD is valid, GnuCash should take care of that until being told otherwise.

As usual, good news and bad news:

Bad news:
Surprise surprise, it seems GnuCash can't do this by default. There are druids to calculate mortgages and loans, but none for savings and FDs. (I checked the wiki and help files on gnucash.org, to no avail. In fact, the formula gnc:computerInterestIncrement on the wiki FAQ is wrong). You can verify it with any financial calculators.

Good news:
The underlying toolchain is written in scheme. This makes GnuCash very flexible and hacking possible. What follow are some pointers.

Assumptions:
  • You have read the GnuCash help files and know the concept of debit and credit
  • You know how to create accounts under GnuCash
  • You already have at least one FD account under Assets and one under Incomes. If your bank charges you on this, add one more account under Expenses and the following steps need some adjustments.
Steps to Fix:
  1. Exit GnuCash
  2. Edit fin.scm (inside /usr/local/share/scm if you use the default configuration)
  3. Add the following at the start of the file, right under the comments (comments are lines starting with semicolons ';').
  4. Note: Blogspot has broken some of the comment lines, please fix those by yourself.
  5. ;
    ; By HKC Dec 02, 2006
    ;
    (define (futureValue p r n i)
    (let ((rate (/ r 100)))
    (* p (expt (+ 1.0 (/ rate n)) i))))

    ;;
    ;; This function calculates the interest yield for the i-th month.
    ;;
    ;; Example: With principal of 10000, interest rate 10%, and interest ;; is calculated and reinvested
    ;; monthly at the same rate, we want to know how much money we ;;can get during the 8-th month.
    ;;
    ;; Invoke (gnc:interestYield 10000 10 12 8) and you should get 88.31767424426289
    ;;
    ;;
    (define (gnc:interestYield p r n i)
    (let ((this-val (futureValue p r n i))
    (prev-val (futureValue p r n (- i 1))))
    (- this-val prev-val)))

    ;;
    ;; This function calculates total interest accrued, assuming all ;;interests are reinvested at the same rate.
    ;;
    ;;
    (define (gnc:interestAccrued p r n i)
    (define (sum-it sum i)
    (if (= i 0) sum
    (sum-it (+ sum (interestYield p r n i)) (- i 1))))
    (sum-it 0 i))

  6. Start GnuCash, and Actions->Scheduled Transaction Editor. Click on 'new'.

  7. Enter a name and set the date according to the maturity of your FD.
  8. Under 'Template Transactions', enter a description, then click on the 'Enter' icon. We need 2 action items: one for debit and one for credit. If you are not sure about this concept or how to do all these, please refer to the GnuCash help files.
  9. At the debit field, enter 'interestYield(p:interest_rate:compound_number:i)' where p is your principal amount, interest_rate is the current rate entered as-is (if it is 3.3, just enter 3.3, my function will do the conversion accordingly), compound_number refers to how frequent interest is compounded (monthly -> 12, quarterly->4, semi-annually->2, annually -> 1), i is the i-th occurence of the compound event. This variable can be entered as-is and no need to substitute it.
  10. Examples: Suppose I have principal amount of 1000 to invest. Interest rate is 5% and will be compounded monthly. Hence I would enter:
    interestYield(1000, 5, 12, i). If the interest is compounded yearly, then I would have entered interestYield(1000,5,1,i). The rest is similar.
  11. Enter the same formula for the credit field.
Upon the maturity specified, Gnucash will automatically credit your account and you never need to worry about it anymore.

I wrote this in quite a rush. If there is something unclear, please let me know and I will be happy to clarify.

Tuesday, November 14, 2006

GnuCash on Slackware 11. Running!


Finally I got this baby to run after hours of struggling. But the time was well-spent, first of all: I made it. Yeah!

As cream on the cake, I got the whole Gnome package installed on my computer with lots of sexy programs to play with (hey, completed with source codes. How much more we can ask for?). I am impressed by the quality of some open source software, say Gimp. I was trying to do a screen capture of my desktop and the misconception of "Linux means more nerdy work" still stuck in my mind. I was planning if I got to write a program to access the display framebuffer, read off the bitmap data, convert the raw data to compressed data, and save the file. Fine, I am ready. Guess what, the Ctrl-PrtScr sequence we are so used to under Windoze works on KDE + Gimp! Not only that, Gimp even has dedicated function (under File->Acquire->Screenshot) for this very purpose. The whole process just took 5 minutes (with 4.5 minutes playing with Gimp settings). Cool.

In retrospect, the road to this milestone (if it were really one) has been thorny and buggy, and I virtually touched all parts of the system. What I can pull off my head include:
  • Bad kernel include file. A program is using something only available in 2.6 series kernels (Solution: I pulled that header off 2.6 kernel and stuck that in my 2.4 kernel. It just works. ;) )
  • Pkgconfig problem (Solution: export the proper file path)
  • Docbook2html problem (Solution: Hack the docbook2html function to point directly to openjade, but a nasty hack because I didn't take care of some switches)
  • Guile and Slib problem (Solution: Hack the config file, as posted earlier)
  • Makefile problem (Solution: Manually add library load path on each Makefile)
  • Gnome installation problem (Solution: Clear the garnome cookie and force rebuild)
  • Crappy program Epiphany (the Gnome web browser) showing very useless error message:
    error: "mozilla" flavoured geckos aren't tasty enough!
    Ok, you can be funny, but you still need to provide more information on what the hell your program is expecting. Aren't tasty enough means WHAT??? All other issues are fair game to me, this one really pisses me off. (Solution: Just skip this crap. I have my dear firefoxy with me, I no bird it)

Sunday, November 12, 2006

Slackware 11 and the Adventure with GnuCash & Gnome

I have read quite some rave reviews on the open source financial management package GnuCash. Since I have my Slackware 11 machine up and running, I thought installing this package will be something like 'a walk by the country side'.

There are a few reasons why I am looking around for accounting software. Currently I am doing my balance sheet on an MS Excel spreadsheet but it is still lacking in many ways as an accounting package. On top of that, after spending RM300 on the Windows XP home edition, I am not interested to fork out any more money to MS to get MS Office suite. Time to give GnuCash a try.

Despite this software is built on top of the Gnome environment which is not supported by Slackware 11, I still thought it would be relatively easy to iron out the differences. Well, it is totally out of hand. Until now, I have encountered roughly 20 major or minor build issues (some of them related to Gnome) on my journey to compile this. "Why don't you just download the pre-compiled binary and run it?", yeap I did, but the dependencies of Gnome is nothing trivial either. I will document the major ones that I remember:

Guile vs. Slib
Packages in question: guile-1.8.1, slib3a4

This was the first problem when I ran 'configure'. The error message was cryptic. As a background introduction, guile is a scheme interpreter while Slib is a scheme library. Guile provides a library binding for slib (slib.scm) so that Slib functions can be invoked through Guile. In return, Slib itself also provides a init script for guile (guile.init) for the same purpose.

In the configure script, test for the presense of Slib is done through

guile -c "(use-modules (ice-9 slib)) (require 'printf)"
Explanation:
guile is the program, the -c switch instructs guile to evaluate the statement after the switch (similar to the -e switch for perl). The use-modules directive will ask guile to load the slib module in the ice-9 directory. After the use-modules statement is evaluated, it will proceed to call functions available through Slib, namely require and printf. The apostrophe (') is used to quote printf as a symbol so that guile will pass it to Slib.

The statement above should return no error. However upon running this, there is an error message:

ERROR: Unbound variable: slib:features
After over 10 hours of debugging, I found out Slib changed the function name from *features* to slib:features and thus obsoletes the library binding of Guile. With this in hand the solution is simple and straight forward: either hack the configure and change that line to:

guile -c "(load "/path/to/slib/guile.init") (require 'printf)"

or you could copy guile.init to the ice-9 directory, replacing slib.scm. Some editing is needed on the guile.init file to make it work though. More specifically you need to change the first line to

(define-module (ice-9 slib))

I am not sure if this copy and paste method will break anything. You are warned.