GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Files

Files

file  Scrub.h
 convert single-entry accounts to clean double-entry
 
file  Scrub2.h
 Utilities to Convert Stock Accounts to use Lots.
 
file  Scrub3.h
 High-Level API for imposing Lot constraints.
 
file  ScrubBusiness.h
 Cleanup functions for business objects.
 

Double-Entry Scrubbing

Convert single-entry accounts to clean double-entry

Provides a set of functions and utilities for checking and repairing (formerly called 'scrubbing clean') single-entry accounts so that they can be promoted into self-consistent, clean double-entry accounts. Basically and additionally, this file collects all functions that turn old (deprecated) data structures into the current new data model.

The ScrubOrphans() methods search for transacations that contain splits that do not have a parent account. These "orphaned splits" are placed into an "orphan account" which the user will have to go into and clean up. Kind of like the unix "Lost+Found" directory for orphaned inodes.

void xaccTransScrubOrphans (Transaction *trans)
 
void xaccAccountScrubOrphans (Account *acc)
 
void xaccAccountTreeScrubOrphans (Account *acc)
 
void xaccSplitScrub (Split *split)
 
void xaccTransScrubSplits (Transaction *trans)
 
void xaccAccountScrubSplits (Account *account)
 
void xaccAccountTreeScrubSplits (Account *account)
 
void xaccTransScrubImbalance (Transaction *trans, Account *root, Account *parent)
 
void xaccAccountScrubImbalance (Account *acc)
 
void xaccAccountTreeScrubImbalance (Account *acc)
 
void xaccTransScrubCurrency (Transaction *trans)
 
void xaccAccountScrubCommodity (Account *account)
 
void xaccAccountTreeScrubCommodities (Account *acc)
 
void xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
 
void xaccAccountScrubKvp (Account *account)
 

Lot Management Routines

Provides the low-level API for checking and repairing ('scrubbing clean') the usage of Lots and lot balances in stock and commodity accounts. Broken lots are repaired using a first-in, first-out (FIFO) accounting schedule.

This is a 'low-level' API in the sense that each routine accomplishes only one particular task needed to clean up a Lot. To clean up a Lot as a whole, you almost certainly want to use one of the high-level API routines from the Scrub3.h file.

void xaccAccountAssignLots (Account *acc)
 
void xaccLotFill (GNCLot *lot)
 
void xaccLotScrubDoubleBalance (GNCLot *lot)
 
gboolean xaccScrubMergeSubSplits (Split *split, gboolean strict)
 
gboolean xaccScrubMergeLotSubSplits (GNCLot *lot, gboolean strict)
 

High-Level Lot Constraint

Provides the high-level API for checking and repairing ('scrubbing clean') the usage of Lots and Cap Gains transactions in stock and commodity accounts.

gboolean xaccScrubLot (GNCLot *lot)
 
void xaccAccountScrubLots (Account *acc)
 
void xaccAccountTreeScrubLots (Account *acc)
 

Cleanup functions for business objects

Provides the high-level API for checking and repairing ('scrubbing clean') the various data objects used by the business functions.

gboolean gncScrubBusinessLot (GNCLot *lot)
 
void gncScrubBusinessAccountLots (Account *acc)
 
void gncScrubBusinessAccountTreeLots (Account *acc)
 

Detailed Description

Data scrubbing, repairing and forward migration routines. These routines check and repair data, making sure that it is in a format that the current version of the GnuCash Engine likes. These routines serve both to provide backwards compatibility with older versions of GnuCash, and to fix or at least paper over possible current problems.

It is typically expected that the scrub routines are run over newly imported data, as well as during data file input.

In some cases, it is entirely appropriate to invoke these routines from the GUI, to validate that the user input through the GUI is in a format that the system likes. This includes things like balancing individual transactions, or assigning splits to lots, so that capital gains can be computed.

Function Documentation

void gncScrubBusinessAccountLots ( Account acc)

The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given account.

This routine is the primary routine for ensuring that the lot structure of every lot of a business account is in good order.

Definition at line 294 of file ScrubBusiness.c.

295 {
296  LotList *lots, *node;
297  if (!acc) return;
298  if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
299 
300  ENTER ("(acc=%s)", xaccAccountGetName(acc));
302 
303  lots = xaccAccountGetLotList(acc);
304  for (node = lots; node; node = node->next)
305  {
306  GNCLot *lot = node->data;
307  if (lot)
308  gncScrubBusinessLot (lot);
309  }
310  g_list_free(lots);
312  LEAVE ("(acc=%s)", xaccAccountGetName(acc));
313 }
GList LotList
Definition: gnc-engine.h:201
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
#define ENTER(format, args...)
Definition: qoflog.h:261
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3744
gboolean xaccAccountIsAPARType(GNCAccountType t)
Definition: Account.c:4225
gboolean gncScrubBusinessLot(GNCLot *lot)
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void gncScrubBusinessAccountTreeLots ( Account acc)

The gncScrubBusinessAccountTreeLots() function will call gncScrubBusinessAccountLots() on each lot in the given account and its sub accounts.

This routine is the primary routine for ensuring that the lot structure of every lot of a business account is in good order.

Definition at line 325 of file ScrubBusiness.c.

326 {
327  if (!acc) return;
328 
329  gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL);
331 }
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
void gncScrubBusinessAccountLots(Account *acc)
gboolean gncScrubBusinessLot ( GNCLot lot)

The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties required for a lot used in the business features.

Currently this function only does one thing: eliminate lot link transactions between invoice lots and payment lots (which were generated by GnuCash versions 2.6.0-2.6.3). Lot links between invoices and credit notes will still remain.

Scrubbing the lot may cause subsplits to be merged together, i.e. for splits to be deleted. This routine returns true if any splits were modified or deleted.

Definition at line 256 of file ScrubBusiness.c.

257 {
258  gboolean splits_deleted = FALSE;
259  Account *acc;
260  gchar *lotname=NULL;
261 
262  if (!lot) return FALSE;
263  lotname = g_strdup (gnc_lot_get_title (lot));
264  ENTER ("(lot=%p) %s", lot, lotname ? lotname : "(no lotname)");
265 
266  acc = gnc_lot_get_account (lot);
267  if (acc)
269 
270  // Scrub lot links.
271  // They should only remain when two document lots are linked together
272  xaccScrubMergeLotSubSplits (lot, FALSE);
273  splits_deleted = gncScrubLotLinks (lot);
274 
275  // If lot is empty now, delete it
276  if (0 == gnc_lot_count_splits (lot))
277  {
278  PINFO("All splits were removed from lot, deleting");
279  gnc_lot_destroy (lot);
280  }
281 
282  if (acc)
284 
285  LEAVE ("(lot=%s, deleted=%d)", lotname ? lotname : "(no lotname)", splits_deleted);
286  g_free (lotname);
287 
288  return splits_deleted;
289 }
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
Definition: Scrub2.c:398
#define PINFO(format, args...)
Definition: qoflog.h:249
#define ENTER(format, args...)
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountAssignLots ( Account acc)

The xaccAccountAssignLots() routine will walk over all of the splits in an account, and make sure that each belongs to a lot. Currently, the default (and only implemented) assignment policy is a FIFO policy: Any splits that are not in a lot will be used to close the oldest open lot(s). If there are no open lots, a new lot will be started. By trying to close the oldest lots, this effectively implements a FIFO accounting policy.

Loop over all splits, and make sure that every split belongs to some lot. If a split does not belong to any lots, poke it into one.

Definition at line 58 of file Scrub2.c.

59 {
60  SplitList *splits, *node;
61 
62  if (!acc) return;
63 
64  ENTER ("acc=%s", xaccAccountGetName(acc));
66 
67 restart_loop:
68  splits = xaccAccountGetSplitList(acc);
69  for (node = splits; node; node = node->next)
70  {
71  Split * split = node->data;
72 
73  /* If already in lot, then no-op */
74  if (split->lot) continue;
75 
76  /* Skip voided transactions */
77  if (gnc_numeric_zero_p (split->amount) &&
78  xaccTransGetVoidStatus(split->parent)) continue;
79 
80  if (xaccSplitAssign (split)) goto restart_loop;
81  }
83  LEAVE ("acc=%s", xaccAccountGetName(acc));
84 }
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
gboolean gnc_numeric_zero_p(gnc_numeric a)
#define ENTER(format, args...)
Definition: qoflog.h:261
GList SplitList
Definition: gnc-engine.h:203
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2526
gboolean xaccSplitAssign(Split *split)
Definition: cap-gains.c:438
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountScrubCommodity ( Account account)

The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account currency and security.

Definition at line 1110 of file Scrub.c.

1111 {
1112  gnc_commodity *commodity;
1113 
1114  if (!account) return;
1115  if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1116 
1117  commodity = xaccAccountGetCommodity (account);
1118  if (commodity) return;
1119 
1120  /* Use the 'obsolete' routines to try to figure out what the
1121  * account commodity should have been. */
1122  commodity = xaccAccountGetCommodity (account);
1123  if (commodity)
1124  {
1125  xaccAccountSetCommodity (account, commodity);
1126  return;
1127  }
1128 
1129  commodity = DxaccAccountGetCurrency (account);
1130  if (commodity)
1131  {
1132  xaccAccountSetCommodity (account, commodity);
1133  return;
1134  }
1135 
1136  PERR ("Account \"%s\" does not have a commodity!",
1137  xaccAccountGetName(account));
1138 }
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.c:3128
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
#define PERR(format, args...)
Definition: qoflog.h:237
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
void xaccAccountScrubLots ( Account acc)

The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot, and that then, every lot is self-consistent (by calling xaccScrubLot() on each lot).

This routine is the primary routine for ensuring that the lot structure, and the cap-gains for an account are in good order.

Most GUI routines will want to use one of these xacc[*]ScrubLots() routines, instead of the various component routines, since it will usually makes sense to work only with these high-level routines.

Definition at line 159 of file Scrub3.c.

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 }
GList LotList
Definition: gnc-engine.h:201
gboolean xaccAccountHasTrades(const Account *acc)
Definition: cap-gains.c:79
void xaccAccountAssignLots(Account *acc)
Definition: Scrub2.c:58
#define ENTER(format, args...)
Definition: qoflog.h:261
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3744
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
gboolean xaccScrubLot(GNCLot *lot)
Definition: Scrub3.c:85
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountScrubOrphans ( Account acc)

The xaccAccountScrubOrphans() method performs this scrub only for the indicated account, and not for any of its children.

Definition at line 102 of file Scrub.c.

103 {
104  GList *node;
105  const char *str;
106 
107  if (!acc) return;
108 
109  str = xaccAccountGetName (acc);
110  str = str ? str : "(null)";
111  PINFO ("Looking for orphans in account %s \n", str);
112 
113  for (node = xaccAccountGetSplitList(acc); node; node = node->next)
114  {
115  Split *split = node->data;
116 
117  TransScrubOrphansFast (xaccSplitGetParent (split),
118  gnc_account_get_root (acc));
119  }
120 }
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
#define PINFO(format, args...)
Definition: qoflog.h:249
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
Definition: SplitP.h:71
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2630
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountTreeScrubCommodities ( Account acc)

The xaccAccountTreeScrubCommodities will scrub the currency/commodity of all accounts & transactions in the specified account or any child account.

Definition at line 1174 of file Scrub.c.

1175 {
1176  if (!acc) return;
1177 
1178  xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
1179 
1180  scrub_account_commodity_helper (acc, NULL);
1181  gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
1182 }
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
void xaccAccountTreeScrubOrphans ( Account acc)

The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its children.

Definition at line 62 of file Scrub.c.

63 {
64  if (!acc) return;
65 
68  (AccountCb)xaccAccountScrubOrphans, NULL);
69 }
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
void xaccAccountScrubOrphans(Account *acc)
Definition: Scrub.c:102
void xaccAccountTreeScrubQuoteSources ( Account root,
gnc_commodity_table table 
)

This routine will migrate the information about price quote sources from the account data structures to the commodity data structures. It first checks to see if this is necessary since, for the time being, the quote information will still be written out as part of the account. Just in case anyone needs to fall back from CVS to a production version of code.

Parameters
rootA pointer to the root account containing all accounts in the current book.
tableA pointer to the commodity table for the current book.

Definition at line 1231 of file Scrub.c.

1232 {
1233  gboolean new_style = FALSE;
1234  ENTER(" ");
1235 
1236  if (!root || !table)
1237  {
1238  LEAVE("Oops");
1239  return;
1240  }
1241 
1242  gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1243 
1244  move_quote_source(root, GINT_TO_POINTER(new_style));
1245  gnc_account_foreach_descendant (root, move_quote_source,
1246  GINT_TO_POINTER(new_style));
1247  LEAVE("Migration done");
1248 }
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
#define ENTER(format, args...)
Definition: qoflog.h:261
#define LEAVE(format, args...)
Definition: qoflog.h:271
void xaccLotFill ( GNCLot lot)

The xaccLotFill() routine attempts to assign splits to the indicated lot until the lot balance goes to zero, or until there are no suitable (i.e. unassigned) splits left in the account. It uses the default accounting policy to choose the splits to fill out the lot.

Definition at line 96 of file Scrub2.c.

97 {
98  Account *acc;
99  Split *split;
100  GNCPolicy *pcy;
101 
102  if (!lot) return;
103  acc = gnc_lot_get_account(lot);
104  pcy = gnc_account_get_policy(acc);
105 
106  ENTER ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
107 
108  /* If balance already zero, we have nothing to do. */
109  if (gnc_lot_is_closed (lot))
110  {
111  LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
112  xaccAccountGetName(acc));
113  return;
114  }
115  split = pcy->PolicyGetSplit (pcy, lot);
116  if (!split)
117  {
118  LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
119  xaccAccountGetName(acc));
120  return; /* Handle the common case */
121  }
122 
123  /* Reject voided transactions */
124  if (gnc_numeric_zero_p(split->amount) &&
125  xaccTransGetVoidStatus(split->parent))
126  {
127  LEAVE ("Voided transaction (lot=%s, acc=%s)",
129  return;
130  }
131 
132  xaccAccountBeginEdit (acc);
133 
134  /* Loop until we've filled up the lot, (i.e. till the
135  * balance goes to zero) or there are no splits left. */
136  while (1)
137  {
138  Split *subsplit;
139 
140  subsplit = xaccSplitAssignToLot (split, lot);
141  if (subsplit == split)
142  {
143  PERR ("Accounting Policy gave us a split that "
144  "doesn't fit into this lot\n"
145  "lot baln=%s, isclosed=%d, aplit amt=%s",
147  gnc_lot_is_closed (lot),
148  gnc_num_dbg_to_string (split->amount));
149  break;
150  }
151 
152  if (gnc_lot_is_closed (lot)) break;
153 
154  split = pcy->PolicyGetSplit (pcy, lot);
155  if (!split) break;
156  }
157  xaccAccountCommitEdit (acc);
158  LEAVE ("(lot=%s, acc=%s)", gnc_lot_get_title(lot), xaccAccountGetName(acc));
159 }
gchar * gnc_num_dbg_to_string(gnc_numeric n)
gboolean gnc_numeric_zero_p(gnc_numeric a)
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
Split * xaccSplitAssignToLot(Split *split, GNCLot *lot)
Definition: cap-gains.c:222
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2526
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:376
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
GNCPolicy * gnc_account_get_policy(Account *acc)
Definition: Account.c:1880
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
void xaccLotScrubDoubleBalance ( GNCLot lot)

The xaccLotScrubDoubleBalance() routine examines the indicated lot. If it is open, it does nothing. If it is closed, it then verifies that the lot is 'double balanced'. By 'double balance', we mean that both the sum of the split amounts is zero, and that the sum of the split values is zero. If the lot is closed and the sum of the values is not zero, the lot is considered to have a 'realized gain or loss' that hadn't been correctly handled. This routine then creates a balancing transaction to so as to record the realized gain/loss, adds it to the lot, and adds it to a gain/loss account. If there is no default gain/loss account, it creates one.

Definition at line 164 of file Scrub2.c.

165 {
166  gnc_commodity *currency = NULL;
167  SplitList *snode;
168  GList *node;
169  gnc_numeric zero = gnc_numeric_zero();
170  gnc_numeric value = zero;
171 
172  if (!lot) return;
173 
174  ENTER ("lot=%s", gnc_lot_get_title(lot));
175 
176  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
177  {
178  Split *s = snode->data;
179  xaccSplitComputeCapGains (s, NULL);
180  }
181 
182  /* We double-check only closed lots */
183  if (FALSE == gnc_lot_is_closed (lot))
184  {
185  LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
186  return;
187  }
188 
189  for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
190  {
191  Split *s = snode->data;
192  Transaction *trans = s->parent;
193 
194  /* Check to make sure all splits in the lot have a common currency */
195  if (NULL == currency)
196  {
197  currency = trans->common_currency;
198  }
199  if (FALSE == gnc_commodity_equiv (currency, trans->common_currency))
200  {
201  /* This lot has mixed currencies. Can't double-balance.
202  * Silently punt */
203  PWARN ("Lot with multiple currencies:\n"
204  "\ttrans=%s curr=%s", xaccTransGetDescription(trans),
205  gnc_commodity_get_fullname(trans->common_currency));
206  break;
207  }
208 
209  /* Now, total up the values */
210  value = gnc_numeric_add (value, xaccSplitGetValue (s),
212  PINFO ("Split=%p value=%s Accum Lot value=%s", s,
213  gnc_num_dbg_to_string (s->value),
214  gnc_num_dbg_to_string (value));
215 
216  }
217 
218  if (FALSE == gnc_numeric_equal (value, zero))
219  {
220  /* Unhandled error condition. Not sure what to do here,
221  * Since the ComputeCapGains should have gotten it right.
222  * I suppose there might be small rounding errors, a penny or two,
223  * the ideal thing would to figure out why there's a rounding
224  * error, and fix that.
225  */
226  PERR ("Closed lot fails to double-balance !! lot value=%s",
227  gnc_num_dbg_to_string (value));
228  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
229  {
230  Split *s = node->data;
231  PERR ("s=%p amt=%s val=%s", s,
232  gnc_num_dbg_to_string(s->amount),
233  gnc_num_dbg_to_string(s->value));
234  }
235  }
236 
237  LEAVE ("lot=%s", gnc_lot_get_title(lot));
238 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
gchar * gnc_num_dbg_to_string(gnc_numeric n)
#define PINFO(format, args...)
Definition: qoflog.h:249
void xaccSplitComputeCapGains(Split *split, Account *gain_acc)
Definition: cap-gains.c:536
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
#define PWARN(format, args...)
Definition: qoflog.h:243
GList SplitList
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:376
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
#define LEAVE(format, args...)
Definition: qoflog.h:271
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gboolean xaccScrubLot ( GNCLot lot)

The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced, and fixes it if its not. This is an important routine to call if the amount of any split in the lot is changed. That's because (obviously) changing split values is guaranteed to throw off lot balances. This routine may end up closing the lot, or at least trying to. It will also cause cap gains to be recomputed.

Scrubbing the lot may cause subsplits to be merged together, i.e. for splits to be deleted. This routine returns true if any splits were deleted.

Definition at line 85 of file Scrub3.c.

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 }
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
Definition: Scrub2.c:398
gchar * gnc_num_dbg_to_string(gnc_numeric n)
void xaccLotFill(GNCLot *lot)
Definition: Scrub2.c:96
#define PINFO(format, args...)
Definition: qoflog.h:249
gboolean gnc_numeric_zero_p(gnc_numeric a)
#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
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
void xaccLotScrubDoubleBalance(GNCLot *lot)
Definition: Scrub2.c:164
gboolean gnc_numeric_positive_p(gnc_numeric a)
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
GNCPolicy * gnc_account_get_policy(Account *acc)
Definition: Account.c:1880
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
gboolean xaccScrubMergeLotSubSplits ( GNCLot lot,
gboolean  strict 
)

The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits, except that it does it for all of the splits in the lot.

Definition at line 398 of file Scrub2.c.

399 {
400  gboolean rc = FALSE;
401  SplitList *node;
402 
403  if (!lot) return FALSE;
404 
405  ENTER (" ");
406 restart:
407  for (node = gnc_lot_get_split_list(lot); node; node = node->next)
408  {
409  Split *s = node->data;
410  if (!xaccScrubMergeSubSplits(s, strict)) continue;
411 
412  rc = TRUE;
413  goto restart;
414  }
415  LEAVE (" splits merged=%d", rc);
416  return rc;
417 }
#define ENTER(format, args...)
Definition: qoflog.h:261
GList SplitList
Definition: gnc-engine.h:203
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
gboolean xaccScrubMergeSubSplits(Split *split, gboolean strict)
Definition: Scrub2.c:347
Definition: SplitP.h:71
#define LEAVE(format, args...)
Definition: qoflog.h:271
gboolean xaccScrubMergeSubSplits ( Split split,
gboolean  strict 
)

The xaccScrubMergeSubSplits() routine will merge together all of the splits that were at one time split off from this split, but are no longer needed to be kept separate. Splits might be split up if they need to be divided over multiple lots; they can be merged back together if the lots change. In particular, two sub-splits may be merged if they are in the same lot, or in no lot. Note that, by definition, all subsplits belong to the same transaction.

There are two ways to find matching subsplits. The first way will consider splits to be subsplits only if they are explicitly marked as such while splitting the original split. Set strict to TRUE for this matching algorhythm.

The second way is more relaxed. It will consider any two splits that happen to be part of the same lot and the same transaction to be subsplits. Set strict to FALSE for this matching algorhythm.

The routine returns TRUE if a merger was performed, else it returns FALSE.

Definition at line 347 of file Scrub2.c.

348 {
349  gboolean rc = FALSE;
350  Transaction *txn;
351  SplitList *node;
352  GNCLot *lot;
353  const GncGUID *guid;
354 
355  if (strict && (FALSE == is_subsplit (split))) return FALSE;
356 
357  txn = split->parent;
358  lot = xaccSplitGetLot (split);
359 
360  ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
361 restart:
362  for (node = txn->splits; node; node = node->next)
363  {
364  Split *s = node->data;
365  if (xaccSplitGetLot (s) != lot) continue;
366  if (s == split) continue;
367  if (qof_instance_get_destroying(s)) continue;
368 
369  if (strict)
370  {
371  /* OK, this split is in the same lot (and thus same account)
372  * as the indicated split. Make sure it is really a subsplit
373  * of the split we started with. It's possible to have two
374  * splits in the same lot and transaction that are not subsplits
375  * of each other, the test-period test suite does this, for
376  * example. Only worry about adjacent sub-splits. By
377  * repeatedly merging adjacent subsplits, we'll get the non-
378  * adjacent ones too. */
379  guid = qof_instance_get_guid(s);
380  if (gnc_kvp_bag_find_by_guid (split->inst.kvp_data, "lot-split",
381  "peer_guid", guid) == NULL)
382  continue;
383  }
384 
385  merge_splits (split, s);
386  rc = TRUE;
387  goto restart;
388  }
389  if (gnc_numeric_zero_p (split->amount))
390  {
391  PWARN ("Result of merge has zero amt!");
392  }
393  LEAVE (" splits merged=%d", rc);
394  return rc;
395 }
const GncGUID * qof_instance_get_guid(gconstpointer)
gboolean qof_instance_get_destroying(gconstpointer ptr)
gboolean gnc_numeric_zero_p(gnc_numeric a)
#define ENTER(format, args...)
Definition: qoflog.h:261
Definition: guid.h:65
const char * gnc_lot_get_title(const GNCLot *lot)
Definition: gnc-lot.c:437
#define PWARN(format, args...)
Definition: qoflog.h:243
GList SplitList
Definition: gnc-engine.h:203
KvpFrame * gnc_kvp_bag_find_by_guid(KvpFrame *root, const char *path, const char *guid_name, const GncGUID *desired_guid)
Definition: SplitP.h:71
#define LEAVE(format, args...)
Definition: qoflog.h:271
GNCLot * xaccSplitGetLot(const Split *split)
Definition: Split.c:1953
void xaccSplitScrub ( Split split)

The xaccSplitScrub method ensures that if this split has the same commodity and currency, then it will have the same amount and value. If the commodity is the currency, the split->amount is set to the split value. In addition, if this split is an orphan, that is fixed first. If the split account doesn't have a commodity declared, an attempt is made to fix that first.

Definition at line 176 of file Scrub.c.

177 {
178  Account *account;
179  Transaction *trans;
180  gnc_numeric value, amount;
181  gnc_commodity *currency, *acc_commodity;
182  int scu;
183 
184  if (!split) return;
185  ENTER ("(split=%p)", split);
186 
187  trans = xaccSplitGetParent (split);
188  if (!trans)
189  {
190  LEAVE("no trans");
191  return;
192  }
193 
194  account = xaccSplitGetAccount (split);
195 
196  /* If there's no account, this split is an orphan.
197  * We need to fix that first, before proceeding.
198  */
199  if (!account)
200  {
201  xaccTransScrubOrphans (trans);
202  account = xaccSplitGetAccount (split);
203  }
204 
205  /* Grrr... the register gnc_split_register_load() line 203 of
206  * src/register/ledger-core/split-register-load.c will create
207  * free-floating bogus transactions. Ignore these for now ...
208  */
209  if (!account)
210  {
211  PINFO ("Free Floating Transaction!");
212  LEAVE ("no account");
213  return;
214  }
215 
216  /* Split amounts and values should be valid numbers */
217  value = xaccSplitGetValue (split);
218  if (gnc_numeric_check (value))
219  {
220  value = gnc_numeric_zero();
221  xaccSplitSetValue (split, value);
222  }
223 
224  amount = xaccSplitGetAmount (split);
225  if (gnc_numeric_check (amount))
226  {
227  amount = gnc_numeric_zero();
228  xaccSplitSetAmount (split, amount);
229  }
230 
231  currency = xaccTransGetCurrency (trans);
232 
233  /* If the account doesn't have a commodity,
234  * we should attempt to fix that first.
235  */
236  acc_commodity = xaccAccountGetCommodity(account);
237  if (!acc_commodity)
238  {
239  xaccAccountScrubCommodity (account);
240  }
241  if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
242  {
243  LEAVE ("(split=%p) inequiv currency", split);
244  return;
245  }
246 
247  scu = MIN (xaccAccountGetCommoditySCU (account),
248  gnc_commodity_get_fraction (currency));
249 
250  if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
251  {
252  LEAVE("(split=%p) different values", split);
253  return;
254  }
255 
256  /*
257  * This will be hit every time you answer yes to the dialog "The
258  * current transaction has changed. Would you like to record it.
259  */
260  PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
261  " old amount %s %s, new amount %s",
262  trans->description, split->memo,
264  gnc_commodity_get_mnemonic (currency),
266 
267  xaccTransBeginEdit (trans);
268  xaccSplitSetAmount (split, value);
269  xaccTransCommitEdit (trans);
270  LEAVE ("(split=%p)", split);
271 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
gchar * gnc_num_dbg_to_string(gnc_numeric n)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
#define PINFO(format, args...)
Definition: qoflog.h:249
void xaccAccountScrubCommodity(Account *account)
Definition: Scrub.c:1110
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2458
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
#define ENTER(format, args...)
Definition: qoflog.h:261
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
void xaccTransScrubOrphans(Transaction *trans)
Definition: Scrub.c:124
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
#define LEAVE(format, args...)
Definition: qoflog.h:271
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
void xaccTransScrubCurrency ( Transaction trans)

The xaccTransScrubCurrency method fixes transactions without a common_currency by looking for the most commonly used currency among all the splits in the transaction. If this fails it falls back to using the old account currency and security fields of the parent accounts of the transaction's splits.

Definition at line 993 of file Scrub.c.

994 {
995  SplitList *node;
996  gnc_commodity *currency;
997 
998  if (!trans) return;
999 
1000  /* If there are any orphaned splits in a transaction, then the
1001  * this routine will fail. Therefore, we want to make sure that
1002  * there are no orphans (splits without parent account).
1003  */
1004  xaccTransScrubOrphans (trans);
1005 
1006  currency = xaccTransGetCurrency (trans);
1007  if (currency && gnc_commodity_is_currency(currency)) return;
1008 
1009  currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1010  if (currency)
1011  {
1012  xaccTransBeginEdit (trans);
1013  xaccTransSetCurrency (trans, currency);
1014  xaccTransCommitEdit (trans);
1015  }
1016  else
1017  {
1018  if (NULL == trans->splits)
1019  {
1020  PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1021  }
1022  else
1023  {
1024  SplitList *node;
1025  char guid_str[GUID_ENCODING_LENGTH + 1];
1026  guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1027  PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1028  trans->description, guid_str);
1029 
1030  for (node = trans->splits; node; node = node->next)
1031  {
1032  Split *split = node->data;
1033  if (NULL == split->acc)
1034  {
1035  PWARN (" split=\"%s\" is not in any account!", split->memo);
1036  }
1037  else
1038  {
1039  gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1040  PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1041  split->memo, xaccAccountGetName(split->acc),
1042  gnc_commodity_get_mnemonic(currency));
1043 
1044  xaccTransBeginEdit (trans);
1045  xaccTransSetCurrency (trans, currency);
1046  xaccTransCommitEdit (trans);
1047  return;
1048  }
1049  }
1050  }
1051  return;
1052  }
1053 
1054  for (node = trans->splits; node; node = node->next)
1055  {
1056  Split *sp = node->data;
1057 
1059  xaccSplitGetValue (sp)))
1060  {
1061  gnc_commodity *acc_currency;
1062 
1063  acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL;
1064  if (acc_currency == currency)
1065  {
1066  /* This Split needs fixing: The transaction-currency equals
1067  * the account-currency/commodity, but the amount/values are
1068  * inequal i.e. they still correspond to the security
1069  * (amount) and the currency (value). In the new model, the
1070  * value is the amount in the account-commodity -- so it
1071  * needs to be set to equal the amount (since the
1072  * account-currency doesn't exist anymore).
1073  *
1074  * Note: Nevertheless we lose some information here. Namely,
1075  * the information that the 'amount' in 'account-old-security'
1076  * was worth 'value' in 'account-old-currency'. Maybe it would
1077  * be better to store that information in the price database?
1078  * But then, for old currency transactions there is still the
1079  * 'other' transaction, which is going to keep that
1080  * information. So I don't bother with that here. -- cstim,
1081  * 2002/11/20. */
1082 
1083  PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1084  " old amount %s %s, new amount %s",
1085  trans->description, sp->memo,
1087  gnc_commodity_get_mnemonic (currency),
1089  xaccTransBeginEdit (trans);
1091  xaccTransCommitEdit (trans);
1092  }
1093  /*else
1094  {
1095  PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1096  xaccSplitGetMemo (sp),
1097  gnc_num_dbg_to_string (amount),
1098  gnc_commodity_get_mnemonic (currency),
1099  gnc_num_dbg_to_string (value),
1100  gnc_commodity_get_mnemonic (acc_currency));
1101  }*/
1102  }
1103  }
1104 
1105 }
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
gchar * gnc_num_dbg_to_string(gnc_numeric n)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
QofBook * qof_instance_get_book(gconstpointer)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
#define PWARN(format, args...)
Definition: qoflog.h:243
GList SplitList
Definition: gnc-engine.h:203
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
void xaccTransScrubOrphans(Transaction *trans)
Definition: Scrub.c:124
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
void xaccTransScrubImbalance ( Transaction trans,
Account root,
Account parent 
)

The xaccScrubImbalance() method searches for transactions that do not balance to zero. If any such transactions are found, a split is created to offset this amount and is added to an "imbalance" account.

Definition at line 521 of file Scrub.c.

523 {
524  const gnc_commodity *currency;
525 
526  if (!trans) return;
527 
528  ENTER ("()");
529 
530  /* Must look for orphan splits even if there is no imbalance. */
531  xaccTransScrubSplits (trans);
532 
533  /* Return immediately if things are balanced. */
534  if (xaccTransIsBalanced (trans))
535  {
536  LEAVE ("transaction is balanced");
537  return;
538  }
539 
540  currency = xaccTransGetCurrency (trans);
541 
542  if (! xaccTransUseTradingAccounts (trans))
543  {
544  gnc_numeric imbalance;
545 
546  /* Make the value sum to zero */
547  imbalance = xaccTransGetImbalanceValue (trans);
548  if (! gnc_numeric_zero_p (imbalance))
549  {
550  PINFO ("Value unbalanced transaction");
551 
552  add_balance_split (trans, imbalance, root, account);
553  }
554  }
555  else
556  {
557  MonetaryList *imbal_list;
558  MonetaryList *imbalance_commod;
559  GList *splits;
560  gnc_numeric imbalance;
561  Split *balance_split = NULL;
562 
563  /* If there are existing trading splits, adjust the price or exchange
564  rate in each of them to agree with the non-trading splits for the
565  same commodity. If there are multiple non-trading splits for the
566  same commodity in the transaction this will use the exchange rate in
567  the last such split. This shouldn't happen, and if it does then there's
568  not much we can do about it anyway.
569 
570  While we're at it, compute the value imbalance ignoring existing
571  trading splits. */
572 
573  imbalance = gnc_numeric_zero();
574 
575  for (splits = trans->splits; splits; splits = splits->next)
576  {
577  Split *split = splits->data;
578  gnc_numeric value, amount;
579  gnc_commodity *commodity;
580 
581  if (! xaccTransStillHasSplit (trans, split)) continue;
582 
583  commodity = xaccAccountGetCommodity (xaccSplitGetAccount(split));
584  if (!commodity)
585  {
586  PERR("Split has no commodity");
587  continue;
588  }
589 
590  balance_split = find_trading_split (trans, root, commodity);
591 
592  if (balance_split != split)
593  /* this is not a trading split */
594  imbalance = gnc_numeric_add(imbalance, xaccSplitGetValue (split),
596 
597  /* Ignore splits where value or amount is zero */
598  value = xaccSplitGetValue (split);
599  amount = xaccSplitGetAmount (split);
600  if (gnc_numeric_zero_p(amount) || gnc_numeric_zero_p(value))
601  continue;
602 
603  if (balance_split && balance_split != split)
604  {
605  gnc_numeric convrate = gnc_numeric_div (amount, value,
607  gnc_numeric old_value, new_value;
608  old_value = xaccSplitGetValue(balance_split);
609  new_value = gnc_numeric_div (xaccSplitGetAmount(balance_split),
610  convrate,
611  gnc_commodity_get_fraction(currency),
613  if (! gnc_numeric_equal (old_value, new_value))
614  {
615  xaccTransBeginEdit (trans);
616  xaccSplitSetValue (balance_split, new_value);
617  xaccSplitScrub (balance_split);
618  xaccTransCommitEdit (trans);
619  }
620  }
621  }
622 
623  /* Balance the value, ignoring existing trading splits */
624  if (! gnc_numeric_zero_p (imbalance))
625  {
626  PINFO ("Value unbalanced transaction");
627 
628  add_balance_split (trans, imbalance, root, account);
629  }
630 
631  /* If the transaction is balanced, nothing more to do */
632  imbal_list = xaccTransGetImbalance (trans);
633  if (!imbal_list)
634  {
635  LEAVE("transaction is balanced");
636  return;
637  }
638 
639  PINFO ("Currency unbalanced transaction");
640 
641  for (imbalance_commod = imbal_list; imbalance_commod;
642  imbalance_commod = imbalance_commod->next)
643  {
644  gnc_monetary *imbal_mon = imbalance_commod->data;
645  gnc_commodity *commodity;
646  gnc_numeric old_amount, new_amount;
647  gnc_numeric old_value, new_value, val_imbalance;
648  GList *splits;
649 
650  commodity = gnc_monetary_commodity (*imbal_mon);
651 
652  balance_split = get_trading_split(trans, root, commodity);
653  if (!balance_split)
654  {
655  /* Error already logged */
656  gnc_monetary_list_free(imbal_list);
657  LEAVE("");
658  return;
659  }
660 
661  account = xaccSplitGetAccount(balance_split);
662 
663  if (! gnc_commodity_equal (currency, commodity))
664  {
665  /* Find the value imbalance in this commodity */
666  val_imbalance = gnc_numeric_zero();
667  for (splits = trans->splits; splits; splits = splits->next)
668  {
669  Split *split = splits->data;
670  if (xaccTransStillHasSplit (trans, split) &&
671  gnc_commodity_equal (commodity,
673  val_imbalance = gnc_numeric_add (val_imbalance, xaccSplitGetValue (split),
675  }
676  }
677 
678  xaccTransBeginEdit (trans);
679 
680  old_amount = xaccSplitGetAmount (balance_split);
681  new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
682  gnc_commodity_get_fraction(commodity),
684 
685  xaccSplitSetAmount (balance_split, new_amount);
686 
687  if (gnc_commodity_equal (currency, commodity))
688  {
689  /* Imbalance commodity is the transaction currency, value in the
690  split must be the same as the amount */
691  xaccSplitSetValue (balance_split, new_amount);
692  }
693  else
694  {
695  old_value = xaccSplitGetValue (balance_split);
696  new_value = gnc_numeric_sub (old_value, val_imbalance,
697  gnc_commodity_get_fraction(currency),
699 
700  xaccSplitSetValue (balance_split, new_value);
701  }
702 
703  xaccSplitScrub (balance_split);
704  xaccTransCommitEdit (trans);
705  }
706 
707  gnc_monetary_list_free(imbal_list);
708 
710  {
711  /* This is probably because there are splits with zero amount
712  and non-zero value. These are usually realized gain/loss
713  splits. Add a reversing split for each of them to balance
714  the value. */
715 
716  /* Copy the split list so we don't see the splits we're adding */
717  GList *splits_dup = g_list_copy(trans->splits);
718  for (splits = splits_dup; splits; splits = splits->next)
719  {
720  Split *split = splits->data;
721  if (! xaccTransStillHasSplit(trans, split)) continue;
722  if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) &&
724  {
725  gnc_commodity *commodity;
726  gnc_numeric old_value, new_value;
727 
728  commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
729  if (!commodity)
730  {
731  PERR("Split has no commodity");
732  continue;
733  }
734  balance_split = get_trading_split(trans, root, commodity);
735  if (!balance_split)
736  {
737  /* Error already logged */
738  gnc_monetary_list_free(imbal_list);
739  LEAVE("");
740  return;
741  }
742  account = xaccSplitGetAccount(balance_split);
743 
744  xaccTransBeginEdit (trans);
745 
746  old_value = xaccSplitGetValue (balance_split);
747  new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split),
748  gnc_commodity_get_fraction(currency),
750  xaccSplitSetValue (balance_split, new_value);
751 
752  /* Don't change the balance split's amount since the amount
753  is zero in the split we're working on */
754 
755  xaccSplitScrub (balance_split);
756  xaccTransCommitEdit (trans);
757  }
758  }
759 
760  g_list_free(splits_dup);
761 
763  PERR("Balancing currencies unbalanced value");
764  }
765  }
766  LEAVE ("()");
767 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Definition: Transaction.c:1015
#define PINFO(format, args...)
Definition: qoflog.h:249
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_zero_p(gnc_numeric a)
gboolean xaccTransIsBalanced(const Transaction *trans)
Definition: Transaction.c:1124
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
Definition: Transaction.c:1036
void gnc_monetary_list_free(MonetaryList *list)
void xaccSplitScrub(Split *split)
Definition: Scrub.c:176
void xaccTransScrubSplits(Transaction *trans)
Definition: Transaction.c:2616
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
Definition: Transaction.c:1052
#define LEAVE(format, args...)
Definition: qoflog.h:271
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
void xaccTransScrubOrphans ( Transaction trans)

The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.

Definition at line 124 of file Scrub.c.

125 {
126  SplitList *node;
127  QofBook *book = NULL;
128  Account *root = NULL;
129 
130  if (!trans) return;
131 
132  for (node = trans->splits; node; node = node->next)
133  {
134  Split *split = node->data;
135 
136  if (split->acc)
137  {
138  TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
139  return;
140  }
141  }
142 
143  /* If we got to here, then *none* of the splits belonged to an
144  * account. Not a happy situation. We should dig an account
145  * out of the book the transaction belongs to.
146  * XXX we should probably *always* to this, instead of the above loop!
147  */
148  PINFO ("Free Floating Transaction!");
149  book = xaccTransGetBook (trans);
150  root = gnc_book_get_root_account (book);
151  TransScrubOrphansFast (trans, root);
152 }
#define PINFO(format, args...)
Definition: qoflog.h:249
GList SplitList
Definition: gnc-engine.h:203
#define xaccTransGetBook(X)
Definition: Transaction.h:753
Definition: SplitP.h:71
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2630
void xaccTransScrubSplits ( Transaction trans)

The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction, account, account & it's children, account-group.

Definition at line 2616 of file Transaction.c.

2617 {
2618  gnc_commodity *currency;
2619 
2620  if (!trans) return;
2621 
2622  xaccTransBeginEdit(trans);
2623  /* The split scrub expects the transaction to have a currency! */
2624  currency = xaccTransGetCurrency (trans);
2625  if (!currency)
2626  PERR ("Transaction doesn't have a currency!");
2627 
2628  FOR_EACH_SPLIT(trans, xaccSplitScrub(s));
2629  xaccTransCommitEdit(trans);
2630 }
#define PERR(format, args...)
Definition: qoflog.h:237
void xaccSplitScrub(Split *split)
Definition: Scrub.c:176
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348