Lots: Core Function for AR/AP, Inventory, Stock Lots, Cap Gains
[GnuCash Engine: Core, Non-GUI Accounting Functions]


Detailed Description

One often needs to know that the item 'bought' in one transaction is the same one as the item 'sold' in a different transaction. Lots are used to make this association. One Lot holds all of the splits that involve the same item. A lot is typically formed when the item is bought, and is closed when the item is sold out. A lot need not be a single item, it can be a quantity of the same thing e.g. 500 gallons of paint (sold off a few gallons at a time).

Lots are required to correctly implement invoices, inventory, depreciation and stock market investment gains. See the file src/doc/lots.txt for a detailed implementation overview.

A lot is "closed" when the number of items in the lot has gone to zero. It is very easy to compute the gains/losses for a closed lot: it is the sum-total of the values of the items put into/taken out of the lot. (Realized) Gains on still-open lots can be computed by pro-rating the purchase prices.

Lots are nothing more than a collection or grouping of splits in an account. All of the splits in a lot must belong to the same account; there's no mix-n-match. Thus, in this sense, a lot belongs to an accunt as well.

Lots have an implicit "opening date": the date of the earliest split in the lot. The "close date" is the date of the split that brought the lot item balance down to zero.


Files

file  gnc-lot.h

Defines

#define GNC_TYPE_LOT   (gnc_lot_get_type ())
#define GNC_LOT(o)   (G_TYPE_CHECK_INSTANCE_CAST ((o), GNC_TYPE_LOT, GNCLot))
#define GNC_LOT_CLASS(k)   (G_TYPE_CHECK_CLASS_CAST((k), GNC_TYPE_LOT, GNCLotClass))
#define GNC_IS_LOT(o)   (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNC_TYPE_LOT))
#define GNC_IS_LOT_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE ((k), GNC_TYPE_LOT))
#define GNC_LOT_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GNC_TYPE_LOT, GNCLotClass))
#define gnc_lot_get_guid(X)   qof_entity_get_guid(QOF_INSTANCE(X))
#define LOT_IS_CLOSED   "is-closed?"
#define LOT_BALANCE   "balance"
#define LOT_TITLE   "lot-title"
#define LOT_NOTES   "notes"

Typedefs

typedef _GncLotClass GNCLotClass

Functions

GType gnc_lot_get_type (void)
GNCLotgnc_lot_new (QofBook *)
void gnc_lot_destroy (GNCLot *)
GNCLotgnc_lot_lookup (const GUID *guid, QofBook *book)
QofBookgnc_lot_get_book (GNCLot *)
void gnc_lot_begin_edit (GNCLot *lot)
void gnc_lot_commit_edit (GNCLot *lot)
void gnc_lot_add_split (GNCLot *, Split *)
void gnc_lot_remove_split (GNCLot *, Split *)
SplitListgnc_lot_get_split_list (const GNCLot *)
gint gnc_lot_count_splits (const GNCLot *)
Accountgnc_lot_get_account (const GNCLot *)
gnc_numeric gnc_lot_get_balance (GNCLot *)
void gnc_lot_get_balance_before (const GNCLot *, const Split *, gnc_numeric *, gnc_numeric *)
gboolean gnc_lot_is_closed (GNCLot *)
Splitgnc_lot_get_earliest_split (GNCLot *lot)
Splitgnc_lot_get_latest_split (GNCLot *lot)
const char * gnc_lot_get_title (const GNCLot *)
const char * gnc_lot_get_notes (const GNCLot *)
void gnc_lot_set_title (GNCLot *, const char *)
void gnc_lot_set_notes (GNCLot *, const char *)
KvpFramegnc_lot_get_slots (const GNCLot *)
GNCLotgnc_lot_make_default (Account *acc)


Function Documentation

void gnc_lot_add_split ( GNCLot ,
Split  
)

The gnc_lot_add_split() routine adds a split to this lot. Note that *all* splits in a lot must also be in the same account. Note that this routine adds the split unconditionally, with no regard for the accounting policy. To enforce a particular accounting polciy, use the xaccSplitAssignToLot() routine instead.

Definition at line 323 of file gnc-lot.c.

00324 {
00325    Account * acc;
00326    if (!lot || !split) return;
00327 
00328    ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
00329         gnc_lot_get_title (lot), 
00330         gnc_num_dbg_to_string (split->amount),
00331         gnc_num_dbg_to_string (split->value));
00332    gnc_lot_begin_edit(lot);
00333    acc = xaccSplitGetAccount (split);
00334    qof_instance_set_dirty(QOF_INSTANCE(lot));
00335    if (NULL == lot->account)
00336    {
00337       xaccAccountInsertLot (acc, lot);
00338    }
00339    else if (lot->account != acc)
00340    {
00341       PERR ("splits from different accounts cannot "
00342             "be added to this lot!\n"
00343             "\tlot account=\'%s\', split account=\'%s\'\n",
00344             xaccAccountGetName(lot->account), xaccAccountGetName (acc));
00345       gnc_lot_commit_edit(lot);
00346       LEAVE("different accounts");
00347       return;
00348    }
00349 
00350    if (lot == split->lot) {
00351         gnc_lot_commit_edit(lot);
00352         LEAVE("already in lot");
00353         return; /* handle not-uncommon no-op */
00354    }
00355    if (split->lot)
00356    {
00357       gnc_lot_remove_split (split->lot, split);
00358    }
00359    split->lot = lot;
00360 
00361    lot->splits = g_list_append (lot->splits, split);
00362 
00363     /* for recomputation of is-closed */
00364    lot->is_closed = -1;
00365    gnc_lot_commit_edit(lot);
00366 
00367    qof_event_gen (&lot->inst, QOF_EVENT_MODIFY, NULL);
00368    LEAVE("added to lot");
00369 }

Account* gnc_lot_get_account ( const GNCLot  ) 

The gnc_lot_get_account() routine returns the account with which this lot is associated.

Definition at line 175 of file gnc-lot.c.

00176 {
00177    if (!lot) return NULL;
00178    return lot->account;
00179 }

gnc_numeric gnc_lot_get_balance ( GNCLot  ) 

The gnc_lot_get_balance() routine returns the balance of the lot. The commodity in which this balance is expressed is the commodity of the account.

Definition at line 240 of file gnc-lot.c.

00241 {
00242    GList *node;
00243    gnc_numeric zero = gnc_numeric_zero();
00244    gnc_numeric baln = zero;
00245    if (!lot) return zero;
00246 
00247    if (!lot->splits) 
00248    {
00249       lot->is_closed = FALSE;
00250       return zero;
00251    }
00252 
00253    /* Sum over splits; because they all belong to same account
00254     * they will have same denominator. 
00255     */
00256    for (node=lot->splits; node; node=node->next)
00257    {
00258       Split *s = node->data;
00259       gnc_numeric amt = xaccSplitGetAmount (s);
00260       baln = gnc_numeric_add_fixed (baln, amt);
00261    }
00262 
00263    /* cache a zero balance as a closed lot */
00264    if (gnc_numeric_equal (baln, zero))
00265    {
00266       lot->is_closed = TRUE;
00267    }
00268    else
00269    {
00270       lot->is_closed = FALSE;
00271    }
00272    
00273    return baln;
00274 }

void gnc_lot_get_balance_before ( const GNCLot ,
const Split ,
gnc_numeric ,
gnc_numeric  
)

The gnc_lot_get_balance_before routines computes both the balance and value in the lot considering only splits in transactions prior to the one containing the given split or other splits in the same transaction. The first return value is the amount and the second is the value.

Definition at line 279 of file gnc-lot.c.

00281 {
00282    GList *node;
00283    gnc_numeric zero = gnc_numeric_zero();
00284    gnc_numeric amt = zero;
00285    gnc_numeric val = zero;
00286    
00287    if (lot && lot->splits)
00288    {
00289       Transaction *ta, *tb;
00290       const Split *target;
00291       /* If this is a gains split, find the source of the gains and use
00292          its transaction for the comparison.  Gains splits are in separate
00293          transactions that may sort after non-gains transactions.  */
00294       target = xaccSplitGetGainsSourceSplit (split);
00295       if (target == NULL)
00296          target = split;
00297       tb = xaccSplitGetParent (target);
00298       for (node = lot->splits; node; node = node->next)
00299       {
00300          Split *s = node->data;
00301          Split *source = xaccSplitGetGainsSourceSplit (s);
00302          if (source == NULL)
00303             source = s;
00304          ta = xaccSplitGetParent (source);
00305          if ((ta == tb && source != target) ||
00306              xaccTransOrder (ta, tb) < 0)
00307          {
00308             gnc_numeric tmpval = xaccSplitGetAmount (s);
00309             amt = gnc_numeric_add_fixed (amt, tmpval);
00310             tmpval = xaccSplitGetValue (s);
00311             val = gnc_numeric_add_fixed (val, tmpval);
00312          }
00313       }
00314    }
00315 
00316    *amount = amt;
00317    *value = val;
00318 }

Split* gnc_lot_get_earliest_split ( GNCLot lot  ) 

The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the date this lot was opened. It simply loops over all of the splits in the lot, and returns the split with the earliest split->transaction->date_posted.

Definition at line 396 of file gnc-lot.c.

00397 {
00398   if (! lot->splits)
00399     return NULL;
00400   lot->splits = g_list_sort (lot->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00401   return lot->splits->data;
00402 }

Split* gnc_lot_get_latest_split ( GNCLot lot  ) 

The gnc_lot_get_latest_split() routine is a convenience routine that helps identify the date this lot was closed. It simply loops over all of the splits in the lot, and returns the split with the latest split->transaction->date_posted.

Definition at line 405 of file gnc-lot.c.

00406 {
00407   SplitList *node;
00408 
00409   if (! lot->splits)
00410     return NULL;
00411   lot->splits = g_list_sort (lot->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00412 
00413   for (node = lot->splits; node->next; node = node->next)
00414     ;
00415 
00416   return node->data;
00417 }

KvpFrame* gnc_lot_get_slots ( const GNCLot  ) 

Every lot has a place to hang kvp data. This routine returns that place.

Definition at line 182 of file gnc-lot.c.

00183 {
00184     return qof_instance_get_slots(QOF_INSTANCE(lot));
00185 }

SplitList* gnc_lot_get_split_list ( const GNCLot  ) 

The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot. Do *not* not free this list when done; it is a pointer straight into the lots intenal list. Do *not* add to or remove from this list directly. Calling either gnc_lot_add_split() or gnc_lot_remove_split() will invalidate the returned pointer.

Definition at line 188 of file gnc-lot.c.

00189 {
00190    if (!lot) return NULL;
00191    return lot->splits;
00192 }

const char* gnc_lot_get_title ( const GNCLot  ) 

Get and set the account title, or the account notes.

Definition at line 204 of file gnc-lot.c.

00205 {
00206    if (!lot) return NULL;
00207    return kvp_frame_get_string (lot->inst.kvp_data, "/title");
00208 }

gboolean gnc_lot_is_closed ( GNCLot  ) 

The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its balance is zero. This routine is faster than using gnc_lot_get_balance() because once the balance goes to zero, this fact is cached.

Definition at line 167 of file gnc-lot.c.

00168 {
00169    if (!lot) return TRUE;
00170    if (0 > lot->is_closed) gnc_lot_get_balance (lot);
00171    return lot->is_closed;
00172 }

GNCLot* gnc_lot_make_default ( Account acc  ) 

XXX: Document?

Definition at line 461 of file gnc-lot.c.

00462 {
00463    GNCLot * lot;
00464    gint64 id;
00465    char buff[200];
00466 
00467    lot = gnc_lot_new (qof_instance_get_book(acc));
00468 
00469    /* Provide a reasonable title for the new lot */
00470    id = kvp_frame_get_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id");
00471    snprintf (buff, 200, ("%s %" G_GINT64_FORMAT), _("Lot"), id);
00472    kvp_frame_set_str (gnc_lot_get_slots (lot), "/title", buff);
00473    id ++;
00474    kvp_frame_set_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id", id);
00475 
00476    return lot;
00477 }


Generated on Thu Jul 3 05:07:16 2008 for GnuCash by  doxygen 1.5.2