Domain model

The "ledger" domain model of the enfore platform consists of objects that can be separated into three groups: transactions, accounts, and booking periods.

A transaction is a record of the movement of a monetary amount from one account to another. An account is a holder of a monetary amount (aka balance) that is modified by transactions adding to or removing from that balance. Booking periods are timespans that are used to group transactions based on the need of the business rather than a general calendar (see "business day" vs. "calendar day")

Accounts

From a technical point of view, an account is simply a container for a monetary amount called balance. From an accounting point of view, accounts have meaning based on their type and additional properties.
The accounts used by an organization make up its "chart of accounts" (COA) - a financial, organizational tool that provides an index of every account in an accounting system.
Some of these accounts appear on the balance sheets of an organization. They give a summary of the financial balances of the organization, a snapshot of an organization's financial condition, so to speak.
The accounts of the balance sheet represent liabilities, assets and ownership equity of the organization. In our domain model most of them use the Type BalanceSheetAccount.
Some accounts for assets or liabilities are used for PaymentTransactions. We call them "money accounts". Currently there are two kinds of money accounts in our domain model:

  • certain BalanceSheetAccounts
  • CashAccounts

Other "money accounts" will be added later, e.g. BankAccounts.
Other accounts in the COA represent revenue and expenses of the organization.
Furthermore there are accounts representing business partners in their roles as a creditor or debtor, as explained below. They can be seen as sub-accounts of the "accounts receivable" and "accounts payable" accounts of the COA.
Using different account types allows to to define transactions that only work on specific types of accounts.

Balance-sheet accounts

As mentioned, most accounts on the balance sheet use the type BalanceSheetAccount. Typical examples:

  • the asset account for "accounts receivable"
  • the liability account for "accounts payable"
  • the asset account for cash in transit
  • the asset account for transit items like tip or escrow sales
  • the account for the liabilities caused by voucher sales

The latter is an example for a BalanceSheetAccount that can be used as money account.
Many of the BalanceSheetAccounts are not used by any workflows in enforePOS yet, and the available accounts heavily depend on the country of the organization. In a country like Germany, where detailed standardized Charts of Accounts exist, the number of BalanceSheetAccounts can be huge. In other countries, where only coarse specifications for a Chart of Accounts exist, the number of BalanceSheetAccounts provided by the domain model will be small.

Cash accounts

Cash accounts are used to track physical money (that is, coins and bank notes). In the real world, they are therefore represented by some kind of container like a waiter's wallet or a strongbox.

The enfore platform differentiates between three types of cash accounts based on the "container type":

  • WALLET - a wallet is only available as personalized cash containers belonging to a specific staff member like waiter
  • CASH_DRAWER - always located at a particular cash register, either assigned to that register or to a specific staff member; in the former case it is used by all staff members, in the latter case only be the assigned staff member
  • VAULT - for cash containers that belong to a service location rather than a specific staff member or register and are not used used for register-level transactions (e.g. sales and refunds).
  • PETTY_CASH - for cash containers that belong to a service location rather than a specific staff member or register and are not used used for register-level transactions (e.g. sales and refunds).

There are some additional constraints imposed by the enfore plaform regarding management of cash containers:

  1. A Staff member's personalized cash container is managed as a cash account with container type WALLET or CASH_DRAWER on a "per location"-basis. That means, if the staff member works at more than one location (e.g., a waiter switching between different branches of a chain), a separate cash account exists for each location and money must be explicitly transferred between those by recording an appropriate money transfer.
  2. Staff members that are assigned a such cash account cannot perform cash-related operations on registers that are assigned a CASH_DRAWER-type cash account. This is to avoid the ambiguity of "where does the money go/come from" when that staff member sells/refunds something via that register.
  3. CashAccounts of type VAULT can't be used to record PaymentTransactions for revenue, only MoneyTransfers and PaymentTransactions for expenses can be recorded.

Expense accounts

ExpenseAccounts track the expenses of an organization. Depending on the COA being used, there could be one general expense account or many expense accounts where each account represents a particular kind of expense (e.g. travel cost, education etc.).

Income accounts

IncomeAccounts track the revenue made by an organization. Currently they are not exposed by the domain model.

Creditor accounts

A creditor' refers to the party that has delivered a product, service or loan, and is owed money by the organization. A creditor account tracks the credit amounts and their reconciliation for a specific creditor. Creditor accounts are assigned to staff members and suppliers (contacts with a staff or supplier role).
If a creditor in a business process involving transactions is not known (like in expenses made by a supplier not tracked by the organization), many systems use the "accounts payable" account instead of a CreditorAccount. In our model an "Miscellaneous Supplier" with an assigned CreditorAccount is used. This allows to use CreditorAccounts in transactions in a type-safe way and also allows to require the associated fields in the domain model for transactions using CreditorAccounts.

Debtor accounts

A debtor is a party who owes money to the organization. A debtor account tracks the owed amounts and their reconciliation for a specific debtor. Debtor accounts are assigned to customers (contacts with a customer role) or alternative payers (contacts with an alternative payer role).
Usually a DebtorAcount is used for specific customers (or alternative payers) as the debtor.
If a debtor in a business process involving transactions is not known (like in sales to an unknown customer), many systems use the "accounts receivable" account instead of a DebtorAccount. In our model an "Anonymous Customer" with an assigned DebtorAccount is used. This allows to use DebtorAccounts in transactions in a type-safe way and also allows to require the associated fields in the domain model for transactions using DebtorAccounts.

Tracking accounts

Explained in the section about booking periods.

Transactions

Transactions move monetary amounts between accounts. Depending on the types of the accounts involved as well as the meaning of the transaction, different transaction types are used. All transaction types share the same set of basic information (such as number, amount, recording/processing timestamp and by whom/where they were recorded) but have additional field to holds the information necessary for the specific type of transaction.

Money transfers

MoneyTransfers are transactions that differ fundamentally from other transactions in two aspects:

  • they always transfer money between two accounts on the balance sheet (BalanceSheetAccounts and money accounts)
  • they do not have "items", so the whole transfer fulfills a single purpose

The two accounts between them money is transferred are given by the fields active_account and target_account. The former is the account where the transfer is recorded. If this account is a CashAccount with a TSE, this TSE is used to cover the transaction. Depending on the value of the field direction money is either moved away from that account (direction OUTGOING) to the target_account or moved into that account (direction INCOMING) from the target_account.

Transfer of money can be recorded as one MoneyTransfer of type SINGLE or as a pair of MoneyTransfers with types ORIGIN and CONTINUATION that reference each other through the counterpart field and can be recorded at different points in time. If the target_account of a CONTINUATION type MoneyTransfer is a CashAccount with a TSE, this TSE ist used to cover the transaction.

Depending on the type of MoneyTransfers, it is possible that at least one of two accounts in the transfer is empty temporarily:

  • type SINGLE: both accounts are set from the beginning
  • type ORIGIN: target_account may be empty until the matching CONTINUATION is recorded
  • type CONTINUATION: both accounts are set from the beginning

Expense transactions

ExpenseTransactions track expenses of the organization. They contain one or more ExpenseItems, each of them representing a single purchase of goods or services made by the organization. Each ExpenseItem references an ExpenseAccount, and the whole transactions references a CreditorAccount, representing the person or organization that needs to be paid for the received goods or services. So in total the ExpenseTransaction moves money between one or more ExpenseAccounts and a CreditorAccount. If the transactions has the type "CREDIT", the organization owes money to the creditor and the CreditorAccount is charged with a negative amount. If the type is "DEBIT", it's the other way around. This represents a reversal of a prior expense.
Currently ExpenseTransactions in enforePOS only apear as simple transactions with a single item and always directly paid by cash and using the CreditorAccount of the "Miscellaneous Supplier".

IncomeTransactions

IncomeTransactions track revenue made by the organization. In total they move money between one or more IncomeAccounts and a DebtorAccount. A typical use case for an IncomeTransaction is a sales invoice. Additionally, income transactions are created when handling cash overhangs during business day management.

For income transactions created for sales invoices, more information can be accessed via the ERP-API.

Payment transactions

PaymentTransactions represent payments for "payable" transactions (ExpenseTransactions or IncomeTransactions) and those other transactions are "paid by" the former. They always move money between a money account and a DebtorAccount or CreditorAccount.
So if we look on an ExpenseTransaction and a PaymentTransaction that pays it, together they move money between one or more ExpenseAccounts and a money account, using a CreditorAccount as intermediate account, that keeps track of the liability that exists in the time between recording the expense and recording the payment.
In the same way, an IncomeTransaction and the PaymentTransaction that pays it together move money between one or more IncomeAccounts and a money account, using a DebtorAccount as intermediate account, that keeps track of the In general the relation between PaymentTransactions and their paid transactions is m:n, in most cases either 1:1, 1:n or m:1. To represent these relationships, PaymentTransactions have an array of "ReferencedTransactions" and ExpenseTransactions or IncomeTransactions have an array of "payments".
Both are dedicated data structures that hold the necessary information.

Payments

Payment structures are used in transactions paid by other transactions, to record how much was paid via what transaction at what point in time. Note that a transaction can be paid for in parts, resulting in multiple Payment structures being present in the paid transaction.

This kind of structure is used by expense transactions and by inceome transactions.

For each payment that is made for a transaction, that transaction will received a Payment structure with:

FieldMeaning
transactionThe transaction that paid for the transaction holding the Payment structure
methodThe method of payment that was used
amountThe amount that was paid
timestampThe point in time when the payment was processed

Referenced transactions

ReferencedTransaction structures are used in transactions that are payments for other transactions, to record how much of the transaction was payment for the other transaction. As a single transaction can be payment for multiple other transactions, multiple ReferencedTransaction structures may be present in the paying transaction.

This kind of structure is used by payment transactions and by balance-sheet transactions that represent payments.

For each transaction that is fully or partially paid for by a transaction, that transaction will received a ReferencedTransaction structure with:

FieldMeaning
transactionThe transaction that is paid by the transaction holding the ReferencedTransaction structure
amountThe amount that was paid

Example

As an example, consider a user recording a cash drawing for an expense. This will create

  • an ExpenseTransaction that records money being moved from the CreditorAccount of the supplier to the relevant ExpenseAccount (based on the type of expense)
  • a PaymentTransaction that records money being moved from the CashAccount to the CreditorAccount of the supplier

The expense transaction causes the expense's amount to be deducted from the creditor account (meaning the creditor is owned that amount) and added to the expense account (meaning an expense occurred).

The payment transaction causes the payment's amount to be deducted from the cash account (as money was taken out) and added to the creditor account (settling the liability caused by the expense transaction).

Both transactions are linked by their Payment/ReferencedTransaction structures to represent that fact that the payment transaction paid for the expense transaction.

Stripped down to the cross references, the expense transaction looks like this:

{
    "id": "et_0001",
    "creditor_account": {
        "account_id": "cra_0002",
        "account_type": "CREDITOR_ACCOUNT"
    },
    "items": [
        {
            "account": {
                "account_id": "ea_0003",
                "account_type": "EXPENSE_ACCOUNT"
            }
        }
    ],
    "payments": [
        {
            "transaction": {
                "transaction_id": "pt_0004",
                "transaction_type": "PAYMENT_TRANSACTION"
            }
        }
    ]
}

And the payment transaction looks like this:

{
    "id": "pt_0004",
    "money_account": {
        "account_id": "caa_0005",
        "account_type": "CASH_ACCOUNT"
    },
    "payee_account": {
        "account_id": "cra_0002",
        "account_type": "CREDITOR_ACCOUNT"
    },
    "referenced_transactions": [
        {
            "transaction": {
                "transaction_id": "et_0001",
                "transaction_type": "EXPENSE_TRANSACTION"
            }
        }
    ]
}

Booking Periods

Accounts keep a balance, that reflects the total effect of all transactions made on this account. Booking periods keep track of these balances over time. They also accumulate some more KPIs that currently are not exposed through the ledger API.
Booking periods can be started and closed automatically on events, in recurring time frames or based on explicit user actions. They will always record the account balance in different states:

  • when the period is created (and the balance is taken over from the closing balance of the prior period)
  • when the period is started
  • when the period is closed

Though basically every account could use booking periods, they are currently used only on CashAccounts and TrackingAccounts.

Booking periods of TrackingAccounts

Tracking Accounts never appear as account in transactions, they only accumulate the effect of transactions made on other accounts. They are automatically created for:

  • POSLocations
  • Staff members working as cashiers at a POSLocation
  • Cash register devices

Every transaction made at a particular POSLocation will always reference a device and a staff member, and these are assigned to a POSLocation, so every such transaction can be assigned to the current booking period of the tracking accounts of these objects. They modify the balance of these tracking accounts and their booking periods.
In the enforePOS application the booking periods are represented by the register or staff member reports in the accounting UI. Their life cycles exactly match those of the business days or cashier shifts of the owners of the tracking accounts.

Booking periods of CashAccounts

Cash register devices and staff members working as cashiers both can own cash accounts. If they do, enforePOS automatically creates booking periods not only for their tracking accounts, but also for their cash accounts. Their life cyle is exactly in sync with the life cycle of the tracking accounts.
CashAccounts add one feature to booking periods, because they might require counting of cash money at times. The result of that counting might differ from the current balance of the booking period, that is calculated from the recorded transactions. enforePOS requires that these differences are reconciled by recording a suitable transaction before the period is closed. To keep track of that difference, the booking period provides two additional balances: the manual_end_balance for the total amount of the final counting and the closing_difference for the amount of the transaction that is recorded to make the current balance of the period match the manual_end_balance.