gnucash/src/doc/design/engine.texinfo

382 lines
14 KiB
Plaintext
Raw Normal View History

@node Engine, Register, Top Level, Top
@chapter Engine
@cindex The Engine
The Engine provides an interface to a financial engine with three basic
financial entities: Accounts, Transactions (known as Journal Entries in
accounting practice), and Splits (known as Ledger Entries). These three
entities are the central data structures of the GnuCash financial data
model.
In addition, the Engine provides the abstraction of Account Groups
(collections of releated accounts) and Sessions. A Session abstracts
a file-editing session allowing transparent support for locking and
implementation with other backends such as SQL.
The Engine code contains no GUI code whatsoever and is designed to
be created as a shared library for use by other programs.
@menu
* Engine Introduction::
* Globally Unique Identifiers::
* Key-Value Pair Frames::
* Splits::
* Transactions::
* Accounts::
* Account Groups::
* Sessions::
@end menu
@node Engine Introduction, Globally Unique Identifiers, Engine, Engine
@section Introduction
Splits (@pxref{Splits}), or "Journal Entries" are the fundamental
accounting units. Each Split consists of a quantity (number of dollar
bills, number of shares, etc.), the price of that quantity (the price of
one dollar is 1.00 dollars, etc.), a Memo, a pointer to the parent
Transaction, a pointer to the debited Account, a reconciled flag and
timestamp, an "Action" field, and a key-value frame which can store
arbitrary data (@pxref{Key-Value Pair Frames}).
Transactions (@pxref{Transactions}) embody the notion of "double entry"
accounting. A Transaction consists of a date, a description, a number, a
list of one or more Splits, and a key-value frame. When double-entry
rules are properly enabled in the engine (they are settable with various
flags), the total value of the splits is forced to be zero. Note that
if there is just one split, its value must be zero; this is useful
because a zero-valued split can store a price (useful for e.g. tracking
stocks). If there are two splits, then the value of one must be
positive, the other negative: this denotes that one account is credited,
and another is debited by an equal amount. Positive Split values are
'debits' and negative Split values are 'credits'. Forcing the Splits to
'add up' to zero causes a double-entry accounting system to always
balance.
Through various flags, forced double-entry can be disabled; this is
often desirable for novice, home-oriented users. As an alternative, it
may be better to leave double-entry enabled, but credit all dangling
splits to some dummy account, and then simply not show that dummy
account to the user.
Note the sum of the values of Splits in a Transaction is always computed
with respect to a currency; thus splits can be balanced even when they
are in different currencies, as long as they share a common currency.
The conversion price is simply the price stored in the Split. This
feature allows currency-trading accounts to be established.
Every Split must point at its parent Transaction, and that Transaction
must in turn include that Split in the Transaction's list of Splits. A
Split can belong to at most one Transaction. These relationships are
forced by the engine. The engine user cannnot accidentally destroy this
relationship as long as they stick to using the API and never access
internal structures directly.
Splits are grouped into Accounts (@pxref{Accounts}). Each Account
consists of a list of Splits that debit that Account. To ensure
consistency, if a Split points at an Account, then the Account must
point at the Split, and vice-versa. A Split can belong to at most one
Account. Besides merely containing a list of Splits, the Account
structure also give the Account a name, a code number, description and
notes fields, a key-value frame, a pointer to the currency that is used
for all splits in this account, and a pointer to the "security" used for
all splits in this account. The "security" can be the name of a stock
(e.g. "IBM", "McDonald's"), or another currency (e.g. "USD", "GBP").
The security is used during Transaction balancing to enable trading
between accounts denominated in different currencies, or to, for
example, move stocks from one Account to another.
Accounts can be arranged in a hierarchical tree. The nodes of the tree
are called "Account Groups" (@pxref{Account Groups}). By accounting
convention, the value of an Account is equal to the value of all of its
Splits plus the value of all of its sub-Accounts.
@node Globally Unique Identifiers, Key-Value Pair Frames, Engine Introduction, Engine
@section Globally Unique Identifiers
@tindex GUID
@node Key-Value Pair Frames, Splits, Globally Unique Identifiers, Engine
@section Key-Value Pair Frames
@cindex Key-Value Pairs
The number and types of data items which are associated with the
financial abstractions (Accounts, Transactions, and Splits) can vary
widely. For example, an Account which represents a user's checking
account might need to store the bank name, a telephone number, and a
username for online banking purposes. Another Account representing the
user's ownership of a stock might need to store information about
retrieving price quotes online such as the ticker symbol and the
exchange.
To meet this need for varying data storage, the GnuCash accounting
entities use Key-Value Pair Frames (hereafter referred to as the
datatype @code{kvp_frame}). A @code{kvp_frame} is a set of associations
between character strings (keys) and @code{kvp_value} structures. A
@code{kvp_value} is a union with possible types enumerated in the
@code{kvp_value_t} enum which indicates the type of data stored in a
@code{kvp_value} object.
@menu
* kvp_frame::
* kvp_value::
* kvp_list::
* Key-Value Policy::
@end menu
@node kvp_frame, kvp_value, Key-Value Pair Frames, Key-Value Pair Frames
@subsection kvp_frame
@tindex kvp_frame
A @code{kvp_frame} is the datatype used to associate key strings with
@code{kvp_value} objects (@pxref{kvp_value}).
@deftypefun kvp_frame* kvp_frame_new (void)
Create and initialize a new @code{kvp_frame} object and return
a pointer to it.
@end deftypefun
@deftypefun void kvp_frame_delete(kvp_frame * @var{frame})
Free all memory associated with @var{frame}.
@end deftypefun
@deftypefun kvp_frame* kvp_frame_copy(const kvp_frame * frame)
Return a deep copy of @var{frame}.
@end deftypefun
@deftypefun void kvp_frame_set_slot(kvp_frame * @var{frame}, const char * @var{key}, const kvp_value * @var{value})
Associate @var{key} with @var{value} in @var{frame}.
@end deftypefun
@deftypefun kvp_value* kvp_frame_get_slot(kvp_frame * @var{frame}, const char * @var{key})
Return the @code{kvp_value} object associated with @var{key}
in @var{frame} or return @code{NULL} if there is no association
for @var{key}. The value returned is not a copy.
@end deftypefun
@node kvp_value, kvp_list, kvp_frame, Key-Value Pair Frames
@subsection kvp_value
@tindex kvp_value
@tindex kvp_value_t
The @code{kvp_value} object stores the 'value' part of a key-value
association in a @code{kvp_frame} object.
@deftypefun void kvp_value_delete(kvp_value * @var{value})
Free all of the memory associated with @var{value}.
@end deftypefun
@deftypefun kvp_value* kvp_value_copy(const kvp_value * @var{value})
Return a deep copy of @var{value}.
@end deftypefun
@deftypefun kvp_value_t kvp_value_get_type(const kvp_value * @var{value})
Return the type of value stored in @var{value}.
@end deftypefun
A @code{kvp_value_t} enum must have one of the following values:
@table @code
@item KVP_TYPE_NONE
Indicates the abscence of a value in a @code{kvp_frame}.
@item KVP_TYPE_INT64
A @code{gint64} value.
@item KVP_TYPE_FLOAT64
A @code{double} value.
@item KVP_TYPE_STRING
A @code{char *} value of arbitrary length.
@item KVP_TYPE_GUID
A @code{GUID} value. @xref{Globally Unique Identifiers}.
@item KVP_TYPE_BINARY
Arbitrary binary data.
@item KVP_TYPE_LIST
A @code{kvp_list} item which contains a list of @code{kvp_value} items.
@item KVP_TYPE_FRAME
A @code{kvp_frame} object. Thus, frames may contain other frames in a
recursive manner.
@end table
@subsubsection Value Constructors
The following functions create and return @code{kvp_value} objects with
particular values. In the case of pointer arguments, deep copies are
performed.
@deftypefun kvp_value* kvp_value_new_int64(gint64 @var{value})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_float64(double @var{value})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_string(const char * @var{value})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_guid(const GUID * @var{guid})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_binary(const void * @var{data}, int @var{datasize})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_list(const kvp_list * @var{value})
@end deftypefun
@deftypefun kvp_value* kvp_value_new_frame(const kvp_frame * @var{value});
@end deftypefun
@subsubsection Value Accessors
The following functions access the value of a given @code{kvp_value}
object. If the type of the object does not correspond to that named
in the function, @code{NULL} is returned.
@deftypefun gint64 kvp_value_get_int64(const kvp_value * @var{value})
@end deftypefun
@deftypefun double kvp_value_get_float64(const kvp_value * @var{value})
@end deftypefun
@deftypefun char* kvp_value_get_string(const kvp_value * @var{value})
@end deftypefun
@deftypefun GUID* kvp_value_get_guid(const kvp_value * @var{value})
@end deftypefun
@deftypefun void* kvp_value_get_binary(const kvp_value * @var{value}, int * @var{size_return})
@end deftypefun
@deftypefun kvp_list* kvp_value_get_list(const kvp_value * @var{value})
@end deftypefun
@deftypefun kvp_frame* kvp_value_get_frame(const kvp_value * @var{value})
@end deftypefun
@node kvp_list, Key-Value Policy, kvp_value, Key-Value Pair Frames
@subsection kvp_list
@tindex kvp_list
A @code{kvp_list} object abstract a list of @code{kvp_value} objects.
@deftypefun kvp_list* kvp_list_new()
Return a newly allocated @code{kvp_list} object.
@end deftypefun
@deftypefun void kvp_list_delete(kvp_list * @var{list})
Free all memory associated with @var{list}, including the
@code{kvp_value} objects in @var{list}.
@end deftypefun
@deftypefun kvp_list* kvp_list_copy(const kvp_list * @var{list})
Return a deep copy of @var{list}.
@end deftypefun
@deftypefun gboolean kvp_list_null_p(const kvp_list * @var{list})
Return @code{TRUE} if @var{list} is the empty list.
@end deftypefun
@deftypefun kvp_value* kvp_list_car(kvp_list * @var{list})
If @var{list} is @code{NULL} or the empty list, return @code{NULL}.
Otherwise, return the first @code{kvp_value} object in the list.
@end deftypefun
@deftypefun kvp_list* kvp_list_cdr(kvp_list * @var{list})
If @var{list} is @code{NULL} or the empty list, return @code{NULL}.
Otherwise, return a @code{kvp_list} object consisting of @var{list}
with the first value removed. NOTE: the returned list is not a copy!
@end deftypefun
@deftypefun kvp_list* kvp_list_cons(kvp_value * @var{car}, kvp_list * @var{cdr})
If either @var{car} or @var{cdr} is @code{NULL}, return @code{NULL}. Otherwise,
return a @code{kvp_list} object consisting of the value of @var{car} followed
by the values of @var{cdr}. This function uses 'hand-over' semantics, i.e.,
the arguments @var{car} and @var{cdr} are no longer the responsibility of
the caller and should not be accessed after the function returns.
@end deftypefun
@node Key-Value Policy, , kvp_list, Key-Value Pair Frames
@subsection Key-Value Policy
@cindex Key-Value Policy
This section defines the policy that programmers should follow
when using key-value pairs to store information. Because of the
large amount of information which can potentially be stored using
this mechanism, it is important to follow these guidelines so
that order will be maintained.
The following rules should be followed for using key-value pairs:
@itemize
@item
The document @file{src/engine/kvp_doc.txt} should be used to document
the use of keys and values. Please consult this document before planning
any use of new keys.
@item
Key strings should be in all lower case with the '_' character
separating words. If possible, use only alphanumeric characters
and '_'. Example: @code{"bank_info"}
@item
Favor longer, descriptive key strings over short ones. Example:
@code{"online_banking_info"} is better than @code{"onln_bnk"}.
@item
Make use of the fact that frames can be stored in frames. If a group
of keys are used for a related purpose, consider storing them together
in a sub-frame.
@item
Values should generally not be accessed directly through keys, but
should rather be accessed through specific API calls.
@end itemize
@node Splits, Transactions, Key-Value Pair Frames, Engine
@section Splits
@tindex Split
@node Transactions, Accounts, Splits, Engine
@section Transactions
@tindex Transaction
@node Accounts, Account Groups, Transactions, Engine
@section Accounts
@tindex Account
@node Account Groups, Sessions, Accounts, Engine
@section Account Groups
@tindex AccountGroup
@node Sessions, , Account Groups, Engine
@section Sessions
@tindex Session
The @dfn{Session} interface provides wrappers for initiating/concluding
a file-editing session. This class provides several important services:
@itemize
@item
Prevents multiple users from editing the same file at the same time,
thus avoiding lost data due to race conditions. Thus an open session
implies that the associated file is locked.
@item
Provides a search path for the file to be edited. This should simplify
install & maintenance problems for users who may not have a good grasp
of what a file system is, or where they want to keep their data files.
@end itemize
The current implementation assumes the use of files and file locks;
however, the API was designed to be general enough to allow the use
of generic URL's, and/or implementation on top of SQL or other
database/persistant object technology.