diff --git a/src/engine/Scrub.c b/src/engine/Scrub.c index 43e80053dc..934a323154 100644 --- a/src/engine/Scrub.c +++ b/src/engine/Scrub.c @@ -32,8 +32,8 @@ * Copyright (c) 1998, 1999, 2000 Linas Vepstas */ +#include #include -#include #include #include "Account.h" @@ -41,6 +41,7 @@ #include "GroupP.h" #include "Scrub.h" #include "Transaction.h" +#include "TransactionP.h" #include "gnc-engine-util.h" #include "messages.h" @@ -73,9 +74,9 @@ xaccAccountScrubOrphans (Account *acc) { GList *slp; Transaction *trans; Account * parent; - + PINFO ("Looking for orphans in account %s \n", xaccAccountGetName(acc)); - + for(slp = xaccAccountGetSplitList(acc); slp; slp = slp->next) { Split *split = (Split *) slp->data; Split * tsplit; @@ -130,30 +131,57 @@ xaccAccountScrubImbalance (Account *acc) { for(slp = xaccAccountGetSplitList(acc); slp; slp = slp->next) { Split *split = (Split *) slp->data; Transaction *trans = xaccSplitGetParent(split); - double imbalance; - imbalance = DxaccTransGetImbalance (trans); - if (!(DEQ (imbalance, 0.0))) { - Split *splat; - Account *orph; - DEBUG ("Found imbalance of %g\n", imbalance); - /* OK, we found an imbalanced trans. Put it in the imbal account. */ - orph = GetOrMakeAccount (acc, trans, _("Imbalance")); - - /* put split into account before setting split value */ - splat = xaccMallocSplit(); - xaccAccountBeginEdit (orph); - xaccAccountInsertSplit (orph, splat); - xaccAccountCommitEdit (orph); - - xaccTransBeginEdit (trans, 1); - DxaccSplitSetValue (splat, -imbalance); - xaccTransAppendSplit (trans, splat); - xaccTransCommitEdit (trans); - } + xaccTransScrubImbalance (trans); } } +void +xaccTransScrubImbalance (Transaction *trans) +{ + GList *node; + Split *split; + Account *peer; + Account *account; + gnc_numeric imbalance; + + imbalance = xaccTransGetImbalance (trans); + if (gnc_numeric_zero_p (imbalance)) + return; + + DEBUG ("Found imbalance"); + + peer = NULL; + for (node = trans->splits; node; node = node->next) + { + split = node->data; + + peer = xaccSplitGetAccount (split); + if (peer) + break; + } + + if (!peer) + { + PERR ("Transaction with no accounts"); + return; + } + + /* OK, we found an imbalanced trans. Put it in the imbal account. */ + account = GetOrMakeAccount (peer, trans, _("Imbalance")); + + /* put split into account before setting split value */ + split = xaccMallocSplit(); + xaccAccountBeginEdit (account); + xaccAccountInsertSplit (account, split); + xaccAccountCommitEdit (account); + + xaccTransBeginEdit (trans, TRUE); + xaccSplitSetValue (split, gnc_numeric_neg (imbalance)); + xaccTransAppendSplit (trans, split); + xaccTransCommitEdit (trans); +} + /* ================================================================ */ static Account * @@ -166,27 +194,29 @@ GetOrMakeAccount (Account *peer, Transaction *trans, const char *name_root) /* build the account name */ currency = xaccTransFindCommonCurrency (trans); - accname = alloca (strlen (name_root) + - strlen (gnc_commodity_get_mnemonic(currency)) + 2); - strcpy (accname, name_root); - strcat (accname, "-"); - strcat (accname, gnc_commodity_get_mnemonic(currency)); + + accname = g_strconcat (name_root, "-", + gnc_commodity_get_mnemonic(currency), NULL); /* see if we've got one of these going already ... */ acc = xaccGetPeerAccountFromName (peer, accname); - if (acc) return acc; - /* guess not. We'll have to build one */ - acc = xaccMallocAccount (); - xaccAccountBeginEdit (acc); - xaccAccountSetName (acc, accname); - xaccAccountSetCurrency (acc, currency); - xaccAccountSetType (acc, BANK); + if (acc == NULL) + { + /* guess not. We'll have to build one */ + acc = xaccMallocAccount (); + xaccAccountBeginEdit (acc); + xaccAccountSetName (acc, accname); + xaccAccountSetCurrency (acc, currency); + xaccAccountSetType (acc, BANK); - /* hang the account off the root */ - root = xaccGetAccountRoot (peer); - xaccGroupInsertAccount (root, acc); - xaccAccountCommitEdit (acc); + /* hang the account off the root */ + root = xaccGetAccountRoot (peer); + xaccGroupInsertAccount (root, acc); + xaccAccountCommitEdit (acc); + } + + g_free (accname); return acc; } diff --git a/src/engine/Scrub.h b/src/engine/Scrub.h index 4e6fa5a4ad..55d0d414c9 100644 --- a/src/engine/Scrub.h +++ b/src/engine/Scrub.h @@ -62,6 +62,7 @@ void xaccGroupScrubOrphans (AccountGroup *grp); * is created to offset this amount and is added to an "imbalance" * account. */ +void xaccTransScrubImbalance (Transaction *trans); void xaccAccountScrubImbalance (Account *acc); void xaccAccountTreeScrubImbalance (Account *acc); void xaccGroupScrubImbalance (AccountGroup *grp); diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 1b9cc0b2a1..d4b022d6a6 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -959,12 +959,6 @@ ComputeValue (GList *splits, Split * skip_me, return value; } -double -DxaccTransGetImbalance (Transaction * trans) -{ - return gnc_numeric_to_double(xaccTransGetImbalance(trans)); -} - gnc_numeric xaccTransGetImbalance (Transaction * trans) { @@ -973,6 +967,52 @@ xaccTransGetImbalance (Transaction * trans) return imbal; } +Split * +xaccTransGetBalanceSplit (Transaction *trans) +{ + Split *split; + kvp_value *kvp; + GUID *guid; + + if (!trans) + return NULL; + + kvp = kvp_frame_get_slot (xaccTransGetSlots (trans), "balance-split"); + if (!kvp) + return NULL; + + guid = kvp_value_get_guid (kvp); + if (!guid) + return NULL; + + split = xaccSplitLookup (guid); + if (g_list_find (trans->splits, split)) + return split; + + xaccTransSetBalanceSplit (trans, NULL); + + return NULL; +} + +void +xaccTransSetBalanceSplit (Transaction *trans, Split *split) +{ + kvp_value *new_value; + + if (!trans) + return; + + if (split) + new_value = kvp_value_new_guid (xaccSplitGetGUID (split)); + else + new_value = NULL; + + kvp_frame_set_slot(xaccTransGetSlots (trans), "balance-split", new_value); + + if (new_value) + kvp_value_delete(new_value); +} + /********************************************************************\ \********************************************************************/ gboolean @@ -1129,7 +1169,7 @@ xaccSplitRebalance (Split *split) { Transaction *trans; gnc_numeric value; - const gnc_commodity * base_currency = NULL; + const gnc_commodity * base_currency = NULL; trans = split->parent; @@ -1358,7 +1398,7 @@ xaccTransCommitEdit (Transaction *trans) xaccSplitSetShareAmount(s, gnc_numeric_neg(split->damount)); xaccSplitSetValue(s, gnc_numeric_neg(split->value)); } - + trans->open &= ~DEFER_REBALANCE; xaccTransRebalance (trans); diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h index 5f82f4114e..c442a72450 100644 --- a/src/engine/Transaction.h +++ b/src/engine/Transaction.h @@ -290,8 +290,14 @@ xaccTransIsCommonExclSCurrency (Transaction *trans, * in the currency that is returned by the xaccTransFindCommonCurrency() * method. */ -double DxaccTransGetImbalance (Transaction * trans); -gnc_numeric xaccTransGetImbalance (Transaction * trans); +gnc_numeric xaccTransGetImbalance (Transaction * trans); + +/* The xaccTransGetBalanceSplit method returns the 'balance' split of + * a transaction or NULL if there is no balance split. The balance + * split is an 'artificial' split created to make the transaction + * balance. This split is automatically managed by the rebalancing + * routines and is created and destroyed as needed. */ +Split * xaccTransGetBalanceSplit (Transaction *trans); /* ------------- splits --------------- */ Split * xaccMallocSplit (void); @@ -475,7 +481,7 @@ int xaccCountSplits (Split **sarray); * The xaccGetAccountByFullName routine is similar, but uses * full names using the given separator. */ -Account * xaccGetAccountByName (Transaction *, const char *); +Account * xaccGetAccountByName (Transaction *trans, const char *name); Account * xaccGetAccountByFullName (Transaction *trans, const char *name, const char separator); diff --git a/src/engine/TransactionP.h b/src/engine/TransactionP.h index e9f24bbc5a..032259f1f4 100644 --- a/src/engine/TransactionP.h +++ b/src/engine/TransactionP.h @@ -230,6 +230,8 @@ void xaccFreeSplit (Split *split); /* frees memory */ void xaccSplitRebalance (Split *split); +/* Set the balance split of a transaction. */ +void xaccTransSetBalanceSplit (Transaction *trans, Split *split); /* FIXME: this is probably wrong, but it'll have to wait until Bill returns. It's *ONLY* for file IO. Don't use these elsewhere. */