merge changes from currthree branch into head branch.

That side branch implements multiple currency support.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1216 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas
1998-09-21 03:42:58 +00:00
parent 007637be7e
commit c0000344a8
18 changed files with 456 additions and 172 deletions

View File

@@ -187,7 +187,13 @@ xaccLedgerDisplaySimple (Account *acc)
case EQUITY:
reg_type = EQUITY_REGISTER;
break;
}
case CURRENCY:
reg_type = CURRENCY_REGISTER;
break;
default:
PERR (" xaccLedgerDisplaySimple(): unknown account type\n");
return NULL;
}
/* default to single-line display */
reg_type |= REG_SINGLE_LINE;

View File

@@ -194,7 +194,7 @@ LedgerDestroy (SplitRegister *reg)
/* split destroy will automatically remove it
* from its parent account */
trans = xaccSplitGetParent (split);
xaccTransBeginEdit (trans);
xaccTransBeginEdit (trans, 1);
xaccTransDestroy (trans);
reg->user_hook = NULL;
}
@@ -304,7 +304,7 @@ printf ("save split is %p \n", split);
acc = xaccSplitGetAccount (s);
split = xaccMallocSplit ();
xaccTransBeginEdit (trans);
xaccTransBeginEdit (trans, 0);
xaccTransAppendSplit (trans, split);
xaccAccountInsertSplit (acc, split);
@@ -313,7 +313,7 @@ printf ("save split is %p \n", split);
} else {
trans = xaccSplitGetParent (split);
xaccTransBeginEdit (trans);
xaccTransBeginEdit (trans, 0);
}
/* copy the contents from the cursor to the split */
@@ -404,9 +404,10 @@ printf ("save split is %p \n", split);
} else {
new_amount = (reg->ndebitCell->amount) - (reg->ncreditCell->amount);
}
if ((EQUITY_REGISTER == (reg->type & REG_TYPE_MASK)) ||
(STOCK_REGISTER == (reg->type & REG_TYPE_MASK)) ||
(PORTFOLIO == (reg->type & REG_TYPE_MASK)))
if ((EQUITY_REGISTER == (reg->type & REG_TYPE_MASK)) ||
(STOCK_REGISTER == (reg->type & REG_TYPE_MASK)) ||
(CURRENCY_REGISTER == (reg->type & REG_TYPE_MASK)) ||
(PORTFOLIO == (reg->type & REG_TYPE_MASK)))
{
xaccSplitSetShareAmount (split, new_amount);
} else {
@@ -536,9 +537,10 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
buff[1] = 0x0;
xaccSetBasicCellValue (reg->recnCell, buff);
if ((EQUITY_REGISTER == typo) ||
(STOCK_REGISTER == typo) ||
(PORTFOLIO == typo))
if ((EQUITY_REGISTER == typo) ||
(STOCK_REGISTER == typo) ||
(CURRENCY_REGISTER == typo) ||
(PORTFOLIO == typo))
{
amt = xaccSplitGetShareAmount (split);
} else {
@@ -773,11 +775,12 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
Table *table;
int phys_row;
int vrow;
int style;
int type, style;
int multi_line, dynamic;
CellBlock *lead_cursor;
table = reg->table;
type = (reg->type) & REG_TYPE_MASK;
style = (reg->type) & REG_STYLE_MASK;
multi_line = (REG_MULTI_LINE == style);
dynamic = ((REG_SINGLE_DYNAMIC == style) || (REG_DOUBLE_DYNAMIC == style));
@@ -895,7 +898,7 @@ printf ("load split %d at phys row %d addr=%p \n", j, phys_row, secondary);
double last_price = 0.0;
trans = xaccMallocTransaction ();
xaccTransBeginEdit (trans);
xaccTransBeginEdit (trans, 1);
xaccTransSetDateToday (trans);
xaccTransCommitEdit (trans);
split = xaccTransGetSplit (trans, 0);
@@ -907,8 +910,12 @@ printf ("load split %d at phys row %d addr=%p \n", j, phys_row, secondary);
* when doing stock accounts. This will guess incorrectly for a
* ledger showing multiple stocks, but seems cool for a single stock.
*/
last_price = xaccSplitGetSharePrice (last_split);
xaccSplitSetSharePrice (split, last_price);
if ((STOCK_REGISTER == type) ||
(PORTFOLIO == type))
{
last_price = xaccSplitGetSharePrice (last_split);
xaccSplitSetSharePrice (split, last_price);
}
}
/* do the split row of the blank split */
@@ -951,20 +958,37 @@ printf ("load split %d at phys row %d addr=%p \n", j, phys_row, secondary);
/* walk account tree recursively, pulling out all the names */
static void
LoadXferCell (ComboCell *cell, AccountGroup *grp)
LoadXferCell (ComboCell *cell,
AccountGroup *grp,
char *base_currency, char *base_security)
{
Account * acc;
int n;
if (!grp) return;
/* build the xfer menu out of account names */
/* traverse sub-accounts recursively */
/* Build the xfer menu out of account names.
* Traverse sub-accounts recursively.
* Valid transfers can occur only between accounts
* with the same base currency.
*/
n = 0;
acc = xaccGroupGetAccount (grp, n);
while (acc) {
xaccAddComboCellMenuItem (cell, xaccAccountGetName (acc));
LoadXferCell (cell, xaccAccountGetChildren (acc));
char *curr, *secu;
curr = xaccAccountGetCurrency (acc);
secu = xaccAccountGetSecurity (acc);
if ( (!safe_strcmp(curr,base_currency)) ||
(!safe_strcmp(secu,base_currency)) ||
(!safe_strcmp(curr,base_security)) ||
(!safe_strcmp(secu,base_security)) )
{
xaccAddComboCellMenuItem (cell, xaccAccountGetName (acc));
}
LoadXferCell (cell, xaccAccountGetChildren (acc),
base_currency, base_security);
n++;
acc = xaccGroupGetAccount (grp, n);
}
@@ -972,10 +996,17 @@ LoadXferCell (ComboCell *cell, AccountGroup *grp)
/* ======================================================== */
void xaccLoadXferCell (ComboCell *cell, AccountGroup *grp)
void xaccLoadXferCell (ComboCell *cell,
AccountGroup *grp,
Account *base_account)
{
char *curr, *secu;
curr = xaccAccountGetCurrency (base_account);
secu = xaccAccountGetSecurity (base_account);
xaccAddComboCellMenuItem (cell, "");
LoadXferCell (cell, grp);
LoadXferCell (cell, grp, curr, secu);
}
/* ======================= end of file =================== */

View File

@@ -12,13 +12,13 @@ char *account_type_name[NUM_ACCOUNT_TYPES] =
LIABILITY_STR,
STOCK_STR,
MUTUAL_FUND_STR,
CURRENCY_STR,
INCOME_STR,
EXPENSE_STR,
EQUITY_STR,
CHECKING_STR,
SAVINGS_STR,
MONEYMRKT_STR,
CREDITLINE_STR,
CURRENCY_STR
CREDITLINE_STR
};

View File

@@ -33,16 +33,12 @@
#include "config.h"
/* The account types.
* Note: the actual values of these are *very* important,
* as it is the values, not the enums, that are stored
* in the file format!
* hack alert ... note that this is a bug that should be fixed ...
*/
/*
* The account types are used to determine how the transaction data
* in the account is displayed.
* in the account is displayed. These values can be safely changed
* from one release to the next. Note that if values are added,
* the file IO translation routines need to be updated. Note
* also that GUI code depends on these numbers.
*/
enum
{
@@ -73,29 +69,32 @@ enum
* which show three columns: price, number of shares, and value.
*/
INCOME = 7,
EXPENSE = 8,
/* Income and expense accounts are used to denote income and expenses.
* Thus, when data in these accountsare displayed, the sign of the
* splits (entries) must be reversed.
*/
EQUITY = 9,
/* Equity account is used to balance the balance sheet. */
/* bank account types */
CHECKING = 10,
SAVINGS = 11,
MONEYMRKT = 12,
CREDITLINE = 13, /* line of credit */
CURRENCY = 14,
CURRENCY = 7,
/* The currency account type indicates that the account is a currency trading
* account. In many ways, a currency trading account is like a stock trading
* account, where both quantities and prices are set.
*/
NUM_ACCOUNT_TYPES = 15
INCOME = 8,
EXPENSE = 9,
/* Income and expense accounts are used to denote income and expenses.
* Thus, when data in these accountsare displayed, the sign of the
* splits (entries) must be reversed.
*/
EQUITY = 10,
/* Equity account is used to balance the balance sheet. */
NUM_ACCOUNT_TYPES = 11,
/* stop here; the following types just aren't ready for prime time */
/* bank account types */
CHECKING = 11,
SAVINGS = 12,
MONEYMRKT = 13,
CREDITLINE = 14, /* line of credit */
};
/* hack alert -- we need a better way of dealing with

View File

@@ -174,10 +174,11 @@ xaccFreeAccount( Account *acc )
\********************************************************************/
void
xaccAccountBeginEdit (Account *acc)
xaccAccountBeginEdit (Account *acc, int defer)
{
if (!acc) return;
acc->open = 1;
acc->open = ACC_BEGIN_EDIT;
if (defer) acc->open |= ACC_DEFER_REBALANCE;
}
void
@@ -752,13 +753,15 @@ xaccAccountSetCurrency (Account *acc, char *str)
if ((!acc) || (!str)) return;
CHECK (acc);
if (acc->currency) {
if (acc->currency && (0x0 != acc->currency[0])) {
printf ("Error: xacAccountSetCurrency(): "
"the currency denomination of an account "
"cannot be changed!\n"
);
return;
}
/* free the zero-length string */
if (acc->currency) free (acc->currency);
acc->currency = strdup (str);
}
@@ -768,13 +771,15 @@ xaccAccountSetSecurity (Account *acc, char *str)
if ((!acc) || (!str)) return;
CHECK (acc);
if (acc->security) {
if (acc->security && (0x0 != acc->security[0])) {
printf ("Error: xacAccountSetCurrency(): "
"the security denomination of an account "
"the security traded in an account "
"cannot be changed!\n"
);
return;
}
/* free the zero-length string */
if (acc->security) free (acc->security);
acc->security = strdup (str);
}

View File

@@ -43,8 +43,11 @@ void xaccFreeAccount( Account * );
* They are mildly useful for detecting attempted updates outside
* of thier scope. However, they do not provide any true two-phase-anything
* in the current implementation.
*
* The defer flag, if sett, will defer all attempts at rebalancing
* of accounts until the commit.
*/
void xaccAccountBeginEdit (Account *);
void xaccAccountBeginEdit (Account *, int defer);
void xaccAccountCommitEdit (Account *);
int xaccGetAccountID (Account *);

View File

@@ -130,6 +130,10 @@ struct _account {
short open;
};
/* bitflields for theopen flag */
#define ACC_BEGIN_EDIT 0x1
#define ACC_DEFER_REBALANCE 0x2
/* The xaccAccountRemoveSplit() routine will remove the indicated split
* from the indicated account. Note that this will leave the split

View File

@@ -41,11 +41,14 @@
* *
* Version 6 of the file format removes the source split *
* *
* Version 7 of the file format adds currency & security types *
* *
* the format of the data in the file: *
* file ::== token Group *
* Group ::== numAccounts (Account)^numAccounts *
* Account ::== accID flags type accountName description *
* notes numTran (Transaction)^numTrans *
* notes currency security *
* numTran (Transaction)^numTrans *
* numGroups (Group)^numGroups *
* Transaction ::== num date description *
* numSplits (Split)^numSplits *
@@ -60,6 +63,8 @@
* accountName ::== String *
* description ::== String *
* notes ::== String *
* currency ::== String *
* security ::== String *
* *
* num ::== String *
* date ::== Date *
@@ -100,10 +105,17 @@
#define PERMS 0666
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define RFLAGS O_RDONLY
#define VERSION 6
#define VERSION 7
/** GLOBALS *********************************************************/
/* the default currency is used when importin old-style
* file formats, or when importing files with no currency
* specified. This should probably be something that
* is configurable from some user config menu.
*/
#define DEFAULT_CURRENCY "USD"
static int error_code=0; /* error code, if error occurred */
static AccountGroup *holder; /* temporary holder for
@@ -130,6 +142,31 @@ static int writeSplit( int fd, Split *split);
static int writeString( int fd, char *str );
static int writeDate( int fd, time_t secs );
/*******************************************************/
/* backwards compatibility definitions for numeric value
* of account type. These numbers are used (are to be
* used) no where else but here, precisely because they
* are non-portable. The values of these defines MUST
* NOT BE CHANGED; andy changes WILL BREAK FILE COMPATIBILITY.
* YOu HAve BEen WARNed!!!!
*/
#define FF_BANK 0
#define FF_CASH 1
#define FF_ASSET 2
#define FF_CREDIT 3
#define FF_LIABILITY 4
#define FF_STOCK 5
#define FF_MUTUAL 6
#define FF_INCOME 7
#define FF_EXPENSE 8
#define FF_EQUITY 9
#define FF_CHECKING 10
#define FF_SAVINGS 11
#define FF_MONEYMRKT 12
#define FF_CREDITLINE 13
#define FF_CURRENCY 14
/*******************************************************/
int xaccGetFileIOError (void)
@@ -258,7 +295,7 @@ xaccReadAccountGroup( char *datafile )
/* create a lost account, put the missing accounts there */
acc = xaccMallocAccount();
xaccAccountBeginEdit (acc);
xaccAccountBeginEdit (acc, 1);
xaccAccountSetName (acc, LOST_ACC_STR);
acc -> children = holder;
xaccAccountCommitEdit (acc);
@@ -343,7 +380,6 @@ readAccount( int fd, AccountGroup *grp, int token )
int i;
int numTrans, accID;
Account *acc;
char acctype;
char * tmp;
ENTER ("readAccount");
@@ -359,14 +395,36 @@ readAccount( int fd, AccountGroup *grp, int token )
insertAccount (holder, acc);
}
xaccAccountBeginEdit (acc);
xaccAccountBeginEdit (acc, 1);
err = read( fd, &(acc->flags), sizeof(char) );
if( err != sizeof(char) ) { return NULL; }
err = read( fd, &(acctype), sizeof(char) );
if( err != sizeof(char) ) { return NULL; }
xaccAccountSetType (acc, acctype);
/* if (9999>= token) */ {
char ff_acctype;
int acctype;
err = read( fd, &(ff_acctype), sizeof(char) );
if( err != sizeof(char) ) { return NULL; }
switch (ff_acctype) {
case FF_BANK: { acctype = BANK; break; }
case FF_CASH: { acctype = CASH; break; }
case FF_ASSET: { acctype = ASSET; break; }
case FF_CREDIT: { acctype = CREDIT; break; }
case FF_LIABILITY: { acctype = LIABILITY; break; }
case FF_STOCK: { acctype = STOCK; break; }
case FF_MUTUAL: { acctype = MUTUAL; break; }
case FF_INCOME: { acctype = INCOME; break; }
case FF_EXPENSE: { acctype = EXPENSE; break; }
case FF_EQUITY: { acctype = EQUITY; break; }
case FF_CHECKING: { acctype = CHECKING; break; }
case FF_SAVINGS: { acctype = SAVINGS; break; }
case FF_MONEYMRKT: { acctype = MONEYMRKT; break; }
case FF_CREDITLINE: { acctype = CREDITLINE; break; }
case FF_CURRENCY: { acctype = CURRENCY; break; }
default: return NULL;
}
xaccAccountSetType (acc, acctype);
}
tmp = readString( fd, token );
if( NULL == tmp) { free (tmp); return NULL; }
@@ -384,6 +442,24 @@ readAccount( int fd, AccountGroup *grp, int token )
xaccAccountSetNotes (acc, tmp);
free (tmp);
/* currency and security strings first introduced
* in version 7 of the file format */
if (7 <= token) {
tmp = readString( fd, token );
if( NULL == tmp ) { free (tmp); return NULL; }
xaccAccountSetCurrency (acc, tmp);
if (0x0 == tmp[0]) xaccAccountSetCurrency (acc, DEFAULT_CURRENCY);
free (tmp);
tmp = readString( fd, token );
if( NULL == tmp ) { free (tmp); return NULL; }
xaccAccountSetSecurity (acc, tmp);
free (tmp);
} else {
/* set the default currency when importing old files */
xaccAccountSetCurrency (acc, DEFAULT_CURRENCY);
}
err = read( fd, &numTrans, sizeof(int) );
if( err != sizeof(int) ) { return NULL; }
XACC_FLIP_INT (numTrans);
@@ -472,6 +548,7 @@ locateAccount (int acc_id)
* Put it in the drunk tank. */
acc = xaccMallocAccount ();
acc->id = acc_id;
acc->open = ACC_DEFER_REBALANCE;
insertAccount (holder, acc);
/* normalize the account numbers -- positive-definite.
@@ -538,7 +615,7 @@ readTransaction( int fd, Account *acc, int token )
/* create a transaction structure */
trans = xaccMallocTransaction();
xaccTransBeginEdit (trans);
xaccTransBeginEdit (trans, 1);
tmp = readString( fd, token );
if (NULL == tmp)
@@ -1144,7 +1221,6 @@ writeAccount( int fd, Account *acc )
int i, numUnwrittenTrans, ntrans;
int acc_id;
int numChildren = 0;
char acctype;
char * tmp;
INFO_2 ("writeAccount(): writing acct %s \n", acc->accountName);
@@ -1159,25 +1235,52 @@ writeAccount( int fd, Account *acc )
if( err != sizeof(char) )
return -1;
acctype = (char) xaccAccountGetType (acc);
err = write( fd, &(acctype), sizeof(char) );
if( err != sizeof(char) )
return -1;
{
char ff_acctype;
int acctype;
acctype = xaccAccountGetType (acc);
switch (acctype) {
case BANK: { ff_acctype = FF_BANK; break; }
case CASH: { ff_acctype = FF_CASH; break; }
case ASSET: { ff_acctype = FF_ASSET; break; }
case CREDIT: { ff_acctype = FF_CREDIT; break; }
case LIABILITY: { ff_acctype = FF_LIABILITY; break; }
case STOCK: { ff_acctype = FF_STOCK; break; }
case MUTUAL: { ff_acctype = FF_MUTUAL; break; }
case INCOME: { ff_acctype = FF_INCOME; break; }
case EXPENSE: { ff_acctype = FF_EXPENSE; break; }
case EQUITY: { ff_acctype = FF_EQUITY; break; }
case CHECKING: { ff_acctype = FF_CHECKING; break; }
case SAVINGS: { ff_acctype = FF_SAVINGS; break; }
case MONEYMRKT: { ff_acctype = FF_MONEYMRKT; break; }
case CREDITLINE: { ff_acctype = FF_CREDITLINE; break; }
case CURRENCY: { ff_acctype = FF_CURRENCY; break; }
default: return -1;
}
err = write( fd, &(ff_acctype), sizeof(char) );
if( err != sizeof(char) )
return -1;
}
tmp = xaccAccountGetName (acc);
err = writeString( fd, tmp );
if( -1 == err )
return err;
if( -1 == err ) return err;
tmp = xaccAccountGetDescription (acc);
err = writeString( fd, tmp );
if( -1 == err )
return err;
if( -1 == err ) return err;
tmp = xaccAccountGetNotes (acc);
err = writeString( fd, tmp );
if( -1 == err )
return err;
if( -1 == err ) return err;
tmp = xaccAccountGetCurrency (acc);
err = writeString( fd, tmp );
if( -1 == err ) return err;
tmp = xaccAccountGetSecurity (acc);
err = writeString( fd, tmp );
if( -1 == err ) return err;
/* figure out numTrans -- it will be less than the total
* number of transactions in this account, because some
@@ -1363,11 +1466,7 @@ writeString( int fd, char *str )
int tmp;
if (NULL == str) str = ""; /* protect against null arguments */
for( size=0; str[size] != '\0'; size++ )
{}
size++; /* we want to make sure we include the '\0'!
* Otherwise, bad things happen */
size = strlen (str) + 1;
tmp = size;
XACC_FLIP_INT (tmp);

View File

@@ -444,14 +444,19 @@ insertAccount( AccountGroup *grp, Account *acc )
/********************************************************************\
\********************************************************************/
void
xaccRecomputeGroupBalance (AccountGroup *grp)
{
int i;
Account *acc;
char * default_currency;
if (!grp) return;
acc = grp->account[0];
default_currency = acc->currency;
grp->balance = 0.0;
for (i=0; i<grp->numAcc; i++) {
acc = grp->account[i];
@@ -459,12 +464,17 @@ xaccRecomputeGroupBalance (AccountGroup *grp)
/* first, get subtotals recursively */
if (acc->children) {
xaccRecomputeGroupBalance (acc->children);
grp->balance += acc->children->balance;
if (!safe_strcmp (default_currency, acc->currency)) {
grp->balance += acc->children->balance;
}
}
/* then add up accounts in this group */
xaccAccountRecomputeBalance (acc);
grp->balance += acc->balance;
if (!safe_strcmp (default_currency, acc->currency)) {
grp->balance += acc->balance;
}
}
}

View File

@@ -166,7 +166,7 @@ char * xaccReadQIFCategory (int fd, Account * acc)
if (!acc) return NULL;
xaccAccountBeginEdit (acc);
xaccAccountBeginEdit (acc, 0);
xaccAccountSetType (acc, -1);
xaccAccountSetName (acc, "");
xaccAccountSetDescription (acc, "");
@@ -244,7 +244,7 @@ char * xaccReadQIFAccount (int fd, Account * acc)
if (!acc) return NULL;
xaccAccountBeginEdit (acc);
xaccAccountBeginEdit (acc, 0);
xaccAccountSetType (acc, -1);
xaccAccountSetName (acc, "");
xaccAccountSetDescription (acc, "");
@@ -626,6 +626,7 @@ char * xaccReadQIFTransaction (int fd, Account *acc)
if ('!' == qifline [0]) return qifline;
trans = xaccMallocTransaction ();
xaccTransBeginEdit (trans, 1);
source_split = xaccTransGetSplit (trans, 0);
/* scan for transaction date, description, type */
@@ -874,6 +875,7 @@ char * xaccReadQIFTransaction (int fd, Account *acc)
/* the transaction itself appears as a credit */
xaccAccountInsertSplit (acc, source_split);
}
xaccTransCommitEdit (trans);
return qifline;
}

View File

@@ -55,6 +55,10 @@
*/
int force_double_entry = 0;
/* bit-field flags for controlling transaction commits */
#define BEGIN_EDIT 0x1
#define DEFER_REBALANCE 0x2
/********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I *
* can't pretend too! These functions perform actions on the *
@@ -62,6 +66,7 @@ int force_double_entry = 0;
* knowledge of the internals of the Transaction in one file. *
\********************************************************************/
/********************************************************************\
* xaccInitSplit
* Initialize a splitaction structure
@@ -330,6 +335,82 @@ xaccFreeTransaction( Transaction *trans )
/********************************************************************\
\********************************************************************/
void
xaccSplitSetBaseValue (Split *s, double value, char * base_currency)
{
if (!s) return;
assert (s->acc);
if (!safe_strcmp(s->acc->currency, base_currency)) {
s -> damount = - (value / (s->share_price));
} else
if (!safe_strcmp(s->acc->security, base_currency)) {
s -> damount = -value;
} else {
printf ("Error: xaccSplitSetBaseValue(): "
" inappropriate base currency %s "
" given split currency=%s and security=%s\n",
base_currency, s->acc->currency, s->acc->security);
return;
}
}
double
xaccSplitGetBaseValue (Split *s, char * base_currency)
{
double value;
if (!s) return 0.0;
assert (s->acc);
if (!safe_strcmp(s->acc->currency, base_currency)) {
value = s->damount * s->share_price;
} else
if (!safe_strcmp(s->acc->security, base_currency)) {
value = s->damount;
} else {
printf ("Error: xaccSplitGetBaseValue(): "
" inappropriate base currency %s "
" given split currency=%s and security=%s\n",
base_currency, s->acc->currency, s->acc->security);
return 0.0;
}
return value;
}
/********************************************************************\
\********************************************************************/
static double
ComputeValue (Split **sarray, Split * skip_me, char * base_currency)
{
Split *s;
int i=0;
double value = 0.0;
s = sarray[0];
while (s) {
if (s != skip_me) {
if (!safe_strcmp(s->acc->currency, base_currency)) {
value += s->share_price * s->damount;
} else
if (!safe_strcmp(s->acc->security, base_currency)) {
value += s->damount;
} else {
printf ("Internal Error: ComputeValue(): "
" inconsistent currencies \n");
assert (0);
}
}
i++; s = sarray [i];
}
return value;
}
/* hack alert -- the algorithm used in this rebalance routine
* is less than intuitive, and could use some write-up.
* Maybe it does indeed do the right thing, but that is
@@ -349,6 +430,8 @@ xaccSplitRebalance (Split *split)
Split *s;
int i = 0;
double value = 0.0;
char *base_currency=0x0;
char *ra=0x0, *rb =0x0;
trans = split->parent;
@@ -358,10 +441,66 @@ xaccSplitRebalance (Split *split)
* quietly return.
*/
if (!trans) return;
if (!(split->acc)) return;
if (DEFER_REBALANCE & (trans->open)) return;
if (ACC_DEFER_REBALANCE & (split->acc->open)) return;
assert (trans->splits);
assert (trans->splits[0]);
/* lets find out if we are dealing with multiple currencies,
* and which one(s) all of the splits have in common. */
ra = split->acc->currency;
rb = split->acc->security;
if (rb && (0x0==rb[0])) rb = 0x0;
i=0; s = trans->splits[0];
while (s) {
char *sa, *sb;
assert (s->acc);
sa = s->acc->currency;
sb = s->acc->security;
if (sb && (0x0==sb[0])) sb = 0x0;
if (ra && rb) {
int aa = safe_strcmp (ra,sa);
int ab = safe_strcmp (ra,sb);
int ba = safe_strcmp (rb,sa);
int bb = safe_strcmp (rb,sb);
if ( (!aa) && bb) rb = 0x0;
else
if ( (!ab) && ba) rb = 0x0;
else
if ( (!ba) && ab) ra = 0x0;
else
if ( (!bb) && aa) ra = 0x0;
else
if ( aa && bb && ab && ba ) { ra=0x0; rb=0x0; }
if (!ra) { ra=rb; rb=0x0; }
}
else
if (ra && !rb) {
int aa = safe_strcmp (ra,sa);
int ab = safe_strcmp (ra,sb);
if ( aa && ab ) ra= 0x0;
}
if ((!ra) && (!rb)) {
printf ("Internal Error: SplitRebalance(): "
" no common split currencies \n");
printf ("\tbase acc=%s cur=%s base_sec=%s\n"
"\tacc=%s scur=%s ssec=%s \n",
split->acc->accountName, split->acc->currency, split->acc->security,
s->acc->accountName, s->acc->currency, s->acc->security );
assert (0);
return;
}
i++; s = trans->splits[i];
}
base_currency = ra;
if (split == trans->splits[0]) {
/* The indicated split is the source split.
* Pick a destination split (by default,
@@ -371,25 +510,9 @@ xaccSplitRebalance (Split *split)
s = trans->splits[1];
if (s) {
/* first, add the source split */
value = split->share_price * split->damount;
/* now add in the sum of the destination splits */
i = 1;
while (s) {
value += s->share_price * s->damount;
i++;
s = trans->splits[i];
}
/* subtract the first destination split */
s = trans->splits[1];
value -= (s->share_price) * (s->damount);
/* the new value of the destination split
* will be the result.
*/
s -> damount = - (value / (s->share_price));
/* the new value of the destination split will be the result. */
value = ComputeValue (trans->splits, s, base_currency);
xaccSplitSetBaseValue (s, value, base_currency);
MARK_SPLIT (s);
xaccAccountRecomputeBalance (s->acc);
@@ -399,6 +522,11 @@ xaccSplitRebalance (Split *split)
* we just blow it off, or its forbidden,
* in which case we force a balacing split
* to be created.
*
* Note that its ok to have a single split who's amount is zero ..
* this is just a split that is recording a price, and nothing
* else. (i.e. it still obeys the rule that the sum of the
* value of all the splits is zero).
*/
if (force_double_entry) {
@@ -427,17 +555,9 @@ xaccSplitRebalance (Split *split)
* Compute grand total of all destination splits,
* and force the source split to blanace.
*/
i = 1;
s = trans->splits[i];
value = 0.0;
while (s) {
value += s->share_price * s->damount;
i++;
s = trans->splits[i];
}
s = trans->splits[0];
s -> damount = - (value / (s->share_price));
value = ComputeValue (trans->splits, s, base_currency);
xaccSplitSetBaseValue (s, value, base_currency);
MARK_SPLIT (s);
xaccAccountRecomputeBalance (s->acc);
}
@@ -464,10 +584,11 @@ xaccSplitRebalance (Split *split)
}
void
xaccTransBeginEdit (Transaction *trans)
xaccTransBeginEdit (Transaction *trans, int defer)
{
assert (trans);
trans->open = 1;
trans->open = BEGIN_EDIT;
if (defer) trans->open |= DEFER_REBALANCE;
xaccOpenLog ();
xaccTransWriteLog (trans, 'B');
}
@@ -482,6 +603,7 @@ xaccTransCommitEdit (Transaction *trans)
if (!trans) return;
CHECK_OPEN (trans);
trans->open &= ~DEFER_REBALANCE;
xaccTransRebalance (trans);
/* um, theoritically, it is impossible for splits
@@ -708,32 +830,12 @@ xaccSplitOrder (Split **sa, Split **sb)
/* otherwise, sort on memo strings */
da = (*sa)->memo;
db = (*sb)->memo;
if (da && db) {
retval = strcmp (da, db);
/* if strings differ, return */
if (retval) return retval;
} else
if (!da && db) {
return -1;
} else
if (da && !db) {
return +1;
}
SAFE_STRCMP (da, db);
/* otherwise, sort on action strings */
da = (*sa)->action;
db = (*sb)->action;
if (da && db) {
retval = strcmp (da, db);
/* if strings differ, return */
if (retval) return retval;
} else
if (!da && db) {
return -1;
} else
if (da && !db) {
return +1;
}
SAFE_STRCMP (da, db);
return 0;
}
@@ -742,7 +844,6 @@ xaccSplitOrder (Split **sa, Split **sb)
int
xaccTransOrder (Transaction **ta, Transaction **tb)
{
int retval;
char *da, *db;
if ( (*ta) && !(*tb) ) return -1;
@@ -772,32 +873,12 @@ xaccTransOrder (Transaction **ta, Transaction **tb)
/* otherwise, sort on transaction strings */
da = (*ta)->num;
db = (*tb)->num;
if (da && db) {
retval = strcmp (da, db);
/* if strings differ, return */
if (retval) return retval;
} else
if (!da && db) {
return -1;
} else
if (da && !db) {
return +1;
}
SAFE_STRCMP (da, db);
/* otherwise, sort on transaction strings */
da = (*ta)->description;
db = (*tb)->description;
if (da && db) {
retval = strcmp (da, db);
/* if strings differ, return */
if (retval) return retval;
} else
if (!da && db) {
return -1;
} else
if (da && !db) {
return +1;
}
SAFE_STRCMP (da, db);
return 0;
}

View File

@@ -72,7 +72,11 @@ void xaccInitTransaction (Transaction *);/* clears a trans struct */
*/
void xaccTransDestroy (Transaction *);
void xaccTransBeginEdit (Transaction *);
/* The xaccTransBegineEdit() ...
* If the defer flag is set, then automated balancing
* is defered until the commit ...
*/
void xaccTransBeginEdit (Transaction *, int defer);
void xaccTransCommitEdit (Transaction *);
void xaccTransSetDate (Transaction *, int day, int mon, int year);
@@ -164,16 +168,16 @@ void xaccSplitSetReconcile (Split *, char);
* invoking any of them will cause other splits in the transaction
* to be modified so that the net value of the transaction is zero.
*
* The xaccSetShareAmount() method sets the number of shares
* The xaccSplitSetShareAmount() method sets the number of shares
* that the split should have.
*
* The xaccSetSharePrice() method sets the price of the split.
* The xaccSplitSetSharePrice() method sets the price of the split.
*
* The xaccSetValue() method adjusts the number of shares in
* The xaccSplitSetValue() method adjusts the number of shares in
* the split so that the number of shares times the share price
* equals the value passed in.
*
* The xaccSetSharePriceAndAmount() method will simultaneously
* The xaccSplitSetSharePriceAndAmount() method will simultaneously
* update the share price and the number of shares. This
* is a utility routine that is equivalent to a xaccSplitSetSharePrice()
* followed by and xaccSplitSetAmount(), except that it incurs the
@@ -185,6 +189,7 @@ void xaccSplitSetSharePriceAndAmount (Split *, double price,
void xaccSplitSetShareAmount (Split *, double);
void xaccSplitSetSharePrice (Split *, double);
void xaccSplitSetValue (Split *, double);
void xaccSplitSetBaseValue (Split *s, double value, char * base_currency);
/* The following four subroutines return the running balance up
@@ -209,6 +214,8 @@ double xaccSplitGetBalance (Split *);
double xaccSplitGetClearedBalance (Split *);
double xaccSplitGetReconciledBalance (Split *);
double xaccSplitGetShareBalance (Split *);
double xaccSplitGetBaseValue (Split *s, char *base_currency);
/* return the parent transaction of the split */
Transaction * xaccSplitGetParent (Split *);

View File

@@ -70,6 +70,15 @@ dcoresize(void)
}
#endif
/********************************************************************\
\********************************************************************/
int
safe_strcmp (char * da, char * db) {
SAFE_STRCMP (da, db);
return 0;
}
/********************************************************************\
* currency & locale related stuff.
* first attempt at internationalization i18n of currency amounts

View File

@@ -91,6 +91,23 @@ size_t dcoresize();
#define EPS (1.0e-4)
#define DEQ(x,y) (((((x)+EPS)>(y)) ? 1 : 0) && ((((x)-EPS)<(y)) ? 1 : 0))
#define SAFE_STRCMP(da,db) { \
if ((da) && (db)) { \
int retval = strcmp ((da), (db)); \
/* if strings differ, return */ \
if (retval) return retval; \
} else \
if ((!(da)) && (db)) { \
return -1; \
} else \
if ((da) && (!(db))) { \
return +1; \
} \
}
int safe_strcmp (char * da, char * db);
/** PROTOTYPES ******************************************************/
#define PRTSYM 0x1

View File

@@ -81,7 +81,7 @@ add_account_dialog_okclicked_cb(GtkWidget * dialog, gpointer data)
account = xaccMallocAccount();
xaccAccountBeginEdit (account);
xaccAccountBeginEdit (account, 0);
xaccAccountSetName (account, gtk_entry_get_text(GTK_ENTRY(info->textbox_name)));
xaccAccountSetDescription (account, gtk_entry_get_text(GTK_ENTRY(info->textbox_description)));
@@ -91,7 +91,7 @@ add_account_dialog_okclicked_cb(GtkWidget * dialog, gpointer data)
/* Add an opening balance transaction (as the first transaction) */
trans = xaccMallocTransaction();
xaccTransBeginEdit(trans);
xaccTransBeginEdit(trans, 1);
xaccTransSetDateToday (trans);
xaccTransSetDescription (trans, OPEN_BALN_STR);
xaccTransCommitEdit(trans);

View File

@@ -355,9 +355,16 @@ regWindowLedger( xaccLedgerDisplay *ledger)
/* complete GUI initialization */
{
AccountGroup *grp;
Account * base_acc;
grp = xaccGetAccountRoot (ledger->leader);
if (!grp) grp = xaccGetAccountRoot (ledger->displayed_accounts[0]);
xaccLoadXferCell (ledger->ledger->xfrmCell, grp);
base_acc = ledger->leader;
if (!grp) {
grp = xaccGetAccountRoot (ledger->displayed_accounts[0]);
base_acc = ledger->displayed_accounts[0];
}
xaccLoadXferCell (ledger->ledger->xfrmCell, grp, base_acc);
xaccLoadXferCell (ledger->ledger->mxfrmCell, grp, base_acc);
/* xaccLoadXferCell (ledger->ledger->xtoCell, grp); */
}

View File

@@ -158,6 +158,7 @@ configLabels (SplitRegister *reg)
break;
case STOCK_REGISTER:
case PORTFOLIO:
case CURRENCY_REGISTER:
LABEL (DEBT, SOLD_STR);
LABEL (CRED, BOUGHT_STR);
break;
@@ -282,6 +283,7 @@ configLayout (SplitRegister *reg)
/* --------------------------------------------------------- */
case STOCK_REGISTER:
case PORTFOLIO:
case CURRENCY_REGISTER:
{
/* 11 column config */
curs = reg->single_cursor;
@@ -528,6 +530,7 @@ mallocCursors (SplitRegister *reg)
case STOCK_REGISTER:
case PORTFOLIO:
case CURRENCY_REGISTER:
reg->num_cols = 11;
break;
default:

View File

@@ -67,10 +67,11 @@
#define EXPENSE_REGISTER 7
#define EQUITY_REGISTER 8
#define STOCK_REGISTER 9
#define CURRENCY_REGISTER 10
#define GENERAL_LEDGER 10
#define INCOME_LEDGER 11
#define PORTFOLIO 12
#define GENERAL_LEDGER 11
#define INCOME_LEDGER 12
#define PORTFOLIO 13
#define REG_TYPE_MASK 0xff
/*