GnuCash c935c2f+
Loading...
Searching...
No Matches
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.
 
gboolean xaccAccountHasTrades (const Account *)
 The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of commodities.
 
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'.
 
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.
 
Split * xaccSplitGetGainsSourceSplit (const Split *)
 The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in this split.
 
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.
 
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.
 
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.
 
void xaccSplitComputeCapGains (Split *split, Account *gain_acc)
 The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split.
 
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}
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition gnc-lot.cpp:487
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.

◆ xaccAccountFindLatestOpenLot()

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

Definition at line 203 of file cap-gains.cpp.

205{
206 GNCLot *lot;
207 ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
208 sign.num, sign.denom);
209
210 lot = xaccAccountFindOpenLot (acc, sign, currency,
211 G_MININT64, latest_pred);
212 LEAVE ("found lot=%p %s", lot, gnc_lot_get_title (lot));
213 return lot;
214}

◆ xaccAccountHasTrades()

gboolean xaccAccountHasTrades ( const Account acc)

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

◆ xaccLotComputeCapGains()

void xaccLotComputeCapGains ( GNCLot *  lot,
Account gain_acc 
)

Definition at line 1070 of file cap-gains.cpp.

1071{
1072 SplitList *node;
1073 GNCPolicy *pcy;
1074 gboolean is_dirty = FALSE;
1075
1076 /* Note: if the value of the 'opening' split(s) has changed,
1077 * then the cap gains are changed. To capture this, we need
1078 * to mark all splits dirty if the opening splits are dirty. */
1079
1080 ENTER("(lot=%p)", lot);
1082 for (node = gnc_lot_get_split_list(lot); node; node = node->next)
1083 {
1084 Split *s = GNC_SPLIT(node->data);
1085 if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
1086 {
1087 if (GAINS_STATUS_UNKNOWN == s->gains)
1088 xaccSplitDetermineGainStatus(s);
1089 if (s->gains & GAINS_STATUS_VDIRTY)
1090 {
1091 is_dirty = TRUE;
1092 s->gains &= ~GAINS_STATUS_VDIRTY;
1093 }
1094 }
1095 }
1096
1097 if (is_dirty)
1098 {
1099 for (node = gnc_lot_get_split_list(lot); node; node = node->next)
1100 {
1101 Split *s = GNC_SPLIT(node->data);
1102 s->gains |= GAINS_STATUS_VDIRTY;
1103 }
1104 }
1105
1106 for (node = gnc_lot_get_split_list(lot); node; node = node->next)
1107 {
1108 Split *s = GNC_SPLIT(node->data);
1109 xaccSplitComputeCapGains (s, gain_acc);
1110 }
1111 LEAVE("(lot=%p)", lot);
1112}
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account's lot order policy.
Definition Account.cpp:2100
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
The xaccSplitComputeCapGains() routine computes the cap gains or losses for the indicated split.
GList SplitList
GList of Split.
Definition gnc-engine.h:207
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition gnc-lot.cpp:377
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
Definition gnc-lot.cpp:425

◆ 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
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,
999 GNC_HOW_DENOM_REDUCE);
1000 /* Basis for this split: */
1001 auto value = gnc_numeric_mul (frac, lot_value,
1002 gnc_numeric_denom(opening_value),
1003 GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1004 /* Capital gain for this split: */
1005 value = gnc_numeric_sub (value, split->value,
1006 GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
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}
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
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
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition gnc-lot.cpp:658
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
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_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account's commodity.
Definition Split.cpp:1340
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition Split.cpp:2078

◆ 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);
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 }
482
483 LEAVE (" split_up=%d", splits_split_up);
484 return splits_split_up;
485}
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition Account.cpp:1516
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition Account.cpp:1475
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
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot,...
GNCLot * gnc_lot_make_default(Account *acc)
Definition gnc-lot.cpp:765
STRUCTS.

◆ 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;
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));
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;
292 gnc_lot_add_split (lot, split);
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;
312 gnc_lot_add_split (lot, split);
313 PINFO ("simple added split to lot, new lot baln=%s",
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;
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),
338 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
339 baln = gnc_numeric_mul (baln, frac,
341 GNC_HOW_RND_ROUND_HALF_UP);
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,
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,
359 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
360 val_a = gnc_numeric_mul (frac, val_tot,
361 gnc_numeric_denom(val_tot),
362 GNC_HOW_RND_ROUND_HALF_UP | GNC_HOW_DENOM_EXACT);
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",
372 gnc_num_dbg_to_string(val_tot),
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),
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);
425 return new_split;
426 }
427}
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2745
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Definition gnc-lot.cpp:579
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition gnc-lot.cpp:367
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
@ GNC_ERROR_OK
No error.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition Split.cpp:1859
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
void xaccSplitAddPeerSplit(Split *split, const Split *other_split, time64 timestamp)
Add a peer split to this split's lot-split list.
Definition Split.cpp:2084

◆ 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,
720 GNC_HOW_DENOM_REDUCE);
721 /* Basis for this split: */
722 value = gnc_numeric_mul (frac, lot_value,
723 gnc_numeric_denom(opening_value),
724 GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
725 /* Capital gain for this split: */
726 value = gnc_numeric_sub (value, split->value,
727 GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
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) &&
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}
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
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
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.
#define xaccSplitGetGUID(X)
Definition Split.h:579
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
QofBook reference.
Definition qofbook-p.hpp:47

◆ xaccSplitGetCapGains()

gnc_numeric xaccSplitGetCapGains ( Split *  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}

◆ xaccSplitGetCapGainsSplit()

Split * xaccSplitGetCapGainsSplit ( const Split *  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 *  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}