|
GnuCash 2.4.99
|
00001 /********************************************************************\ 00002 * Scrub3.c -- Constrain Cap Gains to Track Sources of Gains * 00003 * * 00004 * This program is free software; you can redistribute it and/or * 00005 * modify it under the terms of the GNU General Public License as * 00006 * published by the Free Software Foundation; either version 2 of * 00007 * the License, or (at your option) any later version. * 00008 * * 00009 * This program is distributed in the hope that it will be useful, * 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00012 * GNU General Public License for more details. * 00013 * * 00014 * You should have received a copy of the GNU General Public License* 00015 * along with this program; if not, contact: * 00016 * * 00017 * Free Software Foundation Voice: +1-617-542-5942 * 00018 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00019 * Boston, MA 02110-1301, USA gnu@gnu.org * 00020 \********************************************************************/ 00021 00032 #include "config.h" 00033 00034 #include <glib.h> 00035 00036 #include "cap-gains.h" 00037 #include "gnc-commodity.h" 00038 #include "gnc-engine.h" 00039 #include "gnc-lot.h" 00040 #include "policy-p.h" 00041 #include "Account.h" 00042 #include "AccountP.h" 00043 #include "Scrub2.h" 00044 #include "Scrub3.h" 00045 #include "Transaction.h" 00046 #include "TransactionP.h" 00047 00048 static QofLogModule log_module = GNC_MOD_LOT; 00049 00050 /* ================================================================= */ 00058 static inline gboolean 00059 gains_possible (GNCLot *lot) 00060 { 00061 SplitList *node; 00062 Account *acc; 00063 Split *split; 00064 gboolean comeq; 00065 gnc_commodity *acc_commodity; 00066 00067 acc = gnc_lot_get_account (lot); 00068 00069 node = gnc_lot_get_split_list (lot); 00070 if (!node) return FALSE; 00071 split = node->data; 00072 00073 acc_commodity = xaccAccountGetCommodity(acc); 00074 comeq = gnc_commodity_equiv (acc_commodity, split->parent->common_currency); 00075 return (FALSE == comeq); 00076 } 00077 00078 /* ================================================================= */ 00079 /* XXX What happens if, as a result of scrubbing, the lot is empty? 00080 * I don't think this is handled properly. I think that what will 00081 * happen is we'll end up with an empty, closed lot ... ? 00082 */ 00083 00084 gboolean 00085 xaccScrubLot (GNCLot *lot) 00086 { 00087 gboolean splits_deleted = FALSE; 00088 gnc_numeric lot_baln; 00089 gboolean opening_baln_is_pos, lot_baln_is_pos; 00090 Account *acc; 00091 GNCPolicy *pcy; 00092 00093 if (!lot) return FALSE; 00094 ENTER ("(lot=%p) %s", lot, gnc_lot_get_title(lot)); 00095 00096 acc = gnc_lot_get_account (lot); 00097 pcy = gnc_account_get_policy(acc); 00098 xaccAccountBeginEdit(acc); 00099 xaccScrubMergeLotSubSplits (lot); 00100 00101 /* If the lot balance is zero, we don't need to rebalance */ 00102 lot_baln = gnc_lot_get_balance (lot); 00103 PINFO ("lot baln=%s for %s", gnc_num_dbg_to_string (lot_baln), 00104 gnc_lot_get_title(lot)); 00105 if (! gnc_numeric_zero_p (lot_baln)) 00106 { 00107 SplitList *node; 00108 gnc_numeric opening_baln; 00109 00110 /* Get the opening balance for this lot */ 00111 pcy->PolicyGetLotOpening (pcy, lot, &opening_baln, NULL, NULL); 00112 PINFO ("lot opener baln=%s", gnc_num_dbg_to_string (opening_baln)); 00113 00114 /* If the lot is fat, give the boot to all the non-opening 00115 * splits, and refill it */ 00116 opening_baln_is_pos = gnc_numeric_positive_p(opening_baln); 00117 lot_baln_is_pos = gnc_numeric_positive_p(lot_baln); 00118 if ((opening_baln_is_pos || lot_baln_is_pos) && 00119 ((!opening_baln_is_pos) || (!lot_baln_is_pos))) 00120 { 00121 rethin: 00122 for (node = gnc_lot_get_split_list(lot); node; node = node->next) 00123 { 00124 Split *s = node->data; 00125 if (pcy->PolicyIsOpeningSplit (pcy, lot, s)) continue; 00126 gnc_lot_remove_split (lot, s); 00127 goto rethin; 00128 } 00129 } 00130 00131 /* At this point the lot is thin, so try to fill it */ 00132 xaccLotFill (lot); 00133 00134 /* Make sure there are no subsplits. */ 00135 splits_deleted = xaccScrubMergeLotSubSplits (lot); 00136 } 00137 00138 /* Now re-compute cap gains, and then double-check that. 00139 * But we only compute cap-gains if gains are possible; 00140 * that is if the lot commodity is not the same as the 00141 * currency. That is, one can't possibly have gains 00142 * selling dollars for dollars. The business modules 00143 * use lots with lot commodity == lot currency. 00144 */ 00145 if (gains_possible (lot)) 00146 { 00147 xaccLotComputeCapGains (lot, NULL); 00148 xaccLotScrubDoubleBalance (lot); 00149 } 00150 xaccAccountCommitEdit(acc); 00151 00152 LEAVE ("(lot=%s, deleted=%d)", gnc_lot_get_title(lot), splits_deleted); 00153 return splits_deleted; 00154 } 00155 00156 /* ============================================================== */ 00157 00158 void 00159 xaccAccountScrubLots (Account *acc) 00160 { 00161 LotList *lots, *node; 00162 if (!acc) return; 00163 if (FALSE == xaccAccountHasTrades (acc)) return; 00164 00165 ENTER ("(acc=%s)", xaccAccountGetName(acc)); 00166 xaccAccountBeginEdit(acc); 00167 xaccAccountAssignLots (acc); 00168 00169 lots = xaccAccountGetLotList(acc); 00170 for (node = lots; node; node = node->next) 00171 { 00172 GNCLot *lot = node->data; 00173 xaccScrubLot (lot); 00174 } 00175 g_list_free(lots); 00176 xaccAccountCommitEdit(acc); 00177 LEAVE ("(acc=%s)", xaccAccountGetName(acc)); 00178 } 00179 00180 /* ============================================================== */ 00181 00182 static void 00183 lot_scrub_cb (Account *acc, gpointer data) 00184 { 00185 if (FALSE == xaccAccountHasTrades (acc)) return; 00186 xaccAccountScrubLots (acc); 00187 } 00188 00189 void 00190 xaccAccountTreeScrubLots (Account *acc) 00191 { 00192 if (!acc) return; 00193 00194 gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL); 00195 xaccAccountScrubLots (acc); 00196 } 00197 00198 /* ========================== END OF FILE ========================= */
1.7.4