GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Scrub3.c
Go to the documentation of this file.
1 /********************************************************************\
2  * Scrub3.c -- Constrain Cap Gains to Track Sources of Gains *
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 [email protected] *
20 \********************************************************************/
21 
32 #include "config.h"
33 
34 #include <glib.h>
35 
36 #include "cap-gains.h"
37 #include "gnc-commodity.h"
38 #include "gnc-engine.h"
39 #include "gnc-lot.h"
40 #include "policy-p.h"
41 #include "Account.h"
42 #include "AccountP.h"
43 #include "Scrub2.h"
44 #include "Scrub3.h"
45 #include "Transaction.h"
46 #include "TransactionP.h"
47 
48 static QofLogModule log_module = GNC_MOD_LOT;
49 
50 /* ================================================================= */
58 static inline gboolean
59 gains_possible (GNCLot *lot)
60 {
61  SplitList *node;
62  Account *acc;
63  Split *split;
64  gboolean comeq;
65  gnc_commodity *acc_commodity;
66 
67  acc = gnc_lot_get_account (lot);
68 
69  node = gnc_lot_get_split_list (lot);
70  if (!node) return FALSE;
71  split = node->data;
72 
73  acc_commodity = xaccAccountGetCommodity(acc);
74  comeq = gnc_commodity_equiv (acc_commodity, split->parent->common_currency);
75  return (FALSE == comeq);
76 }
77 
78 /* ================================================================= */
79 /* XXX What happens if, as a result of scrubbing, the lot is empty?
80  * I don't think this is handled properly. I think that what will
81  * happen is we'll end up with an empty, closed lot ... ?
82  */
83 
84 gboolean
86 {
87  gboolean splits_deleted = FALSE;
88  gnc_numeric lot_baln;
89  gboolean opening_baln_is_pos, lot_baln_is_pos;
90  Account *acc;
91  GNCPolicy *pcy;
92 
93  if (!lot) return FALSE;
94  ENTER ("(lot=%p) %s", lot, gnc_lot_get_title(lot));
95 
96  acc = gnc_lot_get_account (lot);
97  pcy = gnc_account_get_policy(acc);
99  xaccScrubMergeLotSubSplits (lot, TRUE);
100 
101  /* If the lot balance is zero, we don't need to rebalance */
102  lot_baln = gnc_lot_get_balance (lot);
103  PINFO ("lot baln=%s for %s", gnc_num_dbg_to_string (lot_baln),
104  gnc_lot_get_title(lot));
105  if (! gnc_numeric_zero_p (lot_baln))
106  {
107  SplitList *node;
108  gnc_numeric opening_baln;
109 
110  /* Get the opening balance for this lot */
111  pcy->PolicyGetLotOpening (pcy, lot, &opening_baln, NULL, NULL);
112  PINFO ("lot opener baln=%s", gnc_num_dbg_to_string (opening_baln));
113 
114  /* If the lot is fat, give the boot to all the non-opening
115  * splits, and refill it */
116  opening_baln_is_pos = gnc_numeric_positive_p(opening_baln);
117  lot_baln_is_pos = gnc_numeric_positive_p(lot_baln);
118  if ((opening_baln_is_pos || lot_baln_is_pos) &&
119  ((!opening_baln_is_pos) || (!lot_baln_is_pos)))
120  {
121 rethin:
122  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
123  {
124  Split *s = node->data;
125  if (pcy->PolicyIsOpeningSplit (pcy, lot, s)) continue;
126  gnc_lot_remove_split (lot, s);
127  goto rethin;
128  }
129  }
130 
131  /* At this point the lot is thin, so try to fill it */
132  xaccLotFill (lot);
133 
134  /* Make sure there are no subsplits. */
135  splits_deleted = xaccScrubMergeLotSubSplits (lot, TRUE);
136  }
137 
138  /* Now re-compute cap gains, and then double-check that.
139  * But we only compute cap-gains if gains are possible;
140  * that is if the lot commodity is not the same as the
141  * currency. That is, one can't possibly have gains
142  * selling dollars for dollars. The business modules
143  * use lots with lot commodity == lot currency.
144  */
145  if (gains_possible (lot))
146  {
147  xaccLotComputeCapGains (lot, NULL);
149  }
151 
152  LEAVE ("(lot=%s, deleted=%d)", gnc_lot_get_title(lot), splits_deleted);
153  return splits_deleted;
154 }
155 
156 /* ============================================================== */
157 
158 void
160 {
161  LotList *lots, *node;
162  if (!acc) return;
163  if (FALSE == xaccAccountHasTrades (acc)) return;
164 
165  ENTER ("(acc=%s)", xaccAccountGetName(acc));
167  xaccAccountAssignLots (acc);
168 
169  lots = xaccAccountGetLotList(acc);
170  for (node = lots; node; node = node->next)
171  {
172  GNCLot *lot = node->data;
173  xaccScrubLot (lot);
174  }
175  g_list_free(lots);
177  LEAVE ("(acc=%s)", xaccAccountGetName(acc));
178 }
179 
180 /* ============================================================== */
181 
182 static void
183 lot_scrub_cb (Account *acc, gpointer data)
184 {
185  if (FALSE == xaccAccountHasTrades (acc)) return;
186  xaccAccountScrubLots (acc);
187 }
188 
189 void
190 xaccAccountTreeScrubLots (Account *acc)
191 {
192  if (!acc) return;
193 
194  gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL);
195  xaccAccountScrubLots (acc);
196 }
197 
198 /* ========================== END OF FILE ========================= */
High-Level API for imposing Lot constraints.
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
Definition: Scrub2.c:398
gchar * gnc_num_dbg_to_string(gnc_numeric n)
GList LotList
Definition: gnc-engine.h:201
void xaccLotFill(GNCLot *lot)
Definition: Scrub2.c:96
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
#define PINFO(format, args...)
Definition: qoflog.h:249
Utilities to Convert Stock Accounts to use Lots.
gboolean xaccAccountHasTrades(const Account *acc)
Definition: cap-gains.c:79
void xaccAccountAssignLots(Account *acc)
Definition: Scrub2.c:58
gboolean gnc_numeric_zero_p(gnc_numeric a)
void xaccAccountScrubLots(Account *acc)
Definition: Scrub3.c:159
#define ENTER(format, args...)
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
GList SplitList
Definition: gnc-engine.h:203
Account handling public routines.
Implement Accounting Policy Private header File.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
void xaccLotScrubDoubleBalance(GNCLot *lot)
Definition: Scrub2.c:164
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3744
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
#define LEAVE(format, args...)
Definition: qoflog.h:271
gboolean xaccScrubLot(GNCLot *lot)
Definition: Scrub3.c:85
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
Utilities to Automatically Compute Capital Gains/Losses.
Commodity handling public routines.
GNCPolicy * gnc_account_get_policy(Account *acc)
Definition: Account.c:1880
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
const gchar * QofLogModule
Definition: qofid.h:89