GnuCash  5.6-133-gc519490283+
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, that 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 188 of file cap-gains.cpp.

190 {
191  GNCLot *lot;
192  ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, sign.num,
193  sign.denom);
194 
195  lot = xaccAccountFindOpenLot (acc, sign, currency,
196  G_MAXINT64, earliest_pred);
197  LEAVE ("found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
199  return lot;
200 }
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:272
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.cpp:445
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.cpp:502

◆ 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 80 of file cap-gains.cpp.

81 {
82  gnc_commodity *acc_comm;
83 
84  if (!acc) return FALSE;
85 
86  if (xaccAccountIsPriced (acc))
87  return TRUE;
88 
89  acc_comm = xaccAccountGetCommodity(acc);
90 
91  for (auto s : xaccAccountGetSplits (acc))
92  {
93  Transaction *t = s->parent;
94  if (s->gains == GAINS_STATUS_GAINS) continue;
95  if (acc_comm != t->common_currency) return TRUE;
96  }
97 
98  return FALSE;
99 }
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4698
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.cpp:3467

◆ 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 426 of file cap-gains.cpp.

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

◆ 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 219 of file cap-gains.cpp.

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

◆ 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 526 of file cap-gains.cpp.

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

◆ 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 900 of file cap-gains.cpp.

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

◆ 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 480 of file cap-gains.cpp.

481 {
482  GncGUID *gains_guid;
483  Split *gains_split;
484 
485  if (!split) return nullptr;
486 
487  qof_instance_get (QOF_INSTANCE (split),
488  "gains-split", &gains_guid,
489  nullptr);
490  if (!gains_guid) return nullptr;
491 
492  /* Both splits will be in the same collection, so search there. */
493  gains_split = (Split*) qof_collection_lookup_entity (
494  qof_instance_get_collection(split), gains_guid);
495  PINFO ("split=%p has gains-split=%p", split, gains_split);
496  guid_free (gains_guid);
497  return gains_split;
498 }
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:212
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
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 503 of file cap-gains.cpp.

504 {
505  GncGUID *source_guid;
506  Split *source_split;
507 
508  if (!split) return nullptr;
509 
510  qof_instance_get (QOF_INSTANCE (split),
511  "gains-source", &source_guid,
512  nullptr);
513  if (!source_guid) return nullptr;
514 
515  /* Both splits will be in the same collection, so search there. */
516  source_split = (Split*) qof_collection_lookup_entity(
517  qof_instance_get_collection(split), source_guid);
518  PINFO ("split=%p has source-split=%p", split, source_split);
519  guid_free (source_guid);
520  return source_split;
521 }
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:212
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
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