GnuCash  4.12-74-g36b33262ad+
Files | Data Structures | Macros | Functions
Lots: Core Function for AR/AP, Inventory, Stock Lots, Cap Gains

One often needs to know that the item 'bought' in one transaction is the same one as the item 'sold' in a different transaction. More...

Files

file  gnc-lot.h
 

Data Structures

struct  GncLotClass
 

Macros

#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)
 
GNCLot * gnc_lot_new (QofBook *)
 
void gnc_lot_destroy (GNCLot *)
 
GNCLot * gnc_lot_lookup (const GncGUID *guid, QofBook *book)
 
QofBook * gnc_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 *)
 The gnc_lot_add_split() routine adds a split to this lot. More...
 
void gnc_lot_remove_split (GNCLot *, Split *)
 
SplitListgnc_lot_get_split_list (const GNCLot *)
 The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot. More...
 
gint gnc_lot_count_splits (const GNCLot *)
 
Accountgnc_lot_get_account (const GNCLot *)
 The gnc_lot_get_account() routine returns the account with which this lot is associated. More...
 
void gnc_lot_set_account (GNCLot *, Account *)
 
GncInvoice * gnc_lot_get_cached_invoice (const GNCLot *lot)
 The gnc_lot_get_cached_invoice() routine returns the invoice with which this lot is associated. More...
 
void gnc_lot_set_cached_invoice (GNCLot *lot, GncInvoice *invoice)
 
gnc_numeric gnc_lot_get_balance (GNCLot *)
 The gnc_lot_get_balance() routine returns the balance of the lot. More...
 
void gnc_lot_get_balance_before (const GNCLot *, const Split *, gnc_numeric *, gnc_numeric *)
 The gnc_lot_get_balance_before routine 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. More...
 
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. More...
 
Split * gnc_lot_get_earliest_split (GNCLot *lot)
 The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest date in the lot. More...
 
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. More...
 
void gnc_lot_set_closed_unknown (GNCLot *)
 Reset closed flag so that it will be recalculated. More...
 
const char * gnc_lot_get_title (const GNCLot *)
 Get and set the account title, or the account notes, or the marker. More...
 
const char * gnc_lot_get_notes (const GNCLot *)
 
void gnc_lot_set_title (GNCLot *, const char *)
 
void gnc_lot_set_notes (GNCLot *, const char *)
 
GNCLot * gnc_lot_make_default (Account *acc)
 XXX: Document?
 

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 account 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

◆ gnc_lot_add_split()

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

627 {
628  GNCLotPrivate* priv;
629  Account * acc;
630  if (!lot || !split) return;
631  priv = GET_PRIVATE(lot);
632 
633  ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
634  gnc_lot_get_title (lot),
635  gnc_num_dbg_to_string (split->amount),
636  gnc_num_dbg_to_string (split->value));
637  gnc_lot_begin_edit(lot);
638  acc = xaccSplitGetAccount (split);
639  qof_instance_set_dirty(QOF_INSTANCE(lot));
640  if (NULL == priv->account)
641  {
642  xaccAccountInsertLot (acc, lot);
643  }
644  else if (priv->account != acc)
645  {
646  PERR ("splits from different accounts cannot "
647  "be added to this lot!\n"
648  "\tlot account=\'%s\', split account=\'%s\'\n",
649  xaccAccountGetName(priv->account), xaccAccountGetName (acc));
650  gnc_lot_commit_edit(lot);
651  LEAVE("different accounts");
652  return;
653  }
654 
655  if (lot == split->lot)
656  {
657  gnc_lot_commit_edit(lot);
658  LEAVE("already in lot");
659  return; /* handle not-uncommon no-op */
660  }
661  if (split->lot)
662  {
663  gnc_lot_remove_split (split->lot, split);
664  }
665  xaccSplitSetLot(split, lot);
666 
667  priv->splits = g_list_append (priv->splits, split);
668 
669  /* for recomputation of is-closed */
670  priv->is_closed = LOT_CLOSED_UNKNOWN;
671  gnc_lot_commit_edit(lot);
672 
673  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
674  LEAVE("added to lot");
675 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2143
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:460
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.c:1883
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition: Account.cpp:3301
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231

◆ gnc_lot_get_account()

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

393 {
394  GNCLotPrivate* priv;
395  if (!lot) return NULL;
396  priv = GET_PRIVATE(lot);
397  return priv->account;
398 }

◆ gnc_lot_get_balance()

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

535 {
536  GNCLotPrivate* priv;
537  GList *node;
538  gnc_numeric zero = gnc_numeric_zero();
539  gnc_numeric baln = zero;
540  if (!lot) return zero;
541 
542  priv = GET_PRIVATE(lot);
543  if (!priv->splits)
544  {
545  priv->is_closed = FALSE;
546  return zero;
547  }
548 
549  /* Sum over splits; because they all belong to same account
550  * they will have same denominator.
551  */
552  for (node = priv->splits; node; node = node->next)
553  {
554  Split *s = node->data;
555  gnc_numeric amt = xaccSplitGetAmount (s);
556  baln = gnc_numeric_add_fixed (baln, amt);
557  g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
558  }
559 
560  /* cache a zero balance as a closed lot */
561  if (gnc_numeric_equal (baln, zero))
562  {
563  priv->is_closed = TRUE;
564  }
565  else
566  {
567  priv->is_closed = FALSE;
568  }
569 
570  return baln;
571 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
No error.
Definition: gnc-numeric.h:224
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Definition: gmock-Split.cpp:69

◆ gnc_lot_get_balance_before()

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

The gnc_lot_get_balance_before routine 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 576 of file gnc-lot.c.

578 {
579  GNCLotPrivate* priv;
580  GList *node;
581  gnc_numeric zero = gnc_numeric_zero();
582  gnc_numeric amt = zero;
583  gnc_numeric val = zero;
584 
585  *amount = amt;
586  *value = val;
587  if (lot == NULL) return;
588 
589  priv = GET_PRIVATE(lot);
590  if (priv->splits)
591  {
592  Transaction *ta, *tb;
593  const Split *target;
594  /* If this is a gains split, find the source of the gains and use
595  its transaction for the comparison. Gains splits are in separate
596  transactions that may sort after non-gains transactions. */
597  target = xaccSplitGetGainsSourceSplit (split);
598  if (target == NULL)
599  target = split;
600  tb = xaccSplitGetParent (target);
601  for (node = priv->splits; node; node = node->next)
602  {
603  Split *s = node->data;
604  Split *source = xaccSplitGetGainsSourceSplit (s);
605  if (source == NULL)
606  source = s;
607  ta = xaccSplitGetParent (source);
608  if ((ta == tb && source != target) ||
609  xaccTransOrder (ta, tb) < 0)
610  {
611  gnc_numeric tmpval = xaccSplitGetAmount (s);
612  amt = gnc_numeric_add_fixed (amt, tmpval);
613  tmpval = xaccSplitGetValue (s);
614  val = gnc_numeric_add_fixed (val, tmpval);
615  }
616  }
617  }
618 
619  *amount = amt;
620  *value = val;
621 }
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.c:505
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
The xaccTransOrder(ta,tb) method is useful for sorting.
Definition: Transaction.c:1896
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69

◆ gnc_lot_get_cached_invoice()

GncInvoice* gnc_lot_get_cached_invoice ( const GNCLot *  lot)

The gnc_lot_get_cached_invoice() routine returns the invoice with which this lot is associated.

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

401 {
402  if (!lot) return NULL;
403  else
404  {
405  GNCLotPrivate *priv = GET_PRIVATE(lot);
406  return priv->cached_invoice;
407  }
408 }

◆ gnc_lot_get_earliest_split()

Split* gnc_lot_get_earliest_split ( GNCLot *  lot)

The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest date in the lot.

It simply loops over all of the splits in the lot, and returns the split with the earliest split->transaction->date_posted. It may not necessarily identify the lot opening split.

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

706 {
707  GNCLotPrivate* priv;
708  if (!lot) return NULL;
709  priv = GET_PRIVATE(lot);
710  if (! priv->splits) return NULL;
711  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
712  return priv->splits->data;
713 }

◆ gnc_lot_get_latest_split()

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

718 {
719  GNCLotPrivate* priv;
720  SplitList *node;
721 
722  if (!lot) return NULL;
723  priv = GET_PRIVATE(lot);
724  if (! priv->splits) return NULL;
725  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
726 
727  for (node = priv->splits; node->next; node = node->next)
728  ;
729 
730  return node->data;
731 }
GList SplitList
GList of Split.
Definition: gnc-engine.h:211

◆ gnc_lot_get_split_list()

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 free this list when done; it is a pointer straight into the lots internal 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 440 of file gnc-lot.c.

441 {
442  GNCLotPrivate* priv;
443  if (!lot) return NULL;
444  priv = GET_PRIVATE(lot);
445  return priv->splits;
446 }

◆ gnc_lot_get_title()

const char* gnc_lot_get_title ( const GNCLot *  )

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

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

461 {
462  GNCLotPrivate* priv;
463  if (!lot) return NULL;
464  priv = GET_PRIVATE (lot);
465  if (priv->title == is_unset)
466  {
467  GNCLotPrivate* priv = GET_PRIVATE (lot);
468  GValue v = G_VALUE_INIT;
469  qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
470  priv->title = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
471  g_value_unset (&v);
472  }
473  return priv->title;
474 }
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.

◆ gnc_lot_is_closed()

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

383 {
384  GNCLotPrivate* priv;
385  if (!lot) return TRUE;
386  priv = GET_PRIVATE(lot);
387  if (0 > priv->is_closed) gnc_lot_get_balance (lot);
388  return priv->is_closed;
389 }
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:534

◆ gnc_lot_set_closed_unknown()

void gnc_lot_set_closed_unknown ( GNCLot *  )

Reset closed flag so that it will be recalculated.

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

430 {
431  GNCLotPrivate* priv;
432  if (lot != NULL)
433  {
434  priv = GET_PRIVATE(lot);
435  priv->is_closed = LOT_CLOSED_UNKNOWN;
436  }
437 }