GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Files | Data Structures | Macros | Functions
Lots: Core Function for AR/AP, Inventory, Stock Lots, Cap Gains

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)
 
GNCLotgnc_lot_new (QofBook *)
 
void gnc_lot_destroy (GNCLot *)
 
GNCLotgnc_lot_lookup (const GncGUID *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 *)
 
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 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

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

570 {
571  LotPrivate* priv;
572  Account * acc;
573  if (!lot || !split) return;
574  priv = GET_PRIVATE(lot);
575 
576  ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
577  gnc_lot_get_title (lot),
578  gnc_num_dbg_to_string (split->amount),
579  gnc_num_dbg_to_string (split->value));
580  gnc_lot_begin_edit(lot);
581  acc = xaccSplitGetAccount (split);
582  qof_instance_set_dirty(QOF_INSTANCE(lot));
583  if (NULL == priv->account)
584  {
585  xaccAccountInsertLot (acc, lot);
586  }
587  else if (priv->account != acc)
588  {
589  PERR ("splits from different accounts cannot "
590  "be added to this lot!\n"
591  "\tlot account=\'%s\', split account=\'%s\'\n",
592  xaccAccountGetName(priv->account), xaccAccountGetName (acc));
593  gnc_lot_commit_edit(lot);
594  LEAVE("different accounts");
595  return;
596  }
597 
598  if (lot == split->lot)
599  {
600  gnc_lot_commit_edit(lot);
601  LEAVE("already in lot");
602  return; /* handle not-uncommon no-op */
603  }
604  if (split->lot)
605  {
606  gnc_lot_remove_split (split->lot, split);
607  }
608  xaccSplitSetLot(split, lot);
609 
610  priv->splits = g_list_append (priv->splits, split);
611 
612  /* for recomputation of is-closed */
613  priv->is_closed = LOT_CLOSED_UNKNOWN;
614  gnc_lot_commit_edit(lot);
615 
616  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
617  LEAVE("added to lot");
618 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
Definition: Account.c:1920
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
void xaccSplitSetLot(Split *split, GNCLot *lot)
Definition: Split.c:1959
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
#define LEAVE(format, args...)
Definition: qoflog.h:271
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
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 386 of file gnc-lot.c.

387 {
388  LotPrivate* priv;
389  if (!lot) return NULL;
390  priv = GET_PRIVATE(lot);
391  return priv->account;
392 }
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 477 of file gnc-lot.c.

478 {
479  LotPrivate* priv;
480  GList *node;
481  gnc_numeric zero = gnc_numeric_zero();
482  gnc_numeric baln = zero;
483  if (!lot) return zero;
484 
485  priv = GET_PRIVATE(lot);
486  if (!priv->splits)
487  {
488  priv->is_closed = FALSE;
489  return zero;
490  }
491 
492  /* Sum over splits; because they all belong to same account
493  * they will have same denominator.
494  */
495  for (node = priv->splits; node; node = node->next)
496  {
497  Split *s = node->data;
499  baln = gnc_numeric_add_fixed (baln, amt);
500  g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
501  }
502 
503  /* cache a zero balance as a closed lot */
504  if (gnc_numeric_equal (baln, zero))
505  {
506  priv->is_closed = TRUE;
507  }
508  else
509  {
510  priv->is_closed = FALSE;
511  }
512 
513  return baln;
514 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Definition: SplitP.h:71
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
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 519 of file gnc-lot.c.

521 {
522  LotPrivate* priv;
523  GList *node;
524  gnc_numeric zero = gnc_numeric_zero();
525  gnc_numeric amt = zero;
526  gnc_numeric val = zero;
527 
528  *amount = amt;
529  *value = val;
530  if (lot == NULL) return;
531 
532  priv = GET_PRIVATE(lot);
533  if (priv->splits)
534  {
535  Transaction *ta, *tb;
536  const Split *target;
537  /* If this is a gains split, find the source of the gains and use
538  its transaction for the comparison. Gains splits are in separate
539  transactions that may sort after non-gains transactions. */
540  target = xaccSplitGetGainsSourceSplit (split);
541  if (target == NULL)
542  target = split;
543  tb = xaccSplitGetParent (target);
544  for (node = priv->splits; node; node = node->next)
545  {
546  Split *s = node->data;
547  Split *source = xaccSplitGetGainsSourceSplit (s);
548  if (source == NULL)
549  source = s;
550  ta = xaccSplitGetParent (source);
551  if ((ta == tb && source != target) ||
552  xaccTransOrder (ta, tb) < 0)
553  {
554  gnc_numeric tmpval = xaccSplitGetAmount (s);
555  amt = gnc_numeric_add_fixed (amt, tmpval);
556  tmpval = xaccSplitGetValue (s);
557  val = gnc_numeric_add_fixed (val, tmpval);
558  }
559  }
560  }
561 
562  *amount = amt;
563  *value = val;
564 }
Split * xaccSplitGetGainsSourceSplit(const Split *split)
Definition: cap-gains.c:514
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
Definition: Transaction.c:1827
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
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 648 of file gnc-lot.c.

649 {
650  LotPrivate* priv;
651  if (!lot) return NULL;
652  priv = GET_PRIVATE(lot);
653  if (! priv->splits) return NULL;
654  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
655  return priv->splits->data;
656 }
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 660 of file gnc-lot.c.

661 {
662  LotPrivate* priv;
663  SplitList *node;
664 
665  if (!lot) return NULL;
666  priv = GET_PRIVATE(lot);
667  if (! priv->splits) return NULL;
668  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
669 
670  for (node = priv->splits; node->next; node = node->next)
671  ;
672 
673  return node->data;
674 }
GList SplitList
Definition: gnc-engine.h:203
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 417 of file gnc-lot.c.

418 {
419  LotPrivate* priv;
420  if (!lot) return NULL;
421  priv = GET_PRIVATE(lot);
422  return priv->splits;
423 }
const char* gnc_lot_get_title ( const GNCLot )

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

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

438 {
439  if (!lot) return NULL;
440  return kvp_frame_get_string (qof_instance_get_slots(QOF_INSTANCE (lot)),
441  "/title");
442 }
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 376 of file gnc-lot.c.

377 {
378  LotPrivate* priv;
379  if (!lot) return TRUE;
380  priv = GET_PRIVATE(lot);
381  if (0 > priv->is_closed) gnc_lot_get_balance (lot);
382  return priv->is_closed;
383 }
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
GNCLot* gnc_lot_make_default ( Account acc)

XXX: Document?

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

756 {
757  GNCLot * lot;
758  gint64 id = 0;
759  gchar *buff;
760 
761  lot = gnc_lot_new (qof_instance_get_book(acc));
762 
763  /* Provide a reasonable title for the new lot */
764  xaccAccountBeginEdit (acc);
765  qof_instance_get (QOF_INSTANCE (acc), "lot-next-id", &id, NULL);
766  buff = g_strdup_printf ("%s %" G_GINT64_FORMAT, _("Lot"), id);
767  gnc_lot_set_title (lot, buff);
768  id ++;
769  qof_instance_set (QOF_INSTANCE (acc), "lot-next-id", id, NULL);
770  xaccAccountCommitEdit (acc);
771  g_free (buff);
772  return lot;
773 }
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
QofBook * qof_instance_get_book(gconstpointer)
void qof_instance_set(QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void gnc_lot_set_closed_unknown ( GNCLot )

Reset closed flag so that it will be recalculated.

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

407 {
408  LotPrivate* priv;
409  if (lot != NULL)
410  {
411  priv = GET_PRIVATE(lot);
412  priv->is_closed = LOT_CLOSED_UNKNOWN;
413  }
414 }