GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 *)
 Adds a split to this lot. More...
 
void gnc_lot_remove_split (GNCLot *, Split *)
 Adds a split from this lot.
 
SplitListgnc_lot_get_split_list (const GNCLot *)
 Returns a list of all the splits in this lot. More...
 
gint gnc_lot_count_splits (const GNCLot *)
 
Accountgnc_lot_get_account (const GNCLot *)
 Returns the account with which this lot is associated.
 
void gnc_lot_set_account (GNCLot *, Account *)
 
GncInvoice * gnc_lot_get_cached_invoice (const GNCLot *lot)
 Returns the invoice with which this lot is associated.
 
void gnc_lot_set_cached_invoice (GNCLot *lot, GncInvoice *invoice)
 
gnc_numeric gnc_lot_get_balance (GNCLot *)
 Returns the lot balance. More...
 
void gnc_lot_get_balance_before (const GNCLot *, const Split *, gnc_numeric *, gnc_numeric *)
 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 *)
 Returns closed status of the given lot. More...
 
Split * gnc_lot_get_earliest_split (GNCLot *lot)
 Convenience routine to identify the earliest date in the lot. More...
 
Split * gnc_lot_get_latest_split (GNCLot *lot)
 Convenience routineto 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...
 
GNCLot * gnc_lot_make_default (Account *acc)
 

Get/set the account title and notes.

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 *)
 

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 *   
)

Adds a split to this lot.

Note
  • All splits in a lot must be in the same account.
  • Splits are added unconditionally, with no regard for the accounting policy. To enforce a particular accounting policy, use the xaccSplitAssignToLot() routine instead.

Definition at line 579 of file gnc-lot.cpp.

580 {
581  GNCLotPrivate* priv;
582  Account * acc;
583  if (!lot || !split) return;
584  priv = GET_PRIVATE(lot);
585 
586  ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
587  gnc_lot_get_title (lot),
588  gnc_num_dbg_to_string (split->amount),
589  gnc_num_dbg_to_string (split->value));
590  gnc_lot_begin_edit(lot);
591  acc = xaccSplitGetAccount (split);
592  qof_instance_set_dirty(QOF_INSTANCE(lot));
593  if (nullptr == priv->account)
594  {
595  xaccAccountInsertLot (acc, lot);
596  }
597  else if (priv->account != acc)
598  {
599  PERR ("splits from different accounts cannot "
600  "be added to this lot!\n"
601  "\tlot account=\'%s\', split account=\'%s\'\n",
602  xaccAccountGetName(priv->account), xaccAccountGetName (acc));
603  gnc_lot_commit_edit(lot);
604  LEAVE("different accounts");
605  return;
606  }
607 
608  if (lot == split->lot)
609  {
610  gnc_lot_commit_edit(lot);
611  LEAVE("already in lot");
612  return; /* handle not-uncommon no-op */
613  }
614  if (split->lot)
615  {
616  gnc_lot_remove_split (split->lot, split);
617  }
618  xaccSplitSetLot(split, lot);
619 
620  priv->splits = g_list_append (priv->splits, split);
621 
622  /* for recomputation of is-closed */
623  priv->is_closed = LOT_CLOSED_UNKNOWN;
624  gnc_lot_commit_edit(lot);
625 
626  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, nullptr);
627  LEAVE("added to lot");
628 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
STRUCTS.
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2142
#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
void gnc_lot_remove_split(GNCLot *lot, Split *split)
Adds a split from this lot.
Definition: gnc-lot.cpp:631
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.cpp:1890
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:3259
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_balance()

gnc_numeric gnc_lot_get_balance ( GNCLot *  )

Returns the lot balance.

This balance will be expressed in the lot account's commodity.

Definition at line 487 of file gnc-lot.cpp.

488 {
489  GNCLotPrivate* priv;
490  GList *node;
491  gnc_numeric zero = gnc_numeric_zero();
492  gnc_numeric baln = zero;
493  if (!lot) return zero;
494 
495  priv = GET_PRIVATE(lot);
496  if (!priv->splits)
497  {
498  priv->is_closed = FALSE;
499  return zero;
500  }
501 
502  /* Sum over splits; because they all belong to same account
503  * they will have same denominator.
504  */
505  for (node = priv->splits; node; node = node->next)
506  {
507  Split *s = GNC_SPLIT(node->data);
508  gnc_numeric amt = xaccSplitGetAmount (s);
509  baln = gnc_numeric_add_fixed (baln, amt);
510  g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
511  }
512 
513  /* cache a zero balance as a closed lot */
514  if (gnc_numeric_equal (baln, zero))
515  {
516  priv->is_closed = TRUE;
517  }
518  else
519  {
520  priv->is_closed = FALSE;
521  }
522 
523  return baln;
524 }
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 a)
Check for error signal in value.
No error.
Definition: gnc-numeric.h:223
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 *   
)

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 529 of file gnc-lot.cpp.

531 {
532  GNCLotPrivate* priv;
533  GList *node;
534  gnc_numeric zero = gnc_numeric_zero();
535  gnc_numeric amt = zero;
536  gnc_numeric val = zero;
537 
538  *amount = amt;
539  *value = val;
540  if (lot == nullptr) return;
541 
542  priv = GET_PRIVATE(lot);
543  if (priv->splits)
544  {
545  Transaction *ta, *tb;
546  const Split *target;
547  /* If this is a gains split, find the source of the gains and use
548  its transaction for the comparison. Gains splits are in separate
549  transactions that may sort after non-gains transactions. */
550  target = xaccSplitGetGainsSourceSplit (split);
551  if (target == nullptr)
552  target = split;
553  tb = xaccSplitGetParent (target);
554  for (node = priv->splits; node; node = node->next)
555  {
556  Split *s = GNC_SPLIT(node->data);
557  Split *source = xaccSplitGetGainsSourceSplit (s);
558  if (source == nullptr)
559  source = s;
560  ta = xaccSplitGetParent (source);
561  if ((ta == tb && source != target) ||
562  xaccTransOrder (ta, tb) < 0)
563  {
564  gnc_numeric tmpval = xaccSplitGetAmount (s);
565  amt = gnc_numeric_add_fixed (amt, tmpval);
566  tmpval = xaccSplitGetValue (s);
567  val = gnc_numeric_add_fixed (val, tmpval);
568  }
569  }
570  }
571 
572  *amount = amt;
573  *value = val;
574 }
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.cpp:503
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.
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_earliest_split()

Split* gnc_lot_get_earliest_split ( GNCLot *  lot)

Convenience routine to identify the earliest date in the lot.

It 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 658 of file gnc-lot.cpp.

659 {
660  GNCLotPrivate* priv;
661  if (!lot) return nullptr;
662  priv = GET_PRIVATE(lot);
663  if (! priv->splits) return nullptr;
664  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
665  return GNC_SPLIT(priv->splits->data);
666 }

◆ gnc_lot_get_latest_split()

Split* gnc_lot_get_latest_split ( GNCLot *  lot)

Convenience routineto 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 670 of file gnc-lot.cpp.

671 {
672  GNCLotPrivate* priv;
673  SplitList *node;
674 
675  if (!lot) return nullptr;
676  priv = GET_PRIVATE(lot);
677  if (! priv->splits) return nullptr;
678  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
679 
680  for (node = priv->splits; node->next; node = node->next)
681  ;
682 
683  return GNC_SPLIT(node->data);
684 }
GList SplitList
GList of Split.
Definition: gnc-engine.h:207

◆ gnc_lot_get_split_list()

SplitList* gnc_lot_get_split_list ( const GNCLot *  )

Returns a list of all the splits in this lot.

Returns
GList

This GList is owned and managed by the lot.

Definition at line 425 of file gnc-lot.cpp.

426 {
427  GNCLotPrivate* priv;
428  if (!lot) return nullptr;
429  priv = GET_PRIVATE(lot);
430  return priv->splits;
431 }

◆ gnc_lot_is_closed()

gboolean gnc_lot_is_closed ( GNCLot *  )

Returns closed status of the given lot.

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.

Returns
boolean

Definition at line 367 of file gnc-lot.cpp.

368 {
369  GNCLotPrivate* priv;
370  if (!lot) return TRUE;
371  priv = GET_PRIVATE(lot);
372  if (0 > priv->is_closed) gnc_lot_get_balance (lot);
373  return priv->is_closed;
374 }
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition: gnc-lot.cpp:487

◆ gnc_lot_make_default()

GNCLot* gnc_lot_make_default ( Account acc)
Todo:
Document this function ?

Definition at line 765 of file gnc-lot.cpp.

766 {
767  GNCLot * lot;
768  gint64 id = 0;
769  gchar *buff;
770 
771  lot = gnc_lot_new (qof_instance_get_book(acc));
772 
773  /* Provide a reasonable title for the new lot */
774  xaccAccountBeginEdit (acc);
775  qof_instance_get (QOF_INSTANCE (acc), "lot-next-id", &id, nullptr);
776  buff = g_strdup_printf ("%s %" G_GINT64_FORMAT, _("Lot"), id);
777  gnc_lot_set_title (lot, buff);
778  id ++;
779  qof_instance_set (QOF_INSTANCE (acc), "lot-next-id", id, nullptr);
780  xaccAccountCommitEdit (acc);
781  g_free (buff);
782  return lot;
783 }
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1477
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1518

◆ gnc_lot_set_closed_unknown()

void gnc_lot_set_closed_unknown ( GNCLot *  )

Reset closed flag so that it will be recalculated.

Definition at line 414 of file gnc-lot.cpp.

415 {
416  GNCLotPrivate* priv;
417  if (lot != nullptr)
418  {
419  priv = GET_PRIVATE(lot);
420  priv->is_closed = LOT_CLOSED_UNKNOWN;
421  }
422 }