GnuCash  5.6-17-gfafc745b1b+
cap-gains.c
Go to the documentation of this file.
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 "AccountP.h"
62 #include "Scrub2.h"
63 #include "Scrub3.h"
64 #include "Transaction.h"
65 #include "TransactionP.h"
66 #include "cap-gains.h"
67 #include "gnc-engine.h"
68 #include "engine-helpers.h"
69 #include "gnc-lot.h"
70 #include "policy.h"
71 #include "policy-p.h"
72 
73 static QofLogModule log_module = GNC_MOD_LOT;
74 
75 
76 /* ============================================================== */
77 
78 gboolean
80 {
81  gnc_commodity *acc_comm;
82  SplitList *splits, *node;
83 
84  if (!acc) return FALSE;
85 
86  if (xaccAccountIsPriced (acc))
87  return TRUE;
88 
89  acc_comm = xaccAccountGetCommodity(acc);
90 
91  splits = xaccAccountGetSplitList(acc);
92  for (node = splits; node; node = node->next)
93  {
94  Split *s = node->data;
95  Transaction *t = s->parent;
96  if (s->gains == GAINS_STATUS_GAINS) continue;
97  if (acc_comm != t->common_currency) return TRUE;
98  }
99 
100  return FALSE;
101 }
102 
103 /* ============================================================== */
104 
106 {
107  GNCLot *lot;
108  gnc_commodity *currency;
109  time64 time;
110  int (*numeric_pred)(gnc_numeric);
111  gboolean (*date_pred)(time64 e, time64 tr);
112 };
113 
114 static gboolean
115 earliest_pred (time64 earl, time64 tran)
116 {
117  return earl > tran;
118 }
119 
120 static gboolean
121 latest_pred (time64 earl, time64 tran)
122 {
123  return earl < tran;
124 }
125 
126 static gpointer
127 finder_helper (GNCLot *lot, gpointer user_data)
128 {
129  struct find_lot_s *els = user_data;
130  Split *s;
131  Transaction *trans;
132  gnc_numeric bal;
133  gboolean opening_is_positive, bal_is_positive;
134  time64 posted = 0;
135 
136  if (gnc_lot_is_closed (lot)) return NULL;
137 
138  s = gnc_lot_get_earliest_split (lot);
139  if (s == NULL) return NULL;
140 
141  /* We want a lot whose balance is of the correct sign. All splits
142  in a lot must be the opposite sign of the opening split. We also
143  want to ignore lots that are overfull, i.e., where the balance in
144  the lot is of opposite sign to the opening split in the lot. */
145  if (0 == (els->numeric_pred) (s->amount)) return NULL;
146  bal = gnc_lot_get_balance (lot);
147  opening_is_positive = gnc_numeric_positive_p (s->amount);
148  bal_is_positive = gnc_numeric_positive_p (bal);
149  if (opening_is_positive != bal_is_positive) return NULL;
150 
151  trans = s->parent;
152  if (els->currency &&
153  (FALSE == gnc_commodity_equiv (els->currency,
154  trans->common_currency)))
155  {
156  return NULL;
157  }
158 
159  posted = trans->date_posted;
160  if (els->date_pred (els->time, posted))
161  {
162  els->time = trans->date_posted;
163  els->lot = lot;
164  }
165 
166  return NULL;
167 }
168 
169 static inline GNCLot *
170 xaccAccountFindOpenLot (Account *acc, gnc_numeric sign,
171  gnc_commodity *currency,
172  gint64 guess,
173  gboolean (*date_pred)(time64, time64))
174 {
175  struct find_lot_s es;
176 
177  es.lot = NULL;
178  es.currency = currency;
179  es.time = guess;
180  es.date_pred = date_pred;
181 
182  if (gnc_numeric_positive_p(sign)) es.numeric_pred = gnc_numeric_negative_p;
183  else es.numeric_pred = gnc_numeric_positive_p;
184 
185  xaccAccountForEachLot (acc, finder_helper, &es);
186  return es.lot;
187 }
188 
189 GNCLot *
190 xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign,
191  gnc_commodity *currency)
192 {
193  GNCLot *lot;
194  ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, sign.num,
195  sign.denom);
196 
197  lot = xaccAccountFindOpenLot (acc, sign, currency,
198  G_MAXINT64, earliest_pred);
199  LEAVE ("found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
201  return lot;
202 }
203 
204 GNCLot *
205 xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign,
206  gnc_commodity *currency)
207 {
208  GNCLot *lot;
209  ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
210  sign.num, sign.denom);
211 
212  lot = xaccAccountFindOpenLot (acc, sign, currency,
213  G_MININT64, latest_pred);
214  LEAVE ("found lot=%p %s", lot, gnc_lot_get_title (lot));
215  return lot;
216 }
217 
218 /* ============================================================== */
219 
220 Split *
221 xaccSplitAssignToLot (Split *split, GNCLot *lot)
222 {
223  Account *acc;
224  gnc_numeric baln;
225  int cmp;
226  gboolean baln_is_positive, amt_is_positive;
227 
228  if (!lot) return split;
229  if (!split) return NULL;
230 
231  /* If this split already belongs to a lot, we are done. */
232  if (split->lot) return NULL;
233 
234  /* Anomalous situation; except for voided transactions,
235  * we don't expect to see splits with no amount ..
236  * unless they're gains splits, and we shouldn't see those.
237  */
238  if (gnc_numeric_zero_p (split->amount))
239  {
240  if (xaccTransGetVoidStatus(split->parent)) return NULL;
241 
242  PWARN ("split with zero amount; value=%s gflag=%x gsplit=%p",
243  gnc_num_dbg_to_string (split->amount),
244  split->gains,
245  split->gains_split);
246  if (split->gains_split)
247  {
248  PWARN ("gains amt=%s value=%s",
249  gnc_num_dbg_to_string (split->gains_split->amount),
250  gnc_num_dbg_to_string (split->gains_split->value));
251  }
252  return NULL;
253  }
254 
255  /* If the lot is closed, we can't add anything to it */
256  baln = gnc_lot_get_balance (lot);
257  if (gnc_lot_is_closed (lot)) return split;
258 
259  /* If the lot balance is zero, but the lot is open, then
260  * the lot is empty. Unconditionally add the split. */
261  if (gnc_numeric_zero_p (baln))
262  {
263  acc = split->acc;
264  xaccAccountBeginEdit (acc);
265  gnc_lot_add_split (lot, split);
266  PINFO ("added split to empty lot, new lot baln=%s (%s)",
268  gnc_lot_get_title (lot));
269  xaccAccountCommitEdit (acc);
270  return NULL;
271  }
272 
273  /* If the sign of the split is the same as the sign of the lot,
274  * add the split, but complain about it ... none of the currently
275  * implemented accounting policies should be giving us splits
276  * that make lots larger. One a lot is open, the FIFO/LIFO
277  * policies should be working only to make the lot smaller.
278  * We can remove the warning emssage come the day we have
279  * fancier policies.
280  */
281  baln_is_positive = gnc_numeric_positive_p (baln);
282  amt_is_positive = gnc_numeric_positive_p (split->amount);
283  if ((baln_is_positive && amt_is_positive) ||
284  ((!baln_is_positive) && (!amt_is_positive)))
285  {
286  PWARN ("accounting policy gave us split that enlarges the lot!\n"
287  "old lot baln=%s split amt=%s lot=%s",
289  gnc_num_dbg_to_string (split->amount),
290  gnc_lot_get_title (lot));
291 
292  acc = split->acc;
293  xaccAccountBeginEdit (acc);
294  gnc_lot_add_split (lot, split);
295  xaccAccountCommitEdit (acc);
296  return NULL;
297  }
298 
299  /* If adding the split would make the lot balance change sign,
300  * then we split the split into two pieces: one piece that will
301  * bring the lot balance to zero, and another to be dealt with
302  * later. */
303  cmp = gnc_numeric_compare (gnc_numeric_abs(split->amount),
304  gnc_numeric_abs(baln));
305 
306  PINFO ("found open lot with baln=%s (%s)", gnc_num_dbg_to_string (baln),
307  gnc_lot_get_title (lot));
308 
309  /* cmp == -1 if amt < baln, ==0 if amt==baln */
310  if (0 >= cmp)
311  {
312  acc = split->acc;
313  xaccAccountBeginEdit (acc);
314  gnc_lot_add_split (lot, split);
315  PINFO ("simple added split to lot, new lot baln=%s",
317  xaccAccountCommitEdit (acc);
318  return NULL;
319  }
320 
321  /* If we are here, then (cmp == +1 iff (amt > baln)) and we need
322  * to split up the split into pieces. Do it. */
323  {
324  time64 now = gnc_time (NULL), time = 0;
325  Split * new_split;
326  gnc_numeric amt_a, amt_b, amt_tot;
327  gnc_numeric val_a, val_b, val_tot;
328  gnc_numeric frac;
329  Transaction *trans;
330 
331  acc = split->acc;
332  xaccAccountBeginEdit (acc);
333  trans = split->parent;
334  xaccTransBeginEdit (trans);
335 
336  amt_tot = split->amount;
337  amt_a = gnc_numeric_neg (baln);
338  amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
339  g_return_val_if_fail(gnc_numeric_check(amt_b) == GNC_ERROR_OK, NULL);
340 
341  PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
342  split,
343  gnc_num_dbg_to_string(amt_a),
344  gnc_num_dbg_to_string(amt_b) );
345 
346  /* Compute the value so that it holds in the same proportion:
347  * i.e. so that (amt_a / amt_tot) = (val_a / val_tot)
348  */
349  val_tot = split->value;
350  frac = gnc_numeric_div (amt_a, amt_tot,
352  val_a = gnc_numeric_mul (frac, val_tot,
353  gnc_numeric_denom(val_tot),
355 
356  val_b = gnc_numeric_sub_fixed (val_tot, val_a);
357  if (gnc_numeric_check(val_a))
358  {
359  PERR("Numeric overflow\n"
360  "Acct=%s Txn=%s\n"
361  "\tval_tot=%s amt_a=%s amt_tot=%s\n",
362  xaccAccountGetName(acc),
364  gnc_num_dbg_to_string(val_tot),
365  gnc_num_dbg_to_string(amt_a),
366  gnc_num_dbg_to_string(amt_tot));
367  }
368 
369  if (gnc_numeric_zero_p(amt_a) || gnc_numeric_zero_p(amt_b))
370  {
371  PERR ("Failed to split into two!");
372  }
373 
374  PINFO ("split value is = %s = %s + %s",
375  gnc_num_dbg_to_string(val_tot),
376  gnc_num_dbg_to_string(val_a),
377  gnc_num_dbg_to_string(val_b) );
378 
379  g_return_val_if_fail (!gnc_numeric_zero_p (amt_a), NULL);
380  g_return_val_if_fail (!gnc_numeric_check (val_a), NULL);
381  xaccSplitSetAmount (split, amt_a);
382  xaccSplitSetValue (split, val_a);
383 
384  /* Adding this split will have the effect of closing this lot,
385  * because the new balance should be precisely zero. */
386  gnc_lot_add_split (lot, split);
387 
388  /* Put the remainder of the balance into a new split,
389  * which is in other respects just a clone of this one. */
390  new_split = xaccMallocSplit (qof_instance_get_book(acc));
391 
392  /* Copy most of the split attributes */
393  xaccSplitSetMemo (new_split, xaccSplitGetMemo (split));
394  /* Set split-action with gnc_set_num_action which is the same as
395  * xaccSplitSetAction with these arguments; use gnc_get_num_action to get
396  * split-action which is the same as xaccSplitGetAction */
397  gnc_set_num_action(NULL, new_split, NULL, gnc_get_num_action(NULL, split));
398  xaccSplitSetReconcile (new_split, xaccSplitGetReconcile (split));
399  time = xaccSplitGetDateReconciled (split);
400  xaccSplitSetDateReconciledSecs (new_split, time);
401 
402  /* Set the lot-split and peer_guid properties on the two
403  * splits to indicate that they're linked.
404  */
405  xaccSplitAddPeerSplit(split, new_split, now);
406  xaccSplitAddPeerSplit(new_split, split, now);
407  xaccAccountInsertSplit (acc, new_split);
408  xaccTransAppendSplit (trans, new_split);
409  /* Set the amount and value after the split is in the transaction
410  so it can find the correct denominator to use. Otherwise it
411  uses 100000 which may cause an overflow in some of the tests
412  in test-period */
413  xaccSplitSetAmount (new_split, amt_b);
414  xaccSplitSetValue (new_split, val_b);
415  xaccTransCommitEdit (trans);
416  xaccAccountCommitEdit (acc);
417  return new_split;
418  }
419 }
420 
421 /* ============================================================== */
422 
423 /* Accounting-policy callback. Given an account and an amount,
424  * this routine should return a lot. By implementing this as
425  * a callback, we can 'easily' add other accounting policies.
426  */
427 gboolean
428 xaccSplitAssign (Split *split)
429 {
430  Account *acc;
431  gboolean splits_split_up = FALSE;
432  GNCLot *lot;
433  GNCPolicy *pcy;
434 
435  if (!split) return FALSE;
436 
437  /* If this split already belongs to a lot or the account doesn't
438  * have lots, we are done.
439  */
440  if (split->lot) return FALSE;
441  g_return_val_if_fail (split->gains == GAINS_STATUS_UNKNOWN ||
442  (split->gains & GAINS_STATUS_GAINS) == FALSE, FALSE);
443  acc = split->acc;
444  if (!xaccAccountHasTrades (acc))
445  return FALSE;
446  if (gnc_numeric_zero_p (split->amount))
447  return FALSE;
448 
449  ENTER ("(split=%p)", split);
450 
451  pcy = gnc_account_get_policy(acc);
452  xaccAccountBeginEdit (acc);
453 
454  /* If we are here, this split does not belong to any lot.
455  * We ask the policy for a lot to assign it to. This
456  * block is written in the form of a while loop, since we
457  * may have to bust a split across several lots.
458  */
459  while (split)
460  {
461  PINFO ("have split %p amount=%s", split,
462  gnc_num_dbg_to_string (split->amount));
463  split->gains |= GAINS_STATUS_VDIRTY;
464  lot = pcy->PolicyGetLot (pcy, split);
465  if (!lot)
466  {
467  lot = gnc_lot_make_default (acc);
468  PINFO ("start new lot (%s)", gnc_lot_get_title(lot));
469  }
470  split = xaccSplitAssignToLot (split, lot);
471  if (split) splits_split_up = TRUE;
472  }
473  xaccAccountCommitEdit (acc);
474 
475  LEAVE (" split_up=%d", splits_split_up);
476  return splits_split_up;
477 }
478 
479 /* ============================================================== */
480 
481 Split *
482 xaccSplitGetCapGainsSplit (const Split *split)
483 {
484  GncGUID *gains_guid;
485  Split *gains_split;
486 
487  if (!split) return NULL;
488 
489  qof_instance_get (QOF_INSTANCE (split),
490  "gains-split", &gains_guid,
491  NULL);
492  if (!gains_guid) return NULL;
493 
494  /* Both splits will be in the same collection, so search there. */
495  gains_split = (Split*) qof_collection_lookup_entity (
496  qof_instance_get_collection(split), gains_guid);
497  PINFO ("split=%p has gains-split=%p", split, gains_split);
498  guid_free (gains_guid);
499  return gains_split;
500 }
501 
502 /* ============================================================== */
503 
504 Split *
505 xaccSplitGetGainsSourceSplit (const Split *split)
506 {
507  GncGUID *source_guid;
508  Split *source_split;
509 
510  if (!split) return NULL;
511 
512  qof_instance_get (QOF_INSTANCE (split),
513  "gains-source", &source_guid,
514  NULL);
515  if (!source_guid) return NULL;
516 
517  /* Both splits will be in the same collection, so search there. */
518  source_split = (Split*) qof_collection_lookup_entity(
519  qof_instance_get_collection(split), source_guid);
520  PINFO ("split=%p has source-split=%p", split, source_split);
521  guid_free (source_guid);
522  return source_split;
523 }
524 
525 /* ============================================================== */
526 
527 void
528 xaccSplitComputeCapGains(Split *split, Account *gain_acc)
529 {
530  SplitList *node;
531  GNCLot *lot;
532  GNCPolicy *pcy;
533  gnc_commodity *currency = NULL;
534  gnc_numeric zero = gnc_numeric_zero();
535  gnc_numeric value;
536  gnc_numeric frac;
537  gnc_numeric opening_amount, opening_value;
538  gnc_numeric lot_amount, lot_value;
539  gnc_commodity *opening_currency;
540 
541  if (!split) return;
542  lot = split->lot;
543  if (!lot) return;
545  currency = split->parent->common_currency;
546 
547  ENTER ("(split=%p gains=%p status=0x%x lot=%s)", split,
548  split->gains_split, split->gains, gnc_lot_get_title(lot));
549 
550  /* Make sure the status flags and pointers are initialized */
551  xaccSplitDetermineGainStatus(split);
552 
553  /* Not possible to have gains if the transaction currency and
554  * account commodity are identical. */
555  if (gnc_commodity_equal (currency,
556  xaccAccountGetCommodity(split->acc)))
557  {
558  LEAVE ("Currency transfer, gains not possible, returning.");
559  return;
560  }
561 
562  if (pcy->PolicyIsOpeningSplit (pcy, lot, split))
563  {
564 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER
565  /* Check to make sure that this opening split doesn't
566  * have a cap-gain transaction associated with it.
567  * If it does, that's wrong, and we ruthlessly destroy it.
568  * XXX Don't do this, it leads to infinite loops.
569  * We need to scrub out errors like this elsewhere!
570  */
571  if (xaccSplitGetCapGainsSplit (split))
572  {
573  Split *gains_split = xaccSplitGetCapGainsSplit(split);
574  Transaction *trans = gains_split->parent;
575  PERR ("Opening Split must not have cap gains!!\n");
576 
577  xaccTransBeginEdit (trans);
578  xaccTransDestroy (trans);
579  xaccTransCommitEdit (trans);
580  }
581 #endif
582  LEAVE ("Lot opening split, returning.");
583  return;
584  }
585 
586  if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
587  {
588  LEAVE ("Stock split split, returning.");
589  return;
590  }
591 
592  if (GAINS_STATUS_GAINS & split->gains)
593  {
594  Split *s;
595  PINFO ("split is a gains recording split, switch over");
596  /* If this is the split that records the gains, then work with
597  * the split that generates the gains.
598  */
599  /* split = xaccSplitGetCapGainsSplit (split); */
600  s = split->gains_split;
601 
602  /* This should never be NULL, and if it is, and its matching
603  * parent can't be found, then its a bug, and we should be
604  * discarding this split. But ... for now .. return.
605  * XXX move appropriate actions to a 'scrub' routine'
606  */
607  if (!s)
608  {
609  PERR ("Bad gains-split pointer! .. trying to recover.");
610  split->gains_split = xaccSplitGetCapGainsSplit (split);
611  s = split->gains_split;
612  if (!s) return;
613 #if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER
614  xaccTransDestroy (trans);
615 #endif
616  }
617  split = s;
618  }
619 
620  /* Note: if the value of the 'opening' split(s) has changed,
621  * then the cap gains are changed. So we need to check not
622  * only if this split is dirty, but also the lot-opening splits. */
623  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
624  {
625  Split *s = node->data;
626  if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
627  {
628  if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus (s);
629  if (s->gains & GAINS_STATUS_VDIRTY)
630  {
631  /* Force a recompute to occur */
632  split->gains |= GAINS_STATUS_VDIRTY;
633  break;
634  }
635  }
636  }
637 
638  /* If it doesn't look like this split is 'dirty', then there's
639  * nothing to do. Just return. */
640  if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) &&
641  (split->gains_split) &&
642  (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
643  {
644  LEAVE ("split not dirty, returning");
645  return;
646  }
647 
648  /* Yow! If amount is zero, there's nothing to do! Amount-zero splits
649  * may exist if users attempted to manually record gains. */
650  if (gnc_numeric_zero_p (split->amount)) return;
651 
652  /* If we got to here, then the split or something related is
653  * 'dirty' and the gains really do need to be recomputed.
654  * So start working things. */
655 
656  /* Get the amount and value in this lot at the time of this transaction. */
657  gnc_lot_get_balance_before (lot, split, &lot_amount, &lot_value);
658 
659  pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
660  &opening_currency);
661 
662  /* Check to make sure the lot-opening currency and this split
663  * use the same currency */
664  if (FALSE == gnc_commodity_equiv (currency, opening_currency))
665  {
666  /* OK, the purchase and the sale were made in different currencies.
667  * I don't know how to compute cap gains for that. This is not
668  * an error. Just punt, silently.
669  */
670  LEAVE ("Can't compute gains, mismatched commodities!");
671  return;
672  }
673 
674  /* Opening amount should be larger (or equal) to current split,
675  * and it should be of the opposite sign.
676  * XXX This should really be a part of a scrub routine that
677  * cleans up the lot, before we get at it!
678  */
679  if (0 > gnc_numeric_compare (gnc_numeric_abs(lot_amount),
680  gnc_numeric_abs(split->amount)))
681  {
682  GList *n;
683  for (n = gnc_lot_get_split_list(lot); n; n = n->next)
684  {
685  Split *s = n->data;
686  PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
687  }
688  PERR ("Malformed Lot \"%s\"! (too thin!) "
689  "opening amt=%s split amt=%s baln=%s",
690  gnc_lot_get_title (lot),
691  gnc_num_dbg_to_string (lot_amount),
692  gnc_num_dbg_to_string (split->amount),
694  return;
695  }
696  if ( (gnc_numeric_negative_p(lot_amount) ||
697  gnc_numeric_positive_p(split->amount)) &&
698  (gnc_numeric_positive_p(lot_amount) ||
699  gnc_numeric_negative_p(split->amount)))
700  {
701  GList *n;
702  for (n = gnc_lot_get_split_list(lot); n; n = n->next)
703  {
704  Split *s = n->data;
705  PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
706  }
707  PERR ("Malformed Lot \"%s\"! (too fat!) "
708  "opening amt=%s split amt=%s baln=%s",
709  gnc_lot_get_title (lot),
710  gnc_num_dbg_to_string (lot_amount),
711  gnc_num_dbg_to_string (split->amount),
713  return;
714  }
715 
716  /* The cap gains is the difference between the basis prior to the
717  * current split, and the current split, pro-rated for an equal
718  * amount of shares.
719  * i.e. purchase_price = lot_value / lot_amount
720  * cost_basis = purchase_price * current_split_amount
721  * cap_gain = current_split_value - cost_basis
722  */
723  /* Fraction of the lot that this split represents: */
724  frac = gnc_numeric_div (split->amount, lot_amount,
727  /* Basis for this split: */
728  value = gnc_numeric_mul (frac, lot_value,
729  gnc_numeric_denom(opening_value),
731  /* Capital gain for this split: */
732  value = gnc_numeric_sub (value, split->value,
734  PINFO ("Open amt=%s val=%s; split amt=%s val=%s; gains=%s\n",
735  gnc_num_dbg_to_string (lot_amount),
736  gnc_num_dbg_to_string (lot_value),
737  gnc_num_dbg_to_string (split->amount),
738  gnc_num_dbg_to_string (split->value),
739  gnc_num_dbg_to_string (value));
740  if (gnc_numeric_check (value))
741  {
742  PERR ("Numeric overflow during gains calculation\n"
743  "Acct=%s Txn=%s\n"
744  "\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
745  xaccAccountGetName(split->acc),
746  xaccTransGetDescription(split->parent),
747  gnc_num_dbg_to_string (lot_amount),
748  gnc_num_dbg_to_string (lot_value),
749  gnc_num_dbg_to_string (split->amount),
750  gnc_num_dbg_to_string (split->value),
751  gnc_num_dbg_to_string (value));
752  return;
753  }
754 
755  /* Are the cap gains zero? If not, add a balancing transaction.
756  * As per design doc lots.txt: the transaction has two splits,
757  * with equal & opposite values. The amt of one iz zero (so as
758  * not to upset the lot balance), the amt of the other is the same
759  * as its value (its the realized gain/loss).
760  */
761  if (FALSE == gnc_numeric_zero_p (value))
762  {
763  Transaction *trans;
764  Split *lot_split, *gain_split;
765  gboolean new_gain_split;
766  gnc_numeric negvalue = gnc_numeric_neg (value);
767 
768  /* See if there already is an associated gains transaction.
769  * If there is, adjust its value as appropriate. Else, create
770  * a new gains transaction.
771  */
772  /* lot_split = xaccSplitGetCapGainsSplit (split); */
773  lot_split = split->gains_split;
774 
775  if (NULL == lot_split)
776  {
777  Account *lot_acc = gnc_lot_get_account(lot);
778  QofBook *book = qof_instance_get_book(lot_acc);
779  Transaction *base_txn = xaccSplitGetParent (split);
780 
781  new_gain_split = TRUE;
782 
783  lot_split = xaccMallocSplit (book);
784  gain_split = xaccMallocSplit (book);
785 
786  /* Check to make sure the gains account currency matches. */
787  if ((NULL == gain_acc) ||
788  (FALSE == gnc_commodity_equiv (currency,
789  xaccAccountGetCommodity(gain_acc))))
790  {
791  gain_acc = xaccAccountGainsAccount (lot_acc, currency);
792  }
793 
794  xaccAccountBeginEdit (gain_acc);
795  xaccAccountInsertSplit (gain_acc, gain_split);
796  xaccAccountCommitEdit (gain_acc);
797 
798  xaccAccountBeginEdit (lot_acc);
799  xaccAccountInsertSplit (lot_acc, lot_split);
800  xaccAccountCommitEdit (lot_acc);
801 
802  trans = xaccMallocTransaction (book);
803 
804  xaccTransBeginEdit (trans);
805  xaccTransSetCurrency (trans, currency);
806  xaccTransSetDescription (trans, _("Realized Gain/Loss"));
807 
808  xaccTransAppendSplit (trans, lot_split);
809  xaccTransAppendSplit (trans, gain_split);
810 
811  xaccSplitSetMemo (lot_split, _("Realized Gain/Loss"));
812  xaccSplitSetMemo (gain_split, _("Realized Gain/Loss"));
813 
814  /* For the new transaction, set the split properties indicating
815  * that this is the gains transaction that corresponds
816  * to the gains source.
817  */
818  xaccTransBeginEdit (base_txn);
819  qof_instance_set (QOF_INSTANCE (split),
820  "gains-split", xaccSplitGetGUID (lot_split),
821  NULL);
822  xaccTransCommitEdit (base_txn);
823  qof_instance_set (QOF_INSTANCE (lot_split),
824  "gains-source", xaccSplitGetGUID (split),
825  NULL);
826 
827  }
828  else
829  {
830  trans = lot_split->parent;
831  gain_split = xaccSplitGetOtherSplit (lot_split);
832 
833  /* If the gains transaction has been edited so that it no longer has
834  just two splits, ignore it and assume it's still correct. */
835  if (!gain_split)
836  {
837  new_gain_split = FALSE;
838  }
839  /* If the gain is already recorded correctly do nothing. This is
840  * more than just an optimization since this may be called during
841  * gnc_book_partition_txn and depending on the order in which things
842  * happen some splits may be in the wrong book at that time. */
843  else if (split->gains_split == lot_split &&
844  lot_split->gains_split == split &&
845  gain_split->gains_split == split &&
846  gnc_numeric_equal (xaccSplitGetValue (lot_split), value) &&
847  gnc_numeric_zero_p (xaccSplitGetAmount (lot_split)) &&
848  gnc_numeric_equal (xaccSplitGetValue (gain_split), negvalue) &&
849  gnc_numeric_equal (xaccSplitGetAmount (gain_split), negvalue))
850  {
851  new_gain_split = FALSE;
852  }
853  else
854  {
855  new_gain_split = TRUE;
856  xaccTransBeginEdit (trans);
857 
858  /* Make sure the existing gains trans has the correct currency,
859  * just in case someone screwed with it! */
860  if (FALSE == gnc_commodity_equiv(currency, trans->common_currency))
861  {
862  PWARN ("Resetting the transaction currency!");
863  xaccTransSetCurrency (trans, currency);
864  }
865  }
866  }
867 
868  if (new_gain_split)
869  {
870  /* Common to both */
871  time64 time = xaccTransRetDatePosted (split->parent);
872  xaccTransSetDatePostedSecs (trans, time);
873  xaccTransSetDateEnteredSecs (trans, gnc_time (NULL));
874 
875  xaccSplitSetAmount (lot_split, zero);
876  xaccSplitSetValue (lot_split, value);
877 
878  xaccSplitSetAmount (gain_split, negvalue);
879  xaccSplitSetValue (gain_split, negvalue);
880 
881  /* Some short-cuts to help avoid the above property lookup. */
882  split->gains = GAINS_STATUS_CLEAN;
883  split->gains_split = lot_split;
884  lot_split->gains = GAINS_STATUS_GAINS;
885  lot_split->gains_split = split;
886  gain_split->gains = GAINS_STATUS_GAINS;
887  gain_split->gains_split = split;
888 
889  /* Do this last since it may generate an event that will call us
890  recursively. */
891  gnc_lot_add_split (lot, lot_split);
892 
893  xaccTransCommitEdit (trans);
894  }
895  }
896  LEAVE ("(lot=%s)", gnc_lot_get_title(lot));
897 }
898 
899 /* ============================================================== */
900 
901 gnc_numeric
902 xaccSplitGetCapGains(Split * split)
903 {
904  if (!split) return gnc_numeric_zero();
905  ENTER("(split=%p)", split);
906 
907  if (GAINS_STATUS_UNKNOWN == split->gains)
908  xaccSplitDetermineGainStatus(split);
909  if ((split->gains & GAINS_STATUS_A_VDIRTY) ||
910  (split->gains_split &&
911  (split->gains_split->gains & GAINS_STATUS_A_VDIRTY)))
912  {
913  xaccSplitComputeCapGains (split, NULL);
914  }
915 
916  /* If this is the source split, get the gains from the one
917  * that records the gains. If this already is the gains split,
918  * its a no-op. */
919  if (!(GAINS_STATUS_GAINS & split->gains))
920  {
921  /* split = xaccSplitGetCapGainsSplit (split); */
922  split = split->gains_split;
923  }
924 
925  LEAVE("(split=%p)", split);
926  if (!split) return gnc_numeric_zero();
927 
928  return split->value;
929 }
930 
931 /* ============================================================== */
932 
933 void
934 xaccLotComputeCapGains (GNCLot *lot, Account *gain_acc)
935 {
936  SplitList *node;
937  GNCPolicy *pcy;
938  gboolean is_dirty = FALSE;
939 
940  /* Note: if the value of the 'opening' split(s) has changed,
941  * then the cap gains are changed. To capture this, we need
942  * to mark all splits dirty if the opening splits are dirty. */
943 
944  ENTER("(lot=%p)", lot);
946  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
947  {
948  Split *s = node->data;
949  if (pcy->PolicyIsOpeningSplit(pcy, lot, s))
950  {
951  if (GAINS_STATUS_UNKNOWN == s->gains)
952  xaccSplitDetermineGainStatus(s);
953  if (s->gains & GAINS_STATUS_VDIRTY)
954  {
955  is_dirty = TRUE;
956  s->gains &= ~GAINS_STATUS_VDIRTY;
957  }
958  }
959  }
960 
961  if (is_dirty)
962  {
963  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
964  {
965  Split *s = node->data;
966  s->gains |= GAINS_STATUS_VDIRTY;
967  }
968  }
969 
970  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
971  {
972  Split *s = node->data;
973  xaccSplitComputeCapGains (s, gain_acc);
974  }
975  LEAVE("(lot=%p)", lot);
976 }
977 
978 /* =========================== 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.c:190
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:2047
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
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...
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:4046
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:4717
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:212
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
Utilities to Convert Stock Accounts to use Lots.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
All arguments are required to have the same denominator, that denominator is to be used in the output...
Definition: gnc-numeric.h:208
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
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.c:528
void gnc_lot_add_split(GNCLot *lot, Split *split)
The gnc_lot_add_split() routine adds a split to this lot.
Definition: gnc-lot.cpp:594
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gboolean xaccAccountHasTrades(const Account *acc)
The xaccAccountHasTrades() method checks to see if the indicated account is used in the trading of co...
Definition: cap-gains.c:79
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.c:505
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:190
gnc_numeric xaccSplitGetCapGains(Split *split)
The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the ind...
Definition: cap-gains.c:902
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Split * xaccSplitGetCapGainsSplit(const Split *split)
The xaccSplitGetCapGainsSplit() routine returns the split that records the cap gains for this split...
Definition: cap-gains.c:482
Split * gnc_lot_get_earliest_split(GNCLot *lot)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest da...
Definition: gnc-lot.cpp:673
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.cpp:445
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:197
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Implement Accounting Policy.
Implement Accounting Policy Private header File.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.cpp:425
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void gnc_lot_get_balance_before(const GNCLot *lot, const Split *split, gnc_numeric *amount, gnc_numeric *value)
The gnc_lot_get_balance_before routine computes both the balance and value in the lot considering onl...
Definition: gnc-lot.cpp:544
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
Definition: Split.h:555
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
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.
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
The xaccSplitAssignToLot() routine will fit the indicated split into the indicated lot...
Definition: cap-gains.c:221
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64. ...
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition: Split.cpp:1854
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)
XXX: Document?
Definition: gnc-lot.cpp:780
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.c:428
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.cpp:367
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:1436
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3443
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1048
This is the private header for the account structure.
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:5255
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:167
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
const char * xaccSplitGetType(const Split *s)
The xaccIsPeerSplit() is a convenience routine that returns TRUE (a non-zero value) if the two splits...
Definition: Split.cpp:2005
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3280
No error.
Definition: gnc-numeric.h:225
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:247
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:1477
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:2090
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.cpp:502
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69