GnuCash  2.7.0
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 191 of file cap-gains.c.

193 {
194  GNCLot *lot;
195  ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, sign.num,
196  sign.denom);
197 
198  lot = xaccAccountFindOpenLot (acc, sign, currency,
199  G_MAXINT64, earliest_pred);
200  LEAVE ("found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
202  return lot;
203 }
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:261
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:432
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:271
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:482

◆ 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.c:3723
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.c:4291
GList SplitList
GList of Split.
Definition: gnc-engine.h:203
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.c:3154

◆ 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 430 of file cap-gains.c.

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

◆ 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 222 of file cap-gains.c.

223 {
224  Account *acc;
225  gnc_numeric baln;
226  int cmp;
227  gboolean baln_is_positive, amt_is_positive;
228 
229  if (!lot) return split;
230  if (!split) return NULL;
231 
232  /* If this split already belongs to a lot, we are done. */
233  if (split->lot) return NULL;
234 
235  /* Anomolous situation; except for voided transactions,
236  * we don't expect to see splits with no amount ..
237  * unless they're gains splits, and we shouldn't see those.
238  */
239  if (gnc_numeric_zero_p (split->amount))
240  {
241  if (xaccTransGetVoidStatus(split->parent)) return NULL;
242 
243  PWARN ("split with zero amount; value=%s gflag=%x gsplit=%p",
244  gnc_num_dbg_to_string (split->amount),
245  split->gains,
246  split->gains_split);
247  if (split->gains_split)
248  {
249  PWARN ("gains amt=%s value=%s",
250  gnc_num_dbg_to_string (split->gains_split->amount),
251  gnc_num_dbg_to_string (split->gains_split->value));
252  }
253  return NULL;
254  }
255 
256  /* If the lot is closed, we can't add anything to it */
257  baln = gnc_lot_get_balance (lot);
258  if (gnc_lot_is_closed (lot)) return split;
259 
260  /* If the lot balance is zero, but the lot is open, then
261  * the lot is empty. Unconditionally add the split. */
262  if (gnc_numeric_zero_p (baln))
263  {
264  acc = split->acc;
265  xaccAccountBeginEdit (acc);
266  gnc_lot_add_split (lot, split);
267  PINFO ("added split to empty lot, new lot baln=%s (%s)",
269  gnc_lot_get_title (lot));
270  xaccAccountCommitEdit (acc);
271  return NULL;
272  }
273 
274  /* If the sign of the split is the same as the sign of the lot,
275  * add the split, but complain about it ... none of the currently
276  * implemented accounting policies should be giving us splits
277  * that make lots larger. One a lot is open, the FIFO/LIFO
278  * policies should be working only to make the lot smaller.
279  * We can remove the warning emssage come the day we have
280  * fancier policies.
281  */
282  baln_is_positive = gnc_numeric_positive_p (baln);
283  amt_is_positive = gnc_numeric_positive_p (split->amount);
284  if ((baln_is_positive && amt_is_positive) ||
285  ((!baln_is_positive) && (!amt_is_positive)))
286  {
287  PWARN ("accounting policy gave us split that enlarges the lot!\n"
288  "old lot baln=%s split amt=%s lot=%s",
290  gnc_num_dbg_to_string (split->amount),
291  gnc_lot_get_title (lot));
292 
293  acc = split->acc;
294  xaccAccountBeginEdit (acc);
295  gnc_lot_add_split (lot, split);
296  xaccAccountCommitEdit (acc);
297  return NULL;
298  }
299 
300  /* If adding the split would make the lot balance change sign,
301  * then we split the split into two pieces: one piece that will
302  * bring the lot balance to zero, and another to be dealt with
303  * later. */
304  cmp = gnc_numeric_compare (gnc_numeric_abs(split->amount),
305  gnc_numeric_abs(baln));
306 
307  PINFO ("found open lot with baln=%s (%s)", gnc_num_dbg_to_string (baln),
308  gnc_lot_get_title (lot));
309 
310  /* cmp == -1 if amt < baln, ==0 if amt==baln */
311  if (0 >= cmp)
312  {
313  acc = split->acc;
314  xaccAccountBeginEdit (acc);
315  gnc_lot_add_split (lot, split);
316  PINFO ("simple added split to lot, new lot baln=%s",
318  xaccAccountCommitEdit (acc);
319  return NULL;
320  }
321 
322  /* If we are here, then (cmp == +1 iff (amt > baln)) and we need
323  * to split up the split into pieces. Do it. */
324  {
325  time64 now = gnc_time (NULL);
326  Split * new_split;
327  gnc_numeric amt_a, amt_b, amt_tot;
328  gnc_numeric val_a, val_b, val_tot;
329  gnc_numeric frac;
330  Transaction *trans;
331  Timespec ts;
332 
333  acc = split->acc;
334  xaccAccountBeginEdit (acc);
335  trans = split->parent;
336  xaccTransBeginEdit (trans);
337 
338  amt_tot = split->amount;
339  amt_a = gnc_numeric_neg (baln);
340  amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
341  g_assert (gnc_numeric_check(amt_b) == GNC_ERROR_OK);
342 
343  PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
344  split,
345  gnc_num_dbg_to_string(amt_a),
346  gnc_num_dbg_to_string(amt_b) );
347 
348  /* Compute the value so that it holds in the same proportion:
349  * i.e. so that (amt_a / amt_tot) = (val_a / val_tot)
350  */
351  val_tot = split->value;
352  frac = gnc_numeric_div (amt_a, amt_tot,
354  val_a = gnc_numeric_mul (frac, val_tot,
355  gnc_numeric_denom(val_tot),
357 
358  val_b = gnc_numeric_sub_fixed (val_tot, val_a);
359  if (gnc_numeric_check(val_a))
360  {
361  PERR("Numeric overflow\n"
362  "Acct=%s Txn=%s\n"
363  "\tval_tot=%s amt_a=%s amt_tot=%s\n",
364  xaccAccountGetName(acc),
366  gnc_num_dbg_to_string(val_tot),
367  gnc_num_dbg_to_string(amt_a),
368  gnc_num_dbg_to_string(amt_tot));
369  }
370 
371  if (gnc_numeric_zero_p(val_a) || gnc_numeric_zero_p(val_b))
372  {
373  PERR ("Failed to split into two!");
374  }
375 
376  PINFO ("split value is = %s = %s + %s",
377  gnc_num_dbg_to_string(val_tot),
378  gnc_num_dbg_to_string(val_a),
379  gnc_num_dbg_to_string(val_b) );
380 
381  g_assert (!gnc_numeric_zero_p (amt_a));
382  g_assert (!gnc_numeric_zero_p (val_a));
383  xaccSplitSetAmount (split, amt_a);
384  xaccSplitSetValue (split, val_a);
385 
386  /* Adding this split will have the effect of closing this lot,
387  * because the new balance should be precisely zero. */
388  gnc_lot_add_split (lot, split);
389 
390  /* Put the remainder of the balance into a new split,
391  * which is in other respects just a clone of this one. */
392  new_split = xaccMallocSplit (qof_instance_get_book(acc));
393 
394  /* Copy most of the split attributes */
395  xaccSplitSetMemo (new_split, xaccSplitGetMemo (split));
396  /* Set split-action with gnc_set_num_action which is the same as
397  * xaccSplitSetAction with these arguments; use gnc_get_num_action to get
398  * split-action which is the same as xaccSplitGetAction */
399  gnc_set_num_action(NULL, new_split, NULL, gnc_get_num_action(NULL, split));
400  xaccSplitSetReconcile (new_split, xaccSplitGetReconcile (split));
401  ts = xaccSplitRetDateReconciledTS (split);
402  xaccSplitSetDateReconciledTS (new_split, &ts);
403 
404  /* Set the lot-split and peer_guid properties on the two
405  * splits to indicate that they're linked.
406  */
407  xaccSplitAddPeerSplit(split, new_split, now);
408  xaccSplitAddPeerSplit(new_split, split, now);
409  xaccAccountInsertSplit (acc, new_split);
410  xaccTransAppendSplit (trans, new_split);
411  /* Set the amount and value after the split is in the transaction
412  so it can find the correct denominator to use. Otherwise it
413  uses 100000 which may cause an overflow in some of the tests
414  in test-period */
415  xaccSplitSetAmount (new_split, amt_b);
416  xaccSplitSetValue (new_split, val_b);
417  xaccTransCommitEdit (trans);
418  xaccAccountCommitEdit (acc);
419  return new_split;
420  }
421 }
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:1258
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:2018
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:357
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:249
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:1823
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Definition: Split.c:1919
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:574
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:1765
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:237
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:432
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:243
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:1222
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:1713
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Definition: Transaction.c:2281
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:1641
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:1442
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: Split.c:546
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
Definition: Transaction.c:2651
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:371
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.c:1294
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:987
void xaccSplitSetDateReconciledTS(Split *split, Timespec *ts)
Set the date on which this split was reconciled by specifying the time as Timespec.
Definition: Split.c:1804
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:251
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:1907
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.c:3031
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.c:1335
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:482

◆ 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 528 of file cap-gains.c.

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

◆ 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 903 of file cap-gains.c.

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

◆ 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 484 of file cap-gains.c.

485 {
486  GncGUID *gains_guid;
487  Split *gains_split;
488 
489  if (!split) return NULL;
490 
491  qof_instance_get (QOF_INSTANCE (split),
492  "gains-split", &gains_guid,
493  NULL);
494  if (!gains_guid) return NULL;
495 
496  /* Both splits will be in the same collection, so search there. */
497  gains_split = (Split*) qof_collection_lookup_entity (
498  qof_instance_get_collection(split), gains_guid);
499  PINFO ("split=%p has gains-split=%p", split, gains_split);
500  return gains_split;
501 }
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:249
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 506 of file cap-gains.c.

507 {
508  GncGUID *source_guid;
509  Split *source_split;
510 
511  if (!split) return NULL;
512 
513  qof_instance_get (QOF_INSTANCE (split),
514  "gains-source", &source_guid,
515  NULL);
516  if (!source_guid) return NULL;
517 
518  /* Both splits will be in the same collection, so search there. */
519  source_split = (Split*) qof_collection_lookup_entity(
520  qof_instance_get_collection(split), source_guid);
521  PINFO ("split=%p has source-split=%p", split, source_split);
522  return source_split;
523 }
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:249
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