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


Data Structures

struct  GncLotClass

Files

file  gnc-lot.h

Defines

#define GNCLotClass   GncLotClass
#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"

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 *)
void gnc_lot_set_account (GNCLot *, Account *)
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)
void gnc_lot_set_closed_unknown (GNCLot *)
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 *)
unsigned char gnc_lot_get_marker (const GNCLot *)
void gnc_lot_set_marker (GNCLot *, unsigned char)
KvpFramegnc_lot_get_slots (const GNCLot *)
GNCLotgnc_lot_make_default (Account *acc)

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.


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 policy, use the xaccSplitAssignToLot() routine instead.

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

00511 {
00512     LotPrivate* priv;
00513     Account * acc;
00514     if (!lot || !split) return;
00515     priv = GET_PRIVATE(lot);
00516 
00517     ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
00518            gnc_lot_get_title (lot),
00519            gnc_num_dbg_to_string (split->amount),
00520            gnc_num_dbg_to_string (split->value));
00521     gnc_lot_begin_edit(lot);
00522     acc = xaccSplitGetAccount (split);
00523     qof_instance_set_dirty(QOF_INSTANCE(lot));
00524     if (NULL == priv->account)
00525     {
00526         xaccAccountInsertLot (acc, lot);
00527     }
00528     else if (priv->account != acc)
00529     {
00530         PERR ("splits from different accounts cannot "
00531               "be added to this lot!\n"
00532               "\tlot account=\'%s\', split account=\'%s\'\n",
00533               xaccAccountGetName(priv->account), xaccAccountGetName (acc));
00534         gnc_lot_commit_edit(lot);
00535         LEAVE("different accounts");
00536         return;
00537     }
00538 
00539     if (lot == split->lot)
00540     {
00541         gnc_lot_commit_edit(lot);
00542         LEAVE("already in lot");
00543         return; /* handle not-uncommon no-op */
00544     }
00545     if (split->lot)
00546     {
00547         gnc_lot_remove_split (split->lot, split);
00548     }
00549     xaccSplitSetLot(split, lot);
00550 
00551     priv->splits = g_list_append (priv->splits, split);
00552 
00553     /* for recomputation of is-closed */
00554     priv->is_closed = LOT_CLOSED_UNKNOWN;
00555     gnc_lot_commit_edit(lot);
00556 
00557     qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
00558     LEAVE("added to lot");
00559 }

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 306 of file gnc-lot.c.

00307 {
00308     LotPrivate* priv;
00309     if (!lot) return NULL;
00310     priv = GET_PRIVATE(lot);
00311     return priv->account;
00312 }

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 419 of file gnc-lot.c.

00420 {
00421     LotPrivate* priv;
00422     GList *node;
00423     gnc_numeric zero = gnc_numeric_zero();
00424     gnc_numeric baln = zero;
00425     if (!lot) return zero;
00426 
00427     priv = GET_PRIVATE(lot);
00428     if (!priv->splits)
00429     {
00430         priv->is_closed = FALSE;
00431         return zero;
00432     }
00433 
00434     /* Sum over splits; because they all belong to same account
00435      * they will have same denominator.
00436      */
00437     for (node = priv->splits; node; node = node->next)
00438     {
00439         Split *s = node->data;
00440         gnc_numeric amt = xaccSplitGetAmount (s);
00441         baln = gnc_numeric_add_fixed (baln, amt);
00442     }
00443 
00444     /* cache a zero balance as a closed lot */
00445     if (gnc_numeric_equal (baln, zero))
00446     {
00447         priv->is_closed = TRUE;
00448     }
00449     else
00450     {
00451         priv->is_closed = FALSE;
00452     }
00453 
00454     return baln;
00455 }

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 460 of file gnc-lot.c.

00462 {
00463     LotPrivate* priv;
00464     GList *node;
00465     gnc_numeric zero = gnc_numeric_zero();
00466     gnc_numeric amt = zero;
00467     gnc_numeric val = zero;
00468 
00469     *amount = amt;
00470     *value = val;
00471     if (lot == NULL) return;
00472 
00473     priv = GET_PRIVATE(lot);
00474     if (priv->splits)
00475     {
00476         Transaction *ta, *tb;
00477         const Split *target;
00478         /* If this is a gains split, find the source of the gains and use
00479            its transaction for the comparison.  Gains splits are in separate
00480            transactions that may sort after non-gains transactions.  */
00481         target = xaccSplitGetGainsSourceSplit (split);
00482         if (target == NULL)
00483             target = split;
00484         tb = xaccSplitGetParent (target);
00485         for (node = priv->splits; node; node = node->next)
00486         {
00487             Split *s = node->data;
00488             Split *source = xaccSplitGetGainsSourceSplit (s);
00489             if (source == NULL)
00490                 source = s;
00491             ta = xaccSplitGetParent (source);
00492             if ((ta == tb && source != target) ||
00493                     xaccTransOrder (ta, tb) < 0)
00494             {
00495                 gnc_numeric tmpval = xaccSplitGetAmount (s);
00496                 amt = gnc_numeric_add_fixed (amt, tmpval);
00497                 tmpval = xaccSplitGetValue (s);
00498                 val = gnc_numeric_add_fixed (val, tmpval);
00499             }
00500         }
00501     }
00502 
00503     *amount = amt;
00504     *value = val;
00505 }

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 588 of file gnc-lot.c.

00589 {
00590     LotPrivate* priv;
00591     if (!lot) return NULL;
00592     priv = GET_PRIVATE(lot);
00593     if (! priv->splits) return NULL;
00594     priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00595     return priv->splits->data;
00596 }

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 599 of file gnc-lot.c.

00600 {
00601     LotPrivate* priv;
00602     SplitList *node;
00603 
00604     if (!lot) return NULL;
00605     priv = GET_PRIVATE(lot);
00606     if (! priv->splits) return NULL;
00607     priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
00608 
00609     for (node = priv->splits; node->next; node = node->next)
00610         ;
00611 
00612     return node->data;
00613 }

KvpFrame* gnc_lot_get_slots ( const GNCLot  ) 

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

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

00358 {
00359     return qof_instance_get_slots(QOF_INSTANCE(lot));
00360 }

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 363 of file gnc-lot.c.

00364 {
00365     LotPrivate* priv;
00366     if (!lot) return NULL;
00367     priv = GET_PRIVATE(lot);
00368     return priv->splits;
00369 }

const char* gnc_lot_get_title ( const GNCLot  ) 

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

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

00384 {
00385     if (!lot) return NULL;
00386     return kvp_frame_get_string (gnc_lot_get_slots(lot), "/title");
00387 }

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 296 of file gnc-lot.c.

00297 {
00298     LotPrivate* priv;
00299     if (!lot) return TRUE;
00300     priv = GET_PRIVATE(lot);
00301     if (0 > priv->is_closed) gnc_lot_get_balance (lot);
00302     return priv->is_closed;
00303 }

GNCLot* gnc_lot_make_default ( Account acc  ) 

XXX: Document?

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

00678 {
00679     GNCLot * lot;
00680     gint64 id;
00681     char buff[200];
00682 
00683     lot = gnc_lot_new (qof_instance_get_book(acc));
00684 
00685     /* Provide a reasonable title for the new lot */
00686     id = kvp_frame_get_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id");
00687     snprintf (buff, 200, ("%s %" G_GINT64_FORMAT), _("Lot"), id);
00688     kvp_frame_set_str (gnc_lot_get_slots (lot), "/title", buff);
00689     id ++;
00690     kvp_frame_set_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id", id);
00691 
00692     return lot;
00693 }

void gnc_lot_set_closed_unknown ( GNCLot  ) 

Reset closed flag so that it will be recalculated.

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

00347 {
00348     LotPrivate* priv;
00349     if (lot != NULL)
00350     {
00351         priv = GET_PRIVATE(lot);
00352         priv->is_closed = LOT_CLOSED_UNKNOWN;
00353     }
00354 }


Generated on Thu Mar 18 04:44:42 2010 for GnuCash by  doxygen 1.5.7.1