19. Accounting and Inventory

An account manager, like Quicken, allows users to open and close accounts, transfer funds from one account to another, view account statements, and view transaction histories.

Users can create two types of accounts: internal and external. External accounts are accounts controlled by external actors such as credit card accounts and employer payroll accounts. External accounts can have negative balances. Internal accounts are accounts controlled by the user, such as checking accounts and saving accounts. These types of accounts may never have negative balances. The sum of the balances of all accounts controlled by an account manager must always be 0 USD. (Although all account balances are in US dollars, users may transfer funds in different currencies.)

Example: Quacken

Initially, users create named accounts using the external and internal commands:

-> external visa
done
-> internal checking
done
-> external employer
done
-> internal savings
done

Users transfer funds between accounts using the transfer command followed by the source account, destination account, and the quantity to be transferred:

-> transfer employer checking 5000 USD
done
-> transfer checking visa 200 DM
done
-> transfer checking savings 6000 USD
error: insufficient funds
-> transfer checking savings 200 JY
done

Users can use the statement command to see a printout of all entries associated with an account as well as its current balance:

-> statement checking
entry 1: 4.20.2001 12:00 5000 USD from employer
entry 2: 4.20.2001 12:01 -200 DM to visa
entry 3: 4.20.2001 12:02 -200 JY to savings
current balance = 4948.32 USD
-> statement employer
entry 1: 4.20.2001 12:00 5000 USD to checking
current balance = -5000 USD

The transaction command shows all transactions that have taken place:

-> transactions
transaction 1: 5000 USD from employer to checking
transaction 2: -200 DM from checking to visa
transaction 3: -200 JY from checking to savings

Design

A C++ Implementation

class Entry
{
public:
   Entry(Quantity amt = 0)
   {
      amount = amt;
      booked = time(0);
   }
   Time getBooked() { return booked; }
   Quantity getQuantity() { return amount; }
private:
   Quantity amount;
   Time booked;
};

class Account
{
public:
   Account(Holder* h = 0, string pswd = "???", bool a = true)
   {
      assetAccount = a;
      balance = 0;
      password = pswd;
      holder = h;
      if (holder) holder->add(this);
   }
   vector<Entry> getStatement()
   {
      if (!authorized())
         throw runtime_error("Access denied!");
      return statement;
   }
   friend class Transaction;
private:
   bool authorized();
   void deposit(Quantity amt);
   void withdraw(Quantity amt);
   Quantity balance;
   bool assetAccount; // 0 <= balance
   vector<Entry> statement;
   string password;
   Holder* holder; // an actor
};

class Transaction
{
public:
   Transaction(Account* fa = 0, Account* ta = 0, Quantity amt = 0)
   {
      fromAccount = fa;
      toAccount = ta;
      amount = amt;
   }
   bool commit();
private:
   Account* fromAccount;
   Account* toAccount;
   Quantity amount;
};

void Account::withdraw(Quantity amt)
{
   if (!authorized())
      throw runtime_error("Access denied!");
   if (assetAccount && balance < amt)
      throw runtime_error("Sorry, insufficient funds!");
   statement.push_back(Entry(-amt));
   balance -= amt;
   cout << "current balance = $" << balance << endl;
}

bool Transaction::commit()
{
   try
   {
      fromAccount->withdraw(amount);
   }
   catch(runtime_error e)
   {
      cerr << e.what() << endl;
      return false;
   }
   try
   {
      toAccount->deposit(amount);
   }
   catch(runtime_error e)
   {
      cerr << e.what() << endl;
      fromAccount->deposit(amount); // roll back
      return false;
   }
   return true;
}

Transaction Processing

An account manager is a simple example of a transaction processor (TP). Generally speaking, a TP is a server that allows multiple clients to create and commit transactions. These transactions can be abstractly understood as transferring quantities from one account to another. The quantities might be money, data, or items.

A TP must guarantee the ACID properties:

A = Atomic: Committing a transaction is an all or nothing situation. If the transaction can't be completed, then the database must be rolled back to its state before the transaction began.

C = Consistency: the database must be consistent after each transaction is committed. For example, the sum of all balances must be 0 before and after each transaction.

I = Indivisible: Transactions can't be interrupted. For example, a wife withdrawing the last $20 from a joint account can't be interrupted by a husband who also withdraws the last $20.

D = Durable: Once committed, the effects of a transaction can't be undone except by a compensating transaction.

Inventory

An inventory system is a collection of line items. A line item is essentially an account: