GnuCash  3.1-61-g2e8df19+
Files | Functions

This file implements the various routines to automatically compute and handle Cap Gains/Losses resulting from trading activities. More...

Files

file  cap-gains.h
 Utilities to Automatically Compute Capital Gains/Losses.
 

Functions

gnc_numeric xaccSplitGetCapGains (Split *)
 The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the indicated split. More...
 
gboolean xaccAccountHasTrades (const Account *)
 The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of commodities. More...
 
GNCLot * xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign, gnc_commodity *currency)
 The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open lot in an account whose lot balance is opposite to the passed argument 'sign'. More...
 
GNCLot * xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign, gnc_commodity *currency)
 
Split * xaccSplitGetCapGainsSplit (const Split *)
 The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split. More...
 
Split * xaccSplitGetGainsSourceSplit (const Split *)
 The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in this split. More...
 
gboolean xaccSplitAssign (Split *split)
 The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lot, it will attempt to assign it to an appropriate lot. More...
 
Split * xaccSplitAssignToLot (Split *split, GNCLot *lot)
 The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot, with the goal of closing the lot, or at least bringing the lot balance closer to closure. More...
 
void xaccSplitComputeCapGains (Split *split, Account *gain_acc)
 The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split. More...
 
void xaccLotComputeCapGains (GNCLot *lot, Account *gain_acc)
 

Detailed Description

This file implements the various routines to automatically compute and handle Cap Gains/Losses resulting from trading activities.

Some of these routines might have broader applicability, for handling depreciation & etc.

This code is under development, and is 'beta': we think we're mostly done, and we've tested and "things work for us", but there may still be something missing, and there might still be some bugs.

This code does not currently handle tax distinctions, e.g the different tax treatment that short-term and long-term cap gains have.

The computation of (Realized) Gains/Losses is performed automatically by the lot "scrub" routines, using a "double-balance" algorithm. Every split has two numbers associated with it: an "amount", which is the number of items that a split describes, and the "value", which is the cost of those items. In a closed lot, the grand-total amount of items in the lot is zero: the number of items bought equals the number of items sold; thus the amount-balance is zero. But since the purchase/sale of the items in the lot typically happen at different prices, there will typically be a gain/loss. This gain/loss is the grand-total value of all the items in the lot (total costs minus total income).

In order to properly account for the gains/losses, an "adjusting split" is added that brings the total gains/losses back to exactly zero (this is the second "balance" of "double balance"). This adjusting split will have an amount of zero (no items are involved) but have a non-zero value (equal to the total gain/loss). This split can then participate in a "gains transaction" which records the gains in another account. Thus, for example, if you record $300 in your bank account due to the purchase and then the sale of some item, the "gains transaction" will record $300 in income in an income account. Thus, the change in the bank balance is always reflected by an equal change in income, assuring that the books are balanced.

Notes about auto-recompute: If the amount in a split is changed, then the lot has to be recomputed. This has a potential trickle-through effect on all later lots. Ideally, later lots are dissolved, and recomputed. However, some lots may have been user-hand-built. These should be left alone.

ToDo: o XXX Need to create a data-integrity scrubber, tht makes sure that the various flags, and pointers & etc. match.

Function Documentation

◆ xaccAccountFindEarliestOpenLot()

GNCLot* xaccAccountFindEarliestOpenLot ( Account acc,
gnc_numeric  sign,
gnc_commodity *  currency 
)

The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open lot in an account whose lot balance is opposite to the passed argument 'sign'.

By 'earliest lot', we mean the lot that has a split with the earliest 'date_posted'. The sign comparison helps identify a lot that can be added to: usually, one wants to add splits to a lot so that the balance only decreases. If 'currency' is non-null, then this attempts to find a lot whose opening transaction has the same currency.

Definition at line 193 of file cap-gains.c.

195 {
196  GNCLot *lot;
197  ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, sign.num,
198  sign.denom);
199 
200  lot = xaccAccountFindOpenLot (acc, sign, currency,
201  G_MAXINT64, earliest_pred);
202  LEAVE ("found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
204  return lot;
205 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:266
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:426
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:276
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:476

◆ xaccAccountHasTrades()

gboolean xaccAccountHasTrades ( const Account )

The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of commodities.

A 'trading' account will contain transactions whose transaction currency is not the same as the account commodity. The existence of such transactions is the very definition of a 'trade'. This routine returns TRUE if this is a trading account, else it returns FALSE.

Definition at line 79 of file cap-gains.c.

80 {
81  gnc_commodity *acc_comm;
82  SplitList *splits, *node;
83 
84  if (!acc) return FALSE;
85 
86  if (xaccAccountIsPriced (acc))
87  return TRUE;
88 
89  acc_comm = xaccAccountGetCommodity(acc);
90 
91  splits = xaccAccountGetSplitList(acc);
92  for (node = splits; node; node = node->next)
93  {
94  Split *s = node->data;
95  Transaction *t = s->parent;
96  if (s->gains == GAINS_STATUS_GAINS) continue;
97  if (acc_comm != t->common_currency) return TRUE;
98  }
99 
100  return FALSE;
101 }
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3709
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4278
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.cpp:3147

◆ xaccSplitAssign()

gboolean xaccSplitAssign ( Split *  split)

The`xaccSplitAssign() routine will take the indicated split and, if it doesn't already belong to a lot, it will attempt to assign it to an appropriate lot.

If the split already belongs to a Lot, this routine does nothing. If there are no open Lots, this routine will create a new lot and place the split into it. If there's an open lot, and its big enough to accept the split in it's entirety, then the split will be placed into that lot. If the split is too big to fit into the currently open lot, it will be busted up into two (or more) pieces, and each placed into a lot accordingly. If the split needed to be broken up into several pieces, this routine will return TRUE, else it returns FALSE.

If the split had to be broken up, kvp markup in the "/lot-split" directory is used to identify the peers. 'gemini'-style kvp's are used.

This routine uses the "FIFOPolicy" callback, and thus implements a "FIFO" First-In First-Out accounting policy. This is currently the only implemented policy; adding new policies should be 'easy'; read the source luke.

Definition at line 432 of file cap-gains.c.

433 {
434  Account *acc;
435  gboolean splits_split_up = FALSE;
436  GNCLot *lot;
437  GNCPolicy *pcy;
438 
439  if (!split) return FALSE;
440 
441  /* If this split already belongs to a lot or the account doesn't
442  * have lots, we are done.
443  */
444  if (split->lot) return FALSE;
445  g_assert (split->gains == GAINS_STATUS_UNKNOWN ||
446  (split->gains & GAINS_STATUS_GAINS) == FALSE);
447  acc = split->acc;
448  if (!xaccAccountHasTrades (acc))
449  return FALSE;
450  if (gnc_numeric_zero_p (split->amount))
451  return FALSE;
452 
453  ENTER ("(split=%p)", split);
454 
455  pcy = gnc_account_get_policy(acc);
456  xaccAccountBeginEdit (acc);
457 
458  /* If we are here, this split does not belong to any lot.
459  * We ask the policy for a lot to assign it to. This
460  * block is written in the form of a while loop, since we
461  * may have to bust a split across several lots.
462  */
463  while (split)
464  {
465  PINFO ("have split %p amount=%s", split,
466  gnc_num_dbg_to_string (split->amount));
467  split->gains |= GAINS_STATUS_VDIRTY;
468  lot = pcy->PolicyGetLot (pcy, split);
469  if (!lot)
470  {
471  lot = gnc_lot_make_default (acc);
472  PINFO ("start new lot (%s)", gnc_lot_get_title(lot));
473  }
474  split = xaccSplitAssignToLot (split, lot);
475  if (split) splits_split_up = TRUE;
476  }
477  xaccAccountCommitEdit (acc);
478 
479  LEAVE (" split_up=%d", splits_split_up);
480  return splits_split_up;
481 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:254
STRUCTS.
gboolean xaccAccountHasTrades(const Account *acc)
The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of co...
Definition: cap-gains.c:79
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:266
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:426
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
Definition: cap-gains.c:224
GNCLot * gnc_lot_make_default(Account *acc)
XXX: Document?
Definition: gnc-lot.c:754
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1287
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:276
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1328
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition: Account.cpp:1887

◆ xaccSplitAssignToLot()

Split* xaccSplitAssignToLot ( Split *  split,
GNCLot *  lot 
)

The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot, with the goal of closing the lot, or at least bringing the lot balance closer to closure.

(A closed lot has a balance of zero). To make this "fit", a variety of checks and actions are performed. First, the lot must be open, and the sign of the split amount must be opposite to the sign of the lot balance. The 'opposite-sign' requirement is so that inserting the split will cause the size of the lot to decrease. If the amount of the split is too small, or is just right to close the lot, the split is added, and NULL is returned. If the split is larger than the lot balance, the split will be divided into sub-splits, one of which is just right to close the lot. A pointer to the other sub-split will be returned.

If the split had to be broken up, kvp markup in the "/lot-split" directory is used to identify the peers. 'gemini'-style kvp's are used.

Definition at line 224 of file cap-gains.c.

225 {
226  Account *acc;
227  gnc_numeric baln;
228  int cmp;
229  gboolean baln_is_positive, amt_is_positive;
230 
231  if (!lot) return split;
232  if (!split) return NULL;
233 
234  /* If this split already belongs to a lot, we are done. */
235  if (split->lot) return NULL;
236 
237  /* Anomolous situation; except for voided transactions,
238  * we don't expect to see splits with no amount ..
239  * unless they're gains splits, and we shouldn't see those.
240  */
241  if (gnc_numeric_zero_p (split->amount))
242  {
243  if (xaccTransGetVoidStatus(split->parent)) return NULL;
244 
245  PWARN ("split with zero amount; value=%s gflag=%x gsplit=%p",
246  gnc_num_dbg_to_string (split->amount),
247  split->gains,
248  split->gains_split);
249  if (split->gains_split)
250  {
251  PWARN ("gains amt=%s value=%s",
252  gnc_num_dbg_to_string (split->gains_split->amount),
253  gnc_num_dbg_to_string (split->gains_split->value));
254  }
255  return NULL;
256  }
257 
258  /* If the lot is closed, we can't add anything to it */
259  baln = gnc_lot_get_balance (lot);
260  if (gnc_lot_is_closed (lot)) return split;
261 
262  /* If the lot balance is zero, but the lot is open, then
263  * the lot is empty. Unconditionally add the split. */
264  if (gnc_numeric_zero_p (baln))
265  {
266  acc = split->acc;
267  xaccAccountBeginEdit (acc);
268  gnc_lot_add_split (lot, split);
269  PINFO ("added split to empty lot, new lot baln=%s (%s)",
271  gnc_lot_get_title (lot));
272  xaccAccountCommitEdit (acc);
273  return NULL;
274  }
275 
276  /* If the sign of the split is the same as the sign of the lot,
277  * add the split, but complain about it ... none of the currently
278  * implemented accounting policies should be giving us splits
279  * that make lots larger. One a lot is open, the FIFO/LIFO
280  * policies should be working only to make the lot smaller.
281  * We can remove the warning emssage come the day we have
282  * fancier policies.
283  */
284  baln_is_positive = gnc_numeric_positive_p (baln);
285  amt_is_positive = gnc_numeric_positive_p (split->amount);
286  if ((baln_is_positive && amt_is_positive) ||
287  ((!baln_is_positive) && (!amt_is_positive)))
288  {
289  PWARN ("accounting policy gave us split that enlarges the lot!\n"
290  "old lot baln=%s split amt=%s lot=%s",
292  gnc_num_dbg_to_string (split->amount),
293  gnc_lot_get_title (lot));
294 
295  acc = split->acc;
296  xaccAccountBeginEdit (acc);
297  gnc_lot_add_split (lot, split);
298  xaccAccountCommitEdit (acc);
299  return NULL;
300  }
301 
302  /* If adding the split would make the lot balance change sign,
303  * then we split the split into two pieces: one piece that will
304  * bring the lot balance to zero, and another to be dealt with
305  * later. */
306  cmp = gnc_numeric_compare (gnc_numeric_abs(split->amount),
307  gnc_numeric_abs(baln));
308 
309  PINFO ("found open lot with baln=%s (%s)", gnc_num_dbg_to_string (baln),
310  gnc_lot_get_title (lot));
311 
312  /* cmp == -1 if amt < baln, ==0 if amt==baln */
313  if (0 >= cmp)
314  {
315  acc = split->acc;
316  xaccAccountBeginEdit (acc);
317  gnc_lot_add_split (lot, split);
318  PINFO ("simple added split to lot, new lot baln=%s",
320  xaccAccountCommitEdit (acc);
321  return NULL;
322  }
323 
324  /* If we are here, then (cmp == +1 iff (amt > baln)) and we need
325  * to split up the split into pieces. Do it. */
326  {
327  time64 now = gnc_time (NULL);
328  Split * new_split;
329  gnc_numeric amt_a, amt_b, amt_tot;
330  gnc_numeric val_a, val_b, val_tot;
331  gnc_numeric frac;
332  Transaction *trans;
333  Timespec ts;
334 
335  acc = split->acc;
336  xaccAccountBeginEdit (acc);
337  trans = split->parent;
338  xaccTransBeginEdit (trans);
339 
340  amt_tot = split->amount;
341  amt_a = gnc_numeric_neg (baln);
342  amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
343  g_assert (gnc_numeric_check(amt_b) == GNC_ERROR_OK);
344 
345  PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
346  split,
347  gnc_num_dbg_to_string(amt_a),
348  gnc_num_dbg_to_string(amt_b) );
349 
350  /* Compute the value so that it holds in the same proportion:
351  * i.e. so that (amt_a / amt_tot) = (val_a / val_tot)
352  */
353  val_tot = split->value;
354  frac = gnc_numeric_div (amt_a, amt_tot,
356  val_a = gnc_numeric_mul (frac, val_tot,
357  gnc_numeric_denom(val_tot),
359 
360  val_b = gnc_numeric_sub_fixed (val_tot, val_a);
361  if (gnc_numeric_check(val_a))
362  {
363  PERR("Numeric overflow\n"
364  "Acct=%s Txn=%s\n"
365  "\tval_tot=%s amt_a=%s amt_tot=%s\n",
366  xaccAccountGetName(acc),
368  gnc_num_dbg_to_string(val_tot),
369  gnc_num_dbg_to_string(amt_a),
370  gnc_num_dbg_to_string(amt_tot));
371  }
372 
373  if (gnc_numeric_zero_p(val_a) || gnc_numeric_zero_p(val_b))
374  {
375  PERR ("Failed to split into two!");
376  }
377 
378  PINFO ("split value is = %s = %s + %s",
379  gnc_num_dbg_to_string(val_tot),
380  gnc_num_dbg_to_string(val_a),
381  gnc_num_dbg_to_string(val_b) );
382 
383  g_assert (!gnc_numeric_zero_p (amt_a));
384  g_assert (!gnc_numeric_zero_p (val_a));
385  xaccSplitSetAmount (split, amt_a);
386  xaccSplitSetValue (split, val_a);
387 
388  /* Adding this split will have the effect of closing this lot,
389  * because the new balance should be precisely zero. */
390  gnc_lot_add_split (lot, split);
391 
392  /* Put the remainder of the balance into a new split,
393  * which is in other respects just a clone of this one. */
394  new_split = xaccMallocSplit (qof_instance_get_book(acc));
395 
396  /* Copy most of the split attributes */
397  xaccSplitSetMemo (new_split, xaccSplitGetMemo (split));
398  /* Set split-action with gnc_set_num_action which is the same as
399  * xaccSplitSetAction with these arguments; use gnc_get_num_action to get
400  * split-action which is the same as xaccSplitGetAction */
401  gnc_set_num_action(NULL, new_split, NULL, gnc_get_num_action(NULL, split));
402  xaccSplitSetReconcile (new_split, xaccSplitGetReconcile (split));
403  ts = xaccSplitRetDateReconciledTS (split);
404  xaccSplitSetDateReconciledTS (new_split, &ts);
405 
406  /* Set the lot-split and peer_guid properties on the two
407  * splits to indicate that they're linked.
408  */
409  xaccSplitAddPeerSplit(split, new_split, now);
410  xaccSplitAddPeerSplit(new_split, split, now);
411  xaccAccountInsertSplit (acc, new_split);
412  xaccTransAppendSplit (trans, new_split);
413  /* Set the amount and value after the split is in the transaction
414  so it can find the correct denominator to use. Otherwise it
415  uses 100000 which may cause an overflow in some of the tests
416  in test-period */
417  xaccSplitSetAmount (new_split, amt_b);
418  xaccSplitSetValue (new_split, val_b);
419  xaccTransCommitEdit (trans);
420  xaccAccountCommitEdit (acc);
421  return new_split;
422  }
423 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: Split.c:1238
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:196
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split&#39;s lot-split list.
Definition: Split.c:1995
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:361
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:254
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
Timespec xaccSplitRetDateReconciledTS(const Split *split)
Returns the date (as Timespec) on which this split was reconciled.
Definition: Split.c:1801
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Definition: Split.c:1897
void gnc_lot_add_split(GNCLot *lot, Split *split)
The gnc_lot_add_split() routine adds a split to this lot.
Definition: gnc-lot.c:568
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Definition: Split.c:1743
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:242
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
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:426
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:248
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: Split.c:1202
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1691
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2307
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Definition: Transaction.c:1628
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Definition: Transaction.c:1429
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.c:526
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2670
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:365
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1287
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:990
void xaccSplitSetDateReconciledTS(Split *split, Timespec *ts)
Set the date on which this split was reconciled by specifying the time as Timespec.
Definition: Split.c:1782
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:248
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: Split.c:1885
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:84
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3024
No error.
Definition: gnc-numeric.h:224
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1328
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:476

◆ xaccSplitComputeCapGains()

void xaccSplitComputeCapGains ( Split *  split,
Account gain_acc 
)

The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split.

The gains are placed into the 'gains_acct'. If the gains_acct is NULL, then the appropriate default account is used (and created, if needed).

To compute the gains, the split must belong to a lot. If the split is the 'opening split', i.e. the earliest split in the lot, then nothing is done, as there are no gains/losses (something must be bought and sold for there to be a gain/loss).

Note also: the 'amount' of the split must be of opposite sign, and must be equal to or smaller, than the 'amount' of the opening split; its an error otherwise. If the 'amount' of the split is less than the opening amount, the gains are pro-rated.

The xaccLotComputeCapGains() routine merely invokes the above on each split in the lot.

Definition at line 530 of file cap-gains.c.

531 {
532  SplitList *node;
533  GNCLot *lot;
534  GNCPolicy *pcy;
535  gnc_commodity *currency = NULL;
536  gnc_numeric zero = gnc_numeric_zero();
537  gnc_numeric value = zero;
538  gnc_numeric frac;
539  gnc_numeric opening_amount, opening_value;
540  gnc_numeric lot_amount, lot_value;
541  gnc_commodity *opening_currency;
542 
543  if (!split) return;
544  lot = split->lot;
545  if (!lot) return;
547  currency = split->parent->common_currency;
548 
549  ENTER ("(split=%p gains=%p status=0x%x lot=%s)", split,
550  split->gains_split, split->gains, gnc_lot_get_title(lot));
551 
552  /* Make sure the status flags and pointers are initialized */
553  xaccSplitDetermineGainStatus(split);
554 
555  /* Not possible to have gains if the transaction currency and
556  * account commodity are identical. */
557  if (gnc_commodity_equal (currency,
558  xaccAccountGetCommodity(split->acc)))
559  {
560  LEAVE ("Currency transfer, gains not possible, returning.");
561  return;
562  }
563 
564  if (pcy->PolicyIsOpeningSplit (pcy, lot, split))
565  {
566 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER
567  /* Check to make sure that this opening split doesn't
568  * have a cap-gain transaction associated with it.
569  * If it does, that's wrong, and we ruthlessly destroy it.
570  * XXX Don't do this, it leads to infinite loops.
571  * We need to scrub out errors like this elsewhere!
572  */
573  if (xaccSplitGetCapGainsSplit (split))
574  {
575  Split *gains_split = xaccSplitGetCapGainsSplit(split);
576  Transaction *trans = gains_split->parent;
577  PERR ("Opening Split must not have cap gains!!\n");
578 
579  xaccTransBeginEdit (trans);
580  xaccTransDestroy (trans);
581  xaccTransCommitEdit (trans);
582  }
583 #endif
584  LEAVE ("Lot opening split, returning.");
585  return;
586  }
587 
588  if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
589  {
590  LEAVE ("Stock split split, returning.");
591  return;
592  }
593 
594  if (GAINS_STATUS_GAINS & split->gains)
595  {
596  Split *s;
597  PINFO ("split is a gains recording split, switch over");
598  /* If this is the split that records the gains, then work with
599  * the split that generates the gains.
600  */
601  /* split = xaccSplitGetCapGainsSplit (split); */
602  s = split->gains_split;
603 
604  /* This should never be NULL, and if it is, and its matching
605  * parent can't be found, then its a bug, and we should be
606  * discarding this split. But ... for now .. return.
607  * XXX move appropriate actions to a 'scrub' routine'
608  */
609  if (!s)
610  {
611  PERR ("Bad gains-split pointer! .. trying to recover.");
612  split->gains_split = xaccSplitGetCapGainsSplit (split);
613  s = split->gains_split;
614  if (!s) return;
615 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER
616  xaccTransDestroy (trans);
617 #endif
618  }
619  split = s;
620  }
621 
622  /* Note: if the value of the 'opening' split(s) has changed,
623  * then the cap gains are changed. So we need to check not
624  * only if this split is dirty, but also the lot-opening splits. */
625  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
626  {
627  Split *s = node->data;
628  if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
629  {
630  if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus (s);
631  if (s->gains & GAINS_STATUS_VDIRTY)
632  {
633  /* Force a recompute to occur */
634  split->gains |= GAINS_STATUS_VDIRTY;
635  break;
636  }
637  }
638  }
639 
640  /* If it doesn't look like this split is 'dirty', then there's
641  * nothing to do. Just return. */
642  if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) &&
643  (split->gains_split) &&
644  (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
645  {
646  LEAVE ("split not dirty, returning");
647  return;
648  }
649 
650  /* Yow! If amount is zero, there's nothing to do! Amount-zero splits
651  * may exist if users attempted to manually record gains. */
652  if (gnc_numeric_zero_p (split->amount)) return;
653 
654  /* If we got to here, then the split or something related is
655  * 'dirty' and the gains really do need to be recomputed.
656  * So start working things. */
657 
658  /* Get the amount and value in this lot at the time of this transaction. */
659  gnc_lot_get_balance_before (lot, split, &lot_amount, &lot_value);
660 
661  pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
662  &opening_currency);
663 
664  /* Check to make sure the lot-opening currency and this split
665  * use the same currency */
666  if (FALSE == gnc_commodity_equiv (currency, opening_currency))
667  {
668  /* OK, the purchase and the sale were made in different currencies.
669  * I don't know how to compute cap gains for that. This is not
670  * an error. Just punt, silently.
671  */
672  LEAVE ("Can't compute gains, mismatched commodities!");
673  return;
674  }
675 
676  /* Opening amount should be larger (or equal) to current split,
677  * and it should be of the opposite sign.
678  * XXX This should really be a part of a scrub routine that
679  * cleans up the lot, before we get at it!
680  */
681  if (0 > gnc_numeric_compare (gnc_numeric_abs(lot_amount),
682  gnc_numeric_abs(split->amount)))
683  {
684  GList *n;
685  for (n = gnc_lot_get_split_list(lot); n; n = n->next)
686  {
687  Split *s = n->data;
688  PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
689  }
690  PERR ("Malformed Lot \"%s\"! (too thin!) "
691  "opening amt=%s split amt=%s baln=%s",
692  gnc_lot_get_title (lot),
693  gnc_num_dbg_to_string (lot_amount),
694  gnc_num_dbg_to_string (split->amount),
696  return;
697  }
698  if ( (gnc_numeric_negative_p(lot_amount) ||
699  gnc_numeric_positive_p(split->amount)) &&
700  (gnc_numeric_positive_p(lot_amount) ||
701  gnc_numeric_negative_p(split->amount)))
702  {
703  GList *n;
704  for (n = gnc_lot_get_split_list(lot); n; n = n->next)
705  {
706  Split *s = n->data;
707  PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
708  }
709  PERR ("Malformed Lot \"%s\"! (too fat!) "
710  "opening amt=%s split amt=%s baln=%s",
711  gnc_lot_get_title (lot),
712  gnc_num_dbg_to_string (lot_amount),
713  gnc_num_dbg_to_string (split->amount),
715  return;
716  }
717 
718  /* The cap gains is the difference between the basis prior to the
719  * current split, and the current split, pro-rated for an equal
720  * amount of shares.
721  * i.e. purchase_price = lot_value / lot_amount
722  * cost_basis = purchase_price * current_split_amount
723  * cap_gain = current_split_value - cost_basis
724  */
725  /* Fraction of the lot that this split represents: */
726  frac = gnc_numeric_div (split->amount, lot_amount,
729  /* Basis for this split: */
730  value = gnc_numeric_mul (frac, lot_value,
731  gnc_numeric_denom(opening_value),
733  /* Capital gain for this split: */
734  value = gnc_numeric_sub (value, split->value,
736  PINFO ("Open amt=%s val=%s; split amt=%s val=%s; gains=%s\n",
737  gnc_num_dbg_to_string (lot_amount),
738  gnc_num_dbg_to_string (lot_value),
739  gnc_num_dbg_to_string (split->amount),
740  gnc_num_dbg_to_string (split->value),
741  gnc_num_dbg_to_string (value));
742  if (gnc_numeric_check (value))
743  {
744  PERR ("Numeric overflow during gains calculation\n"
745  "Acct=%s Txn=%s\n"
746  "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
747  xaccAccountGetName(split->acc),
748  xaccTransGetDescription(split->parent),
749  gnc_num_dbg_to_string (lot_amount),
750  gnc_num_dbg_to_string (lot_value),
751  gnc_num_dbg_to_string (split->amount),
752  gnc_num_dbg_to_string (split->value),
753  gnc_num_dbg_to_string (value));
754  return;
755  }
756 
757  /* Are the cap gains zero? If not, add a balancing transaction.
758  * As per design doc lots.txt: the transaction has two splits,
759  * with equal & opposite values. The amt of one iz zero (so as
760  * not to upset the lot balance), the amt of the other is the same
761  * as its value (its the realized gain/loss).
762  */
763  if (FALSE == gnc_numeric_zero_p (value))
764  {
765  Transaction *trans;
766  Split *lot_split, *gain_split;
767  gboolean new_gain_split;
768  gnc_numeric negvalue = gnc_numeric_neg (value);
769 
770  /* See if there already is an associated gains transaction.
771  * If there is, adjust its value as appropriate. Else, create
772  * a new gains transaction.
773  */
774  /* lot_split = xaccSplitGetCapGainsSplit (split); */
775  lot_split = split->gains_split;
776 
777  if (NULL == lot_split)
778  {
779  Account *lot_acc = gnc_lot_get_account(lot);
780  QofBook *book = qof_instance_get_book(lot_acc);
781  Transaction *base_txn = xaccSplitGetParent (split);
782 
783  new_gain_split = TRUE;
784 
785  lot_split = xaccMallocSplit (book);
786  gain_split = xaccMallocSplit (book);
787 
788  /* Check to make sure the gains account currency matches. */
789  if ((NULL == gain_acc) ||
790  (FALSE == gnc_commodity_equiv (currency,
791  xaccAccountGetCommodity(gain_acc))))
792  {
793  gain_acc = xaccAccountGainsAccount (lot_acc, currency);
794  }
795 
796  xaccAccountBeginEdit (gain_acc);
797  xaccAccountInsertSplit (gain_acc, gain_split);
798  xaccAccountCommitEdit (gain_acc);
799 
800  xaccAccountBeginEdit (lot_acc);
801  xaccAccountInsertSplit (lot_acc, lot_split);
802  xaccAccountCommitEdit (lot_acc);
803 
804  trans = xaccMallocTransaction (book);
805 
806  xaccTransBeginEdit (trans);
807  xaccTransSetCurrency (trans, currency);
808  xaccTransSetDescription (trans, _("Realized Gain/Loss"));
809 
810  xaccTransAppendSplit (trans, lot_split);
811  xaccTransAppendSplit (trans, gain_split);
812 
813  xaccSplitSetMemo (lot_split, _("Realized Gain/Loss"));
814  xaccSplitSetMemo (gain_split, _("Realized Gain/Loss"));
815 
816  /* For the new transaction, set the split properties indicating
817  * that this is the gains transaction that corresponds
818  * to the gains source.
819  */
820  xaccTransBeginEdit (base_txn);
821  qof_instance_set (QOF_INSTANCE (split),
822  "gains-split", xaccSplitGetGUID (lot_split),
823  NULL);
824  xaccTransCommitEdit (base_txn);
825  qof_instance_set (QOF_INSTANCE (lot_split),
826  "gains-source", xaccSplitGetGUID (split),
827  NULL);
828 
829  }
830  else
831  {
832  trans = lot_split->parent;
833  gain_split = xaccSplitGetOtherSplit (lot_split);
834 
835  /* If the gains transaction has been edited so that it no longer has
836  just two splits, ignore it and assume it's still correct. */
837  if (!gain_split)
838  {
839  new_gain_split = FALSE;
840  }
841  /* If the gain is already recorded corectly do nothing. This is
842  * more than just an optimization since this may be called during
843  * gnc_book_partition_txn and depending on the order in which things
844  * happen some splits may be in the wrong book at that time. */
845  else if (split->gains_split == lot_split &&
846  lot_split->gains_split == split &&
847  gain_split->gains_split == split &&
848  gnc_numeric_equal (xaccSplitGetValue (lot_split), value) &&
849  gnc_numeric_zero_p (xaccSplitGetAmount (lot_split)) &&
850  gnc_numeric_equal (xaccSplitGetValue (gain_split), negvalue) &&
851  gnc_numeric_equal (xaccSplitGetAmount (gain_split), negvalue))
852  {
853  new_gain_split = FALSE;
854  }
855  else
856  {
857  new_gain_split = TRUE;
858  xaccTransBeginEdit (trans);
859 
860  /* Make sure the existing gains trans has the correct currency,
861  * just in case someone screwed with it! */
862  if (FALSE == gnc_commodity_equiv(currency, trans->common_currency))
863  {
864  PWARN ("Resetting the transaction currency!");
865  xaccTransSetCurrency (trans, currency);
866  }
867  }
868  }
869 
870  if (new_gain_split)
871  {
872  /* Common to both */
873  time64 time = xaccTransRetDatePosted (split->parent);
874  xaccTransSetDatePostedSecs (trans, time);
875  xaccTransSetDateEnteredSecs (trans, gnc_time (NULL));
876 
877  xaccSplitSetAmount (lot_split, zero);
878  xaccSplitSetValue (lot_split, value);
879 
880  xaccSplitSetAmount (gain_split, negvalue);
881  xaccSplitSetValue (gain_split, negvalue);
882 
883  /* Some short-cuts to help avoid the above property lookup. */
884  split->gains = GAINS_STATUS_CLEAN;
885  split->gains_split = lot_split;
886  lot_split->gains = GAINS_STATUS_GAINS;
887  lot_split->gains_split = split;
888  gain_split->gains = GAINS_STATUS_GAINS;
889  gain_split->gains_split = split;
890 
891  /* Do this last since it may generate an event that will call us
892  recursively. */
893  gnc_lot_add_split (lot, lot_split);
894 
895  xaccTransCommitEdit (trans);
896  }
897  }
898  LEAVE ("(lot=%s)", gnc_lot_get_title(lot));
899 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: Split.c:1238
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:196
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:361
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:509
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:254
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
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.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void gnc_lot_add_split(GNCLot *lot, Split *split)
The gnc_lot_add_split() routine adds a split to this lot.
Definition: gnc-lot.c:568
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Definition: Transaction.c:2122
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Definition: Split.c:1820
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:242
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:266
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split...
Definition: cap-gains.c:486
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1400
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:426
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Definition: Transaction.c:1451
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:248
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: Split.c:1202
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1691
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:406
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2363
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2307
void gnc_lot_get_balance_before(const GNCLot *lot, const Split *split, gnc_numeric *amount, gnc_numeric *value)
The gnc_lot_get_balance_before routine computes both the balance and value in the lot considering onl...
Definition: gnc-lot.c:518
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Definition: Transaction.c:1628
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
Definition: Split.h:553
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
Definition: Transaction.c:1429
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
All arguments are required to have the same denominator, that denominator is to be used in the output...
Definition: gnc-numeric.h:207
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.c:526
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
Definition: Transaction.c:1954
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: Split.c:1910
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1287
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3147
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:990
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Definition: Split.c:2072
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:276
Account * xaccAccountGainsAccount(Account *acc, gnc_commodity *curr)
Retrieve the gains account used by this account for the indicated currency, creating and recording a ...
Definition: Account.cpp:4577
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:248
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:84
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:375
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:1988
const char * xaccSplitGetType(const Split *s)
The xaccIsPeerSplit() is a convenience routine that returns TRUE (a non-zero value) if the two splits...
Definition: Split.c:1964
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3024
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1328
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account&#39;s lot order policy.
Definition: Account.cpp:1887
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:476
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: Split.c:1904

◆ xaccSplitGetCapGains()

gnc_numeric xaccSplitGetCapGains ( Split *  )

The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the indicated split.

In order for there to be any capital gains, several things must hold true about this split: (1) It must have been involved in trading (for aexample, by belonging to a stock or trading account) (2) It must have been assigned to a lot. (3) It cannot be the opening split of a lot; that is, it must be a matching sale of an earlier purchase (or vice versa).

Definition at line 904 of file cap-gains.c.

905 {
906  if (!split) return gnc_numeric_zero();
907  ENTER("(split=%p)", split);
908 
909  if (GAINS_STATUS_UNKNOWN == split->gains)
910  xaccSplitDetermineGainStatus(split);
911  if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
912  (split->gains_split &&
913  (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
914  {
915  xaccSplitComputeCapGains (split, NULL);
916  }
917 
918  /* If this is the source split, get the gains from the one
919  * that records the gains. If this already is the gains split,
920  * its a no-op. */
921  if (!(GAINS_STATUS_GAINS & split->gains))
922  {
923  /* split = xaccSplitGetCapGainsSplit (split); */
924  split = split->gains_split;
925  }
926 
927  LEAVE("(split=%p)", split);
928  if (!split) return gnc_numeric_zero();
929 
930  return split->value;
931 }
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
Definition: cap-gains.c:530
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:266
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:276

◆ xaccSplitGetCapGainsSplit()

Split* xaccSplitGetCapGainsSplit ( const Split *  )

The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split.

It returns NULL if not found. This routine does nothing more than search for the split recorded in the KVP key "/gains-split"

Definition at line 486 of file cap-gains.c.

487 {
488  GncGUID *gains_guid;
489  Split *gains_split;
490 
491  if (!split) return NULL;
492 
493  qof_instance_get (QOF_INSTANCE (split),
494  "gains-split", &gains_guid,
495  NULL);
496  if (!gains_guid) return NULL;
497 
498  /* Both splits will be in the same collection, so search there. */
499  gains_split = (Split*) qof_collection_lookup_entity (
500  qof_instance_get_collection(split), gains_guid);
501  PINFO ("split=%p has gains-split=%p", split, gains_split);
502  return gains_split;
503 }
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:214
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:254
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
The type used to store guids in C.
Definition: guid.h:75

◆ xaccSplitGetGainsSourceSplit()

Split* xaccSplitGetGainsSourceSplit ( const Split *  )

The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in this split.

It returns NULL if not found. This routine does nothing more than search for the split recorded in the KVP key "/gains-source"

Definition at line 508 of file cap-gains.c.

509 {
510  GncGUID *source_guid;
511  Split *source_split;
512 
513  if (!split) return NULL;
514 
515  qof_instance_get (QOF_INSTANCE (split),
516  "gains-source", &source_guid,
517  NULL);
518  if (!source_guid) return NULL;
519 
520  /* Both splits will be in the same collection, so search there. */
521  source_split = (Split*) qof_collection_lookup_entity(
522  qof_instance_get_collection(split), source_guid);
523  PINFO ("split=%p has source-split=%p", split, source_split);
524  return source_split;
525 }
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:214
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:254
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
The type used to store guids in C.
Definition: guid.h:75