GnuCash  5.6-150-g038405b370+
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...
 
gnc_numeric xaccLotFreeSplitCapGain (Split *split, GNCLot *lot)
 The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the indicated split against the indicated lot. 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
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition: gnc-lot.cpp:487

◆ 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:4551
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
Definition: Account.cpp:3408

◆ xaccLotFreeSplitCapGain()

gnc_numeric xaccLotFreeSplitCapGain ( Split *  split,
GNCLot *  lot 
)

The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the indicated split against the indicated lot.

In order for there to be any capital gain, a few things must hold true about this split: (1) It must have been involved in trading (for example, by belonging to a stock or trading account) (2) It must not be 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 896 of file cap-gains.cpp.

897 {
898  g_return_val_if_fail (split && lot && !split->lot, gnc_numeric_zero());
899 
900  ENTER ("(split=%p lot=%s)", split, gnc_lot_get_title(lot));
901 
902  auto pcy = gnc_account_get_policy (gnc_lot_get_account (lot));
903  auto currency = split->parent->common_currency;
904 
905  /* Not possible to have gains if the transaction currency and
906  * account commodity are identical. */
907  if (gnc_commodity_equal (currency,
908  xaccAccountGetCommodity(split->acc)))
909  {
910  LEAVE ("Currency transfer, gains not possible, returning.");
911  return gnc_numeric_zero();
912  }
913 
914  auto *esplit = gnc_lot_get_earliest_split (lot);
915  if (!esplit)
916  {
917  LEAVE ("Lot is empty, returning.");
918  return gnc_numeric_zero();
919  }
920 
922  {
923  LEAVE ("Split is too early, returning.");
924  return gnc_numeric_zero();
925  }
926 
927  if (xaccSplitIsStockSplit (split))
928  {
929  LEAVE ("Stock split split, returning.");
930  return gnc_numeric_zero();
931  }
932 
933  /* If amount is zero, there's nothing to do! Amount-zero splits
934  * may exist if users attempted to manually record gains. */
935  if (gnc_numeric_zero_p (split->amount)) return gnc_numeric_zero();
936 
937  /* If we got to here, then the gains really do need to be recomputed.
938  * So start working things. */
939 
940  /* Get the amount and value in this lot at the time of this transaction. */
941  gnc_numeric lot_amount, lot_value;
942  gnc_lot_get_balance_before (lot, split, &lot_amount, &lot_value);
943 
944  gnc_numeric opening_amount, opening_value;
945  gnc_commodity *opening_currency;
946  pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
947  &opening_currency);
948 
949  /* Check to make sure the lot-opening currency and this split
950  * use the same currency */
951  if (FALSE == gnc_commodity_equiv (currency, opening_currency))
952  {
953  /* OK, the purchase and the sale were made in different currencies.
954  * I don't know how to compute cap gains for that. This is not
955  * an error. Just punt, silently.
956  */
957  LEAVE ("Can't compute gains, mismatched commodities!");
958  return gnc_numeric_zero();
959  }
960 
961  /* Opening amount should be larger (or equal) to current split,
962  * and it should be of the opposite sign.
963  * XXX This should really be a part of a scrub routine that
964  * cleans up the lot, before we get at it!
965  */
966  if (0 > gnc_numeric_compare (gnc_numeric_abs(lot_amount),
968  {
969  for (auto *n = gnc_lot_get_split_list(lot); n; n = n->next)
970  {
971  auto *s = GNC_SPLIT(n->data);
972  PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
973  }
974  return gnc_numeric_zero();
975  }
976  if ( (gnc_numeric_negative_p(lot_amount) ||
978  (gnc_numeric_positive_p(lot_amount) ||
980  {
981  for (auto *n = gnc_lot_get_split_list(lot); n; n = n->next)
982  {
983  auto *s = GNC_SPLIT(n->data);
984  PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
985  }
986  return gnc_numeric_zero();
987  }
988 
989  /* The cap gains is the difference between the basis prior to the
990  * current split, and the current split, pro-rated for an equal
991  * amount of shares.
992  * i.e. purchase_price = lot_value / lot_amount
993  * cost_basis = purchase_price * current_split_amount
994  * cap_gain = current_split_value - cost_basis
995  */
996  /* Fraction of the lot that this split represents: */
997  auto frac = gnc_numeric_div (xaccSplitGetAdjustedAmount (split), lot_amount,
1000  /* Basis for this split: */
1001  auto value = gnc_numeric_mul (frac, lot_value,
1002  gnc_numeric_denom(opening_value),
1004  /* Capital gain for this split: */
1005  value = gnc_numeric_sub (value, split->value,
1007 
1008  PINFO ("Open amt=%s val=%s; split adj amt=%s val=%s; gains=%s\n",
1009  gnc_num_dbg_to_string (lot_amount),
1010  gnc_num_dbg_to_string (lot_value),
1012  gnc_num_dbg_to_string (split->value),
1013  gnc_num_dbg_to_string (value));
1014 
1015  if (gnc_numeric_check (value))
1016  {
1017  PERR ("Numeric overflow during gains calculation\n"
1018  "Acct=%s Txn=%s\n"
1019  "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
1020  xaccAccountGetName(split->acc),
1021  xaccTransGetDescription(split->parent),
1022  gnc_num_dbg_to_string (lot_amount),
1023  gnc_num_dbg_to_string (lot_value),
1025  gnc_num_dbg_to_string (split->value),
1026  gnc_num_dbg_to_string (value));
1027  return gnc_numeric_zero();
1028  }
1029 
1030  LEAVE ("(lot=%s)", gnc_lot_get_title(lot));
1031 
1032  return value;
1033 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
All arguments are required to have the same denominator, that denominator is to be used in the output...
Definition: gnc-numeric.h:206
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
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:188
gint 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 * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition: gnc-lot.cpp:658
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:195
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
Definition: gnc-lot.cpp:425
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)
Computes both the balance and value in the lot considering only splits in transactions prior to the o...
Definition: gnc-lot.cpp:529
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition: Split.cpp:2078
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...
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3408
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3289
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account&#39;s commodity.
Definition: Split.cpp:1340
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account&#39;s lot order policy.
Definition: Account.cpp:2100
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.

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

437 {
438  Account *acc;
439  gboolean splits_split_up = FALSE;
440  GNCLot *lot;
441  GNCPolicy *pcy;
442 
443  if (!split) return FALSE;
444 
445  /* If this split already belongs to a lot or the account doesn't
446  * have lots, we are done.
447  */
448  if (split->lot) return FALSE;
449  g_return_val_if_fail (split->gains == GAINS_STATUS_UNKNOWN ||
450  (split->gains & GAINS_STATUS_GAINS) == FALSE, FALSE);
451  acc = split->acc;
452  if (!xaccAccountHasTrades (acc))
453  return FALSE;
454  if (gnc_numeric_zero_p (split->amount))
455  return FALSE;
456 
457  ENTER ("(split=%p)", split);
458 
459  pcy = gnc_account_get_policy(acc);
460  xaccAccountBeginEdit (acc);
461 
462  /* If we are here, this split does not belong to any lot.
463  * We ask the policy for a lot to assign it to. This
464  * block is written in the form of a while loop, since we
465  * may have to bust a split across several lots.
466  */
467  while (split)
468  {
469  PINFO ("have split %p amount=%s", split,
470  gnc_num_dbg_to_string (split->amount));
471  split->gains |= GAINS_STATUS_VDIRTY;
472  lot = pcy->PolicyGetLot (pcy, split);
473  if (!lot)
474  {
475  lot = gnc_lot_make_default (acc);
476  PINFO ("start new lot (%s)", gnc_lot_get_title(lot));
477  }
478  split = xaccSplitAssignToLot (split, lot);
479  if (split) splits_split_up = TRUE;
480  }
481  xaccAccountCommitEdit (acc);
482 
483  LEAVE (" split_up=%d", splits_split_up);
484  return splits_split_up;
485 }
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
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)
Definition: gnc-lot.cpp:765
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1475
#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:1516
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account&#39;s lot order policy.
Definition: Account.cpp:2100

◆ 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. */
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  /* Adjust split's view of the lot balance for stock splits */
335  if (!gnc_numeric_equal (split->amount, xaccSplitGetAdjustedAmount (split)))
336  {
337  frac = gnc_numeric_div (split->amount, xaccSplitGetAdjustedAmount (split),
339  baln = gnc_numeric_mul (baln, frac,
342  }
343 
344  amt_tot = split->amount;
345  amt_a = gnc_numeric_neg (baln);
346  amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
347  g_return_val_if_fail(gnc_numeric_check(amt_b) == GNC_ERROR_OK, nullptr);
348 
349  PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
350  split,
351  gnc_num_dbg_to_string(amt_a),
352  gnc_num_dbg_to_string(amt_b) );
353 
354  /* Compute the value so that it holds in the same proportion:
355  * i.e. so that (amt_a / amt_tot) = (val_a / val_tot)
356  */
357  val_tot = split->value;
358  frac = gnc_numeric_div (amt_a, amt_tot,
360  val_a = gnc_numeric_mul (frac, val_tot,
361  gnc_numeric_denom(val_tot),
363 
364  val_b = gnc_numeric_sub_fixed (val_tot, val_a);
365  if (gnc_numeric_check(val_a))
366  {
367  PERR("Numeric overflow\n"
368  "Acct=%s Txn=%s\n"
369  "\tval_tot=%s amt_a=%s amt_tot=%s\n",
370  xaccAccountGetName(acc),
372  gnc_num_dbg_to_string(val_tot),
373  gnc_num_dbg_to_string(amt_a),
374  gnc_num_dbg_to_string(amt_tot));
375  }
376 
377  if (gnc_numeric_zero_p(amt_a) || gnc_numeric_zero_p(amt_b))
378  {
379  PERR ("Failed to split into two!");
380  }
381 
382  PINFO ("split value is = %s = %s + %s",
383  gnc_num_dbg_to_string(val_tot),
384  gnc_num_dbg_to_string(val_a),
385  gnc_num_dbg_to_string(val_b) );
386 
387  g_return_val_if_fail (!gnc_numeric_zero_p (amt_a), nullptr);
388  g_return_val_if_fail (!gnc_numeric_check (val_a), nullptr);
389  xaccSplitSetAmount (split, amt_a);
390  xaccSplitSetValue (split, val_a);
391 
392  /* Adding this split will have the effect of closing this lot,
393  * because the new balance should be precisely zero. */
394  gnc_lot_add_split (lot, split);
395 
396  /* Put the remainder of the balance into a new split,
397  * which is in other respects just a clone of this one. */
398  new_split = xaccMallocSplit (qof_instance_get_book(acc));
399 
400  /* Copy most of the split attributes */
401  xaccSplitSetMemo (new_split, xaccSplitGetMemo (split));
402  /* Set split-action with gnc_set_num_action which is the same as
403  * xaccSplitSetAction with these arguments; use gnc_get_num_action to get
404  * split-action which is the same as xaccSplitGetAction */
405  gnc_set_num_action(nullptr, new_split, nullptr, gnc_get_num_action(nullptr, split));
406  xaccSplitSetReconcile (new_split, xaccSplitGetReconcile (split));
407  time = xaccSplitGetDateReconciled (split);
408  xaccSplitSetDateReconciledSecs (new_split, time);
409 
410  /* Set the lot-split and peer_guid properties on the two
411  * splits to indicate that they're linked.
412  */
413  xaccSplitAddPeerSplit(split, new_split, now);
414  xaccSplitAddPeerSplit(new_split, split, now);
415  xaccAccountInsertSplit (acc, new_split);
416  xaccTransAppendSplit (trans, new_split);
417  /* Set the amount and value after the split is in the transaction
418  so it can find the correct denominator to use. Otherwise it
419  uses 100000 which may cause an overflow in some of the tests
420  in test-period */
421  xaccSplitSetAmount (new_split, amt_b);
422  xaccSplitSetValue (new_split, val_b);
423  xaccTransCommitEdit (trans);
424  xaccAccountCommitEdit (acc);
425  return new_split;
426  }
427 }
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:2084
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:380
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
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2745
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)
Adds a split to this lot.
Definition: gnc-lot.cpp:579
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:188
gint 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 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:195
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 x, gnc_numeric y, 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:1859
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
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:1475
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1069
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
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:3289
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account&#39;s commodity.
Definition: Split.cpp:1340
No error.
Definition: gnc-numeric.h:223
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1516
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition: gnc-lot.cpp:487

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

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

1039 {
1040  if (!split) return gnc_numeric_zero();
1041  ENTER("(split=%p)", split);
1042 
1043  if (GAINS_STATUS_UNKNOWN == split->gains)
1044  xaccSplitDetermineGainStatus(split);
1045  if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
1046  (split->gains_split &&
1047  (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
1048  {
1049  xaccSplitComputeCapGains (split, nullptr);
1050  }
1051 
1052  /* If this is the source split, get the gains from the one
1053  * that records the gains. If this already is the gains split,
1054  * its a no-op. */
1055  if (!(GAINS_STATUS_GAINS & split->gains))
1056  {
1057  /* split = xaccSplitGetCapGainsSplit (split); */
1058  split = split->gains_split;
1059  }
1060 
1061  LEAVE("(split=%p)", split);
1062  if (!split) return gnc_numeric_zero();
1063 
1064  return split->value;
1065 }
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split...
Definition: cap-gains.cpp:522
#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 508 of file cap-gains.cpp.

509 {
510  return find_split_by_type ("gains-split", split);
511 }

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

515 {
516  return find_split_by_type ("gains-source", split);
517 }