Business logic against model records

Hi,

I have a small architectural decision to make.

I'm modeling double entry accounts to handle product inventory. An
account is a combination of a product, storage location. Accounts also
have sub-types such as "Available" and "Reserved".

Therefore it is possible to have more than one account for the
combination of ProductA and LocationA, one account with type
"Available" and another with type "Reserved". Accounts contain entries
which add or subtract against the account balance. Entries then belong
to transactions which ensure every addition to one account has a
subtraction from another, essentially that product inventory is
preserved.

class InventoryAccount < AR::Base
   belongs_to :inventory_account_type
   belongs_to :product
   belongs_to :storage_location
   has_many :inventory_account_entries
end

My issue is with InventoryAccountType, currently this is a AR model
and a simple database table holding around 10 rows with a column for
the type name (Available, Reserved etc). I populate this as seed data
at application setup.

InventoryAccountTypes don't necessarily need to be in the database
although each account will need to be identified as one or the other
some how (currently via foreign key to the types table). They are also
fairly static and may only change with application feature updates.

I now need to define posting rules which are basically business logic
for whenever a particular entry is made to an account of a certain
type. Each account type has it's own set of posting rules.

I have considered creating an AR model for the posting rules and
associating them with the account type. However I'm not sure about
leverage the database layer to hold so much hardcoded business logic
and relationships?

I also don't like relying on seed data to put business logic
relationships in place.

I feel like I should place the business logic and available account
types firmly in ruby code. What do people think? Has anyone tackled
anything similar?

Thanks, Andrew.

possibly a case for Single Table Inheritance(STI)?

class InventoryAccount < AR::Base
  belongs_to :product
  belongs_to :storage_location
  has_many :inventory_account_entries

  # common inventory account behaviour, possibly making use of
  # template method pattern
end

class AvailableInvetoryAccount < InventoryAccount
  # specific code/behaviour for Available...
end

class ReservedInvetoryAccount < InventoryAccount
  # specific code/behaviour for Reserved...
end
...

I had be contemplating a STI solution but it still involved account
types in the database.

I can see a number of problems being solved with your suggestion,
hadn't thought of it this way. My initial thought though is that
potentially there are around 10-15 account types, would this start to
look ugly with so many models extending this single feature?

I've also got to check how STI influences AR performance. Potentially
I've got around a million records in the accounts table as each
product will have multiple accounts based on batches. Each time a
delivery arrives it creates a new batch for that product which in turn
creates a new account(s).

Every product has around 10 accounts, and every product creates a new
set when a new batch of stock arrives, approx. 24 times a year. So you
can see each product may spawn around 240 accounts a year at worst
case scenario. It's a little heavy but storage is cheap and it allows
a fantastic level of visibility of inventory progress and history.
Just got to watch performance. Indexes and caching will likely be
first ports of call.

Once an account reaches zero it is essentially dead and no longer
used, however I need to keep it on hand for audit trail purposes. I
will likely implement an accounting period function which archives
older accounts out of the live accounts table.

Are you modeling your accounting according to Fowler
http://martinfowler.com/eaaDev/AccountingNarrative.html ?

Why does a "batch" create new accounts and not only AccountEntries
(or, if two legged transactions, only Transactions)?

Yes, I've been reading up on Martin Fowler's accounting patterns. Very
useful.

I think you're are saying I could have AccountEntries reference the
ProductBatch and then within the Account object scope out the
AccountEntries by ProductBatch? This would then give me my batch
specific balance.

However in this instance Product isn't really the "resource" where
tracking, it's ProductBatches. Your could formulate a Product summary
account that contained all the ProductBatch account entries for that
Product.

I need certain account functions like guarding against negative
balances which would be difficult if all ProductBatch entries were
bundled together in a single account.

This would probably be possible, but I'd just have to be careful of a
few things like negative balances on individual batches within the
account.

I think I need to do some more exploring to understand how the
inventory tracking domain can map to double entry accounts...