GnuCash  5.6-150-g038405b370+
cap-gains.cpp
1 /********************************************************************\
2  * cap-gains.c -- Automatically Compute Capital Gains/Losses *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20 \********************************************************************/
21 
56 #include <config.h>
57 
58 #include <glib.h>
59 #include <glib/gi18n.h>
60 
61 #include "Account.hpp"
62 #include "AccountP.hpp"
63 #include "Scrub2.h"
64 #include "Scrub3.h"
65 #include "Transaction.h"
66 #include "TransactionP.hpp"
67 #include "cap-gains.h"
68 #include "gnc-engine.h"
69 #include "engine-helpers.h"
70 #include "gnc-lot.h"
71 #include "policy.h"
72 #include "policy-p.h"
73 
74 static QofLogModule log_module = GNC_MOD_LOT;
75 
76 
77 /* ============================================================== */
78 
79 gboolean
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 }
100 
101 /* ============================================================== */
102 
103 struct FindLot
104 {
105  GNCLot *lot;
106  gnc_commodity *currency;
107  time64 time;
108  int (*numeric_pred)(gnc_numeric);
109  gboolean (*date_pred)(time64 e, time64 tr);
110 };
111 
112 static gboolean
113 earliest_pred (time64 earl, time64 tran)
114 {
115  return earl > tran;
116 }
117 
118 static gboolean
119 latest_pred (time64 earl, time64 tran)
120 {
121  return earl < tran;
122 }
123 
124 static gpointer
125 finder_helper (GNCLot *lot, gpointer user_data)
126 {
127  auto els = static_cast<FindLot*>(user_data);
128  Split *s;
129  Transaction *trans;
130  gnc_numeric bal;
131  gboolean opening_is_positive, bal_is_positive;
132  time64 posted = 0;
133 
134  if (gnc_lot_is_closed (lot)) return nullptr;
135 
136  s = gnc_lot_get_earliest_split (lot);
137  if (s == nullptr) return nullptr;
138 
139  /* We want a lot whose balance is of the correct sign. All splits
140  in a lot must be the opposite sign of the opening split. We also
141  want to ignore lots that are overfull, i.e., where the balance in
142  the lot is of opposite sign to the opening split in the lot. */
143  if (0 == (els->numeric_pred) (s->amount)) return nullptr;
144  bal = gnc_lot_get_balance (lot);
145  opening_is_positive = gnc_numeric_positive_p (s->amount);
146  bal_is_positive = gnc_numeric_positive_p (bal);
147  if (opening_is_positive != bal_is_positive) return nullptr;
148 
149  trans = s->parent;
150  if (els->currency &&
151  (FALSE == gnc_commodity_equiv (els->currency,
152  trans->common_currency)))
153  {
154  return nullptr;
155  }
156 
157  posted = trans->date_posted;
158  if (els->date_pred (els->time, posted))
159  {
160  els->time = trans->date_posted;
161  els->lot = lot;
162  }
163 
164  return nullptr;
165 }
166 
167 static inline GNCLot *
168 xaccAccountFindOpenLot (Account *acc, gnc_numeric sign,
169  gnc_commodity *currency,
170  gint64 guess,
171  gboolean (*date_pred)(time64, time64))
172 {
173  FindLot es;
174 
175  es.lot = nullptr;
176  es.currency = currency;
177  es.time = guess;
178  es.date_pred = date_pred;
179 
180  if (gnc_numeric_positive_p(sign)) es.numeric_pred = gnc_numeric_negative_p;
181  else es.numeric_pred = gnc_numeric_positive_p;
182 
183  xaccAccountForEachLot (acc, finder_helper, &es);
184  return es.lot;
185 }
186 
187 GNCLot *
188 xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign,
189  gnc_commodity *currency)
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 }
201 
202 GNCLot *
203 xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign,
204  gnc_commodity *currency)
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 }
215 
216 /* ============================================================== */
217 
218 Split *
219 xaccSplitAssignToLot (Split *split, GNCLot *lot)
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 }
428 
429 /* ============================================================== */
430 
431 /* Accounting-policy callback. Given an account and an amount,
432  * this routine should return a lot. By implementing this as
433  * a callback, we can 'easily' add other accounting policies.
434  */
435 gboolean
436 xaccSplitAssign (Split *split)
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 }
486 
487 /* ============================================================== */
488 
489 static Split *
490 find_split_by_type (const gchar *type, const Split *split)
491 {
492  GncGUID *type_guid = nullptr;
493 
494  if (!split) return nullptr;
495 
496  qof_instance_get (QOF_INSTANCE (split), type, &type_guid, nullptr);
497  if (!type_guid) return nullptr;
498 
499  /* Both splits will be in the same collection, so search there. */
500  auto *guid_split = (Split *) qof_collection_lookup_entity (qof_instance_get_collection (split), type_guid);
501  PINFO ("split=%p has %s=%p", split, type, guid_split);
502  guid_free (type_guid);
503  return guid_split;
504 }
505 
506 
507 Split *
508 xaccSplitGetCapGainsSplit (const Split *split)
509 {
510  return find_split_by_type ("gains-split", split);
511 }
512 
513 Split *
514 xaccSplitGetGainsSourceSplit (const Split *split)
515 {
516  return find_split_by_type ("gains-source", split);
517 }
518 
519 /* ============================================================== */
520 
521 void
522 xaccSplitComputeCapGains(Split *split, Account *gain_acc)
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 }
892 
893 /* ============================================================== */
894 
895 gnc_numeric
896 xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
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 }
1034 
1035 /* ============================================================== */
1036 
1037 gnc_numeric
1038 xaccSplitGetCapGains(Split * split)
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 }
1066 
1067 /* ============================================================== */
1068 
1069 void
1070 xaccLotComputeCapGains (GNCLot *lot, Account *gain_acc)
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 }
1113 
1114 /* =========================== END OF FILE ======================= */
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
GNCLot * xaccAccountFindEarliestOpenLot(Account *acc, gnc_numeric sign, gnc_commodity *currency)
The xaccAccountFindEarliestOpenLot() method is a handy utility routine for finding the earliest open ...
Definition: cap-gains.cpp:188
This is the private header for the account structure.
High-Level API for imposing Lot constraints.
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
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.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
gpointer xaccAccountForEachLot(const Account *acc, gpointer(*proc)(GNCLot *lot, gpointer user_data), gpointer user_data)
The xaccAccountForEachLot() method will apply the function &#39;proc&#39; to each lot in the account...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4551
gnc_numeric xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the i...
Definition: cap-gains.cpp:896
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:209
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
Utilities to Convert Stock Accounts to use Lots.
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.
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.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
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
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 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.
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.cpp:514
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:188
gnc_numeric xaccSplitGetCapGains(Split *split)
The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the ind...
Definition: cap-gains.cpp:1038
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
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.
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
Account public routines (C++ api)
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.
Implement Accounting Policy.
Implement Accounting Policy Private header File.
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...
All type declarations for the whole Gnucash engine.
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
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
Definition: cap-gains.cpp:219
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
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Retrieve information on whether or not a transaction has been voided.
GNCLot * gnc_lot_make_default(Account *acc)
Definition: gnc-lot.cpp:765
gboolean xaccSplitAssign(Split *split)
The`xaccSplitAssign() routine will take the indicated split and, if it doesn&#39;t already belong to a lo...
Definition: cap-gains.cpp:436
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition: gnc-lot.cpp:367
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.
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
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
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
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1516
Utilities to Automatically Compute Capital Gains/Losses.
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