Recently Safari 3.1 has been released for Mac and Windows, boasting a whole load of useful new features. One of these is support for CSS transforms - i.e. you can translate, scale, and rotate HTML elements in a web page.

CSS transforms can come in quite handy for making complex dynamic objects, without the need for 3rd party plugins or applets. For example i was able to make the following BBC-esque analogue clock, using only DIV's and JavaScript :

(Note that currently this only works in Safari 3.1)

Yes, DIV's and JavaScript. No Canvas, no Flash, no SilverLight, no Java Applets, no Plugins.

It makes me wonder, considering that browsers seem to be getting so powerful nowadays, should one really bother using Flash & co anymore?

I decided to have another go at writing some awe-inspiring haXe code again. This time, i picked up from where i left off - that was trying to get my infamous SCUMM interpreter working on additional platforms which haXe supports.

For reference, i concentrated on getting it to work on the neko platform.

To start off with, i took notice of a suggestion to simplify the import statements which littered the top of the source code. So instead of this:

 
 #if flash9
import flash.display.Bitmap;
...
#else neko
import noflash.Bitmap;
...
#end
 
 

I consolidated everything into a single file which looked like this:


#if flash9
typedef Bitmap = flash.display.Bitmap;
...
#else neko
typedef ByteArray = noflash.ByteArray;
...
#end

So when i used "import hiscumm.Common", i could now access all of the classes listed with little fuss!

Another change i made was to re-factor the way resources were loaded. Before, i just used flash 9's ByteArray. However as there is no direct equivalent of this on the neko platform, i had to implement my own.

Thinking more, i determined that only a relatively small portion of my code actually needed to use all of the features of ByteArray, so instead i changed all of the IO code to use the neko api's Input & Output classes.

Finally i made all 32bit integers Int32's. Consequently, i had to re-implement the Int32 class for the flash platform, but all things considered it was the best solution.

Problems

As before, i ran into a fair share of problems. Most were minor, and others were solved when i upgraded from haXe 1.17 to 1.18. Here are some of the more notable ones i came across.

"No arrays larger than 115 elements"

I ended up finding a rather obvious solution to this problem which worked transparently with the other platforms. All one has to do is split up the troublesome array into several smaller arrays and then concatenate them together. e.g.


 var longarray = [1,2,3].concat([4,5,6]).concat(7,8,9); // works

Problem solved.

"Beware of classes extending Int"

In an earlier implementation of my Int32 class, i had it extending Int. This turned out to be a fatal mistake, as when i tested out the code absolutely nothing worked.

The solution of course was just to not extend from Int.

"haxe.Timer does not have a constructor"

I kept getting a rather odd compile error. It seemed that no constructor was defined for the Timer class, which i used to run the game loop. This was very odd, as the API documentation didn't state anything unusual about the Timer class on the neko platform.

However after checking out the code to the Timer, i soon came to realise the horrifying truth: the Timer class wasn't implemented for the neko platform. Arrrgh! I got this far and now i'm stopped by something as simple as this?

Thankfully i figured out a rather obvious workaround. Instead of using the timer, i merely made a typical run-of-the-mill game loop. Problem solved.


  while (true)
  {
    onTime();
    neko.Sys.sleep(0.01);
  }

The result

As the output below shows, the interpreter now actually runs on neko. Unfortunately there appears to be a rather nasty bug when decoding the room image. But then again i've not implemented any video code for the neko platform yet, so the usefulness of this is questionable to say the least.


$ neko test.n
NekoTest.hx:42: Engine init
SCUMM.hx:486: boot state
SPUTMResource.hx:308: Loading resource 1 from file 1, room 2 (SCRIPT)
SCUMM.hx:488: Started
SCUMM6.hx:1249: ARRAY = ""
SCUMM6.hx:1249: ARRAY = "ScummC Paused !"
SCUMM6.hx:1249: ARRAY = "Are you sure you want to quit ? (Y/N)Y"
SCUMM6.hx:1249: ARRAY = "Are you sure you want to restart ? (Y/N)Y"
SCUMM6.hx:1249: ARRAY = "Save it"
SCUMM6.hx:1249: ARRAY = "Load it"
SCUMM6.hx:1249: ARRAY = "Continue"
SCUMM6.hx:1249: ARRAY = "Cancel"
SCUMM6.hx:1249: ARRAY = "Quit"
SCUMM6.hx:1249: ARRAY = "Ok"
SCUMM6.hx:1249: ARRAY = "Saveing '%s'"
SCUMM6.hx:1249: ARRAY = "Loading '%s'"
SCUMM6.hx:1249: ARRAY = "ScummC test Menu"
SCUMM6.hx:1249: ARRAY = "Save game"
SCUMM6.hx:1249: ARRAY = "Load game"
SCUMM6.hx:1249: ARRAY = "Game NOT saved"
SCUMM6.hx:1249: ARRAY = "Game NOT loaded"
SCUMM6.hx:1249: ARRAY = "Insert disk %c"
SCUMM6.hx:1249: ARRAY = "You must enter a name"
SCUMM6.hx:1249: ARRAY = "Insert your save disk"
SCUMM6.hx:1249: ARRAY = "Failed to open %s (%c%d)"
SCUMM6.hx:1249: ARRAY = "Read error on disk %c (%c%d)"
SCUMM6.hx:788: 103, 645
SPUTMResource.hx:308: Loading resource 2 from file 1, room 2 (ROOM)
SPUTMRoom.hx:173: RMIM == RMIM
SPUTMImage.hx:109: smap size == 8
SPUTM.hx:1096: Internal exception, aborting! (state=SPUTM_RUNNING)
SPUTM.hx:1097: >>

As before, the hiscumm code is available for reference. Unlike last time however, the code is now hosted in a git repository so you can now see all the nitty gritty changes i have made to it. Great!

Click here to check it out!

You might have notice that during the past few months i've written a few articles about haXe, a language and compiler which pits itself as a "toolbox for the web developer".

Recently i decided to test out haXe's platform support. I did this by taking my SCUMM interpreter code - which i had previously written for flash 9 - and tried to get it to work on the other two major platforms haXe supports, javascript and neko.

To start off with, i had to remove its dependency on flash. This was achieved by making replacement classes and switching between the two using the conditional pre-processor. i.e.:


#if flash9
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;
import flash.events.TimerEvent;
#else neko
import noflash.ByteArray;
import noflash.Bitmap;
import noflash.BitmapData;
import noflash.Point;
import noflash.Rectangle;
import noflash.Timer;
import noflash.TimerEvent;
#end

Most of the modifications to the code looked like this, with liberal sprinklings of "#if flash9 ... #end" round the flash specific code.

Eventually i got to the point where things started to look like they were going to compile, or so i thought...

Problems

"Array too big"

The first problem i encountered was that it wouldn't compile.


hiscumm/SCUMM6.hx:1870: lines 1870-2127 : This array declaration is too big, try to split it

Array declaration too big? What on earth was it going on about?


| TArrayDecl el ->
  if List.length el > 115 then error "This array declaration is too big, try to split it" e.epos;
    call p (field p (ident p "Array") "new1") [array p (List.map (gen_expr ctx) el); int p (List.length el)]

Oh, right. Seems i cannot have arrays declared with more than 115 elements. A seemingly arbitrary limitation that is not referenced anywhere in the documentation - great!

Not needing the opcode table for my little experiment, i commented most of it out. Problem solved.

"32bit? no, 31bit!"

Now the first time i got the interpreter to compile for neko, i thought "Wow, great! Looks like this is going to work." Unfortunately though, it didn't. Instead, i got a rather odd exception when reading out of my replacement ByteArray:


Uncaught exception - Overflow

Turns out the problem was with this code here, in neko.Input:


public function readInt32() {
  var ch1 = readChar();
  var ch2 = readChar();
  var ch3 = readChar();
  var ch4 = readChar();
  if( (ch4 & 128) != 0 ) {
    if( ch4 & 64 == 0 ) throw Error.Overflow;
      return ch1 | (ch2 << 8) | (ch3 << 16) | ((ch4 & 127) << 24);
    } else {
    if( ch4 & 64 != 0 ) throw Error.Overflow;
      return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
    }
}

So basically the reader was trying to stuff the whole 32 bit value into a neko Integer, which is actually 31 bits. Oddly enough though, the value being read was identical to a value i specified in the code.

But haXe never bothered to complain about an overflow!

This can be demonstrated by the following code, which prints "-766623411" instead of the expected "1380860237".


trace(1380860237);

Thankfully, a solution exists. There is an "Int32" type which properly handles 32bit integers. However there is a really big snag with it - it's a class.

That means you cannot use any fancy inbuilt operators with it - you have to use a set of functions instead.


import neko.Int32;

var result: Int = 1 + 2; // simple
var result32: Int32 = Int32.add(Int32.ofInt(1), Int32.ofInt(2)); // aaaarrrghh!!!

result += 1; // simple
result32 += 1; // don't even think about it, it won't work

And to top it all off, this "Int32" class only exists for the neko platform, you cannot use it with flash or javascript. Unless you write it yourself, but that is besides the point. It should at least have been there to fill in the gap.

Conclusion

If you are looking at writing code in haXe and want it to work across all 3 of its supported platforms (flash*, neko and javascript), then beware if you are reading, writing, or otherwise processing 32bit integers.

In addition watch out for mysterious arbitrary limitations such as the 115 item limit for declared arrays.

A while ago now, i writ a piece about haXe, a language and compiler which pits itself as a "toolbox for the web developer".

Now i thought haXe was a great idea, with a great potential for consolidating the mess that is web development. But at the time, i couldn't find any examples of its full use out in the field.

That was until today, when i discovered MyMiniCity!

I have heard that MyMiniCity is the first example of a web based game completely written using haXe. The back-end appears to run on mod_neko, while the front-end uses a mix of JavaScript and Flash, both compiled using haXe (from what i can tell at least).

Getting to the point...

Now i shall get to the point. I was so impressed with MyMiniCity that i decided to have a go at writing a Wiki in haXe. This pretty much took me most of the day as i had to make heads and tails of haXe's library's.

In any case, ended up with something which kind of works. For the code, see overleaf.

A while ago now, i stumbled across a web based double entry accounting solution called Luca (not to be confused with the Mac Application).

Unfortunately though, the documentation was a bit sparse. However with a bit of persistence, i have just about managed to figure out how to use it.

Starting out

(note that for this little walkthrough i am using Luca 1.02, so don't be surprised if you are using a later version and things look that bit different)

Assuming you have managed to download and install Luca, as well as log in, you'll be presented with this rather interesting interface:

Luca main menu

Whoah! Lots of options to choose from, but which of those do we need to start off with?

First things first, you'll need to create a chart of accounts, so select the "Charts of accounts" option. You'll be presented with a list of charts, which should be empty. Click on "Add new chart", and your screen will look something like this:

Luca new chart

The only 2 values which are of interest are "Description" and "Format mask", the former of which can be anything you like. The latter is a bit more tricky, and it took me a while to figure out. It seems that the "Format mask" is basically a sequence of 9's using dots as separators. The more dots you use, the more you can nest your accounts.

For reference, i put the following values in this form:

  • Description: LucaCorp
  • Format Mask: 9999.99 (i.e. 2 levels one using four digits, the other using two)

You should now have a chart you can use. But to be of any use, it needs to be assigned to an Organization. To do this, go back to the main menu, and select "Organizations". Then select "Add new Organization". Your screen should now look something like this:

Luca new organization

Give your Organization a name, a remark if you like, and of course a chart of accounts. The values i used are as follows:

  • Name: LucaCorp
  • Remarks: blank
  • Chart of Accounts: LucaCorp

Note that you will also need to give yourself (and anyone else you trust with a user account) permission to use the Organization when entering transactions. This can be done in the "Users X Organizations" screen.

Creating accounts

Now would be a good idea to actually make some accounts. To do this, go back to the main menu and select "Accounts of the chart". Then for the "Parent chart being edited:" field, select your chart of accounts. Your screen should now look something like this:

Luca add account

For each account you want to create, click on "Add Account" and fill in the form, which should look something like this:

Luca add account

The "Class" is the type of account to be created. You can make Accounts for Assets, Liabilities, Equity, Revenue, and Expenses (note that this list can be altered by playing about with the "Account classes").

The "Std. journal" corresponds to an id of a "Standard Journal Description" which you can make in "Standard Journal Descriptions". From what i can tell this allows you to save on typing repetitive descriptions when entering transactions, though i have not really found a use for it yet.

"Code" is the identifier of this account. It needs to correspond to the "Format Mask" you created earlier, e.g. in my case, "1234" and "1234.01" would both be acceptable.

"Parent account" is the code of the account you wish to be the parent. You can use this to create complex hierarchies of accounts, something which i assume Accountants love to do.

The rest of the fields are pretty obvious, apart from "Mobile clients" which i can only assume allows people using Luca's bluetooth functionality to enter transactions on the account (note though that i have not tried this out).

So now you can create accounts at will. As for which accounts to create, it's really up to you. However if you are a bit stuck, below is a table of values you can enter to reproduce a set of accounts from of one of my favourite tutorials on Double Entry Accounting written by Joseph Mack.

RocketScience LLC Accounts

ClassCodeParentDescriptionSmall description
Asset1234cashcash
Asset1234.011234Joseph Mack, withdrawingjm_withdrawing
Asset1234.021234check accountcheck_account
Asset1234.031234petty cashpetty_cash
Liabilities1235liabilitiesliabilities
Liabilities1235.011235Joseph Mac, capitaljm_capital
Equity1236equityequity
Equity1236.011236accumulated profit and lossacc_profit_loss
Equity1236.021236[clo]profit and lossprofit_loss
Revenue1237revenuerevenue
Revenue1237.011237fees earnedfees_earned
Expenses1238expensesexpenses
Expenses1238.011238advertisingadvertising
Expenses1238.021238food,entertainmentfood_entertainment
Expenses1238.031238office suppliesoffice_supplies

Entering transactions

To enter transactions in Luca, you'll need to first create a Batch. To do this, from the main menu select "Batches". Then on the next screen, select your Organization and click on "Add new batch". Your screen should look something like this:

Luca add batch

As you might have noticed, there is not much to a batch. The only thing to look out for is the dates you enter, which need to be in the format "yyyy/mm/dd", and need to lie within the organization's active period (the default being 1970/01/01 -> 1970/01/01).

If you ever want to change the date range of the active period, all you need to do is select "Active Period" from the main menu, then click on "Edit" next to the relevant accounting period for your organization. Your screen should look something like this:

Luca edit accounting period

Then all you need to do is enter an initial and final date. It's as simple as that!

For my first batch, i used the following:

  • Description: First batch!
  • Initial date: 1970/01/01
  • Final date: 1970/01/01
  • Checksum: 0
  • Status: Open
  • Type: Normal batch

Now you can start entering your transactions, which in Luca are referred to as Journals. To do this, from the main menu select "Journals". Then on the next screen, select your Organization and Batch, then click on "Add new journal". Your screen should look something like this:

Luca add journal

So to sum this up...

"DB account" and "CR account" mean "Account to debit" and "Account to credit" respectively. I'm going to assume you know enough about double entry accounting to figure out which accounts you credit and which you debit.

"Std. journal" i already mentioned when creating accounts.

"Cost center" i have yet to figure out, best to leave this as 1 unless you really need it set.

"Date", "Description", "Value", and "Status" are all pretty obvious.

You can enter as many journals as you like in a batch. It is also interesting to note that you don't have to enter both a credit and debit for an entry - you can quite easily add multiple debit or credits in a row.

Profit and Loss

At the end of the accounting year, you'll probably want to determine profit and loss, which usually involves folding revenue and expense accounts into a single profit and loss account. This is otherwise known as "closing out the accounts".

So how does one do this in Luca? Quite simply in fact. Select "Balance closing" from the main menu, and your screen should look something like this:

Luca closing balance

So basically all you need to do is select your organization, enter in start and end dates, then click "Prepare to close balance".

However you'll probably bump into a few issues first time, as three conditions need to be satisfied:

  1. You need an account which contains "[clo]" somewhere in its description to store the closing values.
  2. The period you specify needs to be within the current active period.
  3. All batches in the specified period need to be set to "Closed"

The first condition is rather easy to satisfy. All you need to do is make an equity account named something like "[clo]Profit and Loss".

The last two conditions we more or less went over when talking about batches.

Assuming you got the balance to close, your "Profit and Loss" equity account should now look something like this:

Luca profit and loss ledger

To sum it all up

Luca is a pretty promising accounting solution. It does accounting, reports, and also includes a bit of multiuser management too. In contrast to other solutions, it doesn't try to do everything - which i believe is one of its strengths. It's a relief not having to wade through a swamp of CRM to do something as simple as sorting out the accounts.

Sadly though Luca doesn't appear to have a very active community, and from what i can tell Elvis Pfützenreuter puts most of the work into it.

Still from what i have been able to gather Luca is still under development so with any luck it'll gain more useful features in the future such as multiple currency support.

After growing tired of Mephisto, and then hearing about the Open Source release of Movable Type, i decided to switch the blog over to.... you guessed it, Movable Type!

Unfortunately Movable Type and Mephisto aren't 100% compatible with each other, so don't be surprised if your RSS/ATOM feeds go haywire and all of your links to my blog entries break.

Still, i will try to get the old URL's mapped across. So there's every chance any broken links will fix themselves.

Enjoy!

Last month, fellow bogger Ian sent me an invite for a social networking site called cre8Buzz.

Signup

Upon following the provided link, i was presented with a rather hideous looking signup form.

While looks aren't everything, i really thought it could do with a bit of TLC. This was demonstrated very nicely when i opened up the drop-down list for "Community".

Check out the long list

Yikes!

So to sum up my pet peeves for this form:

  • The title for the top menu doesn't make sense to me
  • The community list is too long, and isn't sorted (a combo box with autocomplete might have been a better choice).
  • There isn't enough white space, especially around the "Email notifications" fieldset.
  • There is a Cancel link and a Save button next to each other - very inconsistent!
  • I am left wondering does the "Destroy This Account" button and the "Cancel" link perform the same operation.
  • Why would i want to "Destroy This Account" when i haven't logically created it yet?
  • In general, there is no flow

In addition there is the glaring omission of any notice indicating that i am binding myself to their Terms of Use.

Terms of use

The Terms of use are themselves rather interesting. There's mention of "subscription fees", and only "personal use" (i.e. non-commercial) is allowed.

In addition "automated use", "transferring your profile", "displaying an advertisement", "telephone numbers", "street addresses", "last names", "URLs or email addresses" are all prohibited.

Lets not forget the usual indemnity section.

And of course apparently i automatically accepted the agreement when i "used" the site, and further affirmed it by "becoming a Builder" (i.e. making a user account, although technically i didn't make one).

Granted, most of these sites have such agreements nowadays, but it would have been nice if i could have explicitly agreed to it when accepting the invite.

So remember, always read the terms of use.

The front page

After filling in the form and subsequently signing in, i decided to look at the front page. And here it is in all of its glory:

Main page

So pretty much like any other Social Networking Community whatever-you-want-to-call-it site. Although like the form before, i have a few pet peeves about it:

  • Clicking on any of the items on top of the search box merely highlights them, making them feel very disconnected from the search box.
  • In order to edit your profile you need to click on "My Stuff" and then one of the links under "Manage my Profile". Not very obvious.
  • The "Help" is rather odd. It lists a set of categories which you must click in order to reveal a set of questions which have an expander box besides them. In order to reveal the answer you need to click on the question, not the expander box, the question! Yikes!
  • Like the invite form suggests, you can only belong to one community.

Features

From what i can tell by looking at the site, cre8Buzz supports:

  • Blogs
  • Audio, Video, Photos
  • Forums (per community)
  • Group questions
  • Comments on almost everything
  • Friends
  • Personal messaging
  • Favourites
  • Themeing your profile page (hmm, sounds familiar)
  • A widget you can put on your website (see below)

Widget

Conclusion

Rants aside, i wish the best of luck to the cre8Buzz team. I think it will be interesting to see how well their site fares in the ever competitive Social Networking market.

As for whether or not i am going to use it, I'll have to think about that one. Still, i have 5 invites left so if anyone reading wants to try out cre8Buzz, give me a buzz by posting a comment below.

Soon after hearing that version 2.0 of the Ruby on Rails web development framework had been released, i decided to try out my pet project RailsCollab to see if it would work properly in the new release.

Sadly it did not, though it didn't take too long to fix everything. To summarise:

  1. I still used a few deprecated functions and parameters, such as link_to_url, @request, start_form_tag, and so on. Changing references to their new counterparts solved this issue.
  2. Two plugins i use, "enum-column" and "paginating_find" broke. I had to modify the code for these as illustrated below.
  3. A new script, "script/performance/request" was added to i naturally had to add it to my svn repository
  4. The default session container changed to cookies, so i had to fill in "config.action_controller.session" in config/environment.rb
  5. "config.breakpoint_server = true" had to be removed from my development environment
  6. Mongrel decided to through a wobbler and stop working, so i had to do a reinstall of it

How to update

Initially i was a bit confused regarding the correct update procedure, however i believe the following commands should suffice:

 
 sudo gem update rails -y

 # In your app's directory
 rake rails:update
 

enum-column fix

Since database plugins for Rails have been seperated from the core, enum-column runs into a bit of trouble as it assumes the plugins for MySQL and PostgreSQL are loaded when in most cases they are not.

In addition i couldn't even get the PostgreSQL plugin working, though this wasn't so much an issue as i only use the plugin to support the initial database schema from ActiveCollab.

So in "vendor/plugins/enum-column/plugins/enum-column/init.rb", change the following:

 
 require 'enum/mysql_adapter'
 require 'enum/postgresql_adapter'
 

To this:

 
 require 'enum/mysql_adapter' if (ActiveRecord::ConnectionAdapters.const_defined? :MysqlAdapter)
 # require 'enum/postgresql_adapter'
 

paginating_find fix

This one is rather simple. In "vendor/plugins/paginating_find/lib/paginating_find.rb", look for this line:

 
 options = extract_options_from_args!(args)
 

And change it to this:

 
 options = args.extract_options!
 

Initial impressions

I was very impressed to find that RailsCollab was notably faster in development mode. I suspect this is due to a combination of that fancy query caching system and of course the change to cookie-based storage as the default session storage system.

Apart from the minor hiccups i had when updating RailsCollab, i've not had any more issues with Rails 2.0. For my future projects, i will definitely be targeting Rails 2.0.

The first helpful article i found, Double Entry Accounting in a Relational Database, suggests i need at least the following models in my system:

  • Account (has many Postings)
  • Asset Type (e.g. £, $, monkeys)
  • Batch (has many Journals, though not really needed)
  • Journal (has many Postings)
  • Posting (associates with Account, Journal, and Asset Type)

However one problem i noticed with the article was that instead of separate "credit" and "debit" fields, everything is consolidated into an "amount" field. This meant that the abstraction between debiting and crediting needed to be handled in the model rather than the actual database.

Puzzled by this, i decided to look at the database schema used in other Accounting products: LedgerSMB and jGnash.

LedgerSMB Logo

LedgerSMB uses a rather complex database schema. I couldn't make much sense of it, apart from like the aforementioned article it consolidated credits and debits into an "amount" field rather than have them as separate fields.

jGnash Logo

jGnash was a bit different as instead of a proper database it uses an XML file to store its data. Still, there were a few distinctive elements which are the equivalent of models:

  • Account (linked to Transaction and CurrencyNode)
  • SingleEntryTransaction (linked to Account, used to insert money out of thin air)
  • DoubleEntryTransaction (linked to 2 Accounts 'credit' and 'debit'. Also links with CurrencyNode)
  • SplitTransaction (used to link multiple SplitEntryTransaction's together to indicate a split transaction)
  • SplitEntryTransaction (linked to SplitTransaction, otherwise the same as DoubleEntryTransaction)
  • CurrencyNode (e.g. £, $, giraffes)

Personally i found jGnash's XML format needlessly complicated, though much more comprehensible than LedgerSMB's database schema.

Though really, the approach i liked the best was the one mentioned in the article. It made the most sense, and wasn't needlessly complicated. So i decided to implement it.

While implementing it however, i became a bit stuck on how to abstract the credit and debit in the Posting entries.

Whenever i have looked at Double Entry Accounting in the past, i always assumed that when you take money out of one account, you need to put the same amount back into another account. Thus i made this rather mistaken test data:

 
 # Begin asset types

 gbp = AssetType.new(:name => 'GBP', :symbol => '£')
 gbp.save!

 # Begin accounts

 assets = Account.new(:parent_account => nil, 
                     :asset_type => gbp, 
                     :name => 'Assets', 
                     :account_type => :asset)
 assets.save!
 equipment = Account.new(:parent_account => assets, 
                        :asset_type => gbp, 
                        :name => 'Equipment', 
                        :account_type => :asset)
 equipment.save!

 liabilities = Account.new(:parent_account => nil, 
                          :asset_type => gbp, 
                          :name => 'Liabilities', 
                          :account_type => :liability)
 liabilities.save!
 fred = Account.new(:parent_account => liabilities, 
                   :asset_type => gbp, 
                   :name => 'Fred', 
                   :account_type => :liability)
 fred.save!
 george = Account.new(:parent_account => liabilities, 
                     :asset_type => gbp, 
                     :name => 'George', 
                     :account_type => :liability)
 george.save!
 
 # Begin transactions
 
 first_transaction = Journal.new(:transaction_type => :transfer, :start_date => Time.now)
 first_transaction.save!
 Posting.new(:account => george, 
            :asset_type => gbp, 
            :journal => first_transaction, 
            :account_period => 0, 
            :description => 'Funding', 
            :amount => -250.00).save!
 Posting.new(:account => equipment, 
            :asset_type => gbp, 
            :journal => first_transaction, 
            :account_period => 0, 
            :description => 'Funding', 
            :amount => +250.00).save!
 first_transaction.end_date = Time.now
 first_transaction.save!
 
 second_transaction = Journal.new(:transaction_type => :transfer, :start_date => Time.now)
 second_transaction.save!
 Posting.new(:account => equipment, 
            :asset_type => gbp, 
            :journal => second_transaction, 
            :account_period => 0, 
            :description => 'Payback', 
            :amount => -100.00).save!
 Posting.new(:account => george, 
            :asset_type => gbp, 
            :journal => second_transaction, 
            :account_period => 0, 
            :description => 'Payback', 
            :amount => +100.00).save!
 second_transaction.end_date = Time.now
 second_transaction.save!
 
 third_transaction = Journal.new(:transaction_type => :transfer, :start_date => Time.now)
 third_transaction.save!
 Posting.new(:account => fred, 
            :asset_type => gbp, 
            :journal => third_transaction, 
            :account_period => 0, 
            :description => 'Investment', 
            :amount => -300.00).save!
 Posting.new(:account => equipment, 
            :asset_type => gbp, 
            :journal => third_transaction, 
            :account_period => 0, 
            :description => 'Investment', 
            :amount => +300.00).save!
 third_transaction.end_date = Time.now
 third_transaction.save!
 

Which actually appeared to work fine (as in everything sum'd to 0, and if i ignored the minus then Assets = Liabilities) before i started to delve into what debiting and crediting means in relation to whether or not an account is classed as an Asset or a Liability.

(Note that to simplify things when i say Asset i could alternatively be meaning Expenses, and when i say Liability i could alternatively be meaning Shareholder Equity or Revenue)

_.Account_.Debit_.Credit
Assets+-
Expenses+(-)
Liabilities-+
Shareholder Equity-+
Revenue(-)+

After applying the logic from the above table (courtesy of Wikipedia), i noticed something rather odd. The credit and debit columns on my printout didn't match. For reference, i was using the following queries to grab the credit and debit amounts for each account.:

 
  credit_amount = Posting.sum(:amount, :conditions => "amount #{account_type == :asset ? '<' : '>'} 0")
  debit_amount = Posting.sum(:amount, :conditions => "amount #{account_type == :asset ? '>' : '<'} 0")
 

However if i modified the code slightly:

 
  credit_amount = Posting.sum(:amount, :conditions => "amount < 0")
  debit_amount = Posting.sum(:amount, :conditions => "amount > 0")
 

The credit and debit columns mysteriously matched. So what happened?

Well i puzzled over this for a while, until i read Wikipedia's article on Double Entry Accounting again. This rather simple summary was very insightful:

Purchase of a Computer

  • Debit Computer A/c (Fixed Asset A/c)
  • Credit Creditors A/c (Liability A/c)

(A/c being an abbreviation of "account current")

Paying supplier for the computer

  • Debit Creditors A/c (Liability A/c) You are reducing a Liability A/c
  • Credit Bank A/c (Asset A/c) Money going Out, an asset account is being reduced

So in fact all the transactions in my test data should have been increasing the amount in the liability accounts rather than decreasing it (and vice versa when paying back).

It makes sense now i think about it. The second approach worked because in effect i flipped the meaning of debit and credit by decreasing the amount in the liability accounts and calling it credit rather than increasing the amount in the liability accounts and calling it credit (and vice versa).

Now i could just go ahead and fix my test data. But then my amounts would cease to sum up to zero, and i would have to run multiple queries (each for debit and credit) to ensure integrity of the data.

Thus what i really need to do is make an attribute in the Posting model which stores and retrieves the correct "amount" depending on what type of account it is. Something like this should suffice:

 
  def real_amount
    return self.account.account_type == :asset ? self.amount : -self.amount
  end
  
  def real_amount=(val)
    self.amount = self.account.account_type == :asset ? val : -val
  end
 

So to sum it up, the only thing i really have to do with liability accounts to satisfy accounting rules is to subtract when i really mean add, and then flip the balance when calculating it. Confusion eliminated!

Now lets hope i don't get confused again when i start to think "Did i get this right?".

Currently i am looking into how i can effectively incorporate business concepts such as Invoices, Taxation, and so on into my little Double Entry Accounting system. So expect to see a "Double Entry Accounting with Invoicing in Rails" post in the near future.

Last month after bumping into haXe and Doomed Online, i somehow got the strange idea that i could get flash to play SCUMM games, like ScummVM.

While i did get it working as a proof of concept, there was a really off-putting bug in the image decode routines which meant that any displayed room graphics were a jumbled mess.

Recently though i decided to do a bit of intensive debugging to try and solve the problem. To sum it up, after:

I managed to fix the decode routines. Now instead of a jumbled mess like this:

Before, courtesy of Albans Road example

You get something more like this:

After, courtesy of OpenQuest

Which safe to say is much nicer to look at. It's also as far as i am willing to go with this SCUMM implementation.

With a lot of work put into it, i'm sure it could run Day of the Tentacle or Sam N Max Hit the Road. But there would not be much sense in doing that, except for that 5 seconds of awe after seeing it running in a web browser.

As previously, you can download the hiscumm code for reference here.

Add to Technorati Favorites

About

I'm James S Urquhart, an aspring freelance Software Developer and problem solver looking to develop cool 21st century solutions, whilst trying not to fail miserably in the process.

If anything interests you here, feel free to check out my Resume.

Contact