fix how double-entry is maintained

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@698 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 1998-03-23 06:41:26 +00:00
parent 78eab15914
commit 1742d0fc7a
2 changed files with 115 additions and 25 deletions

View File

@ -34,6 +34,14 @@
#include "TransactionP.h" #include "TransactionP.h"
#include "util.h" #include "util.h"
/* if the "force_double_entry" flag has a non-zero value,
* then all transactions will be *forced* to balance.
* This will be forced even if it requires a new split
* to be created.
*/
int force_double_entry = 0;
/********************************************************************\ /********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I * * Because I can't use C++ for this project, doesn't mean that I *
* can't pretend too! These functions perform actions on the * * can't pretend too! These functions perform actions on the *
@ -155,7 +163,7 @@ void xaccSplitSetShareAmount (Split *s, double amt)
s -> damount = amt; s -> damount = amt;
} }
void xaccSplitSetAmount (Split *s, double amt) void xaccSplitSetValue (Split *s, double amt)
{ {
MARK_SPLIT(s); MARK_SPLIT(s);
/* remember, damount is actually share price */ /* remember, damount is actually share price */
@ -268,30 +276,92 @@ xaccFreeTransaction( Transaction *trans )
\********************************************************************/ \********************************************************************/
void void
xaccTransRecomputeAmount (Transaction *trans) xaccSplitRebalance (Split *split)
{ {
Transaction *trans;
Split *s; Split *s;
int i = 0; int i = 0;
double amount = 0.0; double value = 0.0;
s = trans->dest_splits[i];
while (s) {
amount += s->share_price * s->damount;
i++;
s = trans->dest_splits[i];
}
/* if there is just one split, then the credited trans = split->parent;
* and the debited splits should match up. */
if (1 == i) { if (&(trans->source_split) == split) {
/* The indicated split is the source split.
* Pick a destination split (by default,
* the first destination split), and force
* the total on it.
*/
s = trans->dest_splits[0]; s = trans->dest_splits[0];
trans -> source_split.damount = - (s->damount); if (s) {
trans -> source_split.share_price = s->share_price; /* first, add the source split */
value = split->share_price * split->damount;
/* now add in the sum of the destination splits */
i = 0;
while (s) {
value += s->share_price * s->damount;
i++;
s = trans->dest_splits[i];
}
/* subtract the first destination split */
s = trans->dest_splits[0];
value -= (s->share_price) * (s->damount);
/* the new value of the destination split
* will be the result.
*/
s -> damount = - (value / (s->share_price));
MARK_SPLIT (s);
} else{
/* There are no destination splits !!
* Either this is allowed, in which case
* we just blow it off, or its forbidden,
* in which case we force a balacing split
* to be created.
*/
if (force_double_entry) {
value = split->share_price * split->damount;
/* malloc a new split, mirror it to the source split */
s = xaccMallocSplit ();
s->damount = -value;
free (s->memo);
s->memo = strdup (split->memo);
free (s->action);
s->action = strdup (split->action);
/* insert the new split into the transaction and
* the same account as the source split */
xaccTransAppendSplit (trans, s);
xaccAccountInsertSplit (split->acc, s);
MARK_SPLIT (s);
}
}
} else { } else {
trans -> source_split.damount = -amount;
trans -> source_split.share_price = 1.0; /* The indicated split is a destination split.
* Compute grand total of all distination splits,
* and force the source split to blanace.
*/
i = 0;
s = trans->dest_splits[i];
value = 0.0;
while (s) {
value += s->share_price * s->damount;
i++;
s = trans->dest_splits[i];
}
s = &(trans->source_split);
s -> damount = - (value / (s->share_price));
MARK_SPLIT (s);
} }
MARK_SPLIT (&(trans->source_split));
} }
/********************************************************************\ /********************************************************************\
@ -343,9 +413,6 @@ xaccTransRemoveSplit (Transaction *trans, Split *split)
s = trans->dest_splits[n]; s = trans->dest_splits[n];
} }
trans->dest_splits[i] = NULL; trans->dest_splits[i] = NULL;
/* bring dollar amounts into synchrony */
xaccTransRecomputeAmount (trans);
} }
/********************************************************************\ /********************************************************************\

View File

@ -83,10 +83,33 @@ void xaccTransSetReconcile (Transaction *, char);
void xaccTransAppendSplit (Transaction *, Split *); void xaccTransAppendSplit (Transaction *, Split *);
void xaccTransRemoveSplit (Transaction *, Split *); void xaccTransRemoveSplit (Transaction *, Split *);
/* recompute the total transaction value, based /*
* on the sum of the debit splits that belong to this * The xaccSplitRebalance() routine is an important routine for
* transaction. */ * maintaining and ensuring that double-entries balance properly.
void xaccTransRecomputeAmount (Transaction *); * This routine forces the sum-total of the values of all the
* splits in a transaction to total up to exactly zero.
*
* It is worthwhile to understand the algorithm that this routine
* uses to acheive balance. It goes like this:
* If the indicated split is a destination split, then the
* total value of the destination splits is computed, and the
* value of the source split is adjusted to be minus this amount.
* (the share price of the source split is not changed).
* If the indicated split is the source split, then the value
* of the very first destination split is adjusted so that
* the blanace is zero. If there is not destination split,
* one of two outcomes are possible, depending on whether
* "forced_double_entry" is enabled or disabled.
* (1) if forced-double-entry is disabled, the fact that
* the destination is missing is ignored.
* (2) if force-double-entry is enabled, then a destination
* split that exactly mirrors the ource split is created,
* and credited to the same account as the source split.
* Hopefully, the user will notice this, and reparent the
* destination split properly.
*/
void xaccSplitRebalance (Split *);
/* ------------- gets --------------- */ /* ------------- gets --------------- */
/* return pointer to the source split */ /* return pointer to the source split */
@ -115,7 +138,7 @@ void xaccSplitSetAction (Split *, const char *);
void xaccSplitSetReconcile (Split *, char); void xaccSplitSetReconcile (Split *, char);
/* The following two functions set the amount on the split */ /* The following two functions set the amount on the split */
void xaccSplitSetAmount (Split *, double); void xaccSplitSetValue (Split *, double);
void xaccSplitSetShareAmount (Split *, double); void xaccSplitSetShareAmount (Split *, double);